"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.extProcessInit = extProcessInit;
const tslib_1 = require("tslib");
const net_1 = tslib_1.__importDefault(require("net"));
const perf_hooks_1 = require("perf_hooks");
const di_1 = require("@opensumi/di");
const ide_connection_1 = require("@opensumi/ide-connection");
const connection_1 = require("@opensumi/ide-connection/lib/common/connection");
const ide_core_common_1 = require("@opensumi/ide-core-common");
const node_1 = require("@opensumi/ide-core-common/lib/node");
const cli_1 = require("@opensumi/ide-core-common/lib/node/cli");
const common_1 = require("../common");
const ext_process_1 = require("../common/ext.process");
const protocols_1 = require("../common/vscode/protocols");
const util_1 = require("./api/vscode/language/util");
const extension_log2_1 = require("./extension-log2");
require("@opensumi/ide-i18n");
(0, util_1.setPerformance)(perf_hooks_1.performance);
Error.stackTraceLimit = 100;
let logger = console;
let preload;
async function initRPCProtocol(extInjector) {
    const extConnection = cli_1.argv[common_1.KT_PROCESS_SOCK_OPTION_KEY];
    logger = new extension_log2_1.ExtensionLogger2(extInjector);
    logger.log('init rpc protocol for ext connection path', extConnection);
    const socket = net_1.default.createConnection(JSON.parse(extConnection));
    const appConfig = extInjector.get(ext_process_1.ExtHostAppConfig);
    const extProtocol = new ide_connection_1.SumiConnectionMultiplexer(new connection_1.NetSocketConnection(socket), {
        timeout: appConfig.rpcMessageTimeout,
        io: (0, ide_connection_1.createExtMessageIO)(protocols_1.knownProtocols),
    });
    return { extProtocol, logger };
}
function patchProcess() {
    process.exit = function (code) {
        const err = new Error(`An extension called process.exit(${code !== null && code !== void 0 ? code : ''}) and this was prevented.`);
        getWarnLogger()(err.stack);
    };
    // override Electron's process.crash() method
    process.crash = function () {
        const err = new Error('An extension called process.crash() and this was prevented.');
        getWarnLogger()(err.stack);
    };
}
function _wrapConsoleMethod(method) {
    // eslint-disable-next-line no-console
    const original = console[method].bind(console);
    Object.defineProperty(console, method, {
        set: () => { },
        get: () => function (...args) {
            original(...args);
        },
    });
}
function patchConsole() {
    _wrapConsoleMethod('info');
    _wrapConsoleMethod('log');
    _wrapConsoleMethod('warn');
    _wrapConsoleMethod('error');
}
async function extProcessInit(config = {}) {
    const extAppConfig = JSON.parse(cli_1.argv[common_1.KT_APP_CONFIG_KEY] || '{}');
    const { injector, ...extConfig } = config;
    const extInjector = injector || new di_1.Injector();
    const reporterEmitter = new ide_core_common_1.Emitter();
    extInjector.addProviders({
        token: ext_process_1.ExtHostAppConfig,
        useValue: { ...extAppConfig, ...extConfig },
    }, {
        token: ide_core_common_1.IReporter,
        useValue: new ide_core_common_1.CommonProcessReporter(reporterEmitter),
    });
    if (ide_core_common_1.locale) {
        (0, ide_core_common_1.setLanguageId)(ide_core_common_1.locale);
    }
    patchProcess();
    patchConsole();
    const { extProtocol: protocol, logger } = await initRPCProtocol(extInjector);
    try {
        let Preload = require('./ext.host');
        if (Preload.default) {
            Preload = Preload.default;
        }
        preload = new Preload(protocol, logger, extInjector);
        reporterEmitter.event((reportMessage) => {
            if (process && process.send) {
                process.send({
                    type: common_1.ProcessMessageType.REPORTER,
                    data: reportMessage,
                });
            }
        });
        logger.log('preload.init start');
        await preload.init();
        logger.log('preload.init end');
        if (process && process.send) {
            process.send('ready');
            process.on('message', async (msg) => {
                if (msg === 'close') {
                    logger.log('preload.close start');
                    await preload.close();
                    logger.log('preload.close end');
                    if (process && process.send) {
                        process.send('finish');
                    }
                }
            });
        }
    }
    catch (e) {
        logger.error(e);
    }
}
function getErrorLogger() {
    // eslint-disable-next-line no-console
    return (logger && logger.error.bind(logger)) || console.error.bind(console);
}
function getWarnLogger() {
    // eslint-disable-next-line no-console
    return (logger && logger.warn.bind(logger)) || console.warn.bind(console);
}
function unexpectedErrorHandler(e) {
    setTimeout(() => {
        // 上报错误
        preload && preload.reportUnexpectedError(e);
        // 记录错误日志
        getErrorLogger()('[Extension-Host]', e.message, e.stack && '\n\n' + e.stack);
    }, 0);
}
function onUnexpectedError(e) {
    let err = e;
    if (!err) {
        getWarnLogger()(`Unknown Exception ${err}`);
        return;
    }
    if ((0, ide_core_common_1.isPromiseCanceledError)(err)) {
        getWarnLogger()(`Canceled ${err.message}`);
        return;
    }
    if (!(err instanceof Error)) {
        err = new Error(e);
    }
    unexpectedErrorHandler(err);
}
(0, node_1.suppressNodeJSEpipeError)(process, (msg) => {
    getErrorLogger()(msg);
});
process.on('uncaughtException', (err) => {
    onUnexpectedError(err);
});
const unhandledPromises = [];
process.on('unhandledRejection', (reason, promise) => {
    unhandledPromises.push(promise);
    setTimeout(() => {
        const idx = unhandledPromises.indexOf(promise);
        if (idx >= 0) {
            promise.catch((e) => {
                unhandledPromises.splice(idx, 1);
                onUnexpectedError(e);
            });
        }
    }, 1000);
});
process.on('rejectionHandled', (promise) => {
    const idx = unhandledPromises.indexOf(promise);
    if (idx >= 0) {
        unhandledPromises.splice(idx, 1);
    }
});
//# sourceMappingURL=ext.process-base.js.map