UNPKG

@openhps/core

Version:

Open Hybrid Positioning System - Core component

107 lines (94 loc) 4.33 kB
import { DataFrame } from '../data/DataFrame'; import { PullOptions, PushOptions } from '../graph/options'; import { PushCompletedEvent, PushError } from '../graph/events'; import { Model } from '../Model'; import { Node, NodeOptions } from '../Node'; import { RemoteService, RemotePushOptions, RemotePullOptions } from '../service/RemoteService'; import { Serializable } from '../data/decorators'; import { DataSerializer } from '../data/DataSerializer'; /** * A remote node connects to a service in order to provide a remote connection. * @category Node */ export class RemoteNode<In extends DataFrame, Out extends DataFrame, S extends RemoteService> extends Node<In, Out> { protected service: S; protected options: RemoteNodeOptions<S>; proxyNode: Node<any, any>; constructor(options?: RemoteNodeOptions<S>, node?: Node<any, any>) { super(options); this.proxyNode = node; this.options.service = this.options.service || (RemoteService as unknown as Serializable<S>); this.options.serialize = this.options.serialize ?? ((object: DataFrame) => DataSerializer.serialize(object)); this.options.deserialize = this.options.deserialize ?? ((object: any) => DataSerializer.deserialize(object)); this.on('push', this._onPush.bind(this)); this.on('pull', this._onPull.bind(this)); this.on('error', this._onDownstreamError.bind(this)); this.on('completed', this._onDownstreamCompleted.bind(this)); this.on('localpush', this._onLocalPush.bind(this)); this.on('localpull', this._onLocalPull.bind(this)); this.on('localevent', this._onLocalEvent.bind(this)); this.once('build', this._onBuild.bind(this)); } private _onBuild(): Promise<void> { return new Promise<void>((resolve, reject) => { this.service = (this.graph as Model<any, any>).findService<S>(this.options.service as Serializable<S>); if (this.service === undefined || this.service === null) { return reject(new Error(`Remote service was not added to model!`)); } this.service.registerNode(this).then(resolve).catch(reject); }); } private _onPush(frame: In | In[], options?: PushOptions): Promise<void> { return new Promise<void>((resolve) => { // Send push to clients this.service.remotePush(this.uid, frame, { ...options, ...this.options, }); resolve(); }); } private _onPull(options?: PullOptions): Promise<void> { return new Promise<void>((resolve) => { // Send pull to clients this.service.remotePull(this.uid, options); resolve(); }); } private _onLocalPush(frame: any, options?: RemotePushOptions): Promise<void> { return new Promise<void>((resolve) => { const frameDeserialized = frame instanceof DataFrame ? frame : this.options.deserialize(frame, options); this.outlets.forEach((outlet) => outlet.push(frameDeserialized as any, options)); resolve(); }); } private _onLocalPull(options?: RemotePullOptions): Promise<void> { return new Promise<void>((resolve, reject) => { Promise.all(this.inlets.map((inlet) => inlet.pull(options))) .then(() => { resolve(); }) .catch(reject); }); } private _onLocalEvent(event: string, arg: any): void { this.inlets.forEach((inlet) => inlet.emit(event, arg)); } private _onDownstreamCompleted(event: PushCompletedEvent): void { // Send completed event to client this.service.remoteEvent(this.uid, 'completed', event); } private _onDownstreamError(error: PushError): void { // Send error to clients this.service.remoteEvent(this.uid, 'error', error); } } export interface RemoteNodeOptions<S extends RemoteService> extends NodeOptions { /** * Service to use for the remote note * @default RemoteService any remote service */ service?: Serializable<S>; serialize?: (obj: DataFrame, options?: RemotePushOptions) => any; deserialize?: (obj: any, options?: RemotePushOptions) => DataFrame; }