Files
wordcloud-board/server/realtime-server.mjs
T
broccoli 02f5bf14ba
Build, Push and Deploy / build (push) Failing after 1s
Build, Push and Deploy / deploy (push) Skipped
Configure board deployment and backend proxy
2026-09-13 16:09:59 +08:00

92 lines
2.2 KiB
JavaScript

import { createServer } from 'node:http';
import { pathToFileURL } from 'node:url';
import { WebSocketServer } from 'ws';
function isFocusEvent(value) {
return (
typeof value === 'object' &&
value !== null &&
value.type === 'FOCUS_NAME' &&
typeof value.cloudId === 'string' &&
typeof value.name === 'string' &&
typeof value.messageId === 'string' &&
typeof value.sentAt === 'number' &&
(value.targetIndex === undefined ||
(typeof value.targetIndex === 'number' &&
Number.isInteger(value.targetIndex) &&
value.targetIndex >= 0))
);
}
export function createRealtimeServer(port = Number(process.env.REALTIME_PORT || 8787)) {
const server = createServer((request, response) => {
if (request.url === '/healthz') {
response.writeHead(200, { 'content-type': 'application/json' });
response.end(JSON.stringify({ status: 'ok' }));
return;
}
response.writeHead(404, { 'content-type': 'text/plain' });
response.end('Not found');
});
const realtime = new WebSocketServer({
server,
maxPayload: 16 * 1024,
});
const heartbeat = setInterval(() => {
for (const socket of realtime.clients) {
if (socket.isAlive === false) {
socket.terminate();
continue;
}
socket.isAlive = false;
socket.ping();
}
}, 30_000);
heartbeat.unref();
realtime.on('connection', (socket) => {
socket.isAlive = true;
socket.on('pong', () => {
socket.isAlive = true;
});
socket.on('message', (data) => {
let value;
try {
value = JSON.parse(data.toString());
} catch {
return;
}
if (!isFocusEvent(value)) {
return;
}
const message = JSON.stringify(value);
for (const client of realtime.clients) {
if (client !== socket && client.readyState === client.OPEN) {
client.send(message);
}
}
});
});
realtime.on('close', () => {
clearInterval(heartbeat);
});
return server;
}
if (import.meta.url === pathToFileURL(process.argv[1] || '').href) {
const port = Number(process.env.REALTIME_PORT || 8787);
createRealtimeServer(port).listen(port, () => {
console.log(`Realtime WebSocket server listening on port ${port}`);
});
}