import { fileURLToPath } from "node:url"; import path from "node:path"; import { loadConfig } from "./config.js"; import axios from "axios"; import log4js from "log4js"; import { createElectronWindow } from "./electron/window.js"; import { setupIPC } from "./electron/ipc.js"; import { LOCAL_SERVER_PORT, LocalServer } from "./localserver/localserver.js"; import { SocketClient } from "./socket/socketclient.js"; if (!process.env.NODE_ENV) { process.env.NODE_ENV = "production"; } // Load configuration const config = loadConfig(); const logger = log4js.getLogger("App"); logger.level = config.logLevel; const isHeadless = process.argv.includes("--headless"); const isInfo = process.argv.includes("--info"); const printerHostInfo = (host) => { var ref = host?._reference || "Unknown"; if (ref != "Unknown") { ref = "HST:" + ref; } logger.info("Reference:", ref); logger.info("Name:", host?.name || "Unknown"); logger.info("Tags: -", host?.tags?.[0] || "n/a"); for (var i = 0; i < host?.tags?.length - 1; i++) { const tag = host?.tags[i + 1]; logger.info(" -", tag); } logger.info("State:", host?.state?.type || "Unknown"); }; function getArgValue(flag) { const withEquals = process.argv.find((arg) => arg.startsWith(`${flag}=`)); if (withEquals) { return withEquals.slice(flag.length + 1); } const index = process.argv.indexOf(flag); if (index !== -1 && index + 1 < process.argv.length) { return process.argv[index + 1]; } return undefined; } const otpCode = getArgValue("--otp") || undefined; async function checkRunning() { try { const response = await axios.get( `http://127.0.0.1:${LOCAL_SERVER_PORT}/info`, { timeout: 1000 }, ); if (response.data?.running === true) { return response.data; } } catch (err) { return false; } } async function authenticateWithOtp(otpCode) { try { const response = await axios.post( `http://127.0.0.1:${LOCAL_SERVER_PORT}/otpAuth`, { otp: otpCode }, { timeout: 30000 }, ); return response.data; } catch (err) { if (err.response?.data) { return err.response.data; } throw new Error("Failed to authenticate with OTP"); } } export async function init(options = {}) { const headless = options.headless ?? isHeadless; logger.info("⌛ Checking if Farm Control Server is running..."); const runningServer = await checkRunning(); if (otpCode != undefined || isInfo == true) { logger.info("✔ Farm Control Server is running."); } if (isInfo) { const buildNumber = runningServer.buildNumber ?? runningServer.build ?? "n/a"; logger.info("-----FarmControl Server-----"); logger.info( "Version:", runningServer.version ? `v${runningServer.version}` : "n/a", ); logger.info( "Build:", buildNumber === "dev" ? "dev" : `b${buildNumber}`, ); logger.info( "Authenticated:", runningServer.authenticated == true ? "Yes" : "No", ); logger.info("------------Host------------"); printerHostInfo(runningServer.host); logger.info("----------------------------"); return runningServer; } if (otpCode != undefined) { logger.info("🔒 Authenticating with OTP..."); const authenticatedServer = await authenticateWithOtp(otpCode); if (authenticatedServer.valid == false) { logger.error( "✘ Failed to authenticate with OTP -", authenticatedServer.error, ); } else { logger.info("✔ Authenticated with OTP."); logger.info("------------Host------------"); printerHostInfo(authenticatedServer.host); logger.info("----------------------------"); return authenticatedServer; } return authenticatedServer; } if (runningServer != false) { logger.warn("✘ Farm Control Server is already running."); return runningServer; } if (!headless) { // Create Electron window first logger.info("Creating electron window..."); await createElectronWindow().catch((err) => { logger.warn("Failed to create Electron window:", err); }); // Setup IPC communication after window is created setupIPC().catch((err) => { logger.warn("Failed to setup IPC:", err); }); } else { logger.info("Running in headless mode. Skipping window creation."); } const socketClient = new SocketClient(); // Make socket client globally accessible for IPC handlers global.socketClient = socketClient; const localServer = new LocalServer(socketClient); await localServer.start(); socketClient.connect(); process.on("SIGINT", () => { logger.info("Shutting down..."); socketClient.disconnect(); localServer.stop(); process.exit(0); }); } const isMainModule = process.argv[1] && fileURLToPath(import.meta.url) === path.resolve(process.argv[1]); if (isMainModule && !process.env.FC_HEADLESS_ENTRY) { init().catch((err) => { logger.error(err.message); process.exit(1); }); }