Compare commits
11 Commits
ebbf67fba9
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48e4559fa7 | ||
|
|
a25b448db4 | ||
|
|
4df2c12997 | ||
|
|
fa2251861b | ||
|
|
61e441b596 | ||
|
|
b92876fb09 | ||
|
|
b05c626d40 | ||
|
|
3f7ce6b195 | ||
|
|
207cafa645 | ||
|
|
1793ad8e8a | ||
|
|
43269c82e6 |
30
.gitignore
vendored
30
.gitignore
vendored
@@ -5,14 +5,25 @@
|
||||
# https://github.com/SlideWave/gitignore-include?tab=readme-ov-file#examples
|
||||
# https://gitignore.io
|
||||
|
||||
### .gitignore_global ###
|
||||
### .gitignore.global.txt ###
|
||||
|
||||
# Self defined extension to ignore all files/folders containing .gitignore
|
||||
*.gitignore.*
|
||||
*.gitignore.*/
|
||||
*.gitignore
|
||||
*.gitignore/
|
||||
# Self defined pattern to ignore
|
||||
?*.gitignore
|
||||
?*.gitignore/
|
||||
?*.gitignore.*
|
||||
?*.gitignore.*/
|
||||
*.gitomit
|
||||
*.gitomit.*
|
||||
*.gitomit/
|
||||
*.gitomit.*/
|
||||
*.nogit
|
||||
*.nogit.*
|
||||
*.nogit/
|
||||
*.nogit.*/
|
||||
# 保留
|
||||
!.gitignore
|
||||
!.gitignore.*
|
||||
!.gitkeep
|
||||
|
||||
# 通用
|
||||
.svn/
|
||||
@@ -23,7 +34,9 @@
|
||||
/test/unit/coverage/
|
||||
/test/e2e/reports/
|
||||
node_modules/
|
||||
*.aab
|
||||
*.apk
|
||||
*.ipa
|
||||
*.min.js
|
||||
*.min.css
|
||||
*.min.html
|
||||
@@ -96,8 +109,5 @@ _desktop.ini
|
||||
package-lock.json
|
||||
pages4loader.json5
|
||||
|
||||
# 保留
|
||||
!.gitkeep
|
||||
|
||||
### .gitignore_local ###
|
||||
### .gitignore.local.txt ###
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://git.faronear.org/npm/wo-user-websocket-uniapp.git"
|
||||
"url": "https://git.tic.cc/open/wo-user-websocket-uniapp.git"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
|
||||
@@ -6,13 +6,27 @@
|
||||
# 文件在服务器端的后续更改会被同步到客户端,如果客户端也同时修改了这些文件,系统会生成冲突文件。
|
||||
# seafile-ignore.txt 只能忽略还没有被同步的文件。对于已经被同步的文件,如果后来把它添加到 seafile-ignore.txt 中,系统只会忽略后续更改,已经上传的版本不会受影响。
|
||||
|
||||
### seafile-ignore_global ###
|
||||
### seafile-ignore.global.txt ###
|
||||
|
||||
# 自定义的后缀名,凡有 sfignore 后缀的都不进行同步
|
||||
*.sfignore
|
||||
*.sfignore.*
|
||||
*.sfignore/
|
||||
*.sfignore.*
|
||||
*.sfignore.*/
|
||||
*.sfomit
|
||||
*.sfomit.*
|
||||
*.sfomit/
|
||||
*.sfomit.*/
|
||||
*.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
|
||||
@@ -40,12 +54,18 @@ _desktop.ini
|
||||
node_modules/
|
||||
*/node_modules/
|
||||
package-lock.json
|
||||
*/package-lock.json
|
||||
|
||||
pages4loader.json5
|
||||
*/pages4loader.json5
|
||||
|
||||
.deploy_git/
|
||||
*/.deploy_git/
|
||||
|
||||
# next.js 项目
|
||||
.next/
|
||||
*/.next/
|
||||
|
||||
# HBuilder 目录
|
||||
unpackage/
|
||||
*/unpackage/
|
||||
@@ -53,5 +73,12 @@ unpackage/
|
||||
Icon
|
||||
OneDrive/Icon
|
||||
|
||||
### seafile-ignore_local ###
|
||||
# wrangler project
|
||||
|
||||
.dev.vars*
|
||||
*/.dev.vars*
|
||||
.wrangler/
|
||||
*/.wrangler/
|
||||
|
||||
### seafile-ignore.local.txt ###
|
||||
|
||||
|
||||
67
unisocket.js
67
unisocket.js
@@ -1,49 +1,83 @@
|
||||
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 {
|
||||
initSocket (url, reconnect = false) {
|
||||
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')) {
|
||||
console.log(`WebSocket is connecting to ${url}...`)
|
||||
globalThis.wo?.cclog?.({ about: `WebSocket_initSocket connecting to ${url}...` })
|
||||
my.socket = uni.connectSocket({
|
||||
url: url.replace(/^http/, 'ws'),
|
||||
complete: () => {},
|
||||
})
|
||||
my.socket.onOpen((res) => {
|
||||
console.log('WebSocket 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
|
||||
|
||||
if (reconnect && uni.getStorageSync('_passtoken')) {
|
||||
console.log('Reporting owner for reconnecting socket')
|
||||
// 前端断线重连时,并不会自动提供 _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) => {
|
||||
console.log('Websocket onClose: ', res)
|
||||
globalThis.wo?.cclog?.({ about: 'Websocket_onClose: ', res })
|
||||
stateManager.socketAlive = false
|
||||
if (!my.reconnecting)
|
||||
my.reconnecting = setInterval(() => {
|
||||
console.log(new Date().toJSON(), 'WebSocket reconnecting...')
|
||||
this.initSocket(url, true)
|
||||
}, 5000) // 每5秒尝试重连
|
||||
globalThis.wo?.cclog?.({ about: 'Websocket_reconnecting...' })
|
||||
this.initSocket({ url, relogin: true, stateManager })
|
||||
}, reconnectInterval || my.reconnectInterval) // 定时尝试重连
|
||||
})
|
||||
my.socket.onError((err) => {
|
||||
console.log('Websocket 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)
|
||||
console.log('WebSocket onMessage for skevent: ', skevent)
|
||||
globalThis.wo?.cclog?.({ about: 'Websocket_onMessage', skevent, apiWhat })
|
||||
let listeners = my.listeners[skevent] || []
|
||||
for (let listener of listeners) {
|
||||
listener(apiWhat)
|
||||
}
|
||||
} catch (exception) {
|
||||
console.log(new Date().toJSON(), 'unknown message', data, exception)
|
||||
globalThis.wo?.cclog?.({ about: 'Websocket_onMessage unknown data format', data, exception })
|
||||
return
|
||||
}
|
||||
})
|
||||
@@ -76,11 +110,18 @@ export default {
|
||||
}
|
||||
return 0
|
||||
},
|
||||
sendObject (dataObj) {
|
||||
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)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user