"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExtHostProxy = void 0;
const tslib_1 = require("tslib");
const net_1 = tslib_1.__importDefault(require("net"));
const ide_connection_1 = require("@opensumi/ide-connection");
const connection_1 = require("@opensumi/ide-connection/lib/common/connection");
const ide_core_node_1 = require("@opensumi/ide-core-node");
const ext_host_proxy_1 = require("../common/ext.host.proxy");
const extension_host_manager_1 = require("../node/extension.host.manager");
class ExtHostProxyRPCService extends ide_connection_1.RPCService {
    constructor(extServerProxy) {
        super();
        this.extServerProxy = extServerProxy;
        this.LOG_TAG = '[ExtHostProxyRPCService]';
        this.extensionHostManager = new extension_host_manager_1.ExtensionHostManager();
    }
    async $send(pid, message) {
        return this.extensionHostManager.send(pid, message);
    }
    async $isRunning(pid) {
        return this.extensionHostManager.isRunning(pid);
    }
    async $treeKill(pid) {
        return this.extensionHostManager.treeKill(pid);
    }
    async $kill(pid, signal) {
        return this.extensionHostManager.kill(pid, signal);
    }
    async $isKilled(pid) {
        return this.extensionHostManager.isKilled(pid);
    }
    async $fork(modulePath, args = [], options = {}) {
        // 需要 merge ide server 的环境变量和插件运行的环境变量
        const forkOptions = {
            ...options,
            env: {
                ...options.env,
                ...process.env,
            },
        };
        return this.extensionHostManager.fork(modulePath, args, forkOptions);
    }
    async $onExit(callId, pid) {
        this.extensionHostManager.onExit(pid, (code, signal) => this.extServerProxy.$callback(callId, code, signal));
    }
    async $onOutput(callId, pid) {
        this.extensionHostManager.onOutput(pid, (output) => this.extServerProxy.$callback(callId, output));
    }
    async $findDebugPort(startPort, giveUpAfter, timeout) {
        return this.extensionHostManager.findDebugPort(startPort, giveUpAfter, timeout);
    }
    async $onMessage(callId, pid) {
        this.extensionHostManager.onMessage(pid, (msg) => this.extServerProxy.$callback(callId, msg));
    }
    async $disposeProcess(pid) {
        this.extensionHostManager.disposeProcess(pid);
    }
    async $dispose() {
        await this.extensionHostManager.dispose();
    }
}
class ExtHostProxy extends ide_core_node_1.Disposable {
    constructor(options) {
        super();
        this.connectedEmitter = this.registerDispose(new ide_core_node_1.Emitter());
        this.logger = (0, ide_core_node_1.getDebugLogger)();
        this.onConnected = this.connectedEmitter.event;
        this.LOG_TAG = '[ExtHostProxy]';
        this.reconnectOnEvent = () => {
            clearTimeout(this.reconnectingTimer);
            this.reconnectingTimer = setTimeout(() => {
                this.logger.warn(this.LOG_TAG, 'reconnecting ext host server');
                this.createSocket();
            }, this.options.retryTime);
        };
        this.connectOnEvent = () => {
            this.logger.info(this.LOG_TAG, 'connect success');
            // this.previouslyConnected = true;
            clearTimeout(this.reconnectingTimer);
            this.setRPCMethods();
            this.connectedEmitter.fire();
        };
        this.connect = () => {
            this.socket.connect(this.options.socketConnectOpts);
            return {
                dispose: () => {
                    this.socket.destroy();
                },
            };
        };
        this.options = {
            retryTime: 1000,
            socketConnectOpts: {
                port: ext_host_proxy_1.EXT_HOST_PROXY_SERVER_PROT,
            },
            ...options,
        };
    }
    init() {
        this.createSocket();
    }
    createSocket() {
        if (this.previouslyDisposer) {
            this.previouslyDisposer.dispose();
        }
        this.disposer = new ide_core_node_1.Disposable();
        // 每次断连后重新生成 Socket 实例
        this.socket = new net_1.default.Socket();
        this.disposer.addDispose(this.bindEvent());
        this.disposer.addDispose(this.connect());
        this.previouslyDisposer = this.disposer;
        this.addDispose(this.previouslyDisposer);
    }
    setRPCMethods() {
        const connection = new connection_1.NetSocketConnection(this.socket);
        this.protocol = new ide_connection_1.SumiConnectionMultiplexer(connection, {
            logger: this.logger,
            timeout: this.options.rpcMessageTimeout,
        });
        this.disposer.addDispose(connection);
        this.extServerProxy = this.protocol.getProxy(ext_host_proxy_1.EXT_SERVER_IDENTIFIER);
        const extHostProxyRPCService = new ExtHostProxyRPCService(this.extServerProxy);
        this.protocol.set(ext_host_proxy_1.EXT_HOST_PROXY_IDENTIFIER, extHostProxyRPCService);
        this.disposer.addDispose({
            dispose: () => extHostProxyRPCService.$dispose(),
        });
    }
    bindEvent() {
        // connect
        this.socket.on('connect', this.connectOnEvent);
        // reconnect
        this.socket.on('end', this.reconnectOnEvent);
        this.socket.on('error', this.reconnectOnEvent);
        this.socket.on('timeout', this.reconnectOnEvent);
        this.socket.on('close', this.reconnectOnEvent);
        return {
            dispose: () => {
                // connect
                this.socket.off('connect', this.connectOnEvent);
                // reconnect
                this.socket.off('end', this.reconnectOnEvent);
                this.socket.off('error', this.reconnectOnEvent);
                this.socket.off('timeout', this.reconnectOnEvent);
                this.socket.off('close', this.reconnectOnEvent);
            },
        };
    }
}
exports.ExtHostProxy = ExtHostProxy;
//# sourceMappingURL=ext.host.proxy-base.js.map