-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.js
More file actions
120 lines (104 loc) · 2.77 KB
/
Copy pathserver.js
File metadata and controls
120 lines (104 loc) · 2.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
const express = require('express');
const http = require('http');
const path = require('path');
const { Server } = require('socket.io');
const app = express();
const server = http.createServer(app);
const io = new Server(server);
const PORT = process.env.PORT || 3000;
app.use(express.static(path.join(__dirname, 'public')));
const state = {
users: new Map(),
revealed: false,
history: []
};
function computeStats() {
const stats = {};
for (const entry of state.history) {
for (const [name, vote] of Object.entries(entry.votes)) {
const num = Number(vote);
if (!Number.isFinite(num)) continue;
if (!stats[name]) {
stats[name] = { count: 0, sum: 0, last: null, min: num, max: num };
}
const s = stats[name];
s.count += 1;
s.sum += num;
s.last = num;
s.min = Math.min(s.min, num);
s.max = Math.max(s.max, num);
}
}
for (const name of Object.keys(stats)) {
const s = stats[name];
s.avg = Number((s.sum / s.count).toFixed(2));
}
return stats;
}
function snapshot() {
const users = Array.from(state.users.values()).map((u) => ({
id: u.id,
name: u.name,
vote: u.vote
}));
let sum = 0;
let count = 0;
for (const user of state.users.values()) {
const num = Number(user.vote);
if (!Number.isFinite(num)) continue;
sum += num;
count += 1;
}
return {
users,
revealed: state.revealed,
history: state.history,
stats: computeStats(),
roundAverage: count ? Number((sum / count).toFixed(2)) : null,
roundCount: count
};
}
function broadcast() {
io.emit('state', snapshot());
}
io.on('connection', (socket) => {
state.users.set(socket.id, { id: socket.id, name: '', vote: null });
socket.emit('state', snapshot());
socket.on('set_name', (name) => {
const user = state.users.get(socket.id);
if (!user) return;
const clean = String(name || '').trim().slice(0, 24);
user.name = clean || `Player-${socket.id.slice(0, 4)}`;
broadcast();
});
socket.on('vote', (vote) => {
const user = state.users.get(socket.id);
if (!user) return;
user.vote = vote;
broadcast();
});
socket.on('reveal', () => {
if (state.revealed) return;
state.revealed = true;
const votes = {};
for (const user of state.users.values()) {
if (user.name) votes[user.name] = user.vote ?? null;
}
state.history.unshift({ ts: new Date().toISOString(), votes });
broadcast();
});
socket.on('reset', () => {
state.revealed = false;
for (const user of state.users.values()) {
user.vote = null;
}
broadcast();
});
socket.on('disconnect', () => {
state.users.delete(socket.id);
broadcast();
});
});
server.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});