import { createServer } from "http"; import { createRequestHandler } from "@remix-run/express"; import express from "express"; import morgan from "morgan"; import { Server, Socket } from "socket.io"; import type { ViteDevServer } from "vite"; import path from 'path'; import { fileURLToPath as _fileURLToPath } from 'url'; import { existsSync } from 'fs'; import type { ServerBuild } from "@remix-run/node"; import { MemoryDB } from "./memdb.js"; import { L33tTaskManager } from "./taskmanager.js"; import { L33tTask , L33tADSPLC, L33tConfig, Shape, L33tAgent } from "l33t-lib"; import { AgentsManager } from "./AgentsManager.js"; import { PlcManager } from "~/l33t-lib/PlcManager.js"; const __filename = _fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); // Parse command line arguments const args = process.argv.slice(2); const dirPathIndex = args.indexOf('--config'); if (dirPathIndex === -1) { console.error('Error: --config argument is required'); console.error('Usage: node server.js --config [--fake-data]'); process.exit(1); } if (dirPathIndex === args.length - 1) { console.error('Error: --config requires a directory path argument'); console.error('Usage: node server.js --config [--fake-data]'); process.exit(1); } // Get and validate the working directory const workingDirPath = args[dirPathIndex + 1]; const WORKING_DIR = path.isAbsolute(workingDirPath) ? workingDirPath : path.resolve(process.cwd(), workingDirPath); // Validate directory exists if (!existsSync(WORKING_DIR)) { console.error(`Error: Directory not found at ${WORKING_DIR}`); console.error('Please provide a valid path to your configuration directory'); process.exit(1); } // Check for l33t.json in the working directory const CONFIG_FILE = path.join(WORKING_DIR, 'l33t.json'); if (!existsSync(CONFIG_FILE)) { console.error(`Error: l33t.json not found in ${WORKING_DIR}`); console.error('Please ensure l33t.json exists in the specified directory'); process.exit(1); } // Export both the config file path and working directory for other services export { CONFIG_FILE, WORKING_DIR }; const memoryDB = new MemoryDB(); memoryDB.load() // Development server setup let viteDevServer: ViteDevServer | undefined; process.env.NODE_ENV = "development" if (process.env.NODE_ENV !== "production") { viteDevServer = await import("vite").then((vite) => vite.createServer({ server: { middlewareMode: true }, }) ); } const app = express(); const httpServer = createServer(app); const io = new Server(httpServer); // Initialize PLC Manager const plcManager = new PlcManager() try { plcManager.initAll(memoryDB, io) } catch (e) { console.log(e) } // Initialize Agents manager const agentsManager = new AgentsManager() try { await agentsManager.initAll(memoryDB, io) } catch(e) { console.log(e) } io.on("connection", (socket: Socket) => { console.log(socket.id, "connected"); plcManager.registerHandler(io, socket, memoryDB) agentsManager.registerHandler(io, socket, memoryDB) socket.on("l33t_db_persist", () => { memoryDB._persist() }); socket.on("l33t_task_save", async (data: { id: string, source?: string, scheduledInterval?: number, timedTTL?: number, autoStart?: boolean }) => { const { id, source, scheduledInterval, timedTTL, autoStart } = data; try { if (source !== undefined) { await taskManager.save(id, source); } if (memoryDB.tasks[id]) { const task = memoryDB.tasks[id]; if (scheduledInterval !== undefined) { task.scheduledInterval = scheduledInterval; } if (timedTTL !== undefined) { task.timedTTL = timedTTL; } if (autoStart !== undefined) { task.autoStart = autoStart; } // Persist changes to disk memoryDB._persist(); } socket.emit("l33t_task_save_result", { success: true }); io.emit("l33t_task_update", id, memoryDB.tasks[id]); console.log("Successfully saved task:", id, memoryDB.tasks[id]); } catch (e) { console.error("Error saving task:", e); socket.emit("l33t_task_save_result", { success: false, error: e }); } }); socket.on("l33t_update_shapes", (obj: { shapes: any, id: string }) => { if (memoryDB.agents[obj.id]) { memoryDB.agents[obj.id].shapes = obj.shapes; console.log("\x1b[31m%s\x1b[0m", "l33t_update_shapes2bis Produc ", memoryDB.agents[obj.id]); } }); socket.on("l33t_update_config", (data: L33tConfig, id: string) => { if (memoryDB.agents[id]) { memoryDB.agents[id].config = data; } console.log("\x1b[31m%s\x1b[0m", "l33t_update_config Produc "); }); // Task Management socket.on("l33t_task_start", ({ taskId }) => { try { console.log("Attempting to start task:", taskId); if (!memoryDB.tasks[taskId]) { socket.emit("l33t_task_start_result", { success: false, error: "Task not found" }); return; } // Start the task taskManager.start(taskId); // Emit success back to the requesting client socket.emit("l33t_task_start_result", { success: true }); // Broadcast the update to all clients io.emit("l33t_task_update", taskId, memoryDB.tasks[taskId]); console.log("Successfully started task:", taskId); } catch (error: any) { console.error("Error starting task:", error); socket.emit("l33t_task_start_result", { success: false, error: error.message }); } }); socket.on("l33t_task_stop", ({ taskId }) => { try { console.log("Attempting to stop task:", taskId); if (!memoryDB.tasks[taskId]) { socket.emit("l33t_task_stop_result", { success: false, error: "Task not found" }); return; } // Stop the task taskManager.stop(taskId); // Emit success back to the requesting client socket.emit("l33t_task_stop_result", { success: true }); // Broadcast the update to all clients io.emit("l33t_task_update", taskId, memoryDB.tasks[taskId]); console.log("Successfully stopped task:", taskId); } catch (error: any) { console.error("Error stopping task:", error); socket.emit("l33t_task_stop_result", { success: false, error: error.message }); } }); socket.on("l33t_add_task", (newId: string, task?: L33tTask) => { try { console.log("server l33t_add_task", newId); const newTask = new L33tTask() newTask.timedLast = Date.now(); newTask.timedPrevious = Date.now(); newTask.timedTTL = 300; memoryDB.tasks[newId] = newTask; socket.emit("l33t_add_task_result", { success: true, streamId: newId }); console.log("\x1b[31m%s\x1b[0m", "emitting l33t_task_update", newId, newTask); io.emit("l33t_task_update", newId, newTask); } catch (error: any) { console.error("Error adding stream:", error); socket.emit("l33t_add_task_result", { success: false, error: error.message }); } }); socket.on("l33t_add_plc", (newId: string, plc: L33tADSPLC) => { try { console.log("server l33t_add_plc", newId); memoryDB.plcs[newId] = plc; socket.emit("l33t_add_plc_result", { success: true, plcId: newId }); io.emit("l33t_plc_update", newId, plc); } catch (error: any) { console.error("Error adding PLC:", error); socket.emit("l33t_add_plc_result", { success: false, error: error.message }); } }); socket.on("l33t_add_agent", (newId: string, agent?: L33tAgent) => { try { console.log("server l33t_add_agent", newId); const newAgent = new L33tAgent() newAgent.timedLast = Date.now(); newAgent.timedPrevious = Date.now(); newAgent.timedTTL = 200; memoryDB.agents[newId] = newAgent; socket.emit("l33t_add_agent_result", { success: true, streamId: newId }); io.emit("l33t_agent_update", newId, newAgent); } catch (error: any) { console.error("Error adding stream:", error); socket.emit("l33t_add_agent_result", { success: false, error: error.message }); } }); socket.on("l33t_delete_plc", ({ plcId }) => { try { console.log("Attempting to delete PLC:", plcId); if (!memoryDB.plcs[plcId]) { socket.emit("l33t_delete_plc_result", { success: false, error: "PLC not found" }); return; } delete memoryDB.plcs[plcId]; socket.emit("l33t_delete_plc_result", { success: true }); io.emit("l33t_plc_update", plcId, null); console.log("Successfully deleted PLC:", plcId); } catch (error: any) { console.error("Error deleting PLC:", error); socket.emit("l33t_delete_plc_result", { success: false, error: error.message }); } }); socket.on("l33t_delete_agent", ({ agentId }) => { try { console.log("Attempting to delete agent:", agentId); if (!memoryDB.agents[agentId]) { socket.emit("l33t_delete_agent_result", { success: false, error: "Agent not found" }); return; } delete memoryDB.agents[agentId]; socket.emit("l33t_delete_agent_result", { success: true }); io.emit("l33t_update", agentId, null); console.log("Successfully deleted agent:", agentId); } catch (error: any) { console.error("Error deleting agent:", error); socket.emit("l33t_delete_agent_result", { success: false, error: error.message }); } }); socket.on("l33t_delete_task", ({ taskId }) => { try { console.log("Attempting to delete task:", taskId); if (!memoryDB.tasks[taskId]) { socket.emit("l33t_delete_task_result", { success: false, error: "Task not found" }); return; } // Stop task if running before delete taskManager.stop(taskId); delete memoryDB.tasks[taskId]; socket.emit("l33t_delete_task_result", { success: true }); io.emit("l33t_task_update", taskId, null); console.log("Successfully deleted task:", taskId); } catch (error: any) { console.error("Error deleting task:", error); socket.emit("l33t_delete_task_result", { success: false, error: error.message }); } }); }); // Task Management Setup const taskManager = new L33tTaskManager(io, memoryDB) var taskconfig = memoryDB.tasks await taskManager.applyConfig(taskconfig) taskManager.startAll() // Express Setup const remixHandler = createRequestHandler({ build: viteDevServer ? async () => { const build = await viteDevServer!.ssrLoadModule("virtual:remix/server-build") as ServerBuild; return build; } : await import("./build/server/index2.js"), getLoadContext: () => ({ memoryDB }), }); app.disable("x-powered-by"); if (viteDevServer) { app.use(viteDevServer.middlewares); } else { app.use( "/assets", express.static("build/client/assets", { immutable: true, maxAge: "1y" }) ); } app.use(express.static("build/client", { maxAge: "1h" })); app.use(morgan("tiny")); app.all("*", remixHandler); const port = process.env.PORT || 1337; httpServer.listen(port, () => { console.log(`Express server listening at http://localhost:${port}`); });