UNPKG

@devgrid/netron

Version:
351 lines 12.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RemotePeer = void 0; const ws_1 = require("ws"); const common_1 = require("@devgrid/common"); const service_stub_1 = require("./service-stub"); const abstract_peer_1 = require("./abstract-peer"); const predicates_1 = require("./predicates"); const common_2 = require("./common"); const packet_1 = require("./packet"); class RemotePeer extends abstract_peer_1.AbstractPeer { constructor(socket, netron, id = '') { super(netron, id); this.socket = socket; this.responseHandlers = new common_1.TimedMap(this.netron.options?.requestTimeout ?? common_2.REQUEST_TIMEOUT, (packetId) => { const handlers = this.deleteResponseHandler(packetId); if (handlers?.errorHandler) { handlers.errorHandler(new Error('Request timeout exceeded')); } }); this.writableStreams = new Map(); this.readableStreams = new Map(); this.eventSubscribers = new Map(); this.remoteSubscriptions = new Map(); this.abilities = {}; this.services = new Map(); this.definitions = new Map(); } async init(isConnector, abilities) { this.socket.on('message', (data, isBinary) => { if (isBinary) { this.handlePacket((0, packet_1.decodePacket)(data)); } else { console.warn('Received non-binary message:', data); } }); if (isConnector) { this.abilities = (await this.runTask('abilities', abilities)); if (this.abilities.services) { for (const [name, definition] of this.abilities.services) { this.definitions.set(definition.id, definition); this.services.set(name, definition); } } if (this.abilities.subsribeForServices) { await this.subscribe(common_2.NETRON_EVENT_SERVICE_EXPOSE, (event) => { this.definitions.set(event.definition.id, event.definition); this.services.set(event.name, event.definition); }); await this.subscribe(common_2.NETRON_EVENT_SERVICE_UNEXPOSE, (event) => { this.definitions.delete(event.defId); this.services.delete(event.name); }); } } } async exposeService(instance) { const meta = Reflect.getMetadata(common_2.SERVICE_ANNOTATION, instance.constructor); if (!meta) { throw new Error('Invalid service'); } if (this.services.has(meta.name)) { throw new Error(`Service already exposed: ${meta.name}`); } const def = await this.runTask('expose_service', meta); const stub = new service_stub_1.ServiceStub(this.netron.peer, instance, meta); this.netron.peer.stubs.set(def.id, stub); this.netron.peer.serviceInstances.set(instance, stub); return def; } async unexposeService(serviceName) { const defId = await this.runTask('unexpose_service', serviceName); for (const i of this.interfaces.values()) { if (i.instance.$def?.parentId === defId) { this.releaseInterface(i.instance); } } const stub = this.netron.peer.stubs.get(defId); if (stub) { this.netron.peer.serviceInstances.delete(stub.instance); this.netron.peer.stubs.delete(defId); } } async subscribe(eventName, handler) { const handlers = this.eventSubscribers.get(eventName); if (!handlers) { this.eventSubscribers.set(eventName, [handler]); await this.runTask('subscribe', eventName); } else if (!handlers.includes(handler)) { handlers.push(handler); } } async unsubscribe(eventName, handler) { const handlers = this.eventSubscribers.get(eventName); if (handlers) { const index = handlers.indexOf(handler); if (index >= 0) { handlers.splice(index, 1); if (handlers.length === 0) { this.eventSubscribers.delete(eventName); await this.runTask('unsubscribe', eventName); } } } } getServiceNames() { return [...this.services.keys()]; } get(defId, name) { const def = this.definitions.get(defId); if (!def) { throw new Error(`Unknown definition: ${defId}`); } return new Promise((resolve, reject) => { this.sendRequest(packet_1.TYPE_GET, [defId, name], (result) => { resolve(this.processResult(def, result)); }, reject).catch(reject); }); } set(defId, name, value) { const def = this.definitions.get(defId); if (!def) { throw new Error(`Unknown definition: ${defId}`); } return new Promise((resolve, reject) => { this.sendRequest(packet_1.TYPE_SET, [defId, name, value], () => { resolve(); }, reject).catch(reject); }); } call(defId, method, args) { const def = this.definitions.get(defId); if (!def) { throw new Error(`Unknown definition: ${defId}`); } args = this.processArgs(def, args); return new Promise((resolve, reject) => { this.sendRequest(packet_1.TYPE_CALL, [defId, method, ...args], (result) => { resolve(this.processResult(def, result)); }, reject).catch(reject); }); } disconnect() { this.socket.close(); this.responseHandlers.clear(); this.writableStreams.clear(); this.readableStreams.clear(); this.eventSubscribers.clear(); this.remoteSubscriptions.clear(); this.services.clear(); this.definitions.clear(); } runTask(name, ...args) { return new Promise((resolve, reject) => { this.sendRequest(packet_1.TYPE_TASK, [name, ...args], (result) => { resolve(result); }, reject).catch(reject); }); } sendRequest(type, data, successHandler, errorHandler) { const packet = (0, packet_1.createPacket)(packet_1.Packet.nextId(), 1, type, data); this.responseHandlers.set(packet.id, { successHandler, errorHandler, }); return this.sendPacket(packet); } sendResponse(packet, data) { packet.setImpulse(0); packet.data = data; return this.sendPacket(packet); } sendErrorResponse(packet, error) { packet.setImpulse(0); packet.setError(1); packet.data = error; return this.sendPacket(packet); } sendPacket(packet) { return new Promise((resolve, reject) => { if (this.socket.readyState === ws_1.WebSocket.OPEN) { this.socket.send((0, packet_1.encodePacket)(packet), { binary: true }, (err) => { if (err) { reject(err); } else { resolve(); } }); } else { reject(new Error('Socket closed')); } }); } sendStreamChunk(streamId, chunk, index, isLast, isLive) { return this.sendPacket((0, packet_1.createStreamPacket)(packet_1.Packet.nextId(), streamId, index, isLast, isLive, chunk)); } handleResponse(packet) { const id = packet.id; const handlers = this.deleteResponseHandler(id); if (handlers) { const data = packet.data; if (packet.getError() === 0) { handlers.successHandler(data); } else { handlers.errorHandler?.(data); } } } async handlePacket(packet) { const pType = packet.getType(); if (packet.getImpulse() === 0) { this.handleResponse(packet); return; } switch (pType) { case packet_1.TYPE_SET: { const [defId, name, value] = packet.data; try { const stub = this.netron.peer.getStubByDefinitionId(defId); await stub.set(name, value); await this.sendResponse(packet, undefined); } catch (err) { console.error('Error setting value:', err); try { await this.sendErrorResponse(packet, err); } catch (err_) { console.error('Error sending error response:', err_); } } break; } case packet_1.TYPE_GET: { const [defId, name] = packet.data; try { const stub = this.netron.peer.getStubByDefinitionId(defId); await this.sendResponse(packet, await stub.get(name)); } catch (err) { try { await this.sendErrorResponse(packet, err); } catch (err_) { console.error('Error sending error response:', err_); } } break; } case packet_1.TYPE_CALL: { const [defId, method, ...args] = packet.data; try { const stub = this.netron.peer.getStubByDefinitionId(defId); await this.sendResponse(packet, await stub.call(method, args)); } catch (err) { try { await this.sendErrorResponse(packet, err); } catch (err_) { console.error('Error sending error response:', err_); } } break; } case packet_1.TYPE_TASK: { const [name, ...args] = packet.data; try { await this.sendResponse(packet, await this.netron.runTask(this, name, ...args)); } catch (err) { try { await this.sendErrorResponse(packet, err); } catch (err_) { console.error('Error sending error response:', err_); } } break; } case packet_1.TYPE_STREAM: { if (!packet.streamId || packet.streamIndex === undefined) return; const stream = this.readableStreams.get(packet.streamId); if (!stream) return; stream.onPacket(packet); break; } default: { console.warn('Unknown packet type:', pType); } } } async releaseInterfaceInternal(iInstance) { await this.runTask('unref_service', iInstance.$def?.id); this.unrefService(iInstance.$def?.id); } refService(def, parentDef) { const existingDef = this.definitions.get(def.id); if (existingDef) { return existingDef; } def.parentId = parentDef.id; this.definitions.set(def.id, def); return def; } unrefService(defId) { if (defId) { this.definitions.delete(defId); } } processResult(parentDef, result) { if ((0, predicates_1.isServiceDefinition)(result)) { const def = this.refService(result, parentDef); return this.queryInterfaceByDefId(def.id, def); } return result; } processArgs(ctxDef, args) { return args; } deleteResponseHandler(packetId) { const handlers = this.responseHandlers.get(packetId); if (handlers) { this.responseHandlers.delete(packetId); } return handlers; } getDefinitionById(defId) { const def = this.definitions.get(defId); if (!def) { throw new Error(`Unknown definition: ${defId}.`); } return def; } getDefinitionByServiceName(name) { const def = this.services.get(name); if (def === void 0) { throw new Error(`Unknown service: ${name}.`); } return def; } } exports.RemotePeer = RemotePeer; //# sourceMappingURL=remote-peer.js.map