feat: 실시간 대기 번호표 웹앱 초기 커밋
PIN 기반 세션으로 관리자·발급기·표시판 3개 역할을 하나의 앱에서 운영. Socket.IO 실시간 동기화, Podman Quadlet(10.89.0.25) 배포 구성 포함. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
71
server.js
Normal file
71
server.js
Normal file
@@ -0,0 +1,71 @@
|
||||
const express = require('express');
|
||||
const http = require('http');
|
||||
const { Server } = require('socket.io');
|
||||
const path = require('path');
|
||||
|
||||
const app = express();
|
||||
const server = http.createServer(app);
|
||||
const io = new Server(server, {
|
||||
pingTimeout: 60000,
|
||||
pingInterval: 25000,
|
||||
});
|
||||
|
||||
app.use(express.static(path.join(__dirname, 'public')));
|
||||
|
||||
// pin -> { issuedCount, calledCount }
|
||||
const sessions = {};
|
||||
|
||||
function sessionState(pin) {
|
||||
const s = sessions[pin] || { issuedCount: 0, calledCount: 0 };
|
||||
return {
|
||||
issuedCount: s.issuedCount,
|
||||
calledCount: s.calledCount,
|
||||
waitingCount: s.issuedCount - s.calledCount,
|
||||
};
|
||||
}
|
||||
|
||||
io.on('connection', (socket) => {
|
||||
let pin = null;
|
||||
|
||||
socket.on('join', ({ pin: p }) => {
|
||||
if (!p || typeof p !== 'string' || p.length < 4) {
|
||||
socket.emit('join_error', 'PIN은 최소 4자리 이상이어야 합니다.');
|
||||
return;
|
||||
}
|
||||
pin = p.trim();
|
||||
if (!sessions[pin]) {
|
||||
sessions[pin] = { issuedCount: 0, calledCount: 0 };
|
||||
}
|
||||
socket.join(pin);
|
||||
socket.emit('join_ok', sessionState(pin));
|
||||
});
|
||||
|
||||
socket.on('issue_ticket', () => {
|
||||
if (!pin || !sessions[pin]) return;
|
||||
sessions[pin].issuedCount += 1;
|
||||
const ticketNumber = sessions[pin].issuedCount;
|
||||
const state = sessionState(pin);
|
||||
socket.emit('ticket_issued', { ticketNumber, waitingCount: state.waitingCount });
|
||||
io.to(pin).emit('state_update', state);
|
||||
});
|
||||
|
||||
socket.on('call_next', () => {
|
||||
if (!pin || !sessions[pin]) return;
|
||||
const s = sessions[pin];
|
||||
if (s.calledCount >= s.issuedCount) return;
|
||||
s.calledCount += 1;
|
||||
io.to(pin).emit('state_update', sessionState(pin));
|
||||
});
|
||||
|
||||
socket.on('reset', () => {
|
||||
if (!pin || !sessions[pin]) return;
|
||||
sessions[pin] = { issuedCount: 0, calledCount: 0 };
|
||||
io.to(pin).emit('state_update', sessionState(pin));
|
||||
io.to(pin).emit('reset_done');
|
||||
});
|
||||
});
|
||||
|
||||
const PORT = process.env.PORT || 3000;
|
||||
server.listen(PORT, '0.0.0.0', () => {
|
||||
console.log(`Queue server running on port ${PORT}`);
|
||||
});
|
||||
Reference in New Issue
Block a user