98 lines
3.6 KiB
JavaScript
98 lines
3.6 KiB
JavaScript
const my = {
|
||
socket: undefined,
|
||
reconnecting: undefined,
|
||
heartbeating: undefined,
|
||
listeners: {},
|
||
}
|
||
|
||
export default {
|
||
initSocket (url, relogin = false) {
|
||
if (!my.socket || (my.socket.readyState !== my.socket.OPEN && typeof url === 'string')) {
|
||
console.log({ _at: new Date().toJSON(), about: `WebSocket is connecting to ${url}...` })
|
||
my.socket = uni.connectSocket({
|
||
url: url.replace(/^http/, 'ws'),
|
||
complete: () => { },
|
||
})
|
||
my.socket.onOpen((res) => {
|
||
console.log({ _at: new Date().toJSON(), about: 'WebSocket onOpen: ', res })
|
||
clearInterval(my.reconnecting)
|
||
delete my.reconnecting
|
||
|
||
// 前端断线重连时,并不会自动提供 _passtoken。在前端的initSocket时,应当把_passtoken送过来,而后台则对_passtoken做验证后再加socketPool。
|
||
if (relogin && uni.getStorageSync('_passtoken')) {
|
||
console.log({ _at: new Date().toJSON(), about: 'Reporting owner for reconnecting socket' })
|
||
my.socket.send({ data: JSON.stringify({ skevent: 'SOCKET_OWNER_RECONNECT', _passtoken: uni.getStorageSync('_passtoken') }) })
|
||
}
|
||
|
||
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
|
||
}
|
||
}, 20000) // 定期发送心跳,避免被关闭
|
||
})
|
||
my.socket.onClose((res) => {
|
||
console.log({ _at: new Date().toJSON(), about: 'Websocket onClose: ', res })
|
||
if (!my.reconnecting)
|
||
my.reconnecting = setInterval(() => {
|
||
console.log({ _at: new Date().toJSON(), about: 'Websocket reconnecting...' })
|
||
this.initSocket(url, true)
|
||
}, 5000) // 每5秒尝试重连
|
||
})
|
||
my.socket.onError((err) => {
|
||
console.log({ _at: new Date().toJSON(), about: 'Websocket onError: ', err })
|
||
})
|
||
my.socket.onMessage(({ data }) => {
|
||
// 在这里统一分发消息(用户端通常不需要返回结果给服务器,因此不用 rpc 模式,而用 event 模式。
|
||
try {
|
||
let { skevent, ...apiWhat } = JSON.parse(data)
|
||
console.log({ _at: new Date().toJSON(), about: 'Websocket onMessage', skevent, apiWhat })
|
||
let listeners = my.listeners[skevent] || []
|
||
for (let listener of listeners) {
|
||
listener(apiWhat)
|
||
}
|
||
} catch (exception) {
|
||
console.log({ _at: new Date().toJSON(), about: 'Websocket onMessage unknown', 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) {
|
||
if (my.socket && my.socket.readyState === my.socket.OPEN) {
|
||
my.socket.send({
|
||
data: typeof dataObj !== 'string' ? JSON.stringify(dataObj) : dataObj,
|
||
})
|
||
}
|
||
},
|
||
}
|