/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module IModelHost
 */
import * as ws from "ws";
import { IpcWebSocket, IpcWebSocketBackend, IpcWebSocketMessage, IpcWebSocketTransport, rpcOverIpcStrings, RpcSessionInvocation, } from "@itwin/core-common";
import { IpcHandler, IpcHost } from "./IpcHost";
class LocalTransport extends IpcWebSocketTransport {
    _server;
    _connections = new Map();
    constructor(opts) {
        super();
        if (!opts.noServer) {
            this._server = new ws.Server({ port: opts.socketPort ?? 3002, host: opts.host ?? "127.0.0.1" });
            this._server.on("connection", (connection) => LocalhostIpcHost.connect(connection));
        }
    }
    send(message) {
        this._connections.forEach((last, connection) => {
            message.sequence = last + 1;
            this._connections.set(connection, message.sequence);
            const parts = this.serialize(message);
            parts.forEach((part) => connection.send(part));
        });
    }
    connect(connection) {
        this._connections.set(connection, -1);
        connection.on("message", async (data) => {
            const message = await this.notifyIncoming(data, connection);
            if (IpcWebSocketMessage.skip(message)) {
                return;
            }
            for (const listener of IpcWebSocket.receivers) {
                listener({}, message);
            }
        });
        connection.on("close", () => {
            this._connections.delete(connection);
            this.notifyClose(connection);
        });
    }
}
class RpcHandler extends IpcHandler {
    channelName = rpcOverIpcStrings.channelName;
    async request(info) {
        const invocation = RpcSessionInvocation.create(info);
        const fulfillment = await invocation.fulfillment;
        return invocation.rejected ? Promise.reject(fulfillment.rawResult) : fulfillment.rawResult; // eslint-disable-line @typescript-eslint/prefer-promise-reject-errors
    }
}
/** @internal */
export class LocalhostIpcHost {
    static _initialized = false;
    static socket;
    static connect(connection) {
        IpcWebSocket.transport.connect(connection);
    }
    static async startup(opts) {
        let registerHandler = false;
        if (!this._initialized) {
            registerHandler = true;
            IpcWebSocket.transport = new LocalTransport(opts?.localhostIpcHost ?? {});
            this.socket = new IpcWebSocketBackend();
            this._initialized = true;
        }
        await IpcHost.startup({ ipcHost: { socket: this.socket }, iModelHost: opts?.iModelHost });
        if (registerHandler)
            RpcHandler.register();
    }
}
//# sourceMappingURL=LocalhostIpcHost.js.map