Add base HTTP server that responds to IO pings.

This commit is contained in:
Patrick Fic
2025-03-25 20:47:56 -07:00
parent d9300f6bc8
commit 791c518920
6 changed files with 928 additions and 54 deletions

View File

@@ -0,0 +1,121 @@
import cors from "cors";
import { app } from "electron";
import log from "electron-log/main";
import express from "express";
export default class LocalServer {
private app: express.Application;
private server: any;
private PORT = 1337;
constructor() {
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",
];
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, res) => {
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.
});
});
// Add more routes as needed
}
public start(): void {
this.server = this.app.listen(this.PORT, () => {
log.info(`[HTTP Server] Local HTTP server running on port ${this.PORT}`);
});
}
public stop(): void {
if (this.server) {
this.server.close();
log.info("[HTTP Server] Local HTTP server stopped");
}
}
}

View File

@@ -9,10 +9,14 @@ import ipcTypes from "../util/ipcTypes.json";
import client from "./graphql/graphql-client";
import store from "./store/store";
import appIcon from "../../resources/diamond.png?asset";
import LocalServer from "./http-server/http-server";
import errorTypeCheck from "../util/errorTypeCheck";
log.initialize();
const isMac = process.platform === "darwin";
var isAppQuitting = false; //Needed on Mac as an override to allow us to fully quit the app.
let isAppQuitting = false; //Needed on Mac as an override to allow us to fully quit the app.
// Initialize the server
const localServer = new LocalServer();
function createWindow(): void {
// Create the browser window.
const { width, height, x, y } = store.get("app.windowBounds") as {
@@ -257,8 +261,17 @@ app.whenReady().then(async () => {
...ErrorTypeCheck(error),
});
}
//Create Tray
//Start the HTTP server.
// Start the local HTTP server
try {
localServer.start();
log.info("HTTP server initialized on port 1337");
} catch (error) {
log.error("Failed to start HTTP server:", errorTypeCheck(error));
}
//Create Tray
const trayicon = nativeImage.createFromPath(appIcon);
const tray = new Tray(trayicon.resize({ width: 16 }));
const contextMenu = Menu.buildFromTemplate([
@@ -279,18 +292,17 @@ app.whenReady().then(async () => {
tray.setContextMenu(contextMenu);
//Check for app updates.
autoUpdater.logger = log;
if (import.meta.env.DEV) {
// Useful for some dev/debugging tasks, but download can
// not be validated becuase dev app is not signed
autoUpdater.updateConfigPath = path.join(
__dirname,
"../../dev-app-update.yml",
);
autoUpdater.forceDevUpdateConfig = true;
autoUpdater.autoDownload = false;
}
// if (import.meta.env.DEV) {
// // Useful for some dev/debugging tasks, but download can
// // not be validated becuase dev app is not signed
// autoUpdater.updateConfigPath = path.join(
// __dirname,
// "../../dev-app-update.yml",
// );
// autoUpdater.forceDevUpdateConfig = true;
// autoUpdater.autoDownload = false;
// }
autoUpdater.on("checking-for-update", () => {
log.info("Checking for update...");
const mainWindow = BrowserWindow.getAllWindows()[0];
@@ -336,6 +348,7 @@ app.on("window-all-closed", () => {
});
app.on("before-quit", () => {
localServer.stop();
isAppQuitting = true;
});

View File

@@ -1,5 +1,5 @@
{
"toolbar": {
"help": "Help"
}
"toolbar": {
"help": "Help"
}
}

View File

@@ -1,27 +1,27 @@
{
"translation": {
"navigation": {
"home": "Home",
"settings": "Settings"
},
"settings": {
"actions": {
"addpath": "Add path",
"startwatcher": "Start Watcher",
"stopwatcher": "Stop Watcher\n"
},
"labels": {
"started": "Started",
"stopped": "Stopped",
"watchedpaths": "Watched Paths",
"watcherstatus": "Watcher Status"
}
},
"updates": {
"apply": "Apply Update",
"available": "An update is available.",
"download": "Download Update",
"downloading": "An update is downloading."
}
}
"translation": {
"navigation": {
"home": "Home",
"settings": "Settings"
},
"settings": {
"actions": {
"addpath": "Add path",
"startwatcher": "Start Watcher",
"stopwatcher": "Stop Watcher\n"
},
"labels": {
"started": "Started",
"stopped": "Stopped",
"watchedpaths": "Watched Paths",
"watcherstatus": "Watcher Status"
}
},
"updates": {
"apply": "Apply Update",
"available": "An update is available.",
"download": "Download Update",
"downloading": "An update is downloading."
}
}
}