Compare commits

...

1 Commits

Author SHA1 Message Date
Luk
7729af631a u 2026-02-07 11:32:44 +08:00
3 changed files with 53 additions and 53 deletions

View File

@@ -6,25 +6,20 @@ const my = {
wsServer: undefined, wsServer: undefined,
// socketPool: {}, // socketPool: {},
listeners: {}, listeners: {},
heartbeat: false,
heartbeatInterval: 30000, heartbeatInterval: 30000,
} }
module.exports = { module.exports = {
initSocket ({ webServer, heartbeat, heartbeatInterval }) { initSocket ({ webServer, heartbeat, heartbeatInterval }) {
my.wsServer = new ws.Server({ server: webServer }) my.wsServer = new ws.Server({ server: webServer })
//console.info({ _at: new Date().toJSON(), _from: 'Socket:initSocket', _type: 'CLOG', about: 'Base Socket Server is initialized.' }, '\n,') //globalThis.wo?.ccinfo?.({ _from: 'Socket:initSocket', _type: 'CLOG', about: 'Base Socket Server is initialized.' })
my.wsServer.on('connection', (socket, req) => { my.wsServer.on('connection', (socket, req) => {
console.info( globalThis.wo?.ccinfo?.({
{
_at: new Date().toJSON(),
_from: 'basesocket:onConnection', _from: 'basesocket:onConnection',
_type: 'CLOG', _type: 'CLOG',
about: `A socket is connecting from ${req.connection.remoteAddress}:${req.connection.remotePort}.`, about: `A socket is connecting from ${req.connection.remoteAddress}:${req.connection.remotePort}.`,
}, })
'\n,'
)
// socket.isAlive = true // socket.isAlive = true
// socket.on('ping', () => { socket.isAlive = true }) // Most WebSocket server implementations, including the ws library, automatically respond to ping frames with pong frames. However, the server can listen for ping events using socket.on('ping', ...) if it wants to perform additional actions. // socket.on('ping', () => { socket.isAlive = true }) // Most WebSocket server implementations, including the ws library, automatically respond to ping frames with pong frames. However, the server can listen for ping events using socket.on('ping', ...) if it wants to perform additional actions.
@@ -37,25 +32,23 @@ module.exports = {
// socket.isAlive = true // socket.isAlive = true
return return
} }
//console.log({ _at: new Date().toJSON(), _from: 'basesocket:onMessage', _type: 'CLOG', usid: socket.usid, skevent: dataObj?.skevent }, '\n,') //globalThis.wo?.cclog?.({ _from: 'basesocket:onMessage', _type: 'CLOG', usid: socket.usid, skevent: dataObj?.skevent })
} catch (exception) { } catch (exception) {
console.error({ _at: new Date().toJSON(), _from: 'basesocket:onMessage', _type: 'CERROR', about: 'Unable to parse socket message', data }, '\n,') globalThis.wo?.ccerror?.({ _from: 'basesocket:onMessage', _type: 'CERROR', about: 'Unable to parse socket message', data })
return return
} }
console.log('WebSocket-onMessage: dataObj', dataObj) globalThis.wo?.cclog?.({ _from: 'Socket:onMessage:dataObj', dataObj })
if (['SOCKET_OWNER', 'SOCKET_OWNER_RECONNECT'].includes(dataObj.skevent)) { if (['SOCKET_OWNER', 'SOCKET_OWNER_RECONNECT'].includes(dataObj.skevent)) {
// 前端断线重连时,并不会自动再次提供 _passtoken。在前端的initSocket时应当把_passtoken送过来。 // 前端断线重连时,并不会自动再次提供 _passtoken。在前端的initSocket时应当把_passtoken送过来。
const _passtokenSource = webtoken.verifyToken(dataObj._passtoken) const _passtokenSource = webtoken.verifyToken(dataObj._passtoken)
console.log('WebSocket-onMessge: _passtokenSource', _passtokenSource) globalThis.wo?.cclog?.({ _from: 'Socket:onMessge:_passtokenSource', _passtokenSource })
if (typeof _passtokenSource?.usid === 'string') { if (typeof _passtokenSource?.usid === 'string') {
socket.appkey = _passtokenSource.appkey socket.appkey = _passtokenSource.appkey
socket.usid = _passtokenSource.usid socket.usid = _passtokenSource.usid
socket.commid = _passtokenSource.commid socket.commid = _passtokenSource.commid
socket.skid = _passtokenSource.clid || socket.skid || 'skid' + crypto.randomBytes(16).toString('hex') // 注意skid 这个名字 仅限在本文件内使用,在外部都使用 clid (client id) socket.skid = _passtokenSource.clid || socket.skid || 'skid' + crypto.randomBytes(16).toString('hex') // 注意skid 这个名字 仅限在本文件内使用,在外部都使用 clid (client id)
// my.socketPool[socket.skid] = socket // my.socketPool[socket.skid] = socket
console.log( globalThis.wo?.cclog?.({
{
_at: new Date().toJSON(),
_from: 'basesocket:onMessage', _from: 'basesocket:onMessage',
_type: 'CLOG', _type: 'CLOG',
skevent: dataObj.skevent, skevent: dataObj.skevent,
@@ -63,9 +56,7 @@ module.exports = {
skid: socket.skid, skid: socket.skid,
// socketPool: Object.keys(my.socketPool), // socketPool: Object.keys(my.socketPool),
clientsSize: my.wsServer.clients.size, clientsSize: my.wsServer.clients.size,
}, })
'\n,'
)
} }
} else { } else {
const listeners = my.listeners[dataObj.skevent] || [] const listeners = my.listeners[dataObj.skevent] || []
@@ -76,27 +67,29 @@ module.exports = {
}) })
socket.on('close', () => { socket.on('close', () => {
console.log({ _at: new Date().toJSON(), _from: 'basesocket:onClose', _type: 'CLOG', usid: socket?.usid, commid: socket?.commid, skid: socket?.skid }, '\n,') // don't know why, but this output happens too often without usid. globalThis.wo?.cclog?.({ _from: 'basesocket:onClose', _type: 'CLOG', usid: socket?.usid, commid: socket?.commid, skid: socket?.skid }) // don't know why, but this output happens too often without usid.
//delete my.socketPool[socket?.usid] // 20240917 恍然大悟同一个用户可以多次登录多个socket会互相覆盖。如果仅仅根据 usid 来删除其他尚在连接的socket也会被删了。 //delete my.socketPool[socket?.usid] // 20240917 恍然大悟同一个用户可以多次登录多个socket会互相覆盖。如果仅仅根据 usid 来删除其他尚在连接的socket也会被删了。
// delete my.socketPool[socket?.skid] // delete my.socketPool[socket?.skid]
}) })
}) })
my.wsServer.on('close', () => { }) my.wsServer.on('close', () => {})
// 一个全局的 heartbeat不必给每个 socket 一个 heartbeat // 一个全局的 heartbeat不必给每个 socket 一个 heartbeat
if (heartbeat) { if (heartbeat) {
console.log('WebSocket_heartbeat: starting...') globalThis.wo?.cclog?.({ _msg: 'WebSocket_heartbeat: starting...' })
setInterval(() => { setInterval(() => {
globalThis.wo?.cclog?.({
_msg: 'WebSocket_heartbeat: clientsSize = ' + my.wsServer.clients.size,
})
my.wsServer.clients.forEach((socket) => { my.wsServer.clients.forEach((socket) => {
console.log('WebSocket_heartbeat: ', { usid: socket.usid, commid: socket.commid, skid: socket.skid, appkey: socket.appkey, readyState: socket.readyState }) globalThis.wo?.cclog?.({ appkey: socket.appkey, usid: socket.usid, commid: socket.commid, skid: socket.skid, readyState: socket.readyState })
if (socket.readyState !== ws.OPEN) { if (socket.readyState !== ws.OPEN) {
//socket.isAlive = false //socket.isAlive = false
} else { } else {
//socket.ping() //socket.ping()
} }
}) })
console.log('WebSocket_heartbeat: clientsSize =', my.wsServer.clients.size)
}, heartbeatInterval || my.heartbeatInterval) }, heartbeatInterval || my.heartbeatInterval)
} }
@@ -123,47 +116,42 @@ module.exports = {
}, },
sendToAll (dataObj) { sendToAll (dataObj) {
console.log('sendToAll: dataObj =', dataObj) globalThis.wo?.cclog?.({ _from: 'Socket:sendToAll:dataObj', dataObj })
my.wsServer.clients.forEach((socket) => { my.wsServer.clients.forEach((socket) => {
try { try {
console.log('sendToOne: socket', { usid: socket.usid, skid: socket.skid }) globalThis.wo?.cclog?.({ _from: 'Socket:sendToAll:socket', usid: socket.usid, skid: socket.skid })
if (socket.readyState === ws.OPEN) { if (socket.readyState === ws.OPEN) {
socket.send(typeof dataObj !== 'string' ? JSON.stringify(dataObj) : dataObj) socket.send(typeof dataObj !== 'string' ? JSON.stringify(dataObj) : dataObj)
} else { } else {
console.warn({ _at: new Date().toJSON(), _from: 'Socket:sendToOne', _type: 'CWARN', msg: 'sendToOne: socket not open', dataObj }, '\n,') globalThis.wo?.ccwarn?.({ _from: 'Socket:sendToAll:socket', _type: 'CWARN', _msg: 'sendToOne: socket not open', dataObj })
} }
} catch (expt) { } catch (expt) {
console.error( globalThis.wo?.ccerror?.({
{
_at: new Date().toJSON(),
_from: 'Socket:sendToAll', _from: 'Socket:sendToAll',
_type: 'CERROR', _type: 'CERROR',
msg: 'sendToAll: Failed sending to unconnected socket', msg: 'sendToAll: Failed sending to unconnected socket',
dataObj, dataObj,
usid: socket.usid, usid: socket.usid,
skid: socket.skid, skid: socket.skid,
}, })
'\n,'
)
// delete my.socketPool[socket.skid] // delete my.socketPool[socket.skid]
} }
}) })
}, },
sendToOne (dataObj = {}) { sendToOne (dataObj = {}) {
console.log('sendToOne: dataObj =', dataObj) globalThis.wo?.cclog?.({ _from: 'Socket:sendToOne:dataObj', dataObj })
my.wsServer.clients.forEach((socket) => { my.wsServer.clients.forEach((socket) => {
console.log('sendToOne: socket', { usid: socket.usid, skid: socket.skid, appkey: socket.appkey })
if ((dataObj.appkey && dataObj.appkey === socket.appkey) || !dataObj.appkey) { if ((dataObj.appkey && dataObj.appkey === socket.appkey) || !dataObj.appkey) {
if ((dataObj.clid && socket.skid === dataObj.clid) || (!dataObj.clid && dataObj.usid && socket.usid === dataObj.usid)) { if ((dataObj.clid && socket.skid === dataObj.clid) || (!dataObj.clid && dataObj.usid && socket.usid === dataObj.usid)) {
try { try {
if (socket.readyState === ws.OPEN) { if (socket.readyState === ws.OPEN) {
socket.send(typeof dataObj !== 'string' ? JSON.stringify(dataObj) : dataObj) socket.send(typeof dataObj !== 'string' ? JSON.stringify(dataObj) : dataObj)
} else { } else {
console.warn({ _at: new Date().toJSON(), _from: 'Socket:sendToOne', _type: 'CWARN', msg: 'sendToOne: socket not open', dataObj }, '\n,') globalThis.wo?.ccwarn?.({ _from: 'Socket:sendToOne', _type: 'CWARN', msg: 'sendToOne: socket not open', dataObj })
} }
} catch (expt) { } catch (expt) {
console.error({ _at: new Date().toJSON(), _from: 'Socket:sendToOne', _type: 'CERROR', msg: 'sendToOne: Failed sending to socket', dataObj }, '\n,') globalThis.wo?.ccerror?.({ _from: 'Socket:sendToOne', _type: 'CERROR', msg: 'sendToOne: Failed sending to socket', dataObj })
// delete my.socketPool[socket.skid] // delete my.socketPool[socket.skid]
} }
} }

View File

@@ -4,7 +4,7 @@
"main": "basesocket.js", "main": "basesocket.js",
"private": true, "private": true,
"dependencies": { "dependencies": {
"wo-base-webtoken": "git+https://git.faronear.org/npm/wo-base-webtoken", "wo-base-webtoken": "git+https://git.tic.cc/open/wo-base-webtoken",
"ws": "^7.3.0" "ws": "^7.3.0"
}, },
"devDependencies": {}, "devDependencies": {},

View File

@@ -22,6 +22,12 @@
*.nosf/ *.nosf/
*.nosf.*/ *.nosf.*/
## everything 'git pull or fetch' will update `.git/FETCH_HEAD`, even if the content doesn't change. To avoid too many useless updates of this file in Seafile history:
FETCH_HEAD
*/FETCH_HEAD
.Trash/
.DS_Store .DS_Store
*/.DS_Store */.DS_Store
@@ -48,12 +54,18 @@ _desktop.ini
node_modules/ node_modules/
*/node_modules/ */node_modules/
package-lock.json package-lock.json
*/package-lock.json
pages4loader.json5 pages4loader.json5
*/pages4loader.json5
.deploy_git/ .deploy_git/
*/.deploy_git/ */.deploy_git/
# next.js 项目
.next/
*/.next/
# HBuilder 目录 # HBuilder 目录
unpackage/ unpackage/
*/unpackage/ */unpackage/