UNPKG

@devgrid/netron

Version:
194 lines 7.66 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Netron = void 0; const node_path_1 = __importDefault(require("node:path")); const cuid_1 = __importDefault(require("@bugsnag/cuid")); const ws_1 = require("ws"); const async_emitter_1 = require("@devgrid/async-emitter"); const local_peer_1 = require("./local-peer"); const remote_peer_1 = require("./remote-peer"); const task_manager_1 = require("./task-manager"); const common_1 = require("./common"); class Netron extends async_emitter_1.AsyncEventEmitter { constructor(options) { super(); this.options = options; this.ownEvents = new Map(); this.peers = new Map(); this.isStarted = false; this.services = new Map(); this.id = options?.id ?? (0, cuid_1.default)(); this.taskManager = new task_manager_1.TaskManager({ timeout: options?.taskTimeout, overwriteStrategy: options?.taskOverwriteStrategy, }); this.peer = new local_peer_1.LocalPeer(this); } async start() { if (this.isStarted) { throw new Error('Netron already started'); } await this.taskManager.loadTasksFromDir(node_path_1.default.join(__dirname, 'core-tasks')); if (!this.options?.listenHost || !this.options?.listenPort) { this.isStarted = true; return Promise.resolve(); } return new Promise((resolve, reject) => { this.wss = new ws_1.WebSocketServer({ host: this.options?.listenHost, port: this.options?.listenPort, }); this.wss.on('listening', () => { this.isStarted = true; resolve(); }); this.wss.on('error', (err) => { reject(err); }); this.wss.on('connection', (ws, req) => { const peerId = new URL(req.url, 'ws://localhost:8080').searchParams.get('id'); if (!peerId) { ws.close(); return; } const peer = new remote_peer_1.RemotePeer(ws, this, peerId); this.peers.set(peer.id, peer); ws.send(JSON.stringify({ type: 'id', id: this.id })); this.emitSpecial(common_1.NETRON_EVENT_PEER_CONNECT, (0, common_1.getPeerEventName)(peer.id), { peerId }); ws.on('close', () => { this.peers.delete(peerId); this.emitSpecial(common_1.NETRON_EVENT_PEER_DISCONNECT, (0, common_1.getPeerEventName)(peerId), { peerId }); }); peer.init(false, this.options?.abilities); }); }); } async stop() { if (this.wss) { this.wss.close(); this.wss = undefined; } this.isStarted = false; } async connect(address, abilities) { return new Promise((resolve, reject) => { const timeout = setTimeout(() => { reject(new Error('Connection timeout')); }, this.options?.connectTimeout ?? common_1.CONNECT_TIMEOUT); const ws = new ws_1.WebSocket(`${address}?id=${this.id}`); const peer = new remote_peer_1.RemotePeer(ws, this); let isResolved = false; ws.on('open', () => { clearTimeout(timeout); const uidHandler = (message, isBinary) => { if (isBinary) { return; } try { const data = JSON.parse(message.toString()); if (data.type === 'id') { peer.id = data.id; this.peers.set(peer.id, peer); if (!isResolved) { isResolved = true; peer.init(true, abilities).then(() => { this.emitSpecial(common_1.NETRON_EVENT_PEER_CONNECT, (0, common_1.getPeerEventName)(peer.id), { peerId: peer.id }); resolve(peer); }); } } else { ws.close(); } } catch (error) { console.error('Message error:', error); ws.close(); if (!isResolved) { isResolved = true; reject(new Error('Message error')); } } finally { ws.removeListener('message', uidHandler); } }; ws.on('message', uidHandler); }); ws.on('error', (err) => { console.error(`Connection error to ${address}:`, err); if (!isResolved) { isResolved = true; reject(err); } }); ws.on('close', () => { if (!isResolved) { console.warn('Connection closed prematurely.'); reject(new Error('Connection closed prematurely')); } this.peers.delete(peer.id); this.emitSpecial(common_1.NETRON_EVENT_PEER_DISCONNECT, (0, common_1.getPeerEventName)(peer.id), { peerId: peer.id }); }); }); } disconnect(peerId) { const peer = this.peers.get(peerId); if (peer) { peer.disconnect(); this.peers.delete(peerId); this.emitSpecial(common_1.NETRON_EVENT_PEER_DISCONNECT, (0, common_1.getPeerEventName)(peerId), { peerId }); } } getServiceNames() { return [...this.services.keys()]; } addTask(fn) { return this.taskManager.addTask(fn); } async runTask(peer, name, ...args) { return await this.taskManager.runTask(name, peer, ...args); } deleteSpecialEvents(id) { this.ownEvents.delete(id); } async emitSpecial(event, id, data) { const events = this.ownEvents.get(id) || []; events.push({ name: event, data }); this.ownEvents.set(id, events); if (events.length > 1) { return; } while (events.length > 0) { const eventData = events.shift(); if (eventData === void 0) { break; } try { const timeoutPromise = new Promise((_, reject) => { const timeoutId = setTimeout(() => { reject(new Error(`Emit timeout for event: ${eventData.name}`)); }, 5000); this.emitParallel(eventData.name, eventData.data) .finally(() => clearTimeout(timeoutId)) .catch(reject); }); await timeoutPromise; } catch (err) { console.error(`Event emit error: ${err.message}`); } } this.ownEvents.delete(id); } static async create(options) { const netron = new Netron(options); await netron.start(); return netron; } } exports.Netron = Netron; //# sourceMappingURL=netron.js.map