UNPKG

@itwin/core-common

Version:

iTwin.js components common to frontend and backend

144 lines 5.67 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ /** @packageDocumentation * @module IpcSocket */ /** @internal */ export var IpcWebSocketMessageType; (function (IpcWebSocketMessageType) { IpcWebSocketMessageType[IpcWebSocketMessageType["Send"] = 0] = "Send"; IpcWebSocketMessageType[IpcWebSocketMessageType["Push"] = 1] = "Push"; IpcWebSocketMessageType[IpcWebSocketMessageType["Invoke"] = 2] = "Invoke"; IpcWebSocketMessageType[IpcWebSocketMessageType["Response"] = 3] = "Response"; IpcWebSocketMessageType[IpcWebSocketMessageType["Internal"] = 4] = "Internal"; IpcWebSocketMessageType[IpcWebSocketMessageType["Duplicate"] = 5] = "Duplicate"; })(IpcWebSocketMessageType || (IpcWebSocketMessageType = {})); /** @internal */ export var IpcWebSocketMessage; (function (IpcWebSocketMessage) { function internal() { return { type: IpcWebSocketMessageType.Internal, channel: "", sequence: Number.MIN_SAFE_INTEGER }; } IpcWebSocketMessage.internal = internal; function duplicate() { return { type: IpcWebSocketMessageType.Duplicate, channel: "", sequence: Number.MIN_SAFE_INTEGER }; } IpcWebSocketMessage.duplicate = duplicate; function skip(message) { return message.type === IpcWebSocketMessageType.Internal || message.type === IpcWebSocketMessageType.Duplicate; } IpcWebSocketMessage.skip = skip; })(IpcWebSocketMessage || (IpcWebSocketMessage = {})); /** @internal */ export class IpcWebSocket { static transport; static receivers = new Set(); _channels = new Map(); constructor() { IpcWebSocket.receivers.add(async (e, m) => this.broadcast(e, m)); } addListener(channel, listener) { let listeners = this._channels.get(channel); if (!listeners) { listeners = new Set(); this._channels.set(channel, listeners); } if (!listeners.has(listener)) listeners.add(listener); return () => listeners.delete(listener); } removeListener(channel, listener) { this._channels.get(channel)?.delete(listener); } async broadcast(evt, message) { if (message.type !== IpcWebSocketMessageType.Send && message.type !== IpcWebSocketMessageType.Push) return; const handlers = this._channels.get(message.channel); if (!handlers) return; let arg = message.data; if (typeof (arg) === "undefined") arg = []; for (const handler of handlers) handler(evt, ...arg); } } /** @internal */ export class IpcWebSocketFrontend extends IpcWebSocket { _nextRequest = 0; _pendingRequests = new Map(); constructor() { super(); IpcWebSocket.receivers.add(async (e, m) => this.dispatch(e, m)); } send(channel, ...data) { IpcWebSocket.transport.send({ type: IpcWebSocketMessageType.Send, channel, data, sequence: -1 }); } async invoke(channel, methodName, ...args) { const requestId = ++this._nextRequest; IpcWebSocket.transport.send({ type: IpcWebSocketMessageType.Invoke, channel, method: methodName, data: args, request: requestId, sequence: -1 }); return new Promise((resolve) => { this._pendingRequests.set(requestId, resolve); }); } async dispatch(_evt, message) { if (message.type !== IpcWebSocketMessageType.Response || !message.response) return; const pendingHandler = this._pendingRequests.get(message.response); if (!pendingHandler) return; this._pendingRequests.delete(message.response); pendingHandler(message.data); } } /** @internal */ export class IpcWebSocketBackend extends IpcWebSocket { _handlers = new Map(); _processingQueue = []; constructor() { super(); IpcWebSocket.receivers.add(async (e, m) => this.dispatch(e, m)); } send(channel, ...data) { IpcWebSocket.transport.send({ type: IpcWebSocketMessageType.Push, channel, data, sequence: -1 }); } handle(channel, handler) { this._handlers.set(channel, handler); return () => { if (this._handlers.get(channel) === handler) this._handlers.delete(channel); }; } async dispatch(_evt, message) { if (message.type !== IpcWebSocketMessageType.Invoke) return; this._processingQueue.push(message); await this.processMessages(); } async processMessages() { if (!this._processingQueue.length) { return; } const message = this._processingQueue.shift(); if (message && message.method) { const handler = this._handlers.get(message.channel); if (handler) { let args = message.data; if (typeof (args) === "undefined") args = []; const response = await handler({}, message.method, ...args); IpcWebSocket.transport.send({ type: IpcWebSocketMessageType.Response, channel: message.channel, response: message.request, data: response, sequence: -1, }); } } await this.processMessages(); } } //# sourceMappingURL=IpcWebSocket.js.map