More work on the (better) AID
This commit is contained in:
+38
-4
@@ -3,6 +3,7 @@ import type { ConnectionConfiguration, AIMCMap } from "./types/aimcConf";
|
||||
import AIMCParser from "./parser/AIMCParser";
|
||||
import Traverser from "./helper/traverser";
|
||||
import AIDParser from "./parser/AIDParser";
|
||||
import type { InterfaceAction, InterfaceActionForm, InterfaceEvent, InterfaceEventForm, InterfaceProperty, InterfacePropertyForm } from "./types/aidConf";
|
||||
|
||||
/**
|
||||
* The AIMC Mapper.
|
||||
@@ -49,14 +50,47 @@ export default class AIMCMapper {
|
||||
const resolved = Traverser.resolveRelationship(this.env, ssm);
|
||||
if (resolved === null) continue;
|
||||
|
||||
// To know if we currently view a property, action or event, they reference keys can help us.
|
||||
// We know the third to last must be the "InterfaceMetadata" and the second to last must be the "Properties", "Actions" or "Events".
|
||||
// As we _maybe_ don't know if the first and second reference are switched we can check for the third to last.
|
||||
const elemType = (ssm as types.RelationshipElement).first.keys.at(-3)?.value.toLocaleLowerCase() === "interfacemetadata" ? (ssm as types.RelationshipElement).first.keys.at(-2)?.value : (ssm as types.RelationshipElement).second.keys.at(-2)?.value;
|
||||
|
||||
let {first, second} = resolved;
|
||||
|
||||
let parsedPropConf = AIDParser.parseInterfaceMetadataProperty(first as types.SubmodelElementCollection);
|
||||
let parsedPropConf: InterfaceProperty | InterfaceAction | InterfaceEvent | null = null;
|
||||
|
||||
switch (elemType?.toLocaleLowerCase()) {
|
||||
case "properties":
|
||||
parsedPropConf = AIDParser.parseInterfaceMetadataProperty(first as types.SubmodelElementCollection);
|
||||
break;
|
||||
case "actions":
|
||||
parsedPropConf = AIDParser.parseInterfaceMetadataAction(first as types.SubmodelElementCollection);
|
||||
break;
|
||||
case "events":
|
||||
parsedPropConf = AIDParser.parseInterfaceMetadataEvent(first as types.SubmodelElementCollection);
|
||||
break;
|
||||
default:
|
||||
// Error. We have not found a valid type of element to parse.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parsedPropConf === null) {
|
||||
// maybe the property is in the first element
|
||||
[first, second] = [second, first];
|
||||
parsedPropConf = AIDParser.parseInterfaceMetadataProperty(first as types.SubmodelElementCollection);
|
||||
|
||||
switch (elemType?.toLocaleLowerCase()) {
|
||||
case "properties":
|
||||
parsedPropConf = AIDParser.parseInterfaceMetadataProperty(first as types.SubmodelElementCollection);
|
||||
break;
|
||||
case "actions":
|
||||
parsedPropConf = AIDParser.parseInterfaceMetadataAction(first as types.SubmodelElementCollection);
|
||||
break;
|
||||
case "events":
|
||||
parsedPropConf = AIDParser.parseInterfaceMetadataEvent(first as types.SubmodelElementCollection);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (parsedPropConf === null) continue;
|
||||
|
||||
this.map.set(second, {
|
||||
@@ -113,8 +147,8 @@ export default class AIMCMapper {
|
||||
const result = [];
|
||||
|
||||
for (const [e, cc] of this.map.entries()) {
|
||||
const formsPath = cc.base + cc.forms.href;
|
||||
if (formsPath === path) result.push(e);
|
||||
const formsPaths = cc.forms.map((f: InterfaceActionForm | InterfacePropertyForm | InterfaceEventForm) => cc.base + f.href);
|
||||
if (formsPaths.includes(path)) result.push(e);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import type { types } from "@aas-core-works/aas-core3.0-typescript";
|
||||
import AIMCMapper from "./AIMCMapper";
|
||||
import { v4 } from "uuid";
|
||||
import type { EndpointMetadata } from "./types/aidConf";
|
||||
import type { EndpointMetadata, FormOp, InterfaceActionForm, InterfaceEventForm, InterfacePropertyForm } from "./types/aidConf";
|
||||
import type { ConnectionConfiguration } from "./types/aimcConf";
|
||||
|
||||
type ConnectionType = "ON_DEMAND" | "PERMANENT";
|
||||
|
||||
@@ -94,51 +95,59 @@ export default abstract class AbstractConnectionObject<ConfigInterface> {
|
||||
|
||||
/**
|
||||
* Read a property value from the asset.
|
||||
* @param prop Property
|
||||
* @param mapping ConnectionConfiguration for the property
|
||||
* @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(mapping: ConnectionConfiguration): void;
|
||||
|
||||
/**
|
||||
* Write a property value to the asset.
|
||||
* @param prop Property
|
||||
* @param mapping ConnectionConfiguration for the property
|
||||
* @param value Value to write.
|
||||
* @public
|
||||
* @virtual
|
||||
*/
|
||||
public abstract writeProperty(prop: types.Property, value: any): void;
|
||||
public abstract writeProperty(mapping: ConnectionConfiguration, value: any): void;
|
||||
|
||||
/**
|
||||
* Observe a property value from the asset.
|
||||
* @param prop Property
|
||||
* @param mapping ConnectionConfiguration for the property
|
||||
* @param callback Callback to call when the property changes.
|
||||
* @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(mapping: ConnectionConfiguration, callback: (value: any) => void): boolean;
|
||||
|
||||
/**
|
||||
* Unobserve a property value from the asset.
|
||||
* @param mapping ConnectionConfiguration for the property
|
||||
* @public
|
||||
* @virtual
|
||||
*/
|
||||
public abstract unobserveProperty(mapping: ConnectionConfiguration): void;
|
||||
|
||||
/**
|
||||
* Call an action on the asset synchronously.
|
||||
* @param action Action
|
||||
* @param mapping ConnectionConfiguration for the action
|
||||
* @param args Arguments
|
||||
* @returns Return value of the action.
|
||||
* @public
|
||||
* @virtual
|
||||
*/
|
||||
public abstract callActionSync(action: types.Operation, args: Record<string, any>): any;
|
||||
public abstract callActionSync(mapping: ConnectionConfiguration, args: Record<string, any>): any;
|
||||
|
||||
/**
|
||||
* Call an action on the asset asynchronously.
|
||||
* @param action Action
|
||||
* @param mapping ConnectionConfiguration for the action
|
||||
* @param args Arguments
|
||||
* @returns Handle for the async action.
|
||||
* @public
|
||||
* @virtual
|
||||
*/
|
||||
public abstract callActionAsync(action: types.Operation, args: Record<string, any>): string | null;
|
||||
public abstract callActionAsync(mapping: ConnectionConfiguration, args: Record<string, any>): string | null;
|
||||
|
||||
/**
|
||||
* Read the state of an async action.
|
||||
@@ -164,21 +173,21 @@ export default abstract class AbstractConnectionObject<ConfigInterface> {
|
||||
|
||||
/**
|
||||
* Subscribe to an event.
|
||||
* @param event Event
|
||||
* @param mapping ConnectionConfiguration for the event
|
||||
* @param callback Callback to call when the event occurs.
|
||||
* @returns Whether the subscription was successful.
|
||||
* @public
|
||||
* @virtual
|
||||
*/
|
||||
public abstract subscribeEvent(event: types.BasicEventElement, callback: (event: types.BasicEventElement) => void): boolean;
|
||||
public abstract subscribeEvent(mapping: ConnectionConfiguration, callback: (event: types.BasicEventElement) => void): boolean;
|
||||
|
||||
/**
|
||||
* Unsubscribe from an event.
|
||||
* @param event Event
|
||||
* @param mapping ConnectionConfiguration for the event
|
||||
* @public
|
||||
* @virtual
|
||||
*/
|
||||
public abstract unsubscribeEvent(event: types.BasicEventElement): void;
|
||||
public abstract unsubscribeEvent(mapping: ConnectionConfiguration): void;
|
||||
|
||||
/**
|
||||
* Generate a handle for an async action.
|
||||
@@ -190,4 +199,8 @@ export default abstract class AbstractConnectionObject<ConfigInterface> {
|
||||
this.asyncActionStateStore[handle] = {finished: false, result: null};
|
||||
return handle;
|
||||
}
|
||||
|
||||
protected static findValidForms(mapping: ConnectionConfiguration, op: FormOp): (InterfacePropertyForm | InterfaceActionForm | InterfaceEventForm)[] {
|
||||
return mapping.forms.filter((form: InterfacePropertyForm | InterfaceActionForm | InterfaceEventForm) => form.op === op);
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,8 @@ import type { Request } from "./types/requests";
|
||||
import type AbstractConnectionObject from "./abstractConnectionObject";
|
||||
import AIMCMapper from "./AIMCMapper";
|
||||
import AIDParser from "./parser/AIDParser";
|
||||
import { EndpointMetadata } from "types/aidConf";
|
||||
import type { EndpointMetadata, InterfaceActionForm, InterfaceEventForm, InterfacePropertyForm } from "./types/aidConf";
|
||||
import type { ConnectionConfiguration } from "./types/aimcConf";
|
||||
|
||||
type AASRegistration = {
|
||||
aas: types.Environment,
|
||||
@@ -165,63 +166,44 @@ export default class MultiMessageBroker {
|
||||
*/
|
||||
private onInterfaceRequest(request: Request, registration: AASRegistrationPrepared): any {
|
||||
|
||||
const getConnector = (target: types.Class) => {
|
||||
const getMapping = (target: types.Class) => {
|
||||
const mapping = registration.mappingConfiguration?.get(target);
|
||||
if (mapping === undefined) throw new ReferenceError(`No mapping found for ${(request.target as any).idShort}`);
|
||||
return mapping;
|
||||
}
|
||||
|
||||
const getConnector = (mapping: ConnectionConfiguration) => {
|
||||
const connector = registration.connectorInterfaces?.find(connector => connector.endpointMetadata.base === mapping.base);
|
||||
if (connector === undefined) throw new ReferenceError(`No connector found for ${(request.target as any).idShort}`);
|
||||
|
||||
return connector;
|
||||
}
|
||||
|
||||
switch (request.type) {
|
||||
case "READ": {
|
||||
const connector = getConnector(request.target);
|
||||
|
||||
return connector.readProperty(request.target);
|
||||
}
|
||||
case "WRITE": {
|
||||
const connector = getConnector(request.target);
|
||||
|
||||
return connector.writeProperty(request.target, request.extraData.value);
|
||||
}
|
||||
case "OBSERVE": {
|
||||
const connector = getConnector(request.target);
|
||||
|
||||
return connector.observeProperty(request.target, request.extraData.callback);
|
||||
}
|
||||
case "SUBSCRIBE": {
|
||||
const connector = getConnector(request.target);
|
||||
|
||||
return connector.subscribeEvent(request.target, request.extraData.callback);
|
||||
}
|
||||
case "UNSUBSCRIBE": {
|
||||
const connector = getConnector(request.target);
|
||||
|
||||
return connector.unsubscribeEvent(request.target);
|
||||
}
|
||||
case "CALL": {
|
||||
const connector = getConnector(request.target);
|
||||
|
||||
return connector.callActionSync(request.target, request.extraData.args);
|
||||
}
|
||||
case "CALL-ASYNC": {
|
||||
const connector = getConnector(request.target);
|
||||
|
||||
return connector.callActionAsync(request.target, request.extraData.args);
|
||||
}
|
||||
case "GET-OP-STATE": {
|
||||
if (request.type === "xAsyncActionState" || request.type === "xAsyncActionResult") {
|
||||
if (request.type === "xAsyncActionState") {
|
||||
const state = registration.connectorInterfaces.map(connector => connector.readAsyncActionState(request.target)).filter(state => state !== undefined)[0];
|
||||
if (state === undefined) throw new ReferenceError(`No connector found for operation handle ${request.target}`);
|
||||
return state;
|
||||
}
|
||||
case "GET-OP-RESULT": {
|
||||
} else {
|
||||
const result = registration.connectorInterfaces.map(connector => connector.readAsyncActionResponse(request.target)).filter(result => result !== undefined)[0];
|
||||
if (result === undefined) throw new ReferenceError(`No connector found for operation handle ${request.target}`);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else {
|
||||
const mapping = getMapping(request.target);
|
||||
const connector = getConnector(mapping);
|
||||
|
||||
switch (request.type) {
|
||||
case "readProperty": return connector.readProperty(mapping);
|
||||
case "writeProperty": return connector.writeProperty(mapping, request.extraData.value);
|
||||
case "observeProperty": return connector.observeProperty(mapping, request.extraData.callback);
|
||||
case "unobserveProperty": return connector.unobserveProperty(mapping);
|
||||
case "subscribeEvent": return connector.subscribeEvent(mapping, request.extraData.callback);
|
||||
case "unsubscribeEvent": return connector.unsubscribeEvent(mapping);
|
||||
case "invokeAction": return request.extraData.async ? connector.callActionAsync(mapping, request.extraData.args) : connector.callActionSync(mapping, request.extraData.args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -48,7 +48,7 @@ It should be pretty easy to extend this.
|
||||
So let's derive some of this from the WoT and see what we can achieve.
|
||||
*/
|
||||
|
||||
type FormOp = "readproperty" |
|
||||
export type FormOp = "readproperty" |
|
||||
"writeproperty" |
|
||||
"observeproperty" |
|
||||
"unobserveproperty" |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { types } from "@aas-core-works/aas-core3.0-typescript";
|
||||
import type { AvailableEndpoint } from "./common";
|
||||
import type { EndpointMetadata, InterfaceProperty } from "./aidConf";
|
||||
import type { EndpointMetadata, InterfaceAction, InterfaceEvent, InterfaceProperty } from "./aidConf";
|
||||
|
||||
export type AssetInterfacesMappingConfiguration = Record<AvailableEndpoint, MappingConfEntry[]>;
|
||||
|
||||
@@ -16,4 +16,5 @@ export type MappingConfiguration = {
|
||||
|
||||
export type AIMCMap = Map<types.Class, ConnectionConfiguration>;
|
||||
|
||||
export type ConnectionConfiguration = EndpointMetadata & InterfaceProperty; // Wenn Transformationen implementiert werden, dann hier anpassen
|
||||
type InterfaceElement = InterfaceProperty | InterfaceAction | InterfaceEvent;
|
||||
export type ConnectionConfiguration = EndpointMetadata & InterfaceElement; // Wenn Transformationen implementiert werden, dann hier anpassen
|
||||
+27
-31
@@ -4,7 +4,7 @@ import type { types } from "@aas-core-works/aas-core3.0-typescript";
|
||||
* Read Property Request
|
||||
*/
|
||||
type GetRequest = {
|
||||
type: "READ";
|
||||
type: "readProperty";
|
||||
target: types.Property;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ type GetRequestCallback = (request: GetRequest) => any;
|
||||
* Write Property Request
|
||||
*/
|
||||
type WriteRequest = {
|
||||
type: "WRITE";
|
||||
type: "writeProperty";
|
||||
target: types.Property;
|
||||
extraData: {
|
||||
value: any;
|
||||
@@ -33,7 +33,7 @@ type WriteRequestCallback = (request: WriteRequest) => void;
|
||||
* Observe Property Request
|
||||
*/
|
||||
type ObserveRequest = {
|
||||
type: "OBSERVE";
|
||||
type: "observeProperty";
|
||||
target: types.Property;
|
||||
extraData: {
|
||||
callback: (value: any) => void;
|
||||
@@ -45,11 +45,27 @@ type ObserveRequest = {
|
||||
*/
|
||||
type ObserveRequestCallback = (request: ObserveRequest) => boolean;
|
||||
|
||||
/**
|
||||
* Unobserve Property Request
|
||||
*/
|
||||
type UnobserveRequest = {
|
||||
type: "unobserveProperty";
|
||||
target: types.Property;
|
||||
extraData: {
|
||||
callback: (value: any) => void;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unobserve Property Request Callback
|
||||
*/
|
||||
type UnobserveRequestCallback = (request: ObserveRequest) => boolean;
|
||||
|
||||
/**
|
||||
* Subscribe Event Request
|
||||
*/
|
||||
type SubscribeRequest = {
|
||||
type: "SUBSCRIBE";
|
||||
type: "subscribeEvent";
|
||||
target: types.BasicEventElement;
|
||||
extraData: {
|
||||
callback: (value: any) => void;
|
||||
@@ -65,7 +81,7 @@ type SubscribeRequestCallback = (request: SubscribeRequest) => boolean;
|
||||
* Unsubscribe Event Request
|
||||
*/
|
||||
type UnsubscribeRequest = {
|
||||
type: "UNSUBSCRIBE";
|
||||
type: "unsubscribeEvent";
|
||||
target: types.BasicEventElement;
|
||||
}
|
||||
|
||||
@@ -78,9 +94,10 @@ type UnsubscribeRequestCallback = (request: UnsubscribeRequest) => void;
|
||||
* Call Operation Request
|
||||
*/
|
||||
type CallRequest = {
|
||||
type: "CALL";
|
||||
type: "invokeAction";
|
||||
target: types.Operation;
|
||||
extraData: {
|
||||
async: boolean;
|
||||
args: Record<string, any>;
|
||||
}
|
||||
}
|
||||
@@ -90,27 +107,11 @@ type CallRequest = {
|
||||
*/
|
||||
type CallRequestCallback = (request: CallRequest) => any;
|
||||
|
||||
/**
|
||||
* Call Async Operation Request
|
||||
*/
|
||||
type CallAsyncRequest = {
|
||||
type: "CALL-ASYNC";
|
||||
target: types.Operation;
|
||||
extraData: {
|
||||
args: Record<string, any>;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call Async Operation Request Callback
|
||||
*/
|
||||
type CallAsyncRequestCallback = (request: CallAsyncRequest) => string | null;
|
||||
|
||||
/**
|
||||
* Get Async Operation State Request
|
||||
*/
|
||||
type AsyncStateRequest = {
|
||||
type: "GET-OP-STATE";
|
||||
type: "xAsyncActionState";
|
||||
target: string;
|
||||
}
|
||||
|
||||
@@ -123,7 +124,7 @@ type AsyncStateRequestCallback = (request: AsyncStateRequest) => boolean;
|
||||
* Get Async Operation Result Request
|
||||
*/
|
||||
type AsyncResultRequest = {
|
||||
type: "GET-OP-RESULT";
|
||||
type: "xAsyncActionResult";
|
||||
target: string;
|
||||
}
|
||||
|
||||
@@ -132,17 +133,12 @@ type AsyncResultRequest = {
|
||||
*/
|
||||
type AsyncResultRequestCallback = (request: AsyncResultRequest) => any;
|
||||
|
||||
/**
|
||||
* Possible Request Types
|
||||
*/
|
||||
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;
|
||||
export type Request = GetRequest | WriteRequest | ObserveRequest | UnobserveRequest | CallRequest | AsyncStateRequest | AsyncResultRequest | SubscribeRequest | UnsubscribeRequest;
|
||||
|
||||
/**
|
||||
* Combined Request Callback Type
|
||||
*/
|
||||
export type OnRequestCallback = (request: Request) => any & GetRequestCallback & WriteRequestCallback & ObserveRequestCallback & CallRequestCallback & CallAsyncRequestCallback & AsyncStateRequestCallback & AsyncResultRequestCallback & SubscribeRequestCallback & UnsubscribeRequestCallback;
|
||||
export type OnRequestCallback = (request: Request) => any & GetRequestCallback & WriteRequestCallback & ObserveRequestCallback & UnobserveRequestCallback & CallRequestCallback & AsyncStateRequestCallback & AsyncResultRequestCallback & SubscribeRequestCallback & UnsubscribeRequestCallback;
|
||||
|
||||
Reference in New Issue
Block a user