Files
discord-rpg-concept/src/web/server.ts

86 lines
2.8 KiB
TypeScript

import { env } from "@/lib/env";
import { router } from "./router";
import type { Server } from "bun";
export class WebServer {
private static server: Server<unknown> | null = null;
private static heartbeatInterval: ReturnType<typeof setInterval> | null = null;
public static start(port?: number) {
this.server = Bun.serve({
port: port ?? (typeof env.PORT === "string" ? parseInt(env.PORT) : 3000),
fetch: (req, server) => {
const url = new URL(req.url);
if (url.pathname === "/ws") {
// Upgrade the request to a WebSocket
// We pass dummy data for now
if (server.upgrade(req, { data: undefined })) {
return undefined;
}
return new Response("WebSocket upgrade failed", { status: 500 });
}
return router(req);
},
websocket: {
open(ws) {
// console.log("ws: client connected");
ws.subscribe("status-updates");
ws.send(JSON.stringify({ type: "WELCOME", message: "Connected to Aurora WebSocket" }));
},
message(ws, message) {
// Handle incoming messages if needed
},
close(ws) {
// console.log("ws: client disconnected");
ws.unsubscribe("status-updates");
},
},
});
console.log(`🌐 Web server listening on http://localhost:${this.server.port}`);
// Start a heartbeat loop
this.heartbeatInterval = setInterval(() => {
if (this.server) {
const uptime = process.uptime();
this.server.publish("status-updates", JSON.stringify({
type: "HEARTBEAT",
data: {
uptime,
timestamp: Date.now()
}
}));
}
}, 5000);
}
public static stop() {
if (this.heartbeatInterval) {
clearInterval(this.heartbeatInterval);
this.heartbeatInterval = null;
}
if (this.server) {
this.server.stop();
console.log("🛑 Web server stopped");
this.server = null;
}
}
public static get port(): number | undefined {
return this.server?.port;
}
public static broadcastLog(type: string, message: string) {
if (this.server) {
this.server.publish("status-updates", JSON.stringify({
type: "LOG",
data: {
timestamp: new Date().toLocaleTimeString(),
type,
message
}
}));
}
}
}