Initial commit: SyncWatch Chrome extension + WebSocket server
This commit is contained in:
98
server/server.js
Normal file
98
server/server.js
Normal file
@@ -0,0 +1,98 @@
|
||||
const { WebSocketServer, WebSocket } = require('ws');
|
||||
const http = require('http');
|
||||
|
||||
const PORT = process.env.PORT || 8080;
|
||||
|
||||
const server = http.createServer((req, res) => {
|
||||
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
||||
res.end('SyncWatch server running\n');
|
||||
});
|
||||
|
||||
const wss = new WebSocketServer({ server });
|
||||
|
||||
// Map<roomCode, Set<WebSocket>>
|
||||
const rooms = new Map();
|
||||
|
||||
function generateCode() {
|
||||
let code;
|
||||
do {
|
||||
code = Math.floor(100000 + Math.random() * 900000).toString();
|
||||
} while (rooms.has(code));
|
||||
return code;
|
||||
}
|
||||
|
||||
function broadcast(room, message, exclude) {
|
||||
const data = JSON.stringify(message);
|
||||
for (const client of room) {
|
||||
if (client !== exclude && client.readyState === WebSocket.OPEN) {
|
||||
client.send(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wss.on('connection', (ws) => {
|
||||
ws.roomCode = null;
|
||||
|
||||
ws.on('message', (raw) => {
|
||||
let msg;
|
||||
try { msg = JSON.parse(raw); } catch { return; }
|
||||
|
||||
switch (msg.type) {
|
||||
case 'create': {
|
||||
if (ws.roomCode) return;
|
||||
const code = generateCode();
|
||||
rooms.set(code, new Set([ws]));
|
||||
ws.roomCode = code;
|
||||
ws.send(JSON.stringify({ type: 'created', code }));
|
||||
break;
|
||||
}
|
||||
|
||||
case 'join': {
|
||||
if (ws.roomCode) return;
|
||||
const code = String(msg.code || '');
|
||||
const room = rooms.get(code);
|
||||
if (!room) {
|
||||
ws.send(JSON.stringify({ type: 'error', message: 'Room not found' }));
|
||||
return;
|
||||
}
|
||||
if (room.size >= 2) {
|
||||
ws.send(JSON.stringify({ type: 'error', message: 'Room is full' }));
|
||||
return;
|
||||
}
|
||||
room.add(ws);
|
||||
ws.roomCode = code;
|
||||
ws.send(JSON.stringify({ type: 'joined', code, memberCount: room.size }));
|
||||
broadcast(room, { type: 'peer_joined' }, ws);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'sync': {
|
||||
if (!ws.roomCode) return;
|
||||
const room = rooms.get(ws.roomCode);
|
||||
if (!room) return;
|
||||
broadcast(room, { type: 'sync', action: msg.action, time: msg.time }, ws);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'ping':
|
||||
ws.send(JSON.stringify({ type: 'pong' }));
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
ws.on('close', () => {
|
||||
if (!ws.roomCode) return;
|
||||
const room = rooms.get(ws.roomCode);
|
||||
if (!room) return;
|
||||
room.delete(ws);
|
||||
if (room.size === 0) {
|
||||
rooms.delete(ws.roomCode);
|
||||
} else {
|
||||
broadcast(room, { type: 'peer_left' }, null);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
server.listen(PORT, () => {
|
||||
console.log(`SyncWatch server listening on port ${PORT}`);
|
||||
});
|
||||
Reference in New Issue
Block a user