UNPKG

@dasf/dasf-messaging

Version:

Typescript bindings for the DASF RPC messaging protocol.

426 lines (364 loc) 11.9 kB
// SPDX-FileCopyrightText: 2022-2024 Helmholtz Centre Potsdam GFZ German Research Centre for Geosciences, Potsdam, Germany // SPDX-FileCopyrightText: 2024 Helmholtz-Zentrum hereon GmbH // // SPDX-License-Identifier: Apache-2.0 import { JsonObject, JsonProperty, Any, JsonConverter, JsonCustomConvert, } from 'json2typescript'; import type { JSONSchema7 } from 'json-schema'; /** Message types for a :class:`DASFModuleRequest` */ export enum MessageType { Ping = 'ping', Pong = 'pong', Info = 'info', ApiInfo = 'api_info', Request = 'request', Response = 'response', Log = 'log', Progress = 'progress', } /** Valid keys for the request properties * * see :attr:`DASFModuleRequest.properties` */ export enum PropertyKeys { ResponseTopic = 'response_topic', RequestContext = 'requestContext', RequestMessageId = 'requestMessageId', MessageType = 'messageType', SourceTopic = 'source_topic', Fragment = 'fragment', NumFragments = 'num_fragments', Status = 'status', } /** Status flag of a request :class:`DASFModuleRequest` */ export enum Status { Success = 'success', Error = 'error', Running = 'running', } type DASFRequestPropertiesBase = { messageType: MessageType; requestContext?: string; }; export type DASFRequestProperties = DASFRequestPropertiesBase & { response_topic?: string; }; export type DASFResponseProperties = DASFRequestPropertiesBase & { requestMessageId?: string; source_topic?: string; fragment?: number; num_fragments?: number; status?: Status; info?: string; api_info?: string; }; /** A request to a DASF backend module * * This class can be used to create a request that is sent via the message * broker to a DASF backend module. */ @JsonObject('DASFModuleRequest') export class DASFModuleRequest { /** The request data. * * usually encoded as byte64 string. */ @JsonProperty('payload', String) payload = ''; /** An identifier for the request to handle identify the response handler */ context = ''; /** Properties of the request * * the properties of the request may be derived from the * :ref:`PropertyKeys` enum. */ @JsonProperty('properties', Any) properties?: DASFRequestProperties; private static createMessage(type: MessageType): DASFModuleRequest { const msg = new DASFModuleRequest(); msg.properties = {} as DASFRequestProperties; msg.properties[PropertyKeys.MessageType] = type; return msg; } /** Shortcut to create a request message * * This static method creates a :class:`DASFModuleRequest` with the * :ref:`MessageType` `MessageType.Request` * * @param data - Optional data as javascript object that will be * json-serialized and added as :attr:`payload` to the request. * * @returns The :class:`DASFModuleRequest` of type `MessageType.Request` */ public static createRequestMessage(data?: object): DASFModuleRequest { const ret = DASFModuleRequest.createMessage(MessageType.Request); if (typeof data != 'undefined') { ret.payload = btoa(JSON.stringify(data)); } return ret; } /** Shortcut to create a Ping message * * This static method creates a :class:`DASFModuleRequest` with the * :ref:`MessageType` `MessageType.Ping` * * @returns The :class:`DASFModuleRequest` of type `MessageType.Ping` */ public static createPingMessage(): DASFModuleRequest { return DASFModuleRequest.createMessage(MessageType.Ping); } /** Shortcut to create a Pong message * * This static method creates a :class:`DASFModuleRequest` with the * :ref:`MessageType` `MessageType.Pong` * * @returns The :class:`DASFModuleRequest` of type `MessageType.Pong` */ public static createPongMessage(): DASFModuleRequest { return DASFModuleRequest.createMessage(MessageType.Pong); } /** Shortcut to create an Info message * * This static method creates a :class:`DASFModuleRequest` with the * :ref:`MessageType` `MessageType.Info` to get the information on the * backend module, see also :meth:`DASFConnection.getModuleInfo` * * @returns The :class:`DASFModuleRequest` of type `MessageType.Info` */ public static createInfoMessage(): DASFModuleRequest { return DASFModuleRequest.createMessage(MessageType.Info); } /** Shortcut to create an Info message * * This static method creates a :class:`DASFModuleRequest` with the * :ref:`MessageType` `MessageType.Info` to get the information on the * backend module, see also :meth:`DASFConnection.getApiInfo` * * @returns The :class:`DASFModuleRequest` of type `MessageType.ApiInfo` */ public static createApiInfoMessage(): DASFModuleRequest { return DASFModuleRequest.createMessage(MessageType.ApiInfo); } /** Shortcut to the the messagetype of the properties */ public getMessageType(): MessageType { if (this.properties) { return this.properties[PropertyKeys.MessageType]; } throw new Error('Missing or empty message type property'); } } /** An acknowledgement answer from the message broker * * This object is retrieved from the message broker if a request has been * submitted successfully. */ @JsonObject('DASFModuleRequestReceipt') export class DASFModuleRequestReceipt { @JsonProperty('result', String) result = ''; @JsonProperty('messageId', String, true) messageId = ''; @JsonProperty('errorMsg', String, true) errorMsg = ''; @JsonProperty('context', String, true) context = ''; public isOk(): boolean { return this.result == 'ok'; } } /** An acknowledgement to a response message * * This message can be sent to a message broker to acknowledge the receipt of * a message. */ @JsonObject('DASFAcknowledgment') export class DASFAcknowledgment { @JsonProperty('messageId', String) messageId = ''; constructor(messageId?: string) { if (messageId) { this.messageId = messageId; } } } /** A response of a backend module. */ @JsonObject('DASFModuleResponse') export class DASFModuleResponse { /** The id of the message assigned by the message broker */ @JsonProperty('messageId', String) messageId = ''; /** The response data. * * usually encoded as byte64 string. */ @JsonProperty('payload', String) payload = ''; /** The time when this message has been published to the message broker. */ @JsonProperty('publishTime', String) publishTime = ''; /** Properties of the response * * the properties of the response may be derived from the * :ref:`PropertyKeys` enum. */ @JsonProperty('properties') properties?: DASFResponseProperties; /** Shortcut to the the messagetype of the properties */ public getMessageType(): MessageType { if (this.properties) { const msgType: MessageType = this.properties[PropertyKeys.MessageType]; if (msgType && msgType.trim().length > 0) { return msgType; } } throw new Error('Missing or empty message type property'); } /** Shortcut to the the request context of the properties */ public getRequestContext(): string { if (this.properties) { const context = this.properties[PropertyKeys.RequestContext] as string; if (context) { return context; } } throw new Error('Missing or empty request context property'); } /** Get the original id of the request */ public getRequestMessageId(): string { if (this.properties) { const messageId = this.properties[ PropertyKeys.RequestMessageId ] as string; if (messageId) { return messageId; } } throw new Error('Missing or empty request messageId property'); } /** Check if the response is fragmented or not. */ public isFragmented(): boolean { return ( this.properties != undefined && Object.prototype.hasOwnProperty.call( this.properties, PropertyKeys.NumFragments, ) && Object.prototype.hasOwnProperty.call( this.properties, PropertyKeys.Fragment, ) ); } /** Get the id of this fragment. */ public getFragmentId(): number { if (this.properties && this.isFragmented()) { return this.properties[PropertyKeys.Fragment] as number; } throw new Error( 'Unable to request fragment id from unfragmented response.', ); } /** Get the total number of fragments */ public getNumberOfFragments(): number { if (this.properties && this.isFragmented()) { return this.properties[PropertyKeys.NumFragments] as number; } throw new Error( 'Unable to request number of fragments from unfragmented response.', ); } } /** A tree-like structured progress report. * * This class can be used to handle a progress report from the backend module. * It is submitted to the `onProgress` callback of the * :meth:`DASFConnection.sendRequest` when a response arrives with the * :ref:`message type <MessageType>` ``MessageType.Progress`` */ @JsonObject('DASFProgressReport') export class DASFProgressReport { @JsonProperty('report_type', String) report_type = ''; /** ID for the report. */ @JsonProperty('report_id', String) report_id = ''; /** The description of the process. */ @JsonProperty('step_message', String) step_message = ''; /** The number of subprocesses in this report. */ @JsonProperty('steps', Number) steps = 0; /** Status of the underlying process. */ @JsonProperty('status', String) status: Status = Status.Running; /** Child reports within the tree */ @JsonProperty('children', [DASFProgressReport]) children?: DASFProgressReport[] = undefined; public hasError(): boolean { return this.status == Status.Error; } public hasSuccess(): boolean { return this.status == Status.Success; } public isRunning(): boolean { return this.status == Status.Running; } public isComplete(): boolean { return !this.isRunning(); } } @JsonConverter class JsonSchemaConverter implements JsonCustomConvert<object> { // dummy JsonSchemaConverter to make sure the json2typescript library does // not complain serialize(data: object): string { return JSON.stringify(data); } deserialize(data: object): JSONSchema7 { return data as JSONSchema7; } } /** A function in the API suitable for RPC via DASF */ @JsonObject('FunctionApiInfo') export class FunctionApiInfo { /** The name of the function that is used as identifier in the RPC. */ @JsonProperty('name', String) name = ''; /** The JSON Schema for the function. */ @JsonProperty('rpc_schema', JsonSchemaConverter) rpcSchema: JSONSchema7 = {}; /** The JSON Schema for the return value. */ @JsonProperty('return_schema', JsonSchemaConverter) returnSchema: JSONSchema7 = {}; } /** A class in the API suitable for RPC via DASF */ @JsonObject('ClassApiInfo') export class ClassApiInfo { /** The name of the class that is used as identifier in the RPC. */ @JsonProperty('name', String) name = ''; /** The JSON Schema for the constructor of the class. */ @JsonProperty('rpc_schema', JsonSchemaConverter) rpcSchema: JSONSchema7 = {}; /** The list of methods that this class provides. */ @JsonProperty('methods', [FunctionApiInfo]) methods: FunctionApiInfo[] = []; } /** An model that represants the API of a backend module. */ @JsonObject('ModuleApiInfo') export class ModuleApiInfo { /** The RPC-enabled classes that this module contains. */ @JsonProperty('classes', [ClassApiInfo]) classes: ClassApiInfo[] = []; /** The RPC-enabled functions that this module contains. */ @JsonProperty('functions', [FunctionApiInfo]) functions: FunctionApiInfo[] = []; /** The aggregated JSON schema for an RPC call to this module. */ @JsonProperty('rpc_schema', JsonSchemaConverter) rpcSchema: JSONSchema7 = {}; }