UNPKG

@stryke/capnp

Version:

A package to assist in running the Cap'n Proto compiler and creating Cap'n Proto serialization protocol schemas.

1 lines 6.39 kB
{"version":3,"file":"rpc-helpers.mjs","names":[],"sources":["../../src/rpc-helpers.ts"],"sourcesContent":["/* -------------------------------------------------------------------\n\n ⚡ Storm Software - Stryke\n\n This code was released as part of the Stryke project. Stryke\n is maintained by Storm Software under the Apache-2.0 license, and is\n free for commercial and private use. For more information, please visit\n our licensing page at https://stormsoftware.com/licenses/projects/stryke.\n\n Website: https://stormsoftware.com\n Repository: https://github.com/storm-software/stryke\n Documentation: https://docs.stormsoftware.com/projects/stryke\n Contact: https://stormsoftware.com/contact\n\n SPDX-License-Identifier: Apache-2.0\n\n ------------------------------------------------------------------- */\n\nimport { Conn, Deferred, DeferredTransport, Message } from \"capnp-es\";\nimport type { Message as RPCMessage } from \"capnp-es/capnp/rpc\";\nimport type { MessagePort } from \"node:worker_threads\";\nimport { MessageChannel } from \"node:worker_threads\";\n\n/**\n * A transport class for Cap'n Proto RPC that uses {@link MessageChannel} for communication.\n */\nexport class CapnpRPCMessageChannelTransport extends DeferredTransport {\n public port: MessagePort;\n\n public constructor(port: MessagePort) {\n super();\n\n this.port = port;\n\n this.port.on(\"message\", this.resolve);\n this.port.on(\"messageerror\", this.reject);\n this.port.on(\"close\", this.close);\n }\n\n /**\n * Closes the transport and removes all event listeners.\n */\n public override close = (): void => {\n this.port.off(\"message\", this.resolve);\n this.port.off(\"messageerror\", this.reject);\n this.port.off(\"close\", this.close);\n this.port.close();\n\n super.close();\n };\n\n /**\n * Sends a Cap'n Proto RPC message over the MessagePort.\n *\n * @param msg - The RPC message to send.\n */\n public sendMessage(msg: RPCMessage): void {\n const m = new Message();\n m.setRoot(msg);\n\n const buf = m.toArrayBuffer();\n this.port.postMessage(buf, [buf]);\n }\n}\n\n/**\n * A class that manages Cap'n Proto RPC connections.\n */\nexport class CapnpRPC {\n /**\n * A queue for deferred connections that are waiting to be accepted.\n *\n * @remarks\n * This is used to manage incoming connections when the accept method is called.\n */\n protected acceptQueue = new Array<Deferred<Conn>>();\n\n /**\n * A map of connections by their ID.\n *\n * @remarks\n * This is used to manage multiple connections and allows for easy retrieval by ID.\n */\n protected connections: Record<number, Conn> = {};\n\n /**\n * A queue for connections that are waiting to be accepted.\n *\n * @remarks\n * This is used to manage incoming connections when the accept method is called.\n */\n protected connectQueue = new Array<MessagePort>();\n\n /**\n * Creates a new {@link Conn} instance.\n *\n * @remarks\n * This class is used to manage connections and accept incoming connections using the {@link MessageChannel} API.\n */\n public connect(id = 0): Conn {\n if (this.connections[id] !== undefined) {\n return this.connections[id];\n }\n\n const ch = new MessageChannel();\n const conn = new Conn(new CapnpRPCMessageChannelTransport(ch.port1));\n const accept = this.acceptQueue.pop();\n this.connections[id] = conn;\n\n if (accept === undefined) {\n this.connectQueue.push(ch.port2);\n } else {\n accept.resolve(new Conn(new CapnpRPCMessageChannelTransport(ch.port2)));\n }\n\n return conn;\n }\n\n /**\n * Accepts a connection from the connect queue.\n *\n * @returns A promise that resolves to a Conn instance when a connection is accepted.\n * @throws If no connections are available in the connect queue.\n */\n public async accept(): Promise<Conn> {\n const port2 = this.connectQueue.pop();\n if (port2 !== undefined) {\n return Promise.resolve(\n new Conn(new CapnpRPCMessageChannelTransport(port2))\n );\n }\n\n const deferred = new Deferred<Conn>();\n this.acceptQueue.push(deferred);\n return deferred.promise;\n }\n\n /**\n * Closes all connections and clears the queues.\n *\n * @remarks\n * This method will reject all pending accept promises and close all\n * connections in the connect queue.\n */\n public close(): void {\n let i = this.acceptQueue.length;\n while (--i >= 0) {\n this.acceptQueue[i]?.reject();\n }\n\n i = this.connectQueue.length;\n while (--i >= 0) {\n this.connectQueue[i]!.close();\n }\n\n for (const id in this.connections) {\n this.connections[id]?.shutdown();\n }\n\n this.acceptQueue.length = 0;\n this.connectQueue.length = 0;\n this.connections = {};\n }\n}\n"],"mappings":";;;;;;;;AA0BA,IAAa,kCAAb,cAAqD,kBAAkB;CACrE,AAAO;CAEP,AAAO,YAAY,MAAmB;AACpC,SAAO;AAEP,OAAK,OAAO;AAEZ,OAAK,KAAK,GAAG,WAAW,KAAK,QAAQ;AACrC,OAAK,KAAK,GAAG,gBAAgB,KAAK,OAAO;AACzC,OAAK,KAAK,GAAG,SAAS,KAAK,MAAM;;;;;CAMnC,AAAgB,cAAoB;AAClC,OAAK,KAAK,IAAI,WAAW,KAAK,QAAQ;AACtC,OAAK,KAAK,IAAI,gBAAgB,KAAK,OAAO;AAC1C,OAAK,KAAK,IAAI,SAAS,KAAK,MAAM;AAClC,OAAK,KAAK,OAAO;AAEjB,QAAM,OAAO;;;;;;;CAQf,AAAO,YAAY,KAAuB;EACxC,MAAM,IAAI,IAAI,SAAS;AACvB,IAAE,QAAQ,IAAI;EAEd,MAAM,MAAM,EAAE,eAAe;AAC7B,OAAK,KAAK,YAAY,KAAK,CAAC,IAAI,CAAC;;;;;;AAOrC,IAAa,WAAb,MAAsB;;;;;;;CAOpB,AAAU,cAAc,IAAI,OAAuB;;;;;;;CAQnD,AAAU,cAAoC,EAAE;;;;;;;CAQhD,AAAU,eAAe,IAAI,OAAoB;;;;;;;CAQjD,AAAO,QAAQ,KAAK,GAAS;AAC3B,MAAI,KAAK,YAAY,QAAQ,OAC3B,QAAO,KAAK,YAAY;EAG1B,MAAM,KAAK,IAAI,gBAAgB;EAC/B,MAAM,OAAO,IAAI,KAAK,IAAI,gCAAgC,GAAG,MAAM,CAAC;EACpE,MAAM,SAAS,KAAK,YAAY,KAAK;AACrC,OAAK,YAAY,MAAM;AAEvB,MAAI,WAAW,OACb,MAAK,aAAa,KAAK,GAAG,MAAM;MAEhC,QAAO,QAAQ,IAAI,KAAK,IAAI,gCAAgC,GAAG,MAAM,CAAC,CAAC;AAGzE,SAAO;;;;;;;;CAST,MAAa,SAAwB;EACnC,MAAM,QAAQ,KAAK,aAAa,KAAK;AACrC,MAAI,UAAU,OACZ,QAAO,QAAQ,QACb,IAAI,KAAK,IAAI,gCAAgC,MAAM,CAAC,CACrD;EAGH,MAAM,WAAW,IAAI,UAAgB;AACrC,OAAK,YAAY,KAAK,SAAS;AAC/B,SAAO,SAAS;;;;;;;;;CAUlB,AAAO,QAAc;EACnB,IAAI,IAAI,KAAK,YAAY;AACzB,SAAO,EAAE,KAAK,EACZ,MAAK,YAAY,IAAI,QAAQ;AAG/B,MAAI,KAAK,aAAa;AACtB,SAAO,EAAE,KAAK,EACZ,MAAK,aAAa,GAAI,OAAO;AAG/B,OAAK,MAAM,MAAM,KAAK,YACpB,MAAK,YAAY,KAAK,UAAU;AAGlC,OAAK,YAAY,SAAS;AAC1B,OAAK,aAAa,SAAS;AAC3B,OAAK,cAAc,EAAE"}