@itwin/core-common
Version:
iTwin.js components common to frontend and backend
150 lines • 6.08 kB
JavaScript
;
/*---------------------------------------------------------------------------------------------
* 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
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.IpcWebSocketBackend = exports.IpcWebSocketFrontend = exports.IpcWebSocket = exports.IpcWebSocketMessage = exports.IpcWebSocketMessageType = void 0;
/** @internal */
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 || (exports.IpcWebSocketMessageType = IpcWebSocketMessageType = {}));
/** @internal */
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 || (exports.IpcWebSocketMessage = IpcWebSocketMessage = {}));
/** @internal */
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);
}
}
exports.IpcWebSocket = IpcWebSocket;
/** @internal */
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);
}
}
exports.IpcWebSocketFrontend = IpcWebSocketFrontend;
/** @internal */
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();
}
}
exports.IpcWebSocketBackend = IpcWebSocketBackend;
//# sourceMappingURL=IpcWebSocket.js.map