{"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"}