Tom Butcher 3f5f02b087
Some checks failed
farmcontrol/farmcontrol-server/pipeline/head There was a failure building this commit
Enhance SocketClient functionality and improve host update handling
Add a new method to handle host updates in SocketClient, ensuring that updates are processed correctly based on the host ID. Additionally, improve logging in index.js to include the first tag of the host for better visibility. This change streamlines the management of host information and enhances the overall logging clarity.
2026-07-26 23:42:48 +01:00

186 lines
5.0 KiB
JavaScript

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");
if (host?.tags?.length > 0) {
logger.info("Tags: -", host?.tags?.[0]);
for (var i = 0; i < host?.tags?.length - 1; i++) {
const tag = host?.tags[i + 1];
logger.info(" -", tag);
}
} else {
logger.info("Tags: n/a");
}
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);
});
}