feat: add Express + WebSocket server entry point
This commit is contained in:
@@ -0,0 +1,34 @@
|
|||||||
|
import express from "express";
|
||||||
|
import cors from "cors";
|
||||||
|
import { createServer } from "http";
|
||||||
|
import path from "path";
|
||||||
|
import { fileURLToPath } from "url";
|
||||||
|
import { initWebSocket, getClientCount } from "./services/ws.service.js";
|
||||||
|
|
||||||
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||||
|
const app = express();
|
||||||
|
const server = createServer(app);
|
||||||
|
|
||||||
|
app.use(cors());
|
||||||
|
app.use(express.json());
|
||||||
|
|
||||||
|
initWebSocket(server);
|
||||||
|
|
||||||
|
app.get("/api/health", (_req, res) => {
|
||||||
|
res.json({
|
||||||
|
status: "ok",
|
||||||
|
wsClients: getClientCount(),
|
||||||
|
uptime: process.uptime(),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const frontendDist = path.resolve(__dirname, "../../frontend/dist");
|
||||||
|
app.use(express.static(frontendDist));
|
||||||
|
app.get("*path", (_req, res) => {
|
||||||
|
res.sendFile(path.join(frontendDist, "index.html"));
|
||||||
|
});
|
||||||
|
|
||||||
|
const PORT = parseInt(process.env.PORT || "3000", 10);
|
||||||
|
server.listen(PORT, "0.0.0.0", () => {
|
||||||
|
console.log(`Layonara Forge listening on http://0.0.0.0:${PORT}`);
|
||||||
|
});
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import { WebSocketServer, WebSocket } from "ws";
|
||||||
|
import type { Server } from "http";
|
||||||
|
|
||||||
|
type EventType = "docker" | "build" | "log" | "toolset" | "git";
|
||||||
|
|
||||||
|
interface ForgeEvent {
|
||||||
|
type: EventType;
|
||||||
|
action: string;
|
||||||
|
data: unknown;
|
||||||
|
timestamp: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const clients = new Set<WebSocket>();
|
||||||
|
|
||||||
|
let wss: WebSocketServer;
|
||||||
|
|
||||||
|
export function initWebSocket(server: Server): WebSocketServer {
|
||||||
|
wss = new WebSocketServer({ server, path: "/ws" });
|
||||||
|
|
||||||
|
wss.on("connection", (ws) => {
|
||||||
|
clients.add(ws);
|
||||||
|
ws.on("close", () => clients.delete(ws));
|
||||||
|
ws.on("error", () => clients.delete(ws));
|
||||||
|
});
|
||||||
|
|
||||||
|
return wss;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function broadcast(type: EventType, action: string, data: unknown): void {
|
||||||
|
const event: ForgeEvent = {
|
||||||
|
type,
|
||||||
|
action,
|
||||||
|
data,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
};
|
||||||
|
const message = JSON.stringify(event);
|
||||||
|
for (const client of clients) {
|
||||||
|
if (client.readyState === WebSocket.OPEN) {
|
||||||
|
client.send(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getClientCount(): number {
|
||||||
|
return clients.size;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user