Documentation should be done

This commit is contained in:
Daniel Kluge
2023-11-02 18:29:04 +01:00
parent 591cf6662b
commit 819a0b1a72
21 changed files with 571 additions and 29 deletions
+129
View File
@@ -15,6 +15,9 @@
}, },
"devDependencies": { "devDependencies": {
"@types/express": "^4.17.20", "@types/express": "^4.17.20",
"typedoc": "^0.25.3",
"typedoc-plugin-extras": "^3.0.0",
"typedoc-plugin-rename-defaults": "^0.7.0",
"typescript": "^5.2.2" "typescript": "^5.2.2"
} }
}, },
@@ -29,6 +32,9 @@
"devDependencies": { "devDependencies": {
"@types/node": "^20.8.2", "@types/node": "^20.8.2",
"@types/uuid": "^9.0.6", "@types/uuid": "^9.0.6",
"typedoc": "^0.25.3",
"typedoc-plugin-extras": "^3.0.0",
"typedoc-plugin-rename-defaults": "^0.7.0",
"typescript": "^5.2.2" "typescript": "^5.2.2"
} }
}, },
@@ -172,6 +178,12 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/ansi-sequence-parser": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.1.tgz",
"integrity": "sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==",
"dev": true
},
"node_modules/array-flatten": { "node_modules/array-flatten": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
@@ -317,6 +329,18 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/camelcase": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz",
"integrity": "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==",
"dev": true,
"engines": {
"node": ">=16"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/commist": { "node_modules/commist": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/commist/-/commist-3.2.0.tgz", "resolved": "https://registry.npmjs.org/commist/-/commist-3.2.0.tgz",
@@ -837,6 +861,12 @@
"url": "https://opencollective.com/js-sdsl" "url": "https://opencollective.com/js-sdsl"
} }
}, },
"node_modules/jsonc-parser": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz",
"integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==",
"dev": true
},
"node_modules/lru-cache": { "node_modules/lru-cache": {
"version": "7.18.3", "version": "7.18.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
@@ -845,6 +875,24 @@
"node": ">=12" "node": ">=12"
} }
}, },
"node_modules/lunr": {
"version": "2.3.9",
"resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz",
"integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==",
"dev": true
},
"node_modules/marked": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz",
"integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==",
"dev": true,
"bin": {
"marked": "bin/marked.js"
},
"engines": {
"node": ">= 12"
}
},
"node_modules/media-typer": { "node_modules/media-typer": {
"version": "0.3.0", "version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@@ -1188,6 +1236,18 @@
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
}, },
"node_modules/shiki": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.5.tgz",
"integrity": "sha512-1gCAYOcmCFONmErGTrS1fjzJLA7MGZmKzrBNX7apqSwhyITJg2O102uFzXUeBxNnEkDA9vHIKLyeKq0V083vIw==",
"dev": true,
"dependencies": {
"ansi-sequence-parser": "^1.1.0",
"jsonc-parser": "^3.2.0",
"vscode-oniguruma": "^1.7.0",
"vscode-textmate": "^8.0.0"
}
},
"node_modules/side-channel": { "node_modules/side-channel": {
"version": "1.0.4", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
@@ -1274,6 +1334,63 @@
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="
}, },
"node_modules/typedoc": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.3.tgz",
"integrity": "sha512-Ow8Bo7uY1Lwy7GTmphRIMEo6IOZ+yYUyrc8n5KXIZg1svpqhZSWgni2ZrDhe+wLosFS8yswowUzljTAV/3jmWw==",
"dev": true,
"dependencies": {
"lunr": "^2.3.9",
"marked": "^4.3.0",
"minimatch": "^9.0.3",
"shiki": "^0.14.1"
},
"bin": {
"typedoc": "bin/typedoc"
},
"engines": {
"node": ">= 16"
},
"peerDependencies": {
"typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x"
}
},
"node_modules/typedoc-plugin-extras": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/typedoc-plugin-extras/-/typedoc-plugin-extras-3.0.0.tgz",
"integrity": "sha512-eiAe3qtm2WbV5owdncpt0zHZPqsNZH2mzNGILPd4zqrvEZie3Et9es4cpGZ+8lHO/SI0pVKwsAj7IuMxPNOdYg==",
"dev": true,
"peerDependencies": {
"typedoc": "0.25.x"
}
},
"node_modules/typedoc-plugin-rename-defaults": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/typedoc-plugin-rename-defaults/-/typedoc-plugin-rename-defaults-0.7.0.tgz",
"integrity": "sha512-NudSQ1o/XLHNF9c4y7LzIZxfE9ltz09yCDklBPJpP5VMRvuBpYGIbQ0ZgmPz+EIV8vPx9Z/OyKwzp4HT2vDtfg==",
"dev": true,
"dependencies": {
"camelcase": "^8.0.0"
},
"peerDependencies": {
"typedoc": "0.22.x || 0.23.x || 0.24.x || 0.25.x"
}
},
"node_modules/typedoc/node_modules/minimatch": {
"version": "9.0.3",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
"integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
"dev": true,
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=16 || 14 >=14.17"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/typescript": { "node_modules/typescript": {
"version": "5.2.2", "version": "5.2.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
@@ -1321,6 +1438,18 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/vscode-oniguruma": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz",
"integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==",
"dev": true
},
"node_modules/vscode-textmate": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz",
"integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==",
"dev": true
},
"node_modules/wrappy": { "node_modules/wrappy": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+4
View File
@@ -5,6 +5,7 @@
"main": "dist/index.js", "main": "dist/index.js",
"scripts": { "scripts": {
"build": "npx tsc", "build": "npx tsc",
"docs": "npx typedoc",
"start": "node dist/index.js", "start": "node dist/index.js",
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
@@ -31,6 +32,9 @@
"license": "ISC", "license": "ISC",
"devDependencies": { "devDependencies": {
"@types/express": "^4.17.20", "@types/express": "^4.17.20",
"typedoc": "^0.25.3",
"typedoc-plugin-extras": "^3.0.0",
"typedoc-plugin-rename-defaults": "^0.7.0",
"typescript": "^5.2.2" "typescript": "^5.2.2"
}, },
"dependencies": { "dependencies": {
+14
View File
@@ -3,6 +3,20 @@ import { MultiMessageBroker, FileImporter } from "aas-multimessagebroker";
import HTTPInterfaceServer from "./modules/httpInterfaceServer"; import HTTPInterfaceServer from "./modules/httpInterfaceServer";
import MQTTConnector from "./modules/mqttConnector"; import MQTTConnector from "./modules/mqttConnector";
/**
* This is an example of how to use the MultiMessageBroker.
* It creates a sample interface and connector and registers them to the broker, then starts it.
*
* @remarks
* In this package a {@link HTTPInterfaceServer} is used to serve the Asset Administration Shell API interface.
* To connect to the asset a {@link MQTTConnector} was created.
* The asset is a Python script located outside of this repository which sends the current timestamp as two parameters.
* The AAS-Package is defined in the file ../owntest.json.
* It was created using the {@link https://github.com/admin-shell-io/aasx-package-explorer|aasx-package-explorer}.
*
* @packageDocumentation
*/
// First we need to import the AAS Package // First we need to import the AAS Package
// It was created using the aasx-package-explorer (https://github.com/admin-shell-io/aasx-package-explorer) // It was created using the aasx-package-explorer (https://github.com/admin-shell-io/aasx-package-explorer)
const aas = FileImporter.readAASByPath("../owntest.json"); const aas = FileImporter.readAASByPath("../owntest.json");
+22 -2
View File
@@ -18,8 +18,20 @@ export type Config = {
* @see {@link aas-multimessagebroker#AbstractInterfaceServer|AbstractInterfaceServer} * @see {@link aas-multimessagebroker#AbstractInterfaceServer|AbstractInterfaceServer}
*/ */
export default class HTTPInterfaceServer extends AbstractInterfaceServer<Config> { export default class HTTPInterfaceServer extends AbstractInterfaceServer<Config> {
public static serverInterfaceName: string = "HTTPInterfaceServer"; /**
public static supportsSubscriptions: boolean = false; // TODO, longpolling? * Server name
* @override
* @readonly
* @alpha
*/
public static readonly serverInterfaceName: string = "HTTPInterfaceServer";
/**
* Whether the server supports subscriptions
* @override
* @readonly
* @alpha
*/
public static readonly supportsSubscriptions: boolean = false; // TODO, longpolling?
/** /**
* This is the {@link express#Express|express app}. * This is the {@link express#Express|express app}.
@@ -39,6 +51,8 @@ export default class HTTPInterfaceServer extends AbstractInterfaceServer<Config>
* *
* @remarks * @remarks
* This is called before the server is started. * This is called before the server is started.
* @override
* @public
*/ */
public prepare(): void { public prepare(): void {
this.app.use(express.json()); this.app.use(express.json());
@@ -47,6 +61,8 @@ export default class HTTPInterfaceServer extends AbstractInterfaceServer<Config>
/** /**
* This should start the server. * This should start the server.
* @override
* @public
*/ */
public run(): void { public run(): void {
this.server = this.app.listen(this.config.bindPort, this.config.bindAddress, () => { this.server = this.app.listen(this.config.bindPort, this.config.bindAddress, () => {
@@ -56,6 +72,8 @@ export default class HTTPInterfaceServer extends AbstractInterfaceServer<Config>
/** /**
* This should stop the server. * This should stop the server.
* @override
* @public
*/ */
public stop(): void { public stop(): void {
if (this.server && this.server.close) this.server.close(); if (this.server && this.server.close) this.server.close();
@@ -63,6 +81,8 @@ export default class HTTPInterfaceServer extends AbstractInterfaceServer<Config>
/** /**
* This should call notify all observers * This should call notify all observers
* @override
* @public
*/ */
public notify(event: any): void { public notify(event: any): void {
this.observers.forEach(observer => { this.observers.forEach(observer => {
+50 -2
View File
@@ -11,9 +11,35 @@ import type { AASCoreTypes } from "aas-multimessagebroker";
* @see {@link aas-multimessagebroker#AbstractConnectionObject|AbstractConnectionObject} * @see {@link aas-multimessagebroker#AbstractConnectionObject|AbstractConnectionObject}
*/ */
export default class MQTTConnector extends AbstractConnectionObject<mqtt.IClientOptions> { export default class MQTTConnector extends AbstractConnectionObject<mqtt.IClientOptions> {
/**
* A name for your connector. Not used yet.
* @override
* @public
* @readonly
* @alpha
*/
public static readonly connectorName: string = "MQTT Connector"; public static readonly connectorName: string = "MQTT Connector";
/**
* The protocol(s) your connector supports. Absolutely critical so the broker knows which connector to use.
* @override
* @public
*/
public static readonly uriProtocol: string[] = ["mqtt", "mqtts"]; public static readonly uriProtocol: string[] = ["mqtt", "mqtts"];
/**
* The type of connection your connector uses. Either "ON_DEMAND" or "PERMANENT".
* @override
* @public
* @readonly
* @alpha
*/
public static readonly connectionType: "ON_DEMAND" | "PERMANENT" = "PERMANENT"; public static readonly connectionType: "ON_DEMAND" | "PERMANENT" = "PERMANENT";
/**
* Whether your connector supports subscriptions.
* @override
* @public
* @readonly
* @alpha
*/
public static readonly supportsSubscriptions: boolean = true; public static readonly supportsSubscriptions: boolean = true;
/** /**
@@ -26,13 +52,15 @@ export default class MQTTConnector extends AbstractConnectionObject<mqtt.IClient
*/ */
private readonly messageStore: Record<string, any> = {}; private readonly messageStore: Record<string, any> = {};
/** /**
* This should connect the Connector to the asset. * This should connect the Connector to the asset.
* *
* @remarks For async connections like HTTP you can just return true and do the connection on demand. * @remarks
* For async connections like HTTP you can just return true and do the connection on demand.
* *
* @returns Whether the connection was successful. * @returns Whether the connection was successful.
* @override
* @public
*/ */
public connect(): boolean { public connect(): boolean {
if (!this.client) this.client = mqtt.connect(this.endpointMetadata.base, this.connectionParameter); if (!this.client) this.client = mqtt.connect(this.endpointMetadata.base, this.connectionParameter);
@@ -51,6 +79,8 @@ export default class MQTTConnector extends AbstractConnectionObject<mqtt.IClient
/** /**
* This should disconnect the Connector from the asset (if it even is connected). * This should disconnect the Connector from the asset (if it even is connected).
* @override
* @public
*/ */
public disconnect(): void { public disconnect(): void {
if (this.client) this.client.end(); if (this.client) this.client.end();
@@ -65,6 +95,8 @@ export default class MQTTConnector extends AbstractConnectionObject<mqtt.IClient
* *
* @param prop Property * @param prop Property
* @returns Value of property casted to the type it says it should be. * @returns Value of property casted to the type it says it should be.
* @override
* @public
*/ */
public readProperty(prop: AASCoreTypes.Property): any { public readProperty(prop: AASCoreTypes.Property): any {
const cc = this.mapper.get(prop); const cc = this.mapper.get(prop);
@@ -94,6 +126,8 @@ export default class MQTTConnector extends AbstractConnectionObject<mqtt.IClient
* @param prop Property * @param prop Property
* @param value Value * @param value Value
* @returns Whether the write was successful. * @returns Whether the write was successful.
* @override
* @public
*/ */
public writeProperty(prop: AASCoreTypes.Property, value: any): boolean { public writeProperty(prop: AASCoreTypes.Property, value: any): boolean {
const cc = this.mapper.get(prop); const cc = this.mapper.get(prop);
@@ -112,6 +146,8 @@ export default class MQTTConnector extends AbstractConnectionObject<mqtt.IClient
* @param prop Property * @param prop Property
* @param callback Callback on change * @param callback Callback on change
* @returns Whether the observer was created successfully. * @returns Whether the observer was created successfully.
* @override
* @public
*/ */
public observeProperty(prop: AASCoreTypes.Property, callback: (value: any) => void): boolean { public observeProperty(prop: AASCoreTypes.Property, callback: (value: any) => void): boolean {
const cc = this.mapper.get(prop); const cc = this.mapper.get(prop);
@@ -130,6 +166,9 @@ export default class MQTTConnector extends AbstractConnectionObject<mqtt.IClient
* @param args Arguments * @param args Arguments
* *
* @returns Return value of action. * @returns Return value of action.
* @override
* @public
* @alpha
*/ */
public callActionSync(action: AASCoreTypes.Operation, args: Record<string, any>): any { public callActionSync(action: AASCoreTypes.Operation, args: Record<string, any>): any {
// TODO // TODO
@@ -144,6 +183,9 @@ export default class MQTTConnector extends AbstractConnectionObject<mqtt.IClient
* @param args Arguments * @param args Arguments
* *
* @returns Handle (uuid) for the result or null if it fails. * @returns Handle (uuid) for the result or null if it fails.
* @override
* @public
* @alpha
*/ */
public callActionAsync(action: AASCoreTypes.Operation, args: Record<string, any>): string | null { public callActionAsync(action: AASCoreTypes.Operation, args: Record<string, any>): string | null {
// TODO // TODO
@@ -157,6 +199,9 @@ export default class MQTTConnector extends AbstractConnectionObject<mqtt.IClient
* @param event Event * @param event Event
* @param callback Callback onEvent * @param callback Callback onEvent
* @returns Whether the subscription was successful. * @returns Whether the subscription was successful.
* @override
* @public
* @alpha
*/ */
public subscribeEvent(event: AASCoreTypes.BasicEventElement, callback: (event: AASCoreTypes.BasicEventElement) => void): boolean { public subscribeEvent(event: AASCoreTypes.BasicEventElement, callback: (event: AASCoreTypes.BasicEventElement) => void): boolean {
// TODO // TODO
@@ -168,6 +213,9 @@ export default class MQTTConnector extends AbstractConnectionObject<mqtt.IClient
/** /**
* Unsubscribe from an event. * Unsubscribe from an event.
* @param event Event * @param event Event
* @override
* @public
* @alpha
*/ */
public unsubscribeEvent(event: AASCoreTypes.BasicEventElement): void { public unsubscribeEvent(event: AASCoreTypes.BasicEventElement): void {
// TODO // TODO
+1 -1
View File
@@ -51,7 +51,7 @@
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
/* Emit */ /* Emit */
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
// "declarationMap": true, /* Create sourcemaps for d.ts files. */ // "declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */ // "sourceMap": true, /* Create source map files for emitted JavaScript files. */
+9
View File
@@ -0,0 +1,9 @@
{
"$schema": "https://typedoc.org/schema.json",
"entryPoints": ["./src/index.ts"],
"out": "docs",
"plugin": ["typedoc-plugin-extras", "typedoc-plugin-rename-defaults"],
"footerLastModified": true,
"footerTypedocVersion": true,
"customTitle": "Multimessagebroker Usage Example"
}
+57
View File
@@ -16,6 +16,8 @@
"@types/node": "^20.8.2", "@types/node": "^20.8.2",
"@types/uuid": "^9.0.6", "@types/uuid": "^9.0.6",
"typedoc": "^0.25.3", "typedoc": "^0.25.3",
"typedoc-plugin-extras": "^3.0.0",
"typedoc-plugin-rename-defaults": "^0.7.0",
"typescript": "^5.2.2" "typescript": "^5.2.2"
} }
}, },
@@ -57,6 +59,18 @@
"balanced-match": "^1.0.0" "balanced-match": "^1.0.0"
} }
}, },
"node_modules/camelcase": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz",
"integrity": "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==",
"dev": true,
"engines": {
"node": ">=16"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/jsonc-parser": { "node_modules/jsonc-parser": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz",
@@ -129,6 +143,27 @@
"typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x" "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x"
} }
}, },
"node_modules/typedoc-plugin-extras": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/typedoc-plugin-extras/-/typedoc-plugin-extras-3.0.0.tgz",
"integrity": "sha512-eiAe3qtm2WbV5owdncpt0zHZPqsNZH2mzNGILPd4zqrvEZie3Et9es4cpGZ+8lHO/SI0pVKwsAj7IuMxPNOdYg==",
"dev": true,
"peerDependencies": {
"typedoc": "0.25.x"
}
},
"node_modules/typedoc-plugin-rename-defaults": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/typedoc-plugin-rename-defaults/-/typedoc-plugin-rename-defaults-0.7.0.tgz",
"integrity": "sha512-NudSQ1o/XLHNF9c4y7LzIZxfE9ltz09yCDklBPJpP5VMRvuBpYGIbQ0ZgmPz+EIV8vPx9Z/OyKwzp4HT2vDtfg==",
"dev": true,
"dependencies": {
"camelcase": "^8.0.0"
},
"peerDependencies": {
"typedoc": "0.22.x || 0.23.x || 0.24.x || 0.25.x"
}
},
"node_modules/typescript": { "node_modules/typescript": {
"version": "5.2.2", "version": "5.2.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
@@ -206,6 +241,12 @@
"balanced-match": "^1.0.0" "balanced-match": "^1.0.0"
} }
}, },
"camelcase": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz",
"integrity": "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==",
"dev": true
},
"jsonc-parser": { "jsonc-parser": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz",
@@ -257,6 +298,22 @@
"shiki": "^0.14.1" "shiki": "^0.14.1"
} }
}, },
"typedoc-plugin-extras": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/typedoc-plugin-extras/-/typedoc-plugin-extras-3.0.0.tgz",
"integrity": "sha512-eiAe3qtm2WbV5owdncpt0zHZPqsNZH2mzNGILPd4zqrvEZie3Et9es4cpGZ+8lHO/SI0pVKwsAj7IuMxPNOdYg==",
"dev": true,
"requires": {}
},
"typedoc-plugin-rename-defaults": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/typedoc-plugin-rename-defaults/-/typedoc-plugin-rename-defaults-0.7.0.tgz",
"integrity": "sha512-NudSQ1o/XLHNF9c4y7LzIZxfE9ltz09yCDklBPJpP5VMRvuBpYGIbQ0ZgmPz+EIV8vPx9Z/OyKwzp4HT2vDtfg==",
"dev": true,
"requires": {
"camelcase": "^8.0.0"
}
},
"typescript": { "typescript": {
"version": "5.2.2", "version": "5.2.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
+3
View File
@@ -5,6 +5,7 @@
"main": "dist/index.js", "main": "dist/index.js",
"scripts": { "scripts": {
"build": "npx tsc", "build": "npx tsc",
"docs": "npx typedoc",
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"keywords": [ "keywords": [
@@ -33,6 +34,8 @@
"@types/node": "^20.8.2", "@types/node": "^20.8.2",
"@types/uuid": "^9.0.6", "@types/uuid": "^9.0.6",
"typedoc": "^0.25.3", "typedoc": "^0.25.3",
"typedoc-plugin-extras": "^3.0.0",
"typedoc-plugin-rename-defaults": "^0.7.0",
"typescript": "^5.2.2" "typescript": "^5.2.2"
}, },
"dependencies": { "dependencies": {
+13 -6
View File
@@ -1,25 +1,27 @@
import { types } from "@aas-core-works/aas-core3.0-typescript"; import type { types } from "@aas-core-works/aas-core3.0-typescript";
import { ConnectionConfiguration, AIMCMap } from "./types/aimcConf"; import type { ConnectionConfiguration, AIMCMap } from "./types/aimcConf";
import AIMCParser from "./parser/AIMCParser"; import AIMCParser from "./parser/AIMCParser";
import Traverser from "./helper/traverser"; import Traverser from "./helper/traverser";
import AIDParser from "./parser/AIDParser"; import AIDParser from "./parser/AIDParser";
import { SubmodelElementCollection } from "@aas-core-works/aas-core3.0-typescript/dist/types/types";
/** /**
* The AIMC Mapper. * The AIMC Mapper.
* @remarks * @remarks
* This class is used to map properties t endpoints. * This class is used to map properties to endpoints.
* @public
*/ */
export default class AIMCMapper { export default class AIMCMapper {
/** /**
* The map. * The map.
* @private
*/ */
private map: AIMCMap = new Map(); private map: AIMCMap = new Map();
/** /**
* Creates the mapper. * Creates the mapper.
* @param env The AAS Environment * @param env The AAS Environment
* @public
*/ */
public constructor(private readonly env: types.Environment) { public constructor(private readonly env: types.Environment) {
this.generate(); this.generate();
@@ -27,6 +29,7 @@ export default class AIMCMapper {
/** /**
* Generates the map from the AAS Environment. * Generates the map from the AAS Environment.
* @private
*/ */
private generate(): void { private generate(): void {
const aimc = AIMCParser.parse(this.env); const aimc = AIMCParser.parse(this.env);
@@ -48,11 +51,11 @@ export default class AIMCMapper {
let {first, second} = resolved; let {first, second} = resolved;
let parsedPropConf = AIDParser.parseInterfaceMetadataProperty(first as SubmodelElementCollection); let parsedPropConf = AIDParser.parseInterfaceMetadataProperty(first as types.SubmodelElementCollection);
if (parsedPropConf === null) { if (parsedPropConf === null) {
// maybe the property is in the first element // maybe the property is in the first element
[first, second] = [second, first]; [first, second] = [second, first];
parsedPropConf = AIDParser.parseInterfaceMetadataProperty(first as SubmodelElementCollection); parsedPropConf = AIDParser.parseInterfaceMetadataProperty(first as types.SubmodelElementCollection);
} }
if (parsedPropConf === null) continue; if (parsedPropConf === null) continue;
@@ -69,6 +72,7 @@ export default class AIMCMapper {
/** /**
* *
* @returns The complete map * @returns The complete map
* @public
*/ */
public getMap(): AIMCMap { public getMap(): AIMCMap {
return this.map; return this.map;
@@ -78,6 +82,7 @@ export default class AIMCMapper {
* Get endpoint for a specific Element * Get endpoint for a specific Element
* @param element Element * @param element Element
* @returns Endpoint description or undefined if not found * @returns Endpoint description or undefined if not found
* @public
*/ */
public get(element: types.Class): ConnectionConfiguration | undefined { public get(element: types.Class): ConnectionConfiguration | undefined {
return this.map.get(element); return this.map.get(element);
@@ -88,6 +93,7 @@ export default class AIMCMapper {
* Can return multiple as idShorts are not necessarily unique * Can return multiple as idShorts are not necessarily unique
* @param idShort idShort of the element * @param idShort idShort of the element
* @returns Endpoints descriptions of elements with that idShort * @returns Endpoints descriptions of elements with that idShort
* @public
*/ */
public getByIdShort(idShort: string): ConnectionConfiguration[] { public getByIdShort(idShort: string): ConnectionConfiguration[] {
const result = []; const result = [];
@@ -101,6 +107,7 @@ export default class AIMCMapper {
* Get an element by its endpoint * Get an element by its endpoint
* @param path Absolute endpoint path * @param path Absolute endpoint path
* @returns Elements that use that path * @returns Elements that use that path
* @public
*/ */
public reverseGet(path: string): types.Class[] { public reverseGet(path: string): types.Class[] {
const result = []; const result = [];
+4
View File
@@ -4,6 +4,7 @@ import { types, jsonization } from "@aas-core-works/aas-core3.0-typescript";
/** /**
* Helper class to import AAS-Environments from files. * Helper class to import AAS-Environments from files.
* @public
*/ */
export default class FileImporter { export default class FileImporter {
@@ -13,6 +14,7 @@ export default class FileImporter {
* @returns Environment * @returns Environment
* @throws Error if file is not a JSON file * @throws Error if file is not a JSON file
* @throws Any IO error on file read operation * @throws Any IO error on file read operation
* @public
*/ */
public static readAASByPath(path: string): types.Environment { public static readAASByPath(path: string): types.Environment {
if (!path.endsWith(".json")) throw new Error("File must be a JSON file"); if (!path.endsWith(".json")) throw new Error("File must be a JSON file");
@@ -30,6 +32,7 @@ export default class FileImporter {
* Import all AAS-Environments from a directory. * Import all AAS-Environments from a directory.
* @param path Directory path * @param path Directory path
* @returns Environments * @returns Environments
* @public
*/ */
public static readAllAASFromPath(path: string): types.Environment[] { public static readAllAASFromPath(path: string): types.Environment[] {
@@ -47,6 +50,7 @@ export default class FileImporter {
* Get all JSON files from a directory. * Get all JSON files from a directory.
* @param aasPath Directory path * @param aasPath Directory path
* @returns Paths of the JSON files * @returns Paths of the JSON files
* @private
*/ */
private static getAllAASFilePaths(aasPath: string): string[] { private static getAllAASFilePaths(aasPath: string): string[] {
const files = readdirSync(aasPath); const files = readdirSync(aasPath);
+10
View File
@@ -10,6 +10,7 @@ const GLOBALLY_IDENTIFIABLES = [types.KeyTypes.GlobalReference, types.KeyTypes.A
/** /**
* Helper to traverse the AAS-Environment. * Helper to traverse the AAS-Environment.
* @public
*/ */
export default class Traverser { export default class Traverser {
@@ -18,6 +19,7 @@ export default class Traverser {
* @param environment Environment to search in * @param environment Environment to search in
* @param id ID * @param id ID
* @returns AAS or null if not found * @returns AAS or null if not found
* @public
*/ */
public static findAASById(environment: types.Environment, id: string): types.AssetAdministrationShell | null { public static findAASById(environment: types.Environment, id: string): types.AssetAdministrationShell | null {
if (environment.assetAdministrationShells === null) return null; if (environment.assetAdministrationShells === null) return null;
@@ -30,6 +32,7 @@ export default class Traverser {
* @param environment Environment to search in * @param environment Environment to search in
* @param id ID * @param id ID
* @returns Submodel or null if not found * @returns Submodel or null if not found
* @public
*/ */
public static findSMById(environment: types.Environment, id: string): types.Submodel | null { public static findSMById(environment: types.Environment, id: string): types.Submodel | null {
if (environment.submodels === null) return null; if (environment.submodels === null) return null;
@@ -42,6 +45,7 @@ export default class Traverser {
* @param environment Environment to search in * @param environment Environment to search in
* @param id idShort * @param id idShort
* @returns Submodel or null if not found * @returns Submodel or null if not found
* @public
*/ */
public static findSMByIdShort(environment: types.Environment, id: string): types.Submodel | null { public static findSMByIdShort(environment: types.Environment, id: string): types.Submodel | null {
if (environment.submodels === null) return null; if (environment.submodels === null) return null;
@@ -54,6 +58,7 @@ export default class Traverser {
* @param env Environment to search in * @param env Environment to search in
* @param ref Reference * @param ref Reference
* @returns Element or null if not found * @returns Element or null if not found
* @public
*/ */
public static resolveReference(env: types.Environment, ref: types.Reference): types.Class | null { public static resolveReference(env: types.Environment, ref: types.Reference): types.Class | null {
if (ref.type === types.ReferenceTypes.ExternalReference) return null; // Not implemented if (ref.type === types.ReferenceTypes.ExternalReference) return null; // Not implemented
@@ -77,6 +82,7 @@ export default class Traverser {
* @param env Environment to search in * @param env Environment to search in
* @param relationship Relationship element * @param relationship Relationship element
* @returns Resolved relationship element or null if not found * @returns Resolved relationship element or null if not found
* @public
*/ */
public static resolveRelationship(env: types.Environment, relationship: RelationshipElement): ResolvedRelationshipElement | null { public static resolveRelationship(env: types.Environment, relationship: RelationshipElement): ResolvedRelationshipElement | null {
const first = Traverser.resolveReference(env, relationship.first); const first = Traverser.resolveReference(env, relationship.first);
@@ -91,6 +97,7 @@ export default class Traverser {
* @param start Start element * @param start Start element
* @param idShorts Array of idShorts to traverse by * @param idShorts Array of idShorts to traverse by
* @returns Target element at the end of the path or null if not found * @returns Target element at the end of the path or null if not found
* @public
*/ */
public static traverseByShortIds(start: types.Class, idShorts: string[]): types.Class | null { public static traverseByShortIds(start: types.Class, idShorts: string[]): types.Class | null {
let current: types.Class | null = start; let current: types.Class | null = start;
@@ -109,6 +116,7 @@ export default class Traverser {
* @param submodelOrIdShort Submodel element or Submodel idShort * @param submodelOrIdShort Submodel element or Submodel idShort
* @param idShorts idShorts to traverse by * @param idShorts idShorts to traverse by
* @returns Target element at the end of the path or null if not found * @returns Target element at the end of the path or null if not found
* @public
*/ */
public static getElementByIdPath(env: types.Environment, submodelOrIdShort: string | types.Submodel, idShorts: string[]): types.Class | null { public static getElementByIdPath(env: types.Environment, submodelOrIdShort: string | types.Submodel, idShorts: string[]): types.Class | null {
const sm = typeof submodelOrIdShort === "string" ? Traverser.findSMByIdShort(env, submodelOrIdShort) : submodelOrIdShort; const sm = typeof submodelOrIdShort === "string" ? Traverser.findSMByIdShort(env, submodelOrIdShort) : submodelOrIdShort;
@@ -121,6 +129,7 @@ export default class Traverser {
* @param start Start element * @param start Start element
* @param checkFunction Function to find the element. First element which evaluates to true using this function will be returned. * @param checkFunction Function to find the element. First element which evaluates to true using this function will be returned.
* @returns Element or null if not found * @returns Element or null if not found
* @public
*/ */
public static findElement(start: types.Class, checkFunction: (element: types.Class) => boolean): types.Class | null { public static findElement(start: types.Class, checkFunction: (element: types.Class) => boolean): types.Class | null {
for (const element of start.descend()) { for (const element of start.descend()) {
@@ -135,6 +144,7 @@ export default class Traverser {
* @param start Start element * @param start Start element
* @param idShort idShort to search for * @param idShort idShort to search for
* @returns Child element or null if not found * @returns Child element or null if not found
* @public
*/ */
public static findChildByIdShort(start: types.Class, idShort: string): types.Class | null { public static findChildByIdShort(start: types.Class, idShort: string): types.Class | null {
for (const child of start.descendOnce()) { for (const child of start.descendOnce()) {
+14
View File
@@ -8,3 +8,17 @@ export { Traverser, FileImporter } from "./helper";
export { AIDParser, AIMCParser } from "./parser"; export { AIDParser, AIMCParser } from "./parser";
export { jsonization as AASCoreJsonization, types as AASCoreTypes } from "@aas-core-works/aas-core3.0-typescript"; export { jsonization as AASCoreJsonization, types as AASCoreTypes } from "@aas-core-works/aas-core3.0-typescript";
/**
* A modular library for a Multimessagebroker for Industry 4.0 Applications.
* It can be used to create your own modules and run the broker.
*
* @remarks
* This is the library which defines {@link MultiMessageBroker|the logic} used to create {@link AbstractInterfaceServer|server interfaces} to the user (north-bound) following
* the Asset Administration Shell API specification and {@link AbstractConnectionObject|interface connectors} to the asset (south-bound) which
* can be arbitrary but defined in the AssetInterfacesDescription Submodel of the AAS.
* Mappings from the AssetInterfacesMappingConfiguration Submodel of the AAS are used to map specific elements of the AAS
* to dynamic data (using endpoints) of the asset.
*
* @packageDocumentation
*/
+44 -6
View File
@@ -10,42 +10,55 @@ export type OnEventCallback = (response: any) => void
/** /**
* Abstract class for an connector to an asset. * Abstract class for an connector to an asset.
* This should be used as base class for your own connectors. * This should be used as base class for your own connectors.
* @public
*/ */
export default abstract class InterfaceConnectionObject<ConfigInterface> { export default abstract class InterfaceConnectionObject<ConfigInterface> {
/** /**
* A name for your connector. * A name for your connector.
* @remarks * @public
* Currently not used. * @virtual
* @readonly
* @alpha
*/ */
public static readonly connectorName: string; public static readonly connectorName: string;
/** /**
* Which protocols are supported by your connector. * Which protocols are supported by your connector.
* This is really important later so the AAS can decide which connector to use! * This is really important later so the AAS can decide which connector to use!
* @public
* @virtual
* @readonly
*/ */
public static readonly uriProtocol: string[]|string; public static readonly uriProtocol: string[]|string;
/** /**
* The type of connection your connector uses. * The type of connection your connector uses.
* @remarks * @public
* Currently not used. * @virtual
* @readonly
* @alpha
*/ */
public static readonly connectionType: ConnectionType; public static readonly connectionType: ConnectionType;
/** /**
* Whether your connector supports subscriptions. * Whether your connector supports subscriptions.
* @remarks * @public
* Currently not used. * @virtual
* @readonly
* @alpha
*/ */
public static readonly supportsSubscriptions: boolean; public static readonly supportsSubscriptions: boolean;
/** /**
* A store for all observers and their callbacks. * A store for all observers and their callbacks.
* @sealed
*/ */
protected readonly observerStore: Record<any, ((value: any) => void)[]> = {}; protected readonly observerStore: Record<any, ((value: any) => void)[]> = {};
/** /**
* A store for all event subscriptions and their callbacks. * A store for all event subscriptions and their callbacks.
* @sealed
*/ */
protected readonly eventSubStore: Record<any, ((value: any) => void)[]> = {}; protected readonly eventSubStore: Record<any, ((value: any) => void)[]> = {};
/** /**
* A store for all async action handles and their results. * A store for all async action handles and their results.
* @sealed
*/ */
protected readonly asyncActionStateStore: Record<any, {finished: boolean, result: any}> = {}; protected readonly asyncActionStateStore: Record<any, {finished: boolean, result: any}> = {};
@@ -55,6 +68,8 @@ export default abstract class InterfaceConnectionObject<ConfigInterface> {
* @param endpointMetadata {@link EndpointMetadata} * @param endpointMetadata {@link EndpointMetadata}
* @param mapper {@link AIMCMapper} * @param mapper {@link AIMCMapper}
* @param onConnectorEvent Callback when an event is received. * @param onConnectorEvent Callback when an event is received.
* @public
* @sealed
*/ */
public constructor( public constructor(
protected readonly connectionParameter: ConfigInterface, protected readonly connectionParameter: ConfigInterface,
@@ -65,11 +80,15 @@ export default abstract class InterfaceConnectionObject<ConfigInterface> {
/** /**
* This should connect the Connector to the asset. * This should connect the Connector to the asset.
* @returns Whether the connection was successful. * @returns Whether the connection was successful.
* @public
* @virtual
*/ */
public abstract connect(): boolean; public abstract connect(): boolean;
/** /**
* This should disconnect the Connector from the asset (if it even is connected). * This should disconnect the Connector from the asset (if it even is connected).
* @public
* @virtual
*/ */
public abstract disconnect(): void; public abstract disconnect(): void;
@@ -77,6 +96,8 @@ export default abstract class InterfaceConnectionObject<ConfigInterface> {
* Read a property value from the asset. * Read a property value from the asset.
* @param prop Property * @param prop Property
* @returns Value of property casted to the type it says it should be. * @returns Value of property casted to the type it says it should be.
* @public
* @virtual
*/ */
public abstract readProperty(prop: types.Property): void; public abstract readProperty(prop: types.Property): void;
@@ -84,6 +105,8 @@ export default abstract class InterfaceConnectionObject<ConfigInterface> {
* Write a property value to the asset. * Write a property value to the asset.
* @param prop Property * @param prop Property
* @param value Value to write. * @param value Value to write.
* @public
* @virtual
*/ */
public abstract writeProperty(prop: types.Property, value: any): void; public abstract writeProperty(prop: types.Property, value: any): void;
@@ -92,6 +115,8 @@ export default abstract class InterfaceConnectionObject<ConfigInterface> {
* @param prop Property * @param prop Property
* @param callback Callback to call when the property changes. * @param callback Callback to call when the property changes.
* @returns Whether the creation of an observer was successful. * @returns Whether the creation of an observer was successful.
* @public
* @virtual
*/ */
public abstract observeProperty(prop: types.Property, callback: (value: any) => void): boolean; public abstract observeProperty(prop: types.Property, callback: (value: any) => void): boolean;
@@ -100,6 +125,8 @@ export default abstract class InterfaceConnectionObject<ConfigInterface> {
* @param action Action * @param action Action
* @param args Arguments * @param args Arguments
* @returns Return value of the action. * @returns Return value of the action.
* @public
* @virtual
*/ */
public abstract callActionSync(action: types.Operation, args: Record<string, any>): any; public abstract callActionSync(action: types.Operation, args: Record<string, any>): any;
@@ -108,6 +135,8 @@ export default abstract class InterfaceConnectionObject<ConfigInterface> {
* @param action Action * @param action Action
* @param args Arguments * @param args Arguments
* @returns Handle for the async action. * @returns Handle for the async action.
* @public
* @virtual
*/ */
public abstract callActionAsync(action: types.Operation, args: Record<string, any>): string | null; public abstract callActionAsync(action: types.Operation, args: Record<string, any>): string | null;
@@ -115,6 +144,8 @@ export default abstract class InterfaceConnectionObject<ConfigInterface> {
* Read the state of an async action. * Read the state of an async action.
* @param handle Handle of the async action. * @param handle Handle of the async action.
* @returns Whether the async action is finished. * @returns Whether the async action is finished.
* @public
* @virtual
*/ */
public readAsyncActionState(handle: string): boolean { public readAsyncActionState(handle: string): boolean {
return this.asyncActionStateStore[handle].finished; return this.asyncActionStateStore[handle].finished;
@@ -124,6 +155,8 @@ export default abstract class InterfaceConnectionObject<ConfigInterface> {
* Read the result of an async action. * Read the result of an async action.
* @param handle Handle of the async action. * @param handle Handle of the async action.
* @returns Result of the async action. * @returns Result of the async action.
* @public
* @virtual
*/ */
public readAsyncActionResponse(handle: string): any { public readAsyncActionResponse(handle: string): any {
return this.asyncActionStateStore[handle].result; return this.asyncActionStateStore[handle].result;
@@ -134,18 +167,23 @@ export default abstract class InterfaceConnectionObject<ConfigInterface> {
* @param event Event * @param event Event
* @param callback Callback to call when the event occurs. * @param callback Callback to call when the event occurs.
* @returns Whether the subscription was successful. * @returns Whether the subscription was successful.
* @public
* @virtual
*/ */
public abstract subscribeEvent(event: types.BasicEventElement, callback: (event: types.BasicEventElement) => void): boolean; public abstract subscribeEvent(event: types.BasicEventElement, callback: (event: types.BasicEventElement) => void): boolean;
/** /**
* Unsubscribe from an event. * Unsubscribe from an event.
* @param event Event * @param event Event
* @public
* @virtual
*/ */
public abstract unsubscribeEvent(event: types.BasicEventElement): void; public abstract unsubscribeEvent(event: types.BasicEventElement): void;
/** /**
* Generate a handle for an async action. * Generate a handle for an async action.
* @returns Handle * @returns Handle
* @sealed
*/ */
protected generateAsyncHandle() { protected generateAsyncHandle() {
const handle = v4(); const handle = v4();
+13
View File
@@ -32,28 +32,40 @@ type InterfaceConnectionEntry<ConfigInterface> = {
* @remarks * @remarks
* Here are all Interface Servers and Connectors are created and managed. * Here are all Interface Servers and Connectors are created and managed.
* Also every request is handled here. * Also every request is handled here.
* @public
*/ */
export default class MultiMessageBroker { export default class MultiMessageBroker {
/**
* MMB singleton instance
* @private
*/
private static instance: MultiMessageBroker|null = null; private static instance: MultiMessageBroker|null = null;
/** /**
* Whether the broker is prepared. * Whether the broker is prepared.
* @private
*/ */
private prepared: boolean = false; private prepared: boolean = false;
/** /**
* All registered AASs. * All registered AASs.
* @private
*/ */
private aasRegistrations: AASRegistrationPrepared[] = []; private aasRegistrations: AASRegistrationPrepared[] = [];
/** /**
* All registered Interface Connectors. * All registered Interface Connectors.
* @private
*/ */
private interfaceConnections: InterfaceConnectionEntry<any>[] = []; private interfaceConnections: InterfaceConnectionEntry<any>[] = [];
/**
* @private
*/
private constructor() {} private constructor() {}
/** /**
* Get the singleton instance of the broker. * Get the singleton instance of the broker.
* @public
*/ */
public static getInstance(): MultiMessageBroker { public static getInstance(): MultiMessageBroker {
if (this.instance === null) this.instance = new MultiMessageBroker(); if (this.instance === null) this.instance = new MultiMessageBroker();
@@ -215,6 +227,7 @@ export default class MultiMessageBroker {
/** /**
* Callback on a connector event. * Callback on a connector event.
* @param response * @param response
* @alpha
*/ */
private onConnectorEvent(response: any) { private onConnectorEvent(response: any) {
for (const aas of this.aasRegistrations) { for (const aas of this.aasRegistrations) {
+59
View File
@@ -3,8 +3,18 @@ import type { AssetInterfacesDescription, EndpointMetadata, InterfaceDescription
import { AvailableEndpoint, endpointAvailable } from "../types/common"; import { AvailableEndpoint, endpointAvailable } from "../types/common";
import Traverser from "../helper/traverser"; import Traverser from "../helper/traverser";
/**
* Class for static methods to parse the AssetInterfacesDescription Submodel
* @public
*/
export default class AIDParser { export default class AIDParser {
/**
* Full parsing of the AID Submodel.
* @param env AAS Environment
* @returns Parsed AID or null if it's not parsable
* @public
*/
public static parse(env: aasCore.types.Environment): AssetInterfacesDescription | null { public static parse(env: aasCore.types.Environment): AssetInterfacesDescription | null {
const sm = Traverser.findSMByIdShort(env, "AssetInterfacesDescription"); const sm = Traverser.findSMByIdShort(env, "AssetInterfacesDescription");
if (sm === null || sm.submodelElements === null) return null; if (sm === null || sm.submodelElements === null) return null;
@@ -27,6 +37,12 @@ export default class AIDParser {
return parsed; return parsed;
} }
/**
* Parses one entry of an SubmodelElementList in die AID, containing one endpoint.
* @param entry AID entry for one endpoint
* @param endpointProtocol Protocol used in the endpoint, so additional properties can be parsed
* @returns Description for one interface or null if not parsable
*/
private static parseAIDEntry(entry: aasCore.types.SubmodelElementCollection, endpointProtocol?: AvailableEndpoint): InterfaceDescription | null { private static parseAIDEntry(entry: aasCore.types.SubmodelElementCollection, endpointProtocol?: AvailableEndpoint): InterfaceDescription | null {
const title = Traverser.findElement(entry, element => (element as any).idShort?.toLocaleLowerCase() === "title"); const title = Traverser.findElement(entry, element => (element as any).idShort?.toLocaleLowerCase() === "title");
const titleString = title !== null && aasCore.types.isProperty(title) && title.value ? title.value : ""; const titleString = title !== null && aasCore.types.isProperty(title) && title.value ? title.value : "";
@@ -47,6 +63,12 @@ export default class AIDParser {
} }
/**
* Parse EndpointMetaData
* @param endpoint EndpointMetaData SubmodelElementCollection
* @param endpointProtocol Protocol used in the endpoint, so additional properties can be parsed
* @returns Parsed EndpointMetaData or null if not parsable
*/
public static parseEndpointMetaData(endpoint: aasCore.types.SubmodelElementCollection, endpointProtocol?: AvailableEndpoint): EndpointMetadata | null { public static parseEndpointMetaData(endpoint: aasCore.types.SubmodelElementCollection, endpointProtocol?: AvailableEndpoint): EndpointMetadata | null {
if (!endpoint.value || endpoint.idShort?.toLocaleLowerCase() !== "endpointmetadata") return null; if (!endpoint.value || endpoint.idShort?.toLocaleLowerCase() !== "endpointmetadata") return null;
@@ -64,6 +86,16 @@ export default class AIDParser {
return parsed; return parsed;
} }
/**
* Parse an InterfaceMetaData SubmodelElementCollection
*
* @remarks
* Parses all properties, actions and events.
*
* @param interfaceMeta Interface MetaData SubmodelElementCollection
* @param endpointProtocol Protocol used in the endpoint, so additional properties can be parsed
* @returns Parsed InterfaceMetaData or null if not parsable
*/
public static parseInterfaceMetaData(interfaceMeta: aasCore.types.SubmodelElementCollection, endpointProtocol?: AvailableEndpoint): InterfaceMetadata | null { public static parseInterfaceMetaData(interfaceMeta: aasCore.types.SubmodelElementCollection, endpointProtocol?: AvailableEndpoint): InterfaceMetadata | null {
if (!interfaceMeta.value || interfaceMeta.idShort?.toLocaleLowerCase() !== "interfacemetadata") return null; if (!interfaceMeta.value || interfaceMeta.idShort?.toLocaleLowerCase() !== "interfacemetadata") return null;
@@ -94,6 +126,13 @@ export default class AIDParser {
return parsed as InterfaceMetadata; return parsed as InterfaceMetadata;
} }
/**
* Parse a single Property InterfaceMetadata
* @param prop SubmodelElementCollection of one Property
* @param endpointProtocol Protocol used in the endpoint, so additional properties can be parsed
* @returns Parsed Property InterfaceMetadata or null if not parsable
* @beta
*/
public static parseInterfaceMetadataProperty(prop: aasCore.types.SubmodelElementCollection, endpointProtocol?: AvailableEndpoint): InterfaceProperty | null { public static parseInterfaceMetadataProperty(prop: aasCore.types.SubmodelElementCollection, endpointProtocol?: AvailableEndpoint): InterfaceProperty | null {
if (!aasCore.types.isSubmodelElementCollection(prop) || !prop.value) return null; if (!aasCore.types.isSubmodelElementCollection(prop) || !prop.value) return null;
@@ -115,6 +154,12 @@ export default class AIDParser {
return { ...parsed, forms: parsedForm } as InterfaceProperty; return { ...parsed, forms: parsedForm } as InterfaceProperty;
} }
/**
* Parse the forms of a single Property InterfaceMetadata
* @param form Form SubmodelElementCollection of one Property
* @param endpointProtocol Protocol used in the endpoint, so additional properties can be parsed
* @returns Parsed Form or null if not parsable
*/
private static parseInterfaceMetadataPropertyForm(form: aasCore.types.SubmodelElementCollection, endpointProtocol?: AvailableEndpoint): InterfacePropertyForm | null { private static parseInterfaceMetadataPropertyForm(form: aasCore.types.SubmodelElementCollection, endpointProtocol?: AvailableEndpoint): InterfacePropertyForm | null {
if (!form.value) return null; if (!form.value) return null;
@@ -132,11 +177,25 @@ export default class AIDParser {
return parsed as InterfacePropertyForm; return parsed as InterfacePropertyForm;
} }
/**
* Parse a single Action InterfaceMetadata
* @param prop SubmodelElementCollection of one Action
* @param endpointProtocol Protocol used in the endpoint, so additional properties can be parsed
* @returns Parsed Action InterfaceMetadata or null if not parsable
* @alpha
*/
public static parseInterfaceMetadataAction(action: aasCore.types.SubmodelElementCollection, endpointProtocol?: AvailableEndpoint): InterfaceAction | null { public static parseInterfaceMetadataAction(action: aasCore.types.SubmodelElementCollection, endpointProtocol?: AvailableEndpoint): InterfaceAction | null {
// TODO // TODO
return null; return null;
} }
/**
* Parse a single Event InterfaceMetadata
* @param prop SubmodelElementCollection of one Event
* @param endpointProtocol Protocol used in the endpoint, so additional properties can be parsed
* @returns Parsed Event InterfaceMetadata or null if not parsable
* @alpha
*/
public static parseInterfaceMetadataEvent(event: aasCore.types.SubmodelElementCollection, endpointProtocol?: AvailableEndpoint): InterfaceEvent | null { public static parseInterfaceMetadataEvent(event: aasCore.types.SubmodelElementCollection, endpointProtocol?: AvailableEndpoint): InterfaceEvent | null {
// TODO // TODO
return null; return null;
+26 -4
View File
@@ -3,8 +3,18 @@ import Traverser from "../helper/traverser";
import { AssetInterfacesMappingConfiguration, MappingConfEntry, MappingConfiguration } from "../types/aimcConf"; import { AssetInterfacesMappingConfiguration, MappingConfEntry, MappingConfiguration } from "../types/aimcConf";
import { endpointAvailable, ResolvedRelationshipElement } from "../types/common"; import { endpointAvailable, ResolvedRelationshipElement } from "../types/common";
/**
* Class for static methods to parse the AssetInterfacesMappingConfiguration Submodel
* @public
*/
export default class AIMCParser { export default class AIMCParser {
/**
* Parse the complete AIMC Submodel
* @param env Environment
* @returns Parsed AIMC or null if not parsable
* @public
*/
public static parse(env: aasCore.types.Environment): AssetInterfacesMappingConfiguration | null { public static parse(env: aasCore.types.Environment): AssetInterfacesMappingConfiguration | null {
const sm = Traverser.findSMByIdShort(env, "AssetInterfacesMappingConfiguration"); const sm = Traverser.findSMByIdShort(env, "AssetInterfacesMappingConfiguration");
if (sm === null || sm.submodelElements === null) return null; if (sm === null || sm.submodelElements === null) return null;
@@ -27,6 +37,14 @@ export default class AIMCParser {
return parsed; return parsed;
} }
/**
* Parse one entry of the AIMC Submodel
* @remarks
* The Environment is necessary so references can be resolved further down the line.
* @param entry Parse one entry of the AIMC Submodel
* @param environment The complete environment
* @returns Parsed Endpoint and MappingConfiguration or null if not parsable
*/
public static parseAIMCEntry(entry: aasCore.types.SubmodelElementCollection, environment: aasCore.types.Environment): MappingConfEntry | null { public static parseAIMCEntry(entry: aasCore.types.SubmodelElementCollection, environment: aasCore.types.Environment): MappingConfEntry | null {
const ep = Traverser.findElement(entry, element => (element as any).idShort?.toLocaleLowerCase() === "endpointmetadatareference"); const ep = Traverser.findElement(entry, element => (element as any).idShort?.toLocaleLowerCase() === "endpointmetadatareference");
const mc = Traverser.findElement(entry, element => (element as any).idShort?.toLocaleLowerCase() === "mappingconfiguration"); const mc = Traverser.findElement(entry, element => (element as any).idShort?.toLocaleLowerCase() === "mappingconfiguration");
@@ -49,6 +67,14 @@ export default class AIMCParser {
}; };
} }
/**
* Parse MappingConfiguration SubmodelElementCollection
* @remarks
* The Environment is necessary so references can be resolved further down the line.
* @param conf MappingConfiguration SubmodelElementCollection
* @param env Environment
* @returns Parsed MappingConfiguration or null if not parsable
*/
public static parseMappingConfiguration(conf: aasCore.types.SubmodelElementCollection, env: aasCore.types.Environment): MappingConfiguration | null { public static parseMappingConfiguration(conf: aasCore.types.SubmodelElementCollection, env: aasCore.types.Environment): MappingConfiguration | null {
if (!conf.value) return null; if (!conf.value) return null;
@@ -68,10 +94,6 @@ export default class AIMCParser {
for (const ssm of sourceSinkMappings.overValueOrEmpty()) { for (const ssm of sourceSinkMappings.overValueOrEmpty()) {
if (!aasCore.types.isRelationshipElement(ssm)) continue; if (!aasCore.types.isRelationshipElement(ssm)) continue;
// No resolve, to allow for mapping
//const resolved = Traverser.resolveRelationship(env, ssm);
//if (resolved === null) continue;
parsed.SourceSinkMappings.push(ssm as ResolvedRelationshipElement); parsed.SourceSinkMappings.push(ssm as ResolvedRelationshipElement);
} }
+18 -1
View File
@@ -6,18 +6,25 @@ import type { OnRequestCallback } from "./types/requests";
* This should be used as base class for your own interface servers! * This should be used as base class for your own interface servers!
* *
* @typeParam ConfigInterface - The config interface for your interface server. * @typeParam ConfigInterface - The config interface for your interface server.
* @public
*/ */
export default abstract class AASInterfaceServer<ConfigInterface> { export default abstract class AASInterfaceServer<ConfigInterface> {
/** /**
* A name for your interface server. * A name for your interface server.
* @remarks * @remarks
* Currently unused * Currently unused
* @public
* @readonly
* @virtual
*/ */
public static readonly serverInterfaceName: string; public static readonly serverInterfaceName: string;
/** /**
* Whether your interface server supports subscriptions. * Whether your interface server supports subscriptions.
* @remarks * @remarks
* Currently unused * Currently unused
* @public
* @readonly
* @virtual
*/ */
public static readonly supportsSubscriptions: boolean; public static readonly supportsSubscriptions: boolean;
@@ -26,8 +33,10 @@ export default abstract class AASInterfaceServer<ConfigInterface> {
* @param config Interface server config * @param config Interface server config
* @param aas AAS Environment for the server * @param aas AAS Environment for the server
* @param onRequestCallback Callback when a request is received and parsed * @param onRequestCallback Callback when a request is received and parsed
* @public
* @sealed
*/ */
constructor( public constructor(
protected readonly config: ConfigInterface, protected readonly config: ConfigInterface,
protected readonly aas: types.Environment, protected readonly aas: types.Environment,
protected readonly onRequestCallback: OnRequestCallback) {} protected readonly onRequestCallback: OnRequestCallback) {}
@@ -36,19 +45,27 @@ export default abstract class AASInterfaceServer<ConfigInterface> {
* Prepare the interface server. * Prepare the interface server.
* @remarks * @remarks
* Here you can create routes, listeners, callbacks,... * Here you can create routes, listeners, callbacks,...
* @virtual
* @public
*/ */
public abstract prepare(): void; public abstract prepare(): void;
/** /**
* Run the interface server. * Run the interface server.
* @public
* @virtual
*/ */
public abstract run(): void; public abstract run(): void;
/** /**
* Stop the interface server. * Stop the interface server.
* @public
* @virtual
*/ */
public abstract stop(): void; public abstract stop(): void;
/** /**
* Notify observers/subscribers about an event. * Notify observers/subscribers about an event.
* @param event Event to notify the interface server about * @param event Event to notify the interface server about
* @public
* @virtual
*/ */
public abstract notify(event: any): void; public abstract notify(event: any): void;
+3 -1
View File
@@ -1,4 +1,4 @@
import { AvailableEndpoint } from "./common"; import type { AvailableEndpoint } from "./common";
export type AssetInterfacesDescription = { export type AssetInterfacesDescription = {
[key in AvailableEndpoint]?: InterfaceDescription[]; [key in AvailableEndpoint]?: InterfaceDescription[];
@@ -77,10 +77,12 @@ type InterfacePropertyFormMQTT = InterfacePropertyFormBase & {
qos?: 0 | 1 | 2; qos?: 0 | 1 | 2;
} }
/** @alpha */
export type InterfaceAction = { export type InterfaceAction = {
// TODO // TODO
} }
/** @alpha */
export type InterfaceEvent = { export type InterfaceEvent = {
// TODO // TODO
} }
+67 -4
View File
@@ -1,16 +1,21 @@
import type { types } from "@aas-core-works/aas-core3.0-typescript"; import type { types } from "@aas-core-works/aas-core3.0-typescript";
export type Request = GetRequest | WriteRequest | ObserveRequest | CallRequest | CallAsyncRequest | AsyncStateRequest | AsyncResultRequest | SubscribeRequest | UnsubscribeRequest; /**
* Read Property Request
export type OnRequestCallback = (request: Request) => any & GetRequestCallback & WriteRequestCallback & ObserveRequestCallback & CallRequestCallback & CallAsyncRequestCallback & AsyncStateRequestCallback & AsyncResultRequestCallback & SubscribeRequestCallback & UnsubscribeRequestCallback; */
type GetRequest = { type GetRequest = {
type: "READ"; type: "READ";
target: types.Property; target: types.Property;
} }
/**
* Read Property Request Callback
*/
type GetRequestCallback = (request: GetRequest) => any; type GetRequestCallback = (request: GetRequest) => any;
/**
* Write Property Request
*/
type WriteRequest = { type WriteRequest = {
type: "WRITE"; type: "WRITE";
target: types.Property; target: types.Property;
@@ -19,8 +24,14 @@ type WriteRequest = {
} }
} }
/**
* Wrote Property Request Callback
*/
type WriteRequestCallback = (request: WriteRequest) => void; type WriteRequestCallback = (request: WriteRequest) => void;
/**
* Observe Property Request
*/
type ObserveRequest = { type ObserveRequest = {
type: "OBSERVE"; type: "OBSERVE";
target: types.Property; target: types.Property;
@@ -29,8 +40,14 @@ type ObserveRequest = {
} }
} }
/**
* Observe Property Request Callback
*/
type ObserveRequestCallback = (request: ObserveRequest) => boolean; type ObserveRequestCallback = (request: ObserveRequest) => boolean;
/**
* Subscribe Event Request
*/
type SubscribeRequest = { type SubscribeRequest = {
type: "SUBSCRIBE"; type: "SUBSCRIBE";
target: types.BasicEventElement; target: types.BasicEventElement;
@@ -39,15 +56,27 @@ type SubscribeRequest = {
} }
} }
/**
* Subscribe Event Request Callback
*/
type SubscribeRequestCallback = (request: SubscribeRequest) => boolean; type SubscribeRequestCallback = (request: SubscribeRequest) => boolean;
/**
* Unsubscribe Event Request
*/
type UnsubscribeRequest = { type UnsubscribeRequest = {
type: "UNSUBSCRIBE"; type: "UNSUBSCRIBE";
target: types.BasicEventElement; target: types.BasicEventElement;
} }
/**
* Unsubscribe Event Request Callback
*/
type UnsubscribeRequestCallback = (request: UnsubscribeRequest) => void; type UnsubscribeRequestCallback = (request: UnsubscribeRequest) => void;
/**
* Call Operation Request
*/
type CallRequest = { type CallRequest = {
type: "CALL"; type: "CALL";
target: types.Operation; target: types.Operation;
@@ -56,8 +85,14 @@ type CallRequest = {
} }
} }
/**
* Call Operation Request Callback
*/
type CallRequestCallback = (request: CallRequest) => any; type CallRequestCallback = (request: CallRequest) => any;
/**
* Call Async Operation Request
*/
type CallAsyncRequest = { type CallAsyncRequest = {
type: "CALL-ASYNC"; type: "CALL-ASYNC";
target: types.Operation; target: types.Operation;
@@ -66,20 +101,48 @@ type CallAsyncRequest = {
} }
} }
/**
* Call Async Operation Request Callback
*/
type CallAsyncRequestCallback = (request: CallAsyncRequest) => string | null; type CallAsyncRequestCallback = (request: CallAsyncRequest) => string | null;
/**
* Get Async Operation State Request
*/
type AsyncStateRequest = { type AsyncStateRequest = {
type: "GET-OP-STATE"; type: "GET-OP-STATE";
target: string; target: string;
} }
/**
* Get Async Operation State Request Callback
*/
type AsyncStateRequestCallback = (request: AsyncStateRequest) => boolean; type AsyncStateRequestCallback = (request: AsyncStateRequest) => boolean;
/**
* Get Async Operation Result Request
*/
type AsyncResultRequest = { type AsyncResultRequest = {
type: "GET-OP-RESULT"; type: "GET-OP-RESULT";
target: string; target: string;
} }
/**
* Get Async Operation Result Request Callback
*/
type AsyncResultRequestCallback = (request: AsyncResultRequest) => any; type AsyncResultRequestCallback = (request: AsyncResultRequest) => any;
/**
* Possible Request Types
*/
type RequestType = "READ" | "WRITE" | "OBSERVE" | "CALL" | "CALL-ASYNC" | "GET-OP-STATE" | "GET-OP-RESULT" | "SUBSCRIBE" | "UNSUBSCRIBE" type RequestType = "READ" | "WRITE" | "OBSERVE" | "CALL" | "CALL-ASYNC" | "GET-OP-STATE" | "GET-OP-RESULT" | "SUBSCRIBE" | "UNSUBSCRIBE"
/**
* Combined Request Type
*/
export type Request = GetRequest | WriteRequest | ObserveRequest | CallRequest | CallAsyncRequest | AsyncStateRequest | AsyncResultRequest | SubscribeRequest | UnsubscribeRequest;
/**
* Combined Request Callback Type
*/
export type OnRequestCallback = (request: Request) => any & GetRequestCallback & WriteRequestCallback & ObserveRequestCallback & CallRequestCallback & CallAsyncRequestCallback & AsyncStateRequestCallback & AsyncResultRequestCallback & SubscribeRequestCallback & UnsubscribeRequestCallback;
+9
View File
@@ -0,0 +1,9 @@
{
"$schema": "https://typedoc.org/schema.json",
"entryPoints": ["./src/index.ts"],
"out": "docs",
"plugin": ["typedoc-plugin-extras", "typedoc-plugin-rename-defaults"],
"footerLastModified": true,
"footerTypedocVersion": true,
"customTitle": "Multimessagebroker for Industry 4.0 Applications"
}