refactor: migrate web server to centralized logger

This commit is contained in:
syntaxbullet
2026-01-14 17:58:28 +01:00
parent 1e20a5a7a0
commit c7730b9355

View File

@@ -6,6 +6,7 @@
import { serve, spawn, type Subprocess } from "bun"; import { serve, spawn, type Subprocess } from "bun";
import { join, resolve, dirname } from "path"; import { join, resolve, dirname } from "path";
import { logger } from "@shared/lib/logger";
export interface WebServerConfig { export interface WebServerConfig {
port?: number; port?: number;
@@ -39,7 +40,7 @@ export async function createWebServer(config: WebServerConfig = {}): Promise<Web
const isDev = process.env.NODE_ENV !== "production"; const isDev = process.env.NODE_ENV !== "production";
if (isDev) { if (isDev) {
console.log("🛠️ Starting Web Bundler in Watch Mode..."); logger.info("web", "Starting Web Bundler in Watch Mode...");
try { try {
buildProcess = spawn(["bun", "run", "build.ts", "--watch"], { buildProcess = spawn(["bun", "run", "build.ts", "--watch"], {
cwd: webRoot, cwd: webRoot,
@@ -47,7 +48,7 @@ export async function createWebServer(config: WebServerConfig = {}): Promise<Web
stderr: "inherit", stderr: "inherit",
}); });
} catch (error) { } catch (error) {
console.error("Failed to start build process:", error); logger.error("web", "Failed to start build process", error);
} }
} }
@@ -75,7 +76,7 @@ export async function createWebServer(config: WebServerConfig = {}): Promise<Web
// Security Check: limit concurrent connections // Security Check: limit concurrent connections
const currentConnections = server.pendingWebSockets; const currentConnections = server.pendingWebSockets;
if (currentConnections >= MAX_CONNECTIONS) { if (currentConnections >= MAX_CONNECTIONS) {
console.warn(`⚠️ [WS] Connection rejected: limit reached (${currentConnections}/${MAX_CONNECTIONS})`); logger.warn("web", `Connection rejected: limit reached (${currentConnections}/${MAX_CONNECTIONS})`);
return new Response("Connection limit reached", { status: 429 }); return new Response("Connection limit reached", { status: 429 });
} }
@@ -94,7 +95,7 @@ export async function createWebServer(config: WebServerConfig = {}): Promise<Web
const stats = await getFullDashboardStats(); const stats = await getFullDashboardStats();
return Response.json(stats); return Response.json(stats);
} catch (error) { } catch (error) {
console.error("Error fetching dashboard stats:", error); logger.error("web", "Error fetching dashboard stats", error);
return Response.json( return Response.json(
{ error: "Failed to fetch dashboard statistics" }, { error: "Failed to fetch dashboard statistics" },
{ status: 500 } { status: 500 }
@@ -124,7 +125,7 @@ export async function createWebServer(config: WebServerConfig = {}): Promise<Web
const activity = await activityPromise; const activity = await activityPromise;
return Response.json(activity); return Response.json(activity);
} catch (error) { } catch (error) {
console.error("Error fetching activity stats:", error); logger.error("web", "Error fetching activity stats", error);
return Response.json( return Response.json(
{ error: "Failed to fetch activity statistics" }, { error: "Failed to fetch activity statistics" },
{ status: 500 } { status: 500 }
@@ -160,7 +161,7 @@ export async function createWebServer(config: WebServerConfig = {}): Promise<Web
return Response.json(result); return Response.json(result);
} }
} catch (error) { } catch (error) {
console.error("Error executing administrative action:", error); logger.error("web", "Error executing administrative action", error);
return Response.json( return Response.json(
{ error: "Failed to execute administrative action" }, { error: "Failed to execute administrative action" },
{ status: 500 } { status: 500 }
@@ -196,7 +197,7 @@ export async function createWebServer(config: WebServerConfig = {}): Promise<Web
return Response.json({ success: true }); return Response.json({ success: true });
} }
} catch (error) { } catch (error) {
console.error("Settings error:", error); logger.error("web", "Settings error", error);
return Response.json( return Response.json(
{ error: "Failed to process settings request", details: error instanceof Error ? error.message : String(error) }, { error: "Failed to process settings request", details: error instanceof Error ? error.message : String(error) },
{ status: 400 } { status: 400 }
@@ -235,7 +236,7 @@ export async function createWebServer(config: WebServerConfig = {}): Promise<Web
return Response.json({ roles, channels, commands }); return Response.json({ roles, channels, commands });
} catch (error) { } catch (error) {
console.error("Error fetching settings meta:", error); logger.error("web", "Error fetching settings meta", error);
return Response.json( return Response.json(
{ error: "Failed to fetch metadata" }, { error: "Failed to fetch metadata" },
{ status: 500 } { status: 500 }
@@ -294,7 +295,7 @@ export async function createWebServer(config: WebServerConfig = {}): Promise<Web
websocket: { websocket: {
open(ws) { open(ws) {
ws.subscribe("dashboard"); ws.subscribe("dashboard");
console.log(`🔌 [WS] Client connected. Total: ${server.pendingWebSockets}`); logger.debug("web", `Client connected. Total: ${server.pendingWebSockets}`);
// Send initial stats // Send initial stats
getFullDashboardStats().then(stats => { getFullDashboardStats().then(stats => {
@@ -308,7 +309,7 @@ export async function createWebServer(config: WebServerConfig = {}): Promise<Web
const stats = await getFullDashboardStats(); const stats = await getFullDashboardStats();
server.publish("dashboard", JSON.stringify({ type: "STATS_UPDATE", data: stats })); server.publish("dashboard", JSON.stringify({ type: "STATS_UPDATE", data: stats }));
} catch (error) { } catch (error) {
console.error("Error in stats broadcast:", error); logger.error("web", "Error in stats broadcast", error);
} }
}, 5000); }, 5000);
} }
@@ -319,7 +320,7 @@ export async function createWebServer(config: WebServerConfig = {}): Promise<Web
// Defense-in-depth: redundant length check before parsing // Defense-in-depth: redundant length check before parsing
if (messageStr.length > MAX_PAYLOAD_BYTES) { if (messageStr.length > MAX_PAYLOAD_BYTES) {
console.error("❌ [WS] Payload exceeded maximum limit"); logger.error("web", "Payload exceeded maximum limit");
return; return;
} }
@@ -328,7 +329,7 @@ export async function createWebServer(config: WebServerConfig = {}): Promise<Web
const parsed = WsMessageSchema.safeParse(rawData); const parsed = WsMessageSchema.safeParse(rawData);
if (!parsed.success) { if (!parsed.success) {
console.error("❌ [WS] Invalid message format:", parsed.error.issues); logger.error("web", "Invalid message format", parsed.error.issues);
return; return;
} }
@@ -336,12 +337,12 @@ export async function createWebServer(config: WebServerConfig = {}): Promise<Web
ws.send(JSON.stringify({ type: "PONG" })); ws.send(JSON.stringify({ type: "PONG" }));
} }
} catch (e) { } catch (e) {
console.error("❌ [WS] Failed to handle message:", e instanceof Error ? e.message : "Malformed JSON"); logger.error("web", "Failed to handle message", e);
} }
}, },
close(ws) { close(ws) {
ws.unsubscribe("dashboard"); ws.unsubscribe("dashboard");
console.log(`🔌 [WS] Client disconnected. Total remaining: ${server.pendingWebSockets}`); logger.debug("web", `Client disconnected. Total remaining: ${server.pendingWebSockets}`);
// Stop broadcast interval if no clients left // Stop broadcast interval if no clients left
if (server.pendingWebSockets === 0 && statsBroadcastInterval) { if (server.pendingWebSockets === 0 && statsBroadcastInterval) {
@@ -382,7 +383,7 @@ export async function createWebServer(config: WebServerConfig = {}): Promise<Web
// Helper to unwrap result or return default // Helper to unwrap result or return default
const unwrap = <T>(result: PromiseSettledResult<T>, defaultValue: T, name: string): T => { const unwrap = <T>(result: PromiseSettledResult<T>, defaultValue: T, name: string): T => {
if (result.status === 'fulfilled') return result.value; if (result.status === 'fulfilled') return result.value;
console.error(`Failed to fetch ${name}:`, result.reason); logger.error("web", `Failed to fetch ${name}`, result.reason);
return defaultValue; return defaultValue;
}; };
@@ -403,7 +404,7 @@ export async function createWebServer(config: WebServerConfig = {}): Promise<Web
const recentEvents = unwrap(results[4], [], 'recentEvents'); const recentEvents = unwrap(results[4], [], 'recentEvents');
const totalItems = unwrap(results[5], 0, 'totalItems'); const totalItems = unwrap(results[5], 0, 'totalItems');
const activeLootdrops = unwrap(results[6], [], 'activeLootdrops'); const activeLootdrops = unwrap(results[6], [], 'activeLootdrops');
const leaderboards = unwrap(results[7], { topLevels: [], topWealth: [] }, 'leaderboards'); const leaderboards = unwrap(results[7], { topLevels: [], topWealth: [], topNetWorth: [] }, 'leaderboards');
const lootdropState = unwrap(results[8], undefined, 'lootdropState'); const lootdropState = unwrap(results[8], undefined, 'lootdropState');
return { return {