Files
wo-user-websocket-uniapp/unisocket.js
2026-02-07 11:35:40 +08:00

128 lines
4.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const my = {
socket: undefined,
reconnecting: undefined,
heartbeating: undefined,
listeners: {},
heartbeatInterval: 20000,
reconnectInterval: 5000,
messageQueue: [],
}
// uni.onSocket* 和 sendSocketMessage/closeSocket 方法,是全局唯一的 api不需要保存 socket 对象。
// SocketTask 的 on* 和 send/close 方法,是针对具体 socket 的,适用于多个连接(但不一定支持)或者需要对唯一连接做更精细控制。
export default {
isAlive () {
return my.socket && my.socket.readyState === my.socket.OPEN
},
initSocket ({ url, relogin = false, stateManager = {}, heartbeat = false, heartbeatInterval, reconnectInterval } = {}) {
if (!my.socket || (my.socket.readyState !== my.socket.OPEN && typeof url === 'string')) {
globalThis.wo?.cclog?.({ about: `WebSocket_initSocket connecting to ${url}...` })
my.socket = uni.connectSocket({
url: url.replace(/^http/, 'ws'),
complete: () => {},
})
my.socket.onOpen((res) => {
globalThis.wo?.cclog?.({ about: 'WebSocket_onOpen: ', res })
stateManager.socketAlive = true
if (my.messageQueue.length) {
globalThis.wo?.cclog?.({ about: 'WebSocket_onOpen: sending messageQueue' })
my.messageQueue.forEach((dataObj) => {
this.sendObject(dataObj)
})
my.messageQueue = []
}
clearInterval(my.reconnecting)
delete my.reconnecting
// 前端断线重连时,并不会自动提供 _passtoken应当把_passtoken送给后台而后台则对_passtoken做验证后再加socketPool。
if (relogin && uni.getStorageSync('_passtoken')) {
globalThis.wo?.cclog?.({ about: 'Reporting owner for reconnecting socket' })
my.socket.send({ data: JSON.stringify({ skevent: 'SOCKET_OWNER_RECONNECT', _passtoken: uni.getStorageSync('_passtoken') }) })
}
if (heartbeat) {
my.heartbeating = setInterval(() => {
if (my.socket && my.socket.readyState === my.socket.OPEN) {
my.socket.send({ data: JSON.stringify({ skevent: 'PING' }) })
} else {
clearInterval(my.heartbeating)
delete my.heartbeating
}
}, heartbeatInterval || my.heartbeatInterval) // 定期发送心跳,避免被关闭
}
})
my.socket.onClose((res) => {
globalThis.wo?.cclog?.({ about: 'Websocket_onClose: ', res })
stateManager.socketAlive = false
if (!my.reconnecting)
my.reconnecting = setInterval(() => {
globalThis.wo?.cclog?.({ about: 'Websocket_reconnecting...' })
this.initSocket({ url, relogin: true, stateManager })
}, reconnectInterval || my.reconnectInterval) // 定时尝试重连
})
my.socket.onError((err) => {
globalThis.wo?.cclog?.({ about: 'Websocket_onError: ', err })
stateManager.socketAlive = false
})
my.socket.onMessage(({ data }) => {
// 在这里统一分发消息(用户端通常不需要返回结果给服务器,因此不用 rpc 模式,而用 event 模式。
try {
let { skevent, ...apiWhat } = JSON.parse(data)
globalThis.wo?.cclog?.({ about: 'Websocket_onMessage', skevent, apiWhat })
let listeners = my.listeners[skevent] || []
for (let listener of listeners) {
listener(apiWhat)
}
} catch (exception) {
globalThis.wo?.cclog?.({ about: 'Websocket_onMessage unknown data format', data, exception })
return
}
})
}
return this
},
closeSocket () {
if (my.socket) my.socket.close()
setTimeout(() => {
clearInterval(my.reconnecting)
delete my.reconnecting
}, 2000)
},
initListener (skevent, listener) {
// 当该 skevent 尚不具有任何 listener 时,添加本 listener
my.listeners[skevent]?.length > 0 || this.addListener(skevent, listener)
return this
},
addListener (skevent, listener) {
if (Array.isArray(my.listeners[skevent]) && typeof listener === 'function') {
my.listeners[skevent].push(listener)
} else {
my.listeners[skevent] = [listener]
}
return this
},
countListener (skevent) {
if (Array.isArray(my.listeners[skevent])) {
return my.listeners[skevent].length
}
return 0
},
sendObject (dataObj = {}) {
globalThis.wo?.cclog?.({ about: 'WebSocket_sendObject', readyState: my.socket.readyState, dataObj })
// 把 sendObject({_passtoken}) 从其他零散地方迁移到这里来
if (!dataObj._passtoken) {
dataObj._passtoken = uni.getStorageSync('_passtoken') || undefined
}
if (my.socket && my.socket.readyState === my.socket.OPEN) {
my.socket.send({
data: typeof dataObj !== 'string' ? JSON.stringify(dataObj) : dataObj,
})
} else {
my.messageQueue.push(dataObj)
}
},
}