"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseCliWorker = void 0;
//#region imports
const rxjs_1 = require("rxjs");
const lib_1 = require("tnp-core/lib");
const lib_2 = require("tnp-core/lib");
const base_cli_worker_config_1 = require("./base-cli-worker-config");
const base_cli_worker_terminal_ui_1 = require("./base-cli-worker-terminal-ui");
const base_cli_worker_models_1 = require("./base-cli-worker.models");
const base_cli_worker_utils_1 = require("./base-cli-worker.utils");
//#endregion
//#region constants
const WORKER_INIT_START_TIME_LIMIT = 25; // 15 seconds max to start worker
const START_PORT_FOR_SERVICES = 3600;
class BaseCliWorker {
    serviceID;
    startCommandFn;
    serviceVersion;
    /**
     * Indicates if worker is part of cloud
     * and should use cloud ip address
     */
    static isCloudEnable = new rxjs_1.BehaviorSubject(false);
    /**
     * Cloud ip address of the worker (if part of cloud)
     */
    static cloudIp = new rxjs_1.BehaviorSubject(null);
    static workers = new Map();
    //#region fields & getters
    SPECIAL_WORKER_READY_MESSAGE = lib_2.CoreModels.SPECIAL_WORKER_READY_MESSAGE;
    /**
     * dependency workers that should be started before this worker
     */
    dependencyWorkers = new Map();
    // @ts-ignore TODO weird inheritance problem
    terminalUI = new base_cli_worker_terminal_ui_1.BaseCliWorkerTerminalUI(this);
    workerContextTemplate;
    /**
     * Name of the worker context
     */
    get contextName() {
        return this.workerContextTemplate().contextName;
    }
    /**
     * Port where worker is running
     * (getter only accessible from host machine)
     */
    get port() {
        return this.processLocalInfoObj.port;
    }
    getWorkerInfoGuiUrl(options) {
        //#region @backendFunc
        options = options || {};
        options.domain = options.domain || lib_2.CoreModels.localhostDomain;
        options.useHttps = lib_2._.isBoolean(options.useHttps) ? options.useHttps : false;
        // console.log({
        //   isCloudEnable: BaseCliWorker.isCloudEnable.getValue(),
        //   cloudIp: BaseCliWorker.cloudIp.getValue(),
        // })
        if (BaseCliWorker.isCloudEnable.getValue()) {
            options.domain = BaseCliWorker.cloudIp.getValue();
            options.useHttps = true;
            options.port = null;
        }
        return (`${options.useHttps ? 'https' : 'http'}://${options.domain}` +
            `${!lib_2._.isUndefined(options.port)
                ? `${options.port === null ? '' : `:${options.port}`}`
                : `:${this.processLocalInfoObj.port}`}` +
            `/api/${this.workerContextTemplate().contextName}` +
            `/${'info'}`);
        //#endregion
    }
    controllerClass;
    //#endregion
    //#region constructor
    constructor(
    /**
     * unique id for service
     */
    serviceID, 
    /**
     * external command that will start service
     */
    startCommandFn, 
    /**
     * unique id for service
     */
    serviceVersion) {
        this.serviceID = serviceID;
        this.startCommandFn = startCommandFn;
        this.serviceVersion = serviceVersion;
        BaseCliWorker.workers.set(serviceID, this);
    }
    //#endregion
    //#region public
    static getAllWorkersStartedInSystemFromCurrentCli() {
        //#region @backendFunc
        return Array.from(BaseCliWorker.workers.values());
        //#endregion
    }
    //#region public fields & getters / process local info json object
    get processLocalInfoObj() {
        //#region @backendFunc
        const configJson = lib_1.Helpers.readJson5(this.pathToProcessLocalInfoJson) || {};
        if (lib_2._.isObject(configJson)) {
            return lib_2._.merge(new base_cli_worker_config_1.BaseCliWorkerConfig(), configJson);
        }
        return new base_cli_worker_config_1.BaseCliWorkerConfig();
        //#endregion
    }
    //#endregion
    //#region public methods / get remote controller
    async getRemoteControllerFor(options) {
        options = options || {};
        options.methodOptions = base_cli_worker_models_1.BaseCliMethodOptions.from(options.methodOptions);
        const remoteEndpointContext = await this.getRemoteContextFor(options);
        const taonProjectsController = remoteEndpointContext.getInstanceBy(options.controllerClass
            ? options.controllerClass
            : this.controllerClass);
        return taonProjectsController;
    }
    //#endregion
    //#region public methods / kill
    /**
     * stop if started
     */
    async kill(options) {
        //#region @backendFunc
        options = options || {};
        options.methodOptions = base_cli_worker_models_1.BaseCliMethodOptions.from(options.methodOptions);
        lib_1.Helpers.info(`Killing service "${this.serviceID}"... `);
        lib_1.Helpers.logInfo(`Reason "${options.reason || '-'}"`);
        const killRequest = async (worker, reason) => {
            try {
                const ctrl = await worker.getRemoteControllerFor({
                    methodOptions: options.methodOptions.clone(opt => {
                        opt.calledFrom = `${opt.calledFrom}.kill`;
                        return opt;
                    }),
                });
                await ctrl.baseCLiWorkerCommand_kill(reason).request();
                await lib_2.Utils.waitMilliseconds(200);
                lib_1.Helpers.log(`Service "${worker.serviceID}" killed...`);
            }
            catch (error) {
                lib_1.Helpers.log(error);
                lib_1.Helpers.log(`Service "${worker.serviceID}" not killed...   `);
            }
        };
        if (!!options && !options.skipDependencies) {
            if (this.dependencyWorkers.size > 0) {
                for (const [serviceId, worker] of this.dependencyWorkers) {
                    lib_1.Helpers.info(`Killing dependency worker "${serviceId}"...`);
                    await killRequest(worker, `killing as dependency`);
                }
            }
        }
        await killRequest(this, options.reason);
        //#endregion
    }
    //#endregion
    //#region public methods / restart
    /**
     * kill detached process and start again
     * @param options.detached - default true
     */
    async restart(options) {
        options = options || {};
        options.methodOptions = base_cli_worker_models_1.BaseCliMethodOptions.from(options.methodOptions);
        await this.kill({
            reason: 'restart of cloud',
            methodOptions: options.methodOptions,
        });
        //longer because os is disposing process previous process
        lib_1.Helpers.info(`Restarting service "${this.serviceID}" ` +
            `in ${options.methodOptions.cliParams.mode} mode...`);
        if (options.methodOptions.cliParams.mode ===
            base_cli_worker_models_1.BaseCLiWorkerStartMode.IN_CURRENT_PROCESS) {
            await this.startNormallyInCurrentProcess({
                methodOptions: options.methodOptions,
            });
        }
        else {
            await this.startDetached({
                methodOptions: options.methodOptions,
            });
        }
    }
    //#endregion
    //#region public methods / cli start
    /**
     * only for cli start
     * @param cliParams on from cli
     */
    async cliStartProcedure(options) {
        //#region @backendFunc
        options = options || {};
        const methodOptions = base_cli_worker_models_1.BaseCliMethodOptions.from(options.methodOptions);
        if (methodOptions.cliParams.restart) {
            lib_1.Helpers.logInfo(`--- RESTARTING ----`);
            await this.restart({
                methodOptions,
            });
            process.exit(0);
        }
        if (methodOptions.cliParams.kill) {
            await this.kill({
                reason: 'kill from parm arg',
                methodOptions,
            });
            process.exit(0);
        }
        if (options.methodOptions.cliParams.mode ===
            base_cli_worker_models_1.BaseCLiWorkerStartMode.IN_CURRENT_PROCESS) {
            await this.startNormallyInCurrentProcess({
                methodOptions,
            });
        }
        else {
            await this.startDetachedIfNeedsToBeStarted({
                methodOptions,
            });
        }
        const controller = await this.getRemoteControllerFor({
            methodOptions: methodOptions.clone(opt => {
                opt.calledFrom = `${opt.calledFrom}.cliStartProcedure`;
                return opt;
            }),
        });
        return { controller, worker: this, serviceId: this.serviceID };
        //#endregion
    }
    //#endregion
    //#endregion
    //#region protected
    //#region protected methods / get remote context
    async getRemoteContextFor(options) {
        options = options || {};
        options.methodOptions = base_cli_worker_models_1.BaseCliMethodOptions.from(options.methodOptions);
        const ipAddressOfTaonInstance = options.methodOptions.connectionOptions.ipAddressOfTaonInstance ||
            lib_2.CoreModels.localhostDomain;
        // on localhost read data from  processLocalInfoObj json
        let port = options.methodOptions.connectionOptions.port ||
            this.processLocalInfoObj.port;
        if (ipAddressOfTaonInstance === lib_2.CoreModels.localhostDomain && !port) {
            if (this.workerIsStarting) {
                try {
                    await this.waitForProcessPortSavedToDisk({
                        methodOptions: options.methodOptions.clone(opt => {
                            opt.calledFrom = `${opt.calledFrom}.getRemoteContextFor.localhost`;
                            return opt;
                        }),
                    });
                }
                catch (error) {
                    console.error(`[getRemoteContextFor] Error while waiting for process port saved to disk`);
                }
            }
            if (this.processLocalInfoPortNotInited) {
                throw new Error(`Can't connect to remote context on localhost - port is not defined.
        This can happen when the worker process is not started yet.
      `);
            }
            else {
                port = this.processLocalInfoObj.port;
            }
        }
        // this.workerRemoteContextFor[ipAddressOfTaonInstance] = remoteCtx;
        const useHttps = ipAddressOfTaonInstance !== lib_2.CoreModels.localhostDomain &&
            ipAddressOfTaonInstance !== lib_2.CoreModels.localhostIp127;
        const protocol = useHttps ? 'https' : 'http';
        const overrideRemoteHost = `${protocol}://${ipAddressOfTaonInstance}${port ? `:${port}` : ''}`;
        const remoteCtx = this.workerContextTemplate().cloneAsRemote({
            overrideRemoteHost,
        });
        // @LAST chache remote context per ipAddressOfTaonInstance
        const remoteEndpoitnContext = await remoteCtx.initialize();
        return remoteEndpoitnContext;
    }
    //#endregion
    //#region protected fields & getters / path to process local info
    get pathToProcessLocalInfoJson() {
        //#region @backendFunc
        // console.log('os.userInfo()', os.userInfo());
        return base_cli_worker_utils_1.BaseCliWorkerUtils.getPathToProcessLocalInfoJson(this.serviceID);
        //#endregion
    }
    //#endregion
    //#region protected fields & getters / should wait for process port saved to disk
    get processLocalInfoPortNotInited() {
        return (!this.processLocalInfoObj.port ||
            isNaN(Number(this.processLocalInfoObj.port)));
    }
    //#endregion
    //#region protected fields & getters / worker is starting
    get workerIsStarting() {
        return !!this.processLocalInfoObj.startTimestamp;
    }
    //#endregion
    //#region protected methods / start if needs to be started
    async startDetachedIfNeedsToBeStarted(options) {
        //#region @backendFunc
        options = options || {};
        options.methodOptions = base_cli_worker_models_1.BaseCliMethodOptions.from(options.methodOptions);
        if (this.processLocalInfoObj.isEmpty) {
            // not started ever yet
            await this.startDetached({
                methodOptions: options.methodOptions,
            });
            return;
        }
        const serviceIsHealthy = await this.isServiceHealthy({
            healthCheckRequestTrys: 1, // just quick check
            methodOptions: options.methodOptions,
        });
        if (!serviceIsHealthy) {
            await this.startDetached({
                methodOptions: options.methodOptions,
            });
            return;
        }
        lib_1.Helpers.log(`Service "${this.serviceID}" is already started/healthy...`);
        //#endregion
    }
    //#endregion
    //#region protected methods / start normally in current process
    /**
     * <strong>IMPORTANT USE ONLY IN DEVELOPMENT !!!</strong>
     * for production use startDetachedIfNeedsToBeStarted()
     * start normally process
     * this will crash if process already started
     */
    async startNormallyInCurrentProcess(options) {
        //#region @backendFunc
        options = options || {};
        options.methodOptions = base_cli_worker_models_1.BaseCliMethodOptions.from(options.methodOptions);
        lib_1.Helpers.taskStarted(`[${this.serviceID}] Process start in current process...`);
        await this.killWorkerWithLowerVersion({
            methodOptions: options.methodOptions,
        });
        await this.preventStartIfAlreadyStarted({
            methodOptions: options.methodOptions,
        });
        const port = await this.getServicePort();
        this.saveProcessInfo({
            port,
            serviceID: this.serviceID,
            pid: process.pid,
            startTimestamp: Date.now(),
            version: this.serviceVersion,
        });
        const workerMainContext = this.workerContextTemplate().cloneAsNormal({
            overrideHost: `http://localhost:${port}`,
        });
        await workerMainContext.initialize();
        await this.initializeWorkerMetadata({
            methodOptions: options.methodOptions,
        });
        lib_1.Helpers.info(`Service started !`);
        if (lib_2._.isFunction(options.actionBeforeTerminalUI)) {
            await options.actionBeforeTerminalUI();
        }
        if (this.terminalUI) {
            this.terminalUI.displaySpecialWorkerReadyMessage();
            await this.terminalUI.infoScreen();
        }
        else {
            console.log(`
      [${lib_1.config.frameworkName}-helpers] No terminal UI configured. Not displaying anything.
      `);
        }
        //#endregion
    }
    //#endregion
    //#region protected methods / prevent prevent start if already started
    async preventStartIfAlreadyStarted(options) {
        //#region @backendFunc
        options = options || {};
        options.methodOptions = base_cli_worker_models_1.BaseCliMethodOptions.from(options.methodOptions);
        if (!this.processLocalInfoObj.pid || this.processLocalInfoPortNotInited) {
            return;
        }
        try {
            const isHealthy = await this.isServiceHealthy({
                methodOptions: options.methodOptions,
                healthCheckRequestTrys: 2, // check only twice
            });
            if (isHealthy) {
                lib_1.Helpers.error(`Service already started on port ${this.processLocalInfoObj.port} !`, false, true);
            }
        }
        catch (error) { }
        //#endregion
    }
    //#endregion
    //#region protected methods / prevent kill worker with lower version
    async killWorkerWithLowerVersion(options) {
        //#region @backendFunc
        options = options || {};
        options.methodOptions = base_cli_worker_models_1.BaseCliMethodOptions.from(options.methodOptions);
        if (!this.processLocalInfoObj.pid) {
            lib_1.Helpers.logInfo(`No pid found - skipping version check...`);
            return;
        }
        lib_1.Helpers.taskStarted(`[${this.serviceID}] Checking if current working version is up to date...`);
        try {
            const ctrl = await this.getRemoteControllerFor({
                methodOptions: options.methodOptions.clone(opt => {
                    opt.calledFrom = `${opt.calledFrom}.killWorkerWithLowerVersion`;
                    return opt;
                }),
            });
            lib_1.Helpers.logInfo(`[${this.serviceID}] Checking if current working version is up to date...`);
            // console.log('this.processLocalInfoObj', this.processLocalInfoObj);
            const req = await ctrl
                .baseCLiWorkerCommand_hasUpToDateVersion(lib_2._.merge(this.processLocalInfoObj, {
                version: this.serviceVersion,
            }))
                .request();
            lib_1.Helpers.logInfo(`[${this.serviceID}] Request done...`);
            const isUpToDate = req.body.booleanValue;
            if (!isUpToDate) {
                lib_1.Helpers.info(`[${this.serviceID}] Killing service with lower version...`);
                await this.kill({
                    reason: 'kill because lower version of framework',
                    methodOptions: options.methodOptions,
                    skipDependencies: true,
                });
            }
        }
        catch (error) {
            lib_1.Helpers.logInfo(`Probably no need to kill worker with lower version`);
        }
        lib_1.Helpers.taskDone(`[${this.serviceID}] Current working version is up to date !`);
        //#endregion
    }
    //#endregion
    //#region protected methods / is service healthy
    /**
     * This has 2 purposes:
     * - infinite check when when detached process finished starting
     * - quick check if service is healthy / already started
     */
    async isServiceHealthy(options) {
        //#region @backendFunc
        options = options || {};
        options.methodOptions = base_cli_worker_models_1.BaseCliMethodOptions.from(options.methodOptions);
        const healthCheckRequestTrys = options.healthCheckRequestTrys || 1;
        //#region timestamp checking
        let i = 0; // 15 seconds to start worker
        while (true) {
            i++;
            lib_1.Helpers.logInfo(`[${this.serviceID}][timestamp-checking][${options.methodOptions.calledFrom}]
         Checking if service "${this.serviceID}" is starting...`);
            if (!this.workerIsStarting) {
                // initialized worker does not have startTimestamp
                break;
            }
            if (i > WORKER_INIT_START_TIME_LIMIT) {
                lib_1.Helpers.logInfo(`[${this.serviceID}][timestamp-checking] Worker "${this.serviceID}" did not start in time...`);
                return false;
            }
            const compareTimestamp = Date.now() - this.processLocalInfoObj.startTimestamp;
            if (compareTimestamp > 60000) {
                lib_1.Helpers.logInfo(`[${this.serviceID}][timestamp-checking] Worker "${this.serviceID}" exceeds start time...`);
                return false;
            }
            lib_1.Helpers.log('[timestamp-checking] Waiting 500 miliseonds for service to start...');
            await lib_2.UtilsTerminal.wait(1);
        }
        //#endregion
        i = 0;
        const isWaitingNotCheckingWhen = 40;
        while (true) {
            i++;
            try {
                //#region initial message
                if (isWaitingNotCheckingWhen === i) {
                    lib_1.Helpers.info(`[${this.serviceID}] Waiting for service "${this.serviceID}" ` +
                        `to start...`);
                }
                else {
                    lib_1.Helpers.log(`[${this.serviceID}] Checking if service "${this.serviceID}" ` +
                        `is healthy...`);
                }
                //#endregion
                //#region request check
                const ctrl = await this.getRemoteControllerFor({
                    methodOptions: options.methodOptions.clone(opt => {
                        opt.calledFrom = `${opt.calledFrom}.isServiceHealthy`;
                        return opt;
                    }),
                });
                lib_1.Helpers.log(`Sending is healthy request...`);
                // console.log('this.processLocalInfoObj', this.processLocalInfoObj);
                const req = await ctrl
                    .baseCLiWorkerCommand_isHealthy(this.processLocalInfoObj)
                    .request({
                // timeout: 1000,
                });
                const isHealthy = req.body.booleanValue;
                // console.log('isHealthy', { isHealthy });
                if (isHealthy) {
                    lib_1.Helpers.log(`Service "${this.serviceID}" is healthy (response is true)...`);
                }
                else {
                    lib_1.Helpers.log(`Service "${this.serviceID}" is not healthy (response is false)...`);
                }
                //#endregion
                if (isHealthy || i === healthCheckRequestTrys) {
                    return isHealthy;
                }
            }
            catch (error) {
                //#region error handling
                if (i >= isWaitingNotCheckingWhen && error?.message) {
                    console.error(error.message);
                }
                lib_1.Helpers.log(`Service "${this.serviceID}" is not healthy (can't check health)...`);
                if (i === healthCheckRequestTrys) {
                    return false;
                }
                //#endregion
            }
            lib_1.Helpers.log('Trying again...');
            await lib_2.UtilsTerminal.wait(1);
        }
        //#endregion
    }
    //#endregion
    //#region protected methods / start detached
    /**
     * start if not started detached process
     */
    async startDetached(options) {
        //#region @backendFunc
        options = options || {};
        options.methodOptions = base_cli_worker_models_1.BaseCliMethodOptions.from(options.methodOptions);
        if (options.methodOptions.cliParams.mode ===
            base_cli_worker_models_1.BaseCLiWorkerStartMode.CHILD_PROCESS) {
            lib_1.Helpers.logInfo(`[${this.serviceID}][startDetached] ` +
                ` Starting in current terminal
          "${lib_2.chalk.bold(this.startCommandFn())}"...`);
            await lib_2.UtilsProcess.startAsyncChildProcessCommandUntil(this.startCommandFn(), {
                untilOptions: {
                    stdout: [this.SPECIAL_WORKER_READY_MESSAGE],
                    stderr: [this.SPECIAL_WORKER_READY_MESSAGE],
                },
                displayOutputInParentProcess: lib_1.Helpers.getIsVerboseMode(),
                resolveAfterAnyExitCode: true,
            });
        }
        else {
            lib_1.Helpers.logInfo(`[${this.serviceID}][startDetached] ` +
                `Starting in new terminal
          "${lib_2.chalk.bold(this.startCommandFn())}"...`);
            await lib_2.UtilsProcess.startInNewTerminalWindow(this.startCommandFn());
        }
        lib_1.Helpers.logInfo(`"${lib_2.chalk.bold(this.serviceID)}" - waiting until healthy (Infinite health check trys )...`);
        const isServiceHealthy = await this.isServiceHealthy({
            methodOptions: options.methodOptions,
            healthCheckRequestTrys: Infinity, // wait infinity until started
        });
        if (!isServiceHealthy) {
            throw `Not able to start service "${this.serviceID}"...`;
        }
        lib_1.Helpers.logInfo(`Healthy service "${lib_2.chalk.bold(this.serviceID)}" started.`);
        //#endregion
    }
    //#endregion
    //#region protected methods / save process info
    saveProcessInfo(processConfig) {
        //#region @backendFunc
        processConfig = processConfig || {};
        if (lib_1.Helpers.exists(this.pathToProcessLocalInfoJson)) {
            const jsonConfig = lib_1.Helpers.readJson(this.pathToProcessLocalInfoJson);
            if (lib_2._.isObject(jsonConfig) && Object.keys(jsonConfig).length > 0) {
                processConfig = lib_2._.merge(jsonConfig, processConfig);
            }
        }
        lib_1.Helpers.log(`Saving process info to "${this.pathToProcessLocalInfoJson}"...`);
        // Helpers.log(processConfig);
        processConfig.pathToFile = this.pathToProcessLocalInfoJson;
        lib_1.Helpers.writeJson(this.pathToProcessLocalInfoJson, processConfig);
        //#endregion
    }
    //#endregion
    //#region protected methods / initialize worker
    async initializeWorkerMetadata(options) {
        //#region @backendFunc
        options = options || {};
        options.methodOptions = base_cli_worker_models_1.BaseCliMethodOptions.from(options.methodOptions);
        while (true) {
            try {
                const portControllerInstance = await this.getRemoteControllerFor({
                    methodOptions: options.methodOptions.clone(opt => {
                        opt.calledFrom = `${opt.calledFrom}.initializeWorkerMetadata`;
                        return opt;
                    }),
                });
                await portControllerInstance
                    .baseCLiWorkerCommand_initializeMetadata(this.serviceID, this.serviceVersion)
                    .request();
                this.saveProcessInfo({
                    startTimestamp: null,
                });
                break;
            }
            catch (error) {
                lib_1.Helpers.error(error, false, false);
                this.saveProcessInfo({
                    startTimestamp: null,
                });
                lib_1.Helpers.info(`[${this.serviceID}][${this.serviceVersion}] Retrying to initialize worker metadata...`);
                await lib_2.UtilsTerminal.wait(1);
            }
        }
        // process.on('SIGINT', () => {
        //   this.kill();
        // });
        //#endregion
    }
    //#endregion
    //#region protected methods / wait for process port saved to disk
    async waitForProcessPortSavedToDisk(options) {
        //#region @backendFunc
        options = options || {};
        options.methodOptions = base_cli_worker_models_1.BaseCliMethodOptions.from(options.methodOptions);
        lib_1.Helpers.logInfo(`[${this.serviceID}][${[options.methodOptions.calledFrom]}]` +
            ` Waiting for process port saved to disk...`);
        lib_1.Helpers.log(`in ${this.pathToProcessLocalInfoJson}`);
        const MAX_TRYS = 30;
        let i = 0;
        if (this.processLocalInfoPortNotInited) {
            while (this.processLocalInfoPortNotInited) {
                i++;
                if (this.processLocalInfoPortNotInited) {
                    lib_1.Helpers.logInfo(`[${this.serviceID}][${this.serviceVersion}][${options.methodOptions.calledFrom}]
             waiting/checking again for port...`);
                    if (i > MAX_TRYS) {
                        throw `[${this.serviceID}][${this.serviceVersion}][${options.methodOptions.calledFrom}]
              Can't get port for remote connection..
              worker process did not start correctly`;
                    }
                    await lib_2.UtilsTerminal.wait(1);
                }
                else {
                    lib_1.Helpers.taskDone(`[${this.serviceID}][${this.serviceVersion}][${options.methodOptions.calledFrom}]
             port assigned: ${this.processLocalInfoObj.port}`);
                    break;
                }
            }
        }
        //#endregion
    }
    //#endregion
    //#region protected methods / get free port
    async getServicePort() {
        //#region @backendFunc
        lib_1.Helpers.logInfo(`Getting free port for service...`);
        const port = await lib_2.Utils.getFreePort({
            startFrom: START_PORT_FOR_SERVICES,
        });
        lib_1.Helpers.logInfo(`Done getting free port for service...`);
        return port;
        //#endregion
    }
}
exports.BaseCliWorker = BaseCliWorker;
//# sourceMappingURL=base-cli-worker.js.map