import { authenticateWithOtp, checkRunning, getFlagValue, hasFlag, printAuthCommand, printerHostInfo, setLogLevel, startWaiting, stopWaiting, } from "./commandlineutils.js"; import { VALID_LOG_LEVELS } from "./logging.js"; import chalk from "chalk"; async function getRunningServer(cli, logger) { try { startWaiting("Checking if Farm Control Server is running...", logger); const runningServer = await checkRunning(); await stopWaiting(); return runningServer; } catch (err) { await stopWaiting(); cli.failure("Failed to check if Farm Control Server is running:", err); cli.blank(); return null; } } async function checkServerRunning(cli, logger) { const runningServer = await getRunningServer(cli, logger); if (runningServer == false) { cli.failure("Farm Control Server is not running."); cli.blank(); return false; } if (runningServer == null) { return false; } cli.success("Farm Control Server is running."); return runningServer; } function printServerInfo(cli, runningServer) { const buildNumber = runningServer.buildNumber ?? runningServer.build ?? "n/a"; cli.blank(); cli.sectionHeader("FarmControl Server"); cli.label( "Version:", runningServer.version ? `v${runningServer.version}` : "n/a", ); cli.label("Build:", buildNumber === "dev" ? "dev" : `b${buildNumber}`); cli.label("Config:", runningServer.configPath || "n/a"); cli.label("Data Dir:", runningServer.dataDir || "n/a"); cli.label("Connected:", cli.yesNo(runningServer.connected == true)); cli.label("Authenticated:", cli.yesNo(runningServer.authenticated == true)); cli.sectionFooter(); cli.blank(); if (runningServer.authenticated == false && runningServer.connected == true) { cli.sectionHeader("Authenticate"); printAuthCommand(cli); cli.sectionFooter(); } else if ( runningServer.connected == true && runningServer.authenticated == true ) { cli.sectionHeader("Host"); printerHostInfo(runningServer.host, cli); cli.sectionFooter(); } cli.blank(); } function printHelp(cli) { cli.sectionHeader("Help"); cli.label( chalk.bold.white("Usage: ") + chalk.bold.cyanBright("farmcontrol-server ") + chalk.white.dim("[options]"), ); cli.sectionFooter(); const optionsPadding = " ".repeat(9); cli.label( chalk.bold.white("Options: ") + chalk.bold.magentaBright("--info") + " Outputs server information", ); cli.label( optionsPadding + chalk.bold.magentaBright("--logLevel") + " " + chalk.dim("") + " Sets log level (" + chalk.bold.cyan("trace") + ", " + chalk.bold.blue("debug") + ", " + chalk.bold.green("info") + ", " + chalk.bold.yellow("warn") + ", " + chalk.bold.red("error") + ")", ); cli.label( optionsPadding + chalk.bold.magentaBright("--otp") + " " + chalk.dim("") + " Authenticates with OTP", ); cli.sectionFooter(); cli.blank(); } async function runOtpCommand(cli, logger, otpCode) { cli.blank(); if (otpCode == undefined) { cli.failure("OTP code is required."); cli.blank(); return { handled: true, result: false }; } if (!/^\d{6}$/.test(String(otpCode))) { cli.failure("OTP code must be a 6-digit number."); cli.blank(); return { handled: true, result: false }; } startWaiting("Authenticating with OTP...", logger); let authenticatedServer; try { authenticatedServer = await authenticateWithOtp(otpCode); await stopWaiting(); } catch (err) { await stopWaiting(); throw err; } if (authenticatedServer.valid == false) { cli.failure("Failed to authenticate!"); cli.failure(authenticatedServer.error); cli.blank(); return authenticatedServer; } cli.success("Authenticated with OTP."); cli.blank(); cli.sectionHeader("Host"); printerHostInfo(authenticatedServer.host, cli); cli.sectionFooter(); cli.blank(); return authenticatedServer; } async function runLogLevelCommand(cli, logger, level) { cli.blank(); if (level == undefined) { cli.failure("Log level is required."); cli.blank(); return { handled: true, result: false }; } const normalized = String(level).toLowerCase(); if (!VALID_LOG_LEVELS.includes(normalized)) { cli.failure( `Invalid log level. Must be one of: ${VALID_LOG_LEVELS.join(", ")}`, ); cli.blank(); return { handled: true, result: false }; } startWaiting("Setting log level...", logger); let result; try { result = await setLogLevel(normalized); await stopWaiting(); } catch (err) { await stopWaiting(); throw err; } if (result.valid == false) { cli.failure("Failed to set log level!"); cli.failure(result.error); cli.blank(); return result; } cli.success(`Log level set to ${result.logLevel}.`); cli.blank(); return result; } const commands = [ { matches: () => hasFlag("info"), run: async ({ cli, logger }) => { const runningServer = await checkServerRunning(cli, logger); if (runningServer == false) { return { handled: true, result: false }; } printServerInfo(cli, runningServer); return { handled: true, result: true }; }, }, { matches: () => hasFlag("help") || hasFlag("h"), run: async ({ cli }) => { printHelp(cli); return true; }, }, { matches: () => getFlagValue("logLevel") != undefined || hasFlag("logLevel"), run: async ({ cli, logger }) => { const runningServer = await checkServerRunning(cli, logger); if (runningServer == false) { return { handled: true, result: false }; } const result = await runLogLevelCommand( cli, logger, getFlagValue("logLevel"), ); return { handled: true, result }; }, }, { matches: () => getFlagValue("otp") != undefined || hasFlag("otp"), run: async ({ cli, logger }) => { const runningServer = await checkServerRunning(cli, logger); if (runningServer == false) { return { handled: true, result: false }; } const result = await runOtpCommand(cli, logger, getFlagValue("otp")); return { handled: true, result }; }, }, ]; export async function handleCommandLine(cli, logger) { const command = commands.find((entry) => entry.matches()); if (!command) { const runningServer = await getRunningServer(cli, logger); if (runningServer == null) { return { handled: true, result: false }; } return { handled: false, runningServer }; } const result = await command.run({ cli, logger }); return { handled: true, result }; }