83 lines
2.7 KiB
JavaScript
83 lines
2.7 KiB
JavaScript
const express = require('express');
|
|
const http = require('http');
|
|
const { Server } = require('socket.io');
|
|
const { db, init } = require('./database');
|
|
|
|
const app = express();
|
|
const server = http.createServer(app);
|
|
const io = new Server(server);
|
|
|
|
// Initialize DB
|
|
init();
|
|
|
|
app.use(express.static('public'));
|
|
|
|
// Rate limit helper
|
|
function canClick(name) {
|
|
const row = db.prepare('SELECT timestamp FROM logs WHERE name = ? ORDER BY timestamp DESC LIMIT 1').get(name);
|
|
if (!row) return true;
|
|
|
|
const lastClickTime = new Date(row.timestamp).getTime();
|
|
const now = Date.now();
|
|
// 30 seconds cooldown
|
|
return (now - lastClickTime) >= 30000;
|
|
}
|
|
|
|
function getGlobalCount() {
|
|
return db.prepare('SELECT count FROM global_count WHERE id = 1').get().count;
|
|
}
|
|
|
|
io.on('connection', (socket) => {
|
|
// Send current count immediately
|
|
socket.emit('update', { count: getGlobalCount() });
|
|
|
|
// Handle increment
|
|
socket.on('increment', (data) => {
|
|
const { name, quote } = data;
|
|
|
|
if (!name || name.trim() === "") {
|
|
socket.emit('error', 'Name is required');
|
|
return;
|
|
}
|
|
|
|
if (!canClick(name)) {
|
|
socket.emit('error', 'You must wait 30 seconds between clicks.');
|
|
return;
|
|
}
|
|
|
|
// Transaction to ensure consistency
|
|
const incrementTx = db.transaction(() => {
|
|
db.prepare('UPDATE global_count SET count = count + 1 WHERE id = 1').run();
|
|
db.prepare('INSERT INTO logs (name, quote) VALUES (?, ?)').run(name, quote || '');
|
|
return getGlobalCount();
|
|
});
|
|
|
|
const newCount = incrementTx();
|
|
|
|
// Broadcast new count to EVERYONE
|
|
io.emit('update', { count: newCount });
|
|
|
|
// Broadcast new log entry to admins (in a real app, we'd check auth, here we broadcast to "admin" room or just all for simplicity, but let's be nice and use a room if we were distinguishing. For now, I'll just emit a 'new_log' event globally or maybe just to the sender?
|
|
// The admin panel "gets logs". I should probably emit 'new_log' to everyone on the admin page.
|
|
// Let's assume admin listeners join a room 'admin'.
|
|
io.to('admin').emit('new_log', {
|
|
name,
|
|
quote,
|
|
timestamp: new Date().toISOString()
|
|
});
|
|
});
|
|
|
|
// Admin room join
|
|
socket.on('join_admin', () => {
|
|
socket.join('admin');
|
|
// Send recent logs
|
|
const logs = db.prepare('SELECT * FROM logs ORDER BY timestamp DESC LIMIT 50').all();
|
|
socket.emit('admin_data', { logs });
|
|
});
|
|
});
|
|
|
|
const PORT = process.env.PORT || 3000;
|
|
server.listen(PORT, () => {
|
|
console.log(`Server running on http://localhost:${PORT}`);
|
|
});
|