const ws = require('ws') const webtoken = require('wo-base-webtoken') const my = { wsServer: undefined, socketPool: {}, listeners: {}, } module.exports = { initSocket (webServer) { my.wsServer = new ws.Server({ server: webServer }) console.info('Base Socket Server is initialized.') my.wsServer.on('connection', (socket, req) => { console.info(`A socket is connecting from ${req.connection.remoteAddress}:${req.connection.remotePort}.`) // socket.isAlive = true // socket.on('pong', function() { console.log('👈 ASS: on Pong'); this.isAlive = true }) socket.on('message', (data) => { // 在这里统一分发消息 console.log('App Socket Client message: ', data) let dataObj try { dataObj = JSON.parse(data) } catch (exception) { console.log(new Date().toJSON(), 'Unable to parse socket message: ', data) return } if (dataObj.skevent === 'SOCKET_OWNER') { dataObj._passtokenSource = webtoken.verifyToken(dataObj._passtoken) // todo: 为防止前端欺骗,应当用和login里类似的方法来检查来检查 if (typeof dataObj._passtokenSource?.usid === 'string') { my.socketPool[dataObj._passtokenSource.usid] = socket console.log('收到 Login 成功的消息,绑定socket', Object.keys(my.socketPool)) } } const listeners = my.listeners[dataObj.skevent] || [] for (const listener of listeners) { listener(dataObj) } }) }) // const heartbeat = setInterval(() => { // my.wsServer.clients.forEach((socket) => { // if (socket.isAlive === false) return socket.terminate() // socket.isAlive = false // socket.ping(function() { wo.cclog('👉 ASS: sent Ping') }) // }) // }, 30000) // my.wsServer.on('close', () => { clearInterval(heartbeat) }) return this }, removeUserSocket (usid) { delete my.socketPool[usid] }, addListener (skevent, listener) { if (Array.isArray(my.listeners[skevent]) && typeof listener === 'function') { my.listeners[skevent].push(listener) } else { my.listeners[skevent] = [listener] } return this }, sendToAll (dataObj) { my.wsServer.clients.forEach((socket) => { if (socket.readyState === socket.OPEN) { socket.send(typeof dataObj !== 'string' ? JSON.stringify(dataObj) : dataObj) } else { delete my.socketPool[socket.usid] } }) }, sendToOne (dataObj, usid) { const socket = my.socketPool[usid] if (socket && socket.readyState === socket.OPEN) { socket.send(typeof dataObj !== 'string' ? JSON.stringify(dataObj) : dataObj) } else { delete my.socketPool[usid] } }, } // todo: 前端断线重连时,并不会再次 login_success。也许在前端的initSocket时,应当把_passtoken送过来,而后台则对_passtoken做验证后再加socketPool。