import { verifyToken } from '../utils/token.js' import { SocketController } from '../controllers/socketController.js' import { GeneralService } from '../share/generalservice.js' import redis from '../utils/redis.js' // ใช้ Redis ที่มีเก็บ Session export class SocketManager { constructor(io) { this.io = io this.generalService = new GeneralService() this.socketController = new SocketController() } initialize() { this.generalService.devhint(1, 'SocketManager.js', 'Initializing Socket.io') // Middleware: Authentication (เช็ค Token ก่อน Connect) this.io.use(async (socket, next) => { try { const token = socket.handshake.auth.token || socket.handshake.headers.token if (!token) return next(new Error('Authentication error')) const decoded = verifyToken(token) if (!decoded) return next(new Error('Invalid Token')) // เก็บข้อมูล User เข้า Socket Session socket.user = decoded socket.organization = decoded.organization // ใช้สำหรับ Schema next() } catch (err) { next(new Error('Authentication failed')) } }) this.io.on('connection', async (socket) => { this.generalService.devhint(1, 'SocketManager.js', `User Connected: ${socket.user.usrnam}`) // 1. Save User Session to Redis (Pattern การเก็บ state) // key: "online:user_id", value: socket_id await redis.set(`online:${socket.user.id}`, socket.id) // Join Room ส่วนตัว (ตาม User ID) socket.join(socket.user.id.toString()) // ========================================== // Event Handlers (เรียก Controller Pattern) // ========================================== // 1. Send Notification (User ส่งหา User) socket.on('send_notification', async (data) => { await this.socketController.onSendNotification(this.io, socket, data) }) // 2. VoIP: Call Request socket.on('call_user', async (data) => { await this.socketController.onCallUser(this.io, socket, data) }) // 3. VoIP: Answer Call socket.on('answer_call', async (data) => { await this.socketController.onAnswerCall(this.io, socket, data) }) // 4. VoIP: ICE Candidate (Network info) socket.on('ice_candidate', async (data) => { await this.socketController.onIceCandidate(this.io, socket, data) }) // 5. VoIP: End Call socket.on('end_call', async (data) => { await this.socketController.onEndCall(this.io, socket, data) }) // Disconnect socket.on('disconnect', async () => { this.generalService.devhint(1, 'SocketManager.js', `User Disconnected: ${socket.user.usrnam}`) await redis.del(`online:${socket.user.id}`) }) }) } }