const { Server } = require('socket.io'); const axios = require('axios'); let io; let users = {}; let connectionLog = { onpremise : { users : [], count : 0, time : '', }, jangheon : { users : [], count : 0, time : '', }, bim : { users : [], count : 0, time : '', }, overseas : { users : [], count : 0, time : '', }, gtb : { users : [], count : 0, time : '', }, dev : { users : [], count : 0, time : '', }, industry : { users : [], count : 0, time : '', }, }; let curConnectedUsers = { onpremise : [], jangheon : [], bim : [], overseas : [], gtb : [], dev : [], industry : [], } module.exports = { init: (server) => { io = new Server(server, { cors: { origin: "*" } }); io.on('connection', (socket) => { console.log('Client connected:', socket.id); // 실시간 마우스 표시 // socket.on('mouseMove', (data) => { // // 같은 페이지에 있는 사람들에게 // io.emit('mouseMove', { // clientId: socket.id, // x: data.x, // y: data.y, // userInfo: data.userInfo, // }); // }); socket.on('disconnect', () => { console.log('Client disconnected:', (users[socket.id])?users[socket.id].user_nm:socket.id); let me = users[socket.id]; delete users[socket.id]; if(!me || !me.origin) return; //curConnectedUsers에서 해당 id 삭제 let curUser = undefined; if (me.origin.includes('172.16.43.')) { curUser = curConnectedUsers.onpremise; } else if (me.origin.includes('jangheon.')) { curUser = curConnectedUsers.jangheon; } else if (me.origin.includes('bim.')) { curUser = curConnectedUsers.bim; } else if (me.origin.includes('overseas.')) { curUser = curConnectedUsers.overseas; } else if (me.origin.includes('gtb.')) { curUser = curConnectedUsers.gtb; } else if (me.origin.includes('172.')) { curUser = curConnectedUsers.dev; } if(curUser && curUser.length > 0){ for(let i = 0; i < curUser.length; i++){ if(curUser[i] === me.user_id){ curUser.splice(i,1); break; } } } let targetId = Object.keys(users).filter(key=>users[key].project_id === me.project_id); let filterUsers = {}; for(let i =0;i 0){ for(let i = 0; i < targetId.length; i++){ io.to(targetId[i]).emit('connected_user',{users:filterUsers}); } } // io.emit('userDisconnected', (users[socket.id])?users[socket.id].user_nm:socket.id); io.emit('getUsers',users); }); socket.on('popupNotice', (data)=>{ io.emit('popupNotice', data ); }) socket.on('forcedLogout', (data)=>{ if (data && data.targetClientId) { const targetSocket = io.sockets.sockets.get(data.targetClientId); if (targetSocket) { console.log(`🔌 Forcing logout for socket ID: ${data.targetClientId} (${users[data.targetClientId]?.user_nm || 'unknown'})`); targetSocket.emit('forcedLogout', { message: '관리자에 의해 강제 퇴장되었습니다.' }); targetSocket.disconnect(true); } } else { io.emit('forcedLogout'); } }) socket.on('sendMessage', (data)=>{ let { targetClientId } = data; io.to(targetClientId).emit('sendMessage', data ); }) //접속자 관리 socket.on('getUsers', ()=>{ io.to(socket.id).emit('getUsers',users); }); //첫 접속시 user정보 보관 socket.on('setUser', (data)=>{ const {me, stat, origin} = data; // 최대 동시 접속자수가 되었을때 정보 기록 if(stat == 'first'){ // 접속자를 해당 변수에 밀어넣기 let curUser = undefined; let connections = undefined; if (me.origin.includes('172.16.43.')) { curUser = curConnectedUsers.onpremise; connections = connectionLog.onpremise; } else if (me.origin.includes('jangheon.')) { curUser = curConnectedUsers.jangheon; connections = connectionLog.jangheon; } else if (me.origin.includes('bim.')) { curUser = curConnectedUsers.bim; connections = connectionLog.bim; } else if (me.origin.includes('overseas.')) { curUser = curConnectedUsers.overseas; connections = connectionLog.overseas; } else if (me.origin.includes('gtb.')) { curUser = curConnectedUsers.gtb; connections = connectionLog.gtb; } else if (me.origin.includes('172.') || me.origin.includes('localhost')) { curUser = curConnectedUsers.dev; connections = connectionLog.dev; } else if (me.origin.includes('jangheonindustry.')){ curUser = curConnectedUsers.industry; connections = connectionLog.industry; } curUser.push(me.user_id); // 각 접속자들 수 이전과 비교 많아졌으면 정보 저장 if(curUser.length > connections.count){ connections.count = curUser.length; connections.time = getDateNow(); connections.users = structuredClone(curUser); } } if(users[socket.id]){ Object.assign(users[socket.id], me); }else{ users[socket.id] = me; socket.user = me; users[socket.id].clientId = socket.id; } // if(stat == 'first'){ // //동일 프로젝트 사람들에게 접속정보 전달 // let targetId = Object.keys(users).filter(key=>users[key].project_id === me.project_id); // let filterUsers = {}; // for(let i =0;i 0){ // for(let i = 0; i < targetId.length; i++){ // io.to(targetId[i]).emit('connected_user',{users:filterUsers}); // } // } // } //동일 프로젝트 사람들에게 접속정보 전달 let targetId = Object.keys(users).filter(key=>users[key].project_id === me.project_id); let filterUsers = {}; for(let i =0;i 0){ for(let i = 0; i < targetId.length; i++){ // if(stat == 'first') io.to(targetId[i]).emit('connected_user',{users:filterUsers}); io.to(targetId[i]).emit('connected_user',{users:filterUsers}); } } //내가 접속 페이지를 바꿨을때 //우선 front로 보내고 앞에서 동일 curPath 거르기 io.to(socket.id).emit('fileSelected',{users : filterUsers}); io.emit('getUsers',users); }); socket.on('getMe', ()=>{ let me = users[socket.id]; io.to(socket.id).emit('returnMe',me); }); socket.on('fileSelect',(data)=>{ const {me} = data; if(!users[socket.id]) return; Object.assign(users[socket.id], me); //동일 프로젝트, 폴더 사람들에게 내 정보 전달 let targetId = Object.keys(users).filter(key=>users[key].project_id === me.project_id).filter(key=>users[key].curPath === me.curPath); let jsonMe = {}; jsonMe[socket.id] = me; if(targetId && targetId.length > 0){ for(let i = 0; i < targetId.length; i++){ io.to(targetId[i]).emit('fileSelected',{users : jsonMe}); } } }) socket.on('setMouseInfo',(data)=>{ const {x,y} = data; if(!users[socket.id]) return; users[socket.id].x = x; users[socket.id].y = y; let me = users[socket.id]; //동일 프로젝트 사람들에게 접속정보 전달 =>부하 테스트 필요 let targetId = Object.keys(users).filter(key=>users[key].project_id === me.project_id && users[key].curPath === me.curPath); let filterUsers = {}; for(let i =0;i 0){ for(let i = 0; i < targetId.length; i++){ io.to(targetId[i]).emit('setMouse',me); } } }) socket.on('insertLog',async ()=>{ await insertLog(); }); }); //폴더 다운로드 관리용 array io.folderDownloadList = undefined; return io; }, getIo: () => { if (!io) { throw new Error("Socket.io not initialized!"); } return io; } }; // 날짜 string으로 뽑기 function getDateNow(){ const now = new Date(); const year = now.getFullYear(); const month = (now.getMonth() + 1).toString().padStart(2, '0'); const day = now.getDate().toString().padStart(2, '0'); const hours = now.getHours().toString().padStart(2, '0'); const minutes = now.getMinutes().toString().padStart(2, '0'); return `${year}-${month}-${day} ${hours}:${minutes}`; } // 매일 12시에 서버에 로그 남기기 위한 타이머 function timer(){ const now = new Date(); const target = new Date(); target.setHours(0, 0, 0, 0); // test용 시간, 분, 초, 밀리 // target.setHours(17, 33, 0, 0); if(now > target)target.setDate(target.getDate()+1); const delay = target - now; // console용 변환 const totalSeconds = Math.floor(delay / 1000); const hours = Math.floor(totalSeconds / 3600); const minutes = Math.floor((totalSeconds % 3600) / 60); const seconds = totalSeconds % 60; console.log(`다음 실행까지 ${hours}시간 ${minutes}분 ${seconds}초 남음`); setTimeout(async () => { insertLog(); // LOG 기록 초기화 connectionLog = { onpremise : { users : [], count : 0, time : '', }, jangheon : { users : [], count : 0, time : '', }, bim : { users : [], count : 0, time : '', }, overseas : { users : [], count : 0, time : '', }, gtb : { users : [], count : 0, time : '', }, dev : { users : [], count : 0, time : '', } }; // 다음번 실행 timer(); }, delay); }; // 서버 시작시 강제실행 timer(); async function insertLog(){ let json = JSON.stringify(connectionLog); //DB에 로그기록 남기기 요청...101번에서 처리하기. await axios.post(`http://gsim.hanmaceng.co.kr:5151/login/insertConcurrent`,{jsonString:json}); }