wo-user-websocket-uniapp/unisocket.js

106 lines
3.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
}
export default {
isAlive () {
return my.socket && (my.socket.readyState === my.socket.OPEN)
},
initSocket ({ url, relogin = false, stateManager = {} } = {}) {
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 })
stateManager.socketAlive = true
clearInterval(my.reconnecting)
delete my.reconnecting
// 前端断线重连时,并不会自动提供 _passtoken应当把_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
}
}, my.heartbeatInterval) // 定期发送心跳,避免被关闭
})
my.socket.onClose((res) => {
console.log({ _at: new Date().toJSON(), about: 'Websocket onClose: ', res })
stateManager.socketAlive = false
if (!my.reconnecting)
my.reconnecting = setInterval(() => {
console.log({ _at: new Date().toJSON(), about: 'Websocket reconnecting...' })
this.initSocket({ url, relogin: true, stateManager })
}, my.reconnectInterval) // 定时尝试重连
})
my.socket.onError((err) => {
console.log({ _at: new Date().toJSON(), about: 'Websocket onError: ', err })
stateManager.socketAlive = false
})
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,
})
}
},
}