refactor: migrate web server to centralized logger
This commit is contained in:
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user