import cors from "cors"; import { app } from "electron"; import log from "electron-log/main"; import express from "express"; import http from "http"; import errorTypeCheck from "../../util/errorTypeCheck"; import ImportJob from "../decoder/decoder"; import folderScan from "../decoder/folder-scan"; import { handleEMSPartsOrder } from "../ems-parts-order/ems-parts-order-handler"; import { handleShopMetaDataFetch } from "../ipc/ipcMainHandler.user"; import { handlePartsPriceChangeRequest } from "../ppc/ppc-handler"; import { handleQuickBookRequest } from "../quickbooks-desktop/quickbooks-desktop"; export default class LocalServer { private readonly app: express.Application; private server: http.Server | null; private PORT = 1337; constructor() { this.server = null; this.app = express(); this.configureMiddleware(); this.configureRoutes(); } private configureMiddleware(): void { const allowedOrigins = [ "http://localhost", "https://localhost", "http://localhost:3000", "https://localhost:3000", "https://test.imex.online", "https://imex.online", "https://test.romeonline.io", "https://romeonline.io", "https://www.test.imex.online", "https://www.imex.online", "https://www.test.romeonline.io", "https://www.romeonline.io", ]; this.app.use( cors({ origin: (origin, callback) => { // Allow requests with no origin (like mobile apps, curl requests) if (!origin) return callback(null, true); if (allowedOrigins.indexOf(origin) !== -1) { return callback(null, true); } else { return callback(null, false); } }, credentials: true, }), ); // Parse JSON bodies this.app.use(express.json()); this.app.use(express.urlencoded()); //Add logger Middleware this.app.use((req, res, next) => { const startTime = Date.now(); const requestId = Math.random().toString(36).substring(2, 15); // Log request details log.info( `[HTTP Server] [${requestId}] Request: ${req.method} ${req.url}`, ); log.info( `[HTTP Server] [${requestId}] Headers: ${JSON.stringify(req.headers)}`, ); // Log request body if it exists if (req.body && Object.keys(req.body).length > 0) { log.info( `[HTTP Server] [${requestId}] Body: ${JSON.stringify(req.body)}`, ); } // Capture the original methods const originalSend = res.send; const originalJson = res.json; // Override send method to log response res.send = function (body): express.Response { log.info(`[HTTP Server] [${requestId}] Response body: ${body}`); log.info( `[HTTP Server] [${requestId}] Response time: ${Date.now() - startTime}ms`, ); return originalSend.call(this, body); }; // Override json method to log response res.json = function (body): express.Response { log.info( `[HTTP Server] [${requestId}] Response body: ${JSON.stringify(body)}`, ); log.info( `[HTTP Server] [${requestId}] Response time: ${Date.now() - startTime}ms`, ); return originalJson.call(this, body); }; next(); }); } private configureRoutes(): void { // Basic health check endpoint this.app.get("/health", (_req: express.Request, res: express.Response) => { res.status(200).json({ status: "ok" }); }); this.app.post("/ping", (_req, res) => { res.status(200).json({ appVer: app.getVersion(), qbPath: app.getPath("userData"), //TODO: Resolve to actual QB file path. }); }); this.app.post("/qb", handleQuickBookRequest); this.app.post("/scan", async (_req, res): Promise => { log.debug("[HTTP Server] Scan request received"); const files = await folderScan(); res.status(200).json(files); return; }); this.app.post("/ppc", handlePartsPriceChangeRequest); this.app.post("/oec", handleEMSPartsOrder); this.app.post( "/import", async (req: express.Request, res: express.Response) => { log.debug("[HTTP Server] Import request received"); const { filepath } = req.body; if (!filepath) { res.status(400).json({ error: "filepath is required" }); return; } try { await ImportJob(filepath); res.status(200).json({ success: true }); } catch (error) { log.error( "[HTTP Server] Error importing file", errorTypeCheck(error), ); res.status(500).json({ success: false, error: "Error importing file", ...errorTypeCheck(error), }); } }, ); this.app.post( "/refresh", async (_req: express.Request, res: express.Response) => { log.debug("[HTTP Server] Refresh request received"); try { await handleShopMetaDataFetch(true); res.status(200).json({ success: true }); } catch (error) { log.error( "[HTTP Server] Error refreshing shop metadata", errorTypeCheck(error), ); res.status(500).json({ success: false, error: "Error importing file", ...errorTypeCheck(error), }); } }, ); // Add more routes as needed } public start(): void { try { this.server = http.createServer(this.app); this.server.on("error", (error: NodeJS.ErrnoException) => { if (error.code === "EADDRINUSE") { log.error( `[HTTP Server] Port ${this.PORT} is already in use. Please use a different port.`, ); } else { log.error(`[HTTP Server] Server error: ${error.message}`); } }); this.server.listen(this.PORT, () => { log.info( `[HTTP Server] Local HTTP server running on port ${this.PORT}`, ); }); } catch (error: unknown) { log.error("[HTTP Server] Error starting server", errorTypeCheck(error)); } } public stop(): void { if (this.server) { this.server.close(); log.info("[HTTP Server] Local HTTP server stopped"); } } }