98 lines
3.2 KiB
JavaScript
98 lines
3.2 KiB
JavaScript
const { Server: ServerIO } = require('socket.io')
|
||
const { io: ClientIO } = require('socket.io-client')
|
||
const { readHostList } = require('../utils')
|
||
const { clientPort } = require('../config')
|
||
const { verifyAuthSync } = require('../utils')
|
||
|
||
let clientSockets = {}, clientsData = {}
|
||
|
||
async function getClientsInfo(socketId) {
|
||
let hostList = await readHostList()
|
||
hostList
|
||
?.map(({ host, name }) => {
|
||
let clientSocket = ClientIO(`http://${ host }:${ clientPort }`, {
|
||
path: '/client/os-info',
|
||
forceNew: true,
|
||
timeout: 5000,
|
||
reconnectionDelay: 3000,
|
||
reconnectionAttempts: 100
|
||
})
|
||
// 将与客户端连接的socket实例保存起来,web端断开时关闭这些连接
|
||
clientSockets[socketId].push(clientSocket)
|
||
return {
|
||
host,
|
||
name,
|
||
clientSocket
|
||
}
|
||
})
|
||
.map(({ host, name, clientSocket }) => {
|
||
clientSocket
|
||
.on('connect', () => {
|
||
consola.success('client connect success:', host, name)
|
||
clientSocket.on('client_data', (osData) => {
|
||
clientsData[host] = osData
|
||
})
|
||
clientSocket.on('client_error', (error) => {
|
||
clientsData[host] = error
|
||
})
|
||
})
|
||
.on('connect_error', (error) => {
|
||
consola.error('client connect fail:', host, name, error.message)
|
||
clientsData[host] = null
|
||
})
|
||
.on('disconnect', () => {
|
||
consola.info('client connect disconnect:', host, name)
|
||
clientsData[host] = null
|
||
})
|
||
})
|
||
}
|
||
|
||
module.exports = (httpServer) => {
|
||
const serverIo = new ServerIO(httpServer, {
|
||
path: '/clients',
|
||
cors: {
|
||
origin: '*' // 需配置跨域
|
||
}
|
||
})
|
||
|
||
serverIo.on('connection', (socket) => {
|
||
// 前者兼容nginx反代, 后者兼容nodejs自身服务
|
||
let clientIp = socket.handshake.headers['x-forwarded-for'] || socket.handshake.address
|
||
socket.on('init_clients_data', async ({ token }) => {
|
||
// 校验登录态
|
||
const { code, msg } = await verifyAuthSync(token, clientIp)
|
||
if (code !== 1) {
|
||
socket.emit('token_verify_fail', msg || '鉴权失败')
|
||
socket.disconnect()
|
||
return
|
||
}
|
||
|
||
// 收集web端连接的id
|
||
clientSockets[socket.id] = []
|
||
consola.info('client连接socketId: ', socket.id, 'clients-socket已连接数: ', Object.keys(clientSockets).length)
|
||
|
||
// 获取客户端数据
|
||
getClientsInfo(socket.id)
|
||
|
||
// 立即推送一次
|
||
socket.emit('clients_data', clientsData)
|
||
|
||
// 向web端推送数据
|
||
let timer = null
|
||
timer = setInterval(() => {
|
||
socket.emit('clients_data', clientsData)
|
||
}, 1000)
|
||
|
||
// 关闭连接
|
||
socket.on('disconnect', () => {
|
||
// 防止内存泄漏
|
||
if (timer) clearInterval(timer)
|
||
// 当web端与服务端断开连接时, 服务端与每个客户端的socket也应该断开连接
|
||
clientSockets[socket.id].forEach(socket => socket.close && socket.close())
|
||
delete clientSockets[socket.id]
|
||
consola.info('断开socketId: ', socket.id, 'clients-socket剩余连接数: ', Object.keys(clientSockets).length)
|
||
})
|
||
})
|
||
})
|
||
}
|