Skip to content

Commit

Permalink
feat(td-utils): renew output structure of detectProtocolSchemes
Browse files Browse the repository at this point in the history
Signed-off-by: Hasan Eroglu <[email protected]>
  • Loading branch information
hasanheroglu committed Jul 5, 2024
1 parent a19787d commit 3ab15e1
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 114 deletions.
2 changes: 0 additions & 2 deletions node/td-utils/index.js

This file was deleted.

15 changes: 0 additions & 15 deletions node/td-utils/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 1 addition & 5 deletions node/td-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
"@babel/preset-env": "^7.24.7",
"@babel/preset-typescript": "^7.24.7",
"@types/jest": "^29.5.12",
"@types/lodash": "^4.17.6",
"babel-jest": "^29.7.0",
"browserify": "^17.0.0",
"jest": "^28.1.3",
Expand All @@ -33,8 +32,5 @@
"bugs": {
"url": "https://github.com/eclipse-thingweb/td-tools/issues"
},
"homepage": "https://github.com/eclipse-thingweb/td-tools#readme",
"dependencies": {
"lodash": "^4.17.21"
}
"homepage": "https://github.com/eclipse-thingweb/td-tools#readme"
}
105 changes: 61 additions & 44 deletions node/td-utils/src/detectProtocolSchemes.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { uniqWith, isEqual } from "lodash";
import {
AnyUri,
Form,
Expand All @@ -8,10 +7,18 @@ import {
EventElement,
} from "wot-thing-description-types";

export interface ProtocolSchemeMap {
[k: string]: ProtocolScheme[];
}

export interface ProtocolScheme {
uri: string;
subprotocol?: string;
}

export interface HrefInfo {
protocol: string;
hostname: string;
port?: number;
uri: string;
}

type AffordanceElement = { [k: string]: PropertyElement | ActionElement | EventElement };
Expand All @@ -21,97 +28,107 @@ type AffordanceElement = { [k: string]: PropertyElement | ActionElement | EventE
* @param {string} td TD string to detect protocols of
* return List of available protocol schemes
*/
export const detectProtocolSchemes = (td: string): ProtocolScheme[] => {
export const detectProtocolSchemes = (td: string): ProtocolSchemeMap => {
let tdJson: ThingDescription;

const protocolSchemes: ProtocolSchemeMap = {};

try {
tdJson = JSON.parse(td);
} catch (err) {
console.error("Could not parse the TD string.");
return [];
return protocolSchemes;
}

const baseUriProtocol: ProtocolScheme | undefined = tdJson.base ? getHrefData(tdJson.base) : undefined;
const thingProtocols: ProtocolScheme[] = tdJson.forms ? detectProtocolInForms(tdJson.forms) : [];
const actionsProtocols: ProtocolScheme[] = tdJson.actions ? detectProtocolInAffordance(tdJson.actions) : [];
const eventsProtocols: ProtocolScheme[] = tdJson.events ? detectProtocolInAffordance(tdJson.events) : [];
const propertiesProtocols: ProtocolScheme[] = tdJson.properties
? detectProtocolInAffordance(tdJson.properties)
: [];
const protocolSchemes: ProtocolScheme[] = [
...thingProtocols,
...actionsProtocols,
...eventsProtocols,
...propertiesProtocols,
];

if (baseUriProtocol) protocolSchemes.push(baseUriProtocol);

return uniqWith(protocolSchemes, isEqual);
const baseHrefInfo = getHrefInfo(tdJson.base);

addProtocolScheme(protocolSchemes, baseHrefInfo);
detectProtocolInForms(protocolSchemes, tdJson.forms);
detectProtocolInAffordance(protocolSchemes, tdJson.actions);
detectProtocolInAffordance(protocolSchemes, tdJson.events);
detectProtocolInAffordance(protocolSchemes, tdJson.properties);

return protocolSchemes;
};

/**
* Detect protocols in a TD affordance
* @param protocolSchemes Protocol scheme map that the protocol scheme will be added
* @param {object} affordance That belongs to a TD
* @returns List of protocol schemes
*/
const detectProtocolInAffordance = (affordance: AffordanceElement): ProtocolScheme[] => {
const detectProtocolInAffordance = (protocolSchemes: ProtocolSchemeMap, affordance?: AffordanceElement) => {
if (!affordance) {
return [];
return;
}

let protocolSchemes: ProtocolScheme[] = [];

for (const key in affordance) {
if (key) {
protocolSchemes = protocolSchemes.concat(detectProtocolInForms(affordance[key].forms));
detectProtocolInForms(protocolSchemes, affordance[key].forms);
}
}

return protocolSchemes;
};

/**
* Detect protocols in a TD forms or a TD affordance forms
* @param protocolSchemes Protocol scheme map that the protocol scheme will be added
* @param {object} forms Forms field of a TD or a TD affordance
* @returns List of protocol schemes
*/
const detectProtocolInForms = (forms: Form[]): ProtocolScheme[] => {
const detectProtocolInForms = (protocolSchemes: ProtocolSchemeMap, forms?: Form[]) => {
if (!forms) {
return [];
return;
}

const protocolSchemes: ProtocolScheme[] = [];

forms.forEach((form) => {
const hrefData = getHrefData(form.href);
const hrefInfo = getHrefInfo(form.href);

if (hrefData) protocolSchemes.push(hrefData);
addProtocolScheme(protocolSchemes, hrefInfo, form.subprotocol);
});

return protocolSchemes;
};

/**
* Get href data
* @param {string} href URI string
* @returns an object with protocol, hostname and port
*/
const getHrefData = (href: AnyUri): ProtocolScheme | undefined => {
const getHrefInfo = (href?: AnyUri): HrefInfo | undefined => {
if (!href) {
return;
}

const splitHref = href.split(":");
const hostAndPort = href.split("/")[2];
const splitHostAndPort = hostAndPort.split(":");
const uri = href.split("/")[2];
const protocol = splitHref[0];
const hostname = splitHostAndPort[0];
const port = splitHostAndPort[1] ? Number(splitHostAndPort[1]) : undefined;

return {
protocol,
hostname,
port,
uri: protocol + "://" + uri,
};
};

/**
*
* @param protocolSchemes Protocol scheme map that the protocol scheme will be added
* @param hrefInfo Protocol scheme's information that is extracted from the href
* @param subprotocol Subprotocol of the protocol scheme
*/
const addProtocolScheme = (protocolSchemes: ProtocolSchemeMap, hrefInfo?: HrefInfo, subprotocol?: string) => {
if (hrefInfo) {
const protocolScheme = {
uri: hrefInfo.uri,
subprotocol: subprotocol,
};

if (protocolSchemes[hrefInfo.protocol]) {
const schemeExists =
protocolSchemes[hrefInfo.protocol].filter(
(s) => s.uri === protocolScheme.uri && s.subprotocol === protocolScheme.subprotocol
).length > 0;

if (!schemeExists) protocolSchemes[hrefInfo.protocol].push(protocolScheme);
} else {
protocolSchemes[hrefInfo.protocol] = [protocolScheme];
}
}
};
59 changes: 18 additions & 41 deletions node/td-utils/test/protocol-detection.test.suite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,62 +8,39 @@ export const testSuite = [
{
name: "httpAndMqtt",
input: httpAndMqtt,
expected: [
{
protocol: "http",
hostname: "mylamp.example.com",
port: 1234,
},
{
protocol: "mqtt",
hostname: "mylamp.example.com",
port: 1234,
},
],
expected: {
http: [{ uri: "http://mylamp.example.com:1234" }],
mqtt: [{ uri: "mqtt://mylamp.example.com:1234" }],
},
},
{
name: "noProtocol",
input: noProtocol,
expected: [],
expected: {},
},
{
name: "onlyHttp",
input: onlyHttp,
expected: [
{
protocol: "http",
hostname: "mylamp.example.com",
port: 4212,
},
{
protocol: "http",
hostname: "mylamp.example.com",
port: 4214,
},
],
expected: {
http: [
{ uri: "http://mylamp.example.com:4212" },
{ uri: "http://mylamp.example.com:4214", subprotocol: "longpoll" },
],
},
},
{
name: "onlyMqtt",
input: onlyMqtt,
expected: [
{
protocol: "mqtt",
hostname: "mylamp.example.com",
},
],
expected: {
mqtt: [{ uri: "mqtt://mylamp.example.com" }, { uri: "mqtt://mylamp.example.com", subprotocol: "longpoll" }],
},
},
{
name: "secureProtocols",
input: secureProtocols,
expected: [
{
protocol: "https",
hostname: "mylamp.example.com",
},
{
protocol: "mqtts",
hostname: "mylamp.example.com",
},
],
expected: {
https: [{ uri: "https://mylamp.example.com", subprotocol: "longpoll" }],
mqtts: [{ uri: "mqtts://mylamp.example.com" }],
},
},
];
11 changes: 4 additions & 7 deletions node/td-utils/test/protocol-detection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
*
* SPDX-License-Identifier: EPL-2.0 OR W3C-20150513
*/
import { detectProtocolSchemes, ProtocolScheme } from "../src/detectProtocolSchemes";
import { detectProtocolSchemes, ProtocolSchemeMap } from "../src/detectProtocolSchemes";
import { ThingDescription } from "wot-thing-description-types";
import { testSuite } from "./protocol-detection.test.suite";

export type ThingDescriptionTest = ThingDescription & { protocolSchemes: ProtocolScheme[] };
export type ThingDescriptionTest = ThingDescription & { protocolSchemes: ProtocolSchemeMap[] };

describe("test examples", () => {
testSuite.forEach((t) => {
Expand All @@ -26,11 +26,8 @@ describe("test examples", () => {
});
});

const testTD = (td: any, expected: ProtocolScheme[]) => {
const testTD = (td: any, expected: ProtocolSchemeMap[]) => {
const detectedProtocolSchemes = detectProtocolSchemes(JSON.stringify(td));

expect(detectedProtocolSchemes.length).toBe(expected.length);
expected.forEach((s: ProtocolScheme) => {
expect(detectedProtocolSchemes).toContainEqual(s);
});
expect(detectedProtocolSchemes).toMatchObject(expected);
};

0 comments on commit 3ab15e1

Please sign in to comment.