Files
server/server.js
bangae1 890d6ce077 asd
2025-10-21 14:35:33 +09:00

136 lines
4.6 KiB
JavaScript

// server.js
const express = require('express');
const http = require('http');
const socketIo = require('socket.io');
const app = express();
const server = http.createServer(app);
const io = socketIo(server, {
cors: {
origin: "*", // 프로덕션에서는 정확한 도메인/포트 지정
methods: ["GET", "POST"]
}
});
// 직원 ID ↔ socket.id 매핑
const employeeSockets = new Map(); // { employeeId: socketId }
const employeeDisplays = new Map(); // { employeeId: displays[] }
io.on('connection', (socket) => {
console.log('새 클라이언트 연결됨:', socket.id);
// 1. 직원이 자신의 ID를 등록 (예: "EMP123")
socket.on('register', (employeeId) => {
if (employeeId) {
employeeSockets.set(employeeId, socket.id);
socket.employeeId = employeeId;
console.log(`직원 등록됨: ${employeeId}${socket.id}`);
// 선택: 관리자에게 직원 온라인 알림
socket.broadcast.emit('employeeOnline', employeeId);
}
});
// 2. 관리자가 연결 요청
socket.on('requestControl', ({ displayId, targetId }) => {
console.log('requestControl', targetId, displayId);
const targetSocketId = employeeSockets.get(targetId);
if (targetSocketId) {
io.to(targetSocketId).emit('responseControl', {
targetId: socket.id,
displayId // 선택된 디스플레이 ID 전달
});
} else {
console.log(`직원 ${targetId}가 오프라인입니다.`);
socket.emit('error', `직원 ${targetId}가 오프라인입니다.`);
}
});
// 2.5. 관리자가 디스플레이 목록 요청
socket.on('requestDisplays', (employeeId) => {
const displays = employeeDisplays.get(employeeId);
if (displays) {
socket.emit('responseDisplays', {displays});
} else {
socket.emit('error', `직원 ${employeeId}의 디스플레이 정보가 없습니다.`);
}
});
// 3. WebRTC 시그널링 (ICE)
socket.on('icecandidate', (data) => {
if(data.server === 'agent') {
if (data.targetId && data.candidate) {
console.log('icecandidate agent', data);
const to = io.to(data.targetId)
data.targetId = socket.id;
to.emit('icecandidate', data);
}
} else {
const targetSocketId = employeeSockets.get(data.targetId);
if (targetSocketId && data.candidate) {
console.log('icecandidate client', data);
const to = io.to(targetSocketId)
data.targetId = socket.id;
to.emit('icecandidate', data);
}
}
});
// 4. 입력 이벤트 전달 (관리자 → 직원)
socket.on('inputEvent', ({ targetId, ...data }) => {
const targetSocketId = employeeSockets.get(targetId);
if (targetSocketId) {
io.to(targetSocketId).emit('inputEvent', data);
}
});
// 연결 종료 시 정리
socket.on('disconnect', () => {
if (socket.employeeId) {
employeeSockets.delete(socket.employeeId);
socket.broadcast.emit('employeeOffline', socket.employeeId);
console.log(`직원 오프라인: ${socket.employeeId}`);
}
});
socket.on('availableDisplays', ({ displays }) => {
if (socket.employeeId && displays) {
employeeDisplays.set(socket.employeeId, displays);
console.log(`디스플레이 목록 저장됨: ${socket.employeeId}`, displays);
}
});
socket.on('requestOffer', (data) => {
const targetSocketId = employeeSockets.get(data.targetId);
console.log('requestOffer', employeeSockets, targetSocketId);
if(targetSocketId) {
const to = io.to(targetSocketId)
data.targetId = socket.id
to.emit('responseOffer', data);
}
})
socket.on('requestAnswer', (data) => {
console.log('requestAnswer', employeeSockets, data.targetId);
if(data.targetId) {
const to = io.to(data.targetId)
data.targetId = socket.id
to.emit('responseAnswer', data);
}
})
socket.on('start', (data) => {
console.log('start', employeeSockets, data);
if(data.targetId) {
const to = io.to(data.targetId)
data.targetId = socket.id
to.emit('start', data);
}
})
});
const PORT = process.env.PORT || 3001;
server.listen(PORT, () => {
console.log(`시그널링 서버 실행 중: http://localhost:${PORT}`);
});