"use strict";
/*
* This program and the accompanying materials are made available under the terms of the
* Eclipse Public License v2.0 which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Copyright Contributors to the Zowe Project.
*
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.DaemonDecider = void 0;
const fs = require("fs");
const net = require("net");
const os = require("os");
const path = require("path");
const imperative_1 = require("@zowe/imperative");
const DaemonClient_1 = require("./DaemonClient");
const DaemonUtil_1 = require("./DaemonUtil");
// TODO(Kelosky): handle prompting cases from login command
// TODO(Kelosky): prompt* broken - hangs, must restart daemon
// TODO(Kelosky): colors do not come through on some terminals (must be started via `node lib/main --daemon` to see colors)
// TODO(Kelosky): stderr
// TODO(Kelosky): plugins install
/**
 * Initial paramter parse to handle conditionally starting as a persistent process (e.g. daemon mode)
 * @export
 * @class DaemonDecider
 */
class DaemonDecider {
    /**
     * Creates an instance of DaemonDecider.
     * @param {string[]} mParms
     * @memberof DaemonDecider
     */
    constructor(mParms) {
        this.mParms = mParms;
    }
    /**
     * Initialize our DaemonDecider parse and optionally start the server
     * @memberof DaemonDecider
     */
    init() {
        this.initialParse();
        if (this.startServer) {
            this.mServer = net.createServer((c) => {
                new DaemonClient_1.DaemonClient(c, this.mServer, this.mUser).run();
            });
            this.mServer.on('error', this.error.bind(this));
            this.mServer.on('close', this.close.bind(this));
            this.recordDaemonPid();
        }
    }
    /**
     * Method to immediately parse or otherwise start the server for later processing from
     * incoming socket connections.
     * @memberof DaemonDecider
     */
    runOrUseDaemon() {
        if (this.mServer) {
            if (process.platform !== "win32" && imperative_1.IO.existsSync(this.mSocket)) {
                imperative_1.IO.deleteFile(this.mSocket);
            }
            ["exit", "SIGINT", "SIGQUIT", "SIGTERM"].forEach((eventType) => {
                process.on(eventType, this.close.bind(this, true));
            });
            this.mServer.maxConnections = 1;
            this.mServer.listen(this.mSocket, () => {
                imperative_1.Imperative.api.appLogger.debug(`daemon server bound ${this.mSocket}`);
                new imperative_1.Console(`info`).info(`server bound ${this.mSocket}`);
            });
        }
        else {
            imperative_1.Imperative.parse();
        }
    }
    /**
     * Record the process ID of the daemon that is being started for the current user.
     * On a multi-user system, each user gets his/her own daemon.
     *
     * @private
     * @memberof DaemonDecider
     */
    recordDaemonPid() {
        const pidForUser = {
            user: this.mUser,
            pid: process.pid
        };
        const pidFilePath = path.join(DaemonUtil_1.DaemonUtil.getDaemonDir(), "daemon_pid.json");
        const pidForUserStr = JSON.stringify(pidForUser, null, 2);
        try {
            fs.writeFileSync(pidFilePath, pidForUserStr);
            const ownerReadWrite = 0o600;
            fs.chmodSync(pidFilePath, ownerReadWrite);
        }
        catch (err) {
            throw new Error("Failed to write file '" + pidFilePath + "'\nDetails = " + err.message);
        }
        imperative_1.Imperative.api.appLogger.trace("Recorded daemon process ID into " + pidFilePath +
            "\n" + pidForUserStr);
    }
    /**
     * Server close handler
     * @private
     * @memberof DaemonDecider
     */
    close(shouldExit) {
        imperative_1.Imperative.api.appLogger.debug(`server closed`);
        if (shouldExit) {
            process.exit();
        }
    }
    /**
     * Server error handler
     * @private
     * @param {Error} err
     * @memberof DaemonDecider
     */
    error(err) {
        imperative_1.Imperative.api.appLogger.error(`daemon server error: ${err.message}`);
        throw err;
    }
    /**
     * Perform initial parsing of undocumented parameters
     * @private
     * @memberof DaemonDecider
     */
    initialParse() {
        var _a, _b;
        if (this.mParms.length > 2) {
            /**
             * NOTE(Kelosky): For now, we use an undocumented parameter `--daemon`.  If found first,
             * we bypass `yargs` and begin running this as a persistent Processor.
             */
            const parm = this.mParms[2];
            const daemonOffset = parm.indexOf(DaemonDecider.DAEMON_KEY);
            if (daemonOffset > -1) {
                this.startServer = true;
                this.mUser = os.userInfo().username;
                if (process.platform === "win32") {
                    this.mUser = this.mUser.toLowerCase();
                    // On windows we use a pipe instead of a socket
                    if (((_b = (_a = process.env) === null || _a === void 0 ? void 0 : _a.ZOWE_DAEMON_PIPE) === null || _b === void 0 ? void 0 : _b.length) > 0) {
                        // user can choose some pipe path
                        this.mSocket = "\\\\.\\pipe\\" + process.env.ZOWE_DAEMON_PIPE;
                    }
                    else {
                        // use default pipe path name
                        this.mSocket = `\\\\.\\pipe\\${this.mUser}\\ZoweDaemon`;
                    }
                }
                else {
                    // Linux-like systems use domain sockets
                    this.mSocket = path.join(DaemonUtil_1.DaemonUtil.getDaemonDir(), "daemon.sock");
                }
                imperative_1.Imperative.api.appLogger.debug(`daemon server will listen on ${this.mSocket}`);
            }
        }
    }
    /**
     * Get whether or not to start the server
     * @private
     * @memberof DaemonDecider
     */
    get startServer() {
        return this.mStartServer;
    }
    /**
     * Set whether or not to start the server
     * @private
     * @memberof DaemonDecider
     */
    set startServer(startServer) {
        this.mStartServer = startServer;
    }
}
exports.DaemonDecider = DaemonDecider;
/**
 * Undocumented paramter for launching in server mode
 * @private
 * @static
 * @memberof DaemonDecider
 */
DaemonDecider.DAEMON_KEY = "--daemon";
//# sourceMappingURL=DaemonDecider.js.map