#!/usr/bin/env node
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const ChildProcess = tslib_1.__importStar(require("child_process"));
require("villa/platform/node");
const h2o2_1 = tslib_1.__importDefault(require("@hapi/h2o2"));
const hapi_1 = require("@hapi/hapi");
const chalk_1 = tslib_1.__importDefault(require("chalk"));
const find_process_1 = tslib_1.__importDefault(require("find-process"));
const get_proxy_settings_1 = require("get-proxy-settings");
const http_proxy_agent_1 = tslib_1.__importDefault(require("http-proxy-agent"));
const lodash_1 = tslib_1.__importDefault(require("lodash"));
const main_function_1 = require("main-function");
const node_fetch_1 = tslib_1.__importDefault(require("node-fetch"));
const open_1 = tslib_1.__importDefault(require("open"));
const v = tslib_1.__importStar(require("villa"));
const shared_1 = require("../../bld/shared");
const _core_1 = require("./@core");
// tslint:disable-next-line: no-var-requires no-require-imports
const { version } = require('../../package.json');
const config = new _core_1.Config('remote-workspace.config.json');
const sshConfig = new _core_1.SSHConfig({
    remoteHost: config.remoteHost,
    filePath: config.sshConfigFilePath,
});
const vscodeStorage = new _core_1.VSCodeStorage();
let tunnelProcess;
let tunnelWorkspaceId;
let agent;
main_function_1.main(async () => {
    const apiServer = new hapi_1.Server({
        port: config.port,
    });
    let proxySettings = await get_proxy_settings_1.getProxySettings();
    let httpProxyUrl = proxySettings && proxySettings.http && proxySettings.http.toString();
    if (httpProxyUrl) {
        console.info(`Using proxy ${httpProxyUrl}.`);
        agent = new http_proxy_agent_1.default(httpProxyUrl);
    }
    await apiServer.register(h2o2_1.default);
    apiServer.route({
        method: 'GET',
        path: '/api/client-host-version',
        handler() {
            return {
                data: version,
            };
        },
    });
    apiServer.route({
        method: 'POST',
        path: '/api/launch',
        handler({ payload }) {
            let { workspace, project: projectName } = payload;
            let project = typeof projectName === 'string'
                ? workspace.projects.find(project => project.name === projectName)
                : undefined;
            let vscodeRemoteURI = `vscode-remote://ssh-remote+${_core_1.SSH_CONFIG_HOST(workspace)}`;
            let subprocess = ChildProcess.spawn(config.vscodeExecutable, project
                ? [
                    '--folder-uri',
                    `${vscodeRemoteURI}${`/root/workspace/${project.name}`}`,
                ]
                : ['--file-uri', vscodeRemoteURI], {
                detached: true,
                shell: true,
                stdio: 'ignore',
            });
            subprocess.unref();
            switchTunnel(workspace);
            return {};
        },
    });
    apiServer.route({
        method: 'GET',
        path: '/api/workspaces',
        async handler() {
            let response = await node_fetch_1.default(`${config.remoteURL}/api/workspaces`, { agent });
            let result = (await response.json());
            let { data: workspaces } = result;
            if (workspaces) {
                sshConfig.update(workspaces);
                let vscodeProcesses = await find_process_1.default('name', /[\\/]code(?:\.exe)?/i);
                if (!vscodeProcesses.length) {
                    vscodeStorage.cleanUp(workspaces);
                }
            }
            return result;
        },
    });
    apiServer.route({
        method: 'POST',
        path: '/api/switch-tunnel',
        handler({ payload }) {
            let { workspace } = payload;
            switchTunnel(workspace);
            return {};
        },
    });
    apiServer.route({
        method: 'GET',
        path: '/api/untunnel',
        handler({}) {
            untunnel();
            return {};
        },
    });
    apiServer.route({
        method: 'GET',
        path: '/api/workspace-id-of-active-tunnel',
        async handler() {
            return {
                data: tunnelWorkspaceId,
            };
        },
    });
    apiServer.route({
        method: '*',
        path: '/{rest*}',
        handler: {
            proxy: {
                passThrough: true,
                uri: `${config.remoteURL}{path}`,
                agent,
            },
        },
    });
    await apiServer.start();
    let url = `http://remote-workspace.localhost:${config.port}`;
    console.info(`Visit ${url} to manage workspaces...`);
    if (config.toLaunchBrowser) {
        await open_1.default(url);
    }
    return shared_1.NEVER;
    function switchTunnel(workspace) {
        if (tunnelWorkspaceId === workspace.id) {
            return;
        }
        let { forwards } = shared_1.groupWorkspaceProjectConfigs(workspace);
        if (!forwards.length) {
            return;
        }
        untunnel();
        tunnelWorkspaceId = workspace.id;
        console.info(`\
Starting port forwarding for workspace ${workspace.displayName}...
${chalk_1.default.yellow(forwards
            .map(forward => `  ${forward.type} ${forward.source} ${forward.target}`)
            .join('\n'))}`);
        tunnelProcess = ChildProcess.spawn(config.sshExecutable, [
            '-N',
            ...lodash_1.default.flatMap(forwards, forward => [`-${forward.flag}`, forward.value]),
            _core_1.SSH_CONFIG_HOST(workspace),
        ], {
            windowsHide: true,
            detached: false,
            shell: false,
            stdio: 'ignore',
        });
        v.awaitable(tunnelProcess)
            .finally(() => {
            if (tunnelWorkspaceId === workspace.id) {
                tunnelProcess = undefined;
                tunnelWorkspaceId = undefined;
            }
        })
            .catch(error => console.error(chalk_1.default.red('Tunnel process stops unexpectedly with error:\n'), error));
    }
    function untunnel() {
        if (tunnelProcess) {
            tunnelProcess.kill('SIGINT');
            tunnelProcess = undefined;
            tunnelWorkspaceId = undefined;
        }
    }
});
//# sourceMappingURL=main.js.map