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