Compare commits

..

10 Commits

3 changed files with 92 additions and 26 deletions

30
.gitignore vendored
View File

@@ -5,14 +5,25 @@
# https://github.com/SlideWave/gitignore-include?tab=readme-ov-file#examples # https://github.com/SlideWave/gitignore-include?tab=readme-ov-file#examples
# https://gitignore.io # https://gitignore.io
### .gitignore_global ### ### .gitignore.global.txt ###
# Self defined extension to ignore all files/folders containing .gitignore # Self defined pattern to ignore
*.gitignore.* ?*.gitignore
*.gitignore.*/ ?*.gitignore/
*.gitignore ?*.gitignore.*
*.gitignore/ ?*.gitignore.*/
*.gitomit
*.gitomit.*
*.gitomit/
*.gitomit.*/
*.nogit
*.nogit.*
*.nogit/
*.nogit.*/
# 保留
!.gitignore !.gitignore
!.gitignore.*
!.gitkeep
# 通用 # 通用
.svn/ .svn/
@@ -23,7 +34,9 @@
/test/unit/coverage/ /test/unit/coverage/
/test/e2e/reports/ /test/e2e/reports/
node_modules/ node_modules/
*.aab
*.apk *.apk
*.ipa
*.min.js *.min.js
*.min.css *.min.css
*.min.html *.min.html
@@ -96,8 +109,5 @@ _desktop.ini
package-lock.json package-lock.json
pages4loader.json5 pages4loader.json5
# 保留 ### .gitignore.local.txt ###
!.gitkeep
### .gitignore_local ###

View File

@@ -6,13 +6,21 @@
# 文件在服务器端的后续更改会被同步到客户端,如果客户端也同时修改了这些文件,系统会生成冲突文件。 # 文件在服务器端的后续更改会被同步到客户端,如果客户端也同时修改了这些文件,系统会生成冲突文件。
# seafile-ignore.txt 只能忽略还没有被同步的文件。对于已经被同步的文件,如果后来把它添加到 seafile-ignore.txt 中,系统只会忽略后续更改,已经上传的版本不会受影响。 # seafile-ignore.txt 只能忽略还没有被同步的文件。对于已经被同步的文件,如果后来把它添加到 seafile-ignore.txt 中,系统只会忽略后续更改,已经上传的版本不会受影响。
### seafile-ignore_global ### ### seafile-ignore.global.txt ###
# 自定义的后缀名,凡有 sfignore 后缀的都不进行同步 # 自定义的后缀名,凡有 sfignore 后缀的都不进行同步
*.sfignore *.sfignore
*.sfignore.*
*.sfignore/ *.sfignore/
*.sfignore.*
*.sfignore.*/ *.sfignore.*/
*.sfomit
*.sfomit.*
*.sfomit/
*.sfomit.*/
*.nosf
*.nosf.*
*.nosf/
*.nosf.*/
.DS_Store .DS_Store
*/.DS_Store */.DS_Store
@@ -53,5 +61,12 @@ unpackage/
Icon Icon
OneDrive/Icon OneDrive/Icon
### seafile-ignore_local ### # wrangler project
.dev.vars*
*/.dev.vars*
.wrangler/
*/.wrangler/
### seafile-ignore.local.txt ###

View File

@@ -1,49 +1,83 @@
const my = { const my = {
socket: undefined, socket: undefined,
reconnecting: undefined, reconnecting: undefined,
heartbeating: undefined,
listeners: {}, listeners: {},
heartbeatInterval: 20000,
reconnectInterval: 5000,
messageQueue: [],
} }
// uni.onSocket* 和 sendSocketMessage/closeSocket 方法,是全局唯一的 api不需要保存 socket 对象。
// SocketTask 的 on* 和 send/close 方法,是针对具体 socket 的,适用于多个连接(但不一定支持)或者需要对唯一连接做更精细控制。
export default { 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')) { if (!my.socket || (my.socket.readyState !== my.socket.OPEN && typeof url === 'string')) {
console.log(`WebSocket is connecting to ${url}...`) console.log({ _at: new Date().toJSON(), about: `WebSocket_initSocket connecting to ${url}...` })
my.socket = uni.connectSocket({ my.socket = uni.connectSocket({
url: url.replace(/^http/, 'ws'), url: url.replace(/^http/, 'ws'),
complete: () => {}, complete: () => {},
}) })
my.socket.onOpen((res) => { my.socket.onOpen((res) => {
console.log('WebSocket onOpen: ', res) console.log({ _at: new Date().toJSON(), about: 'WebSocket_onOpen: ', res })
stateManager.socketAlive = true
if (my.messageQueue.length) {
console.log({ _at: new Date().toJSON(), about: 'WebSocket_onOpen: sending messageQueue' })
my.messageQueue.forEach((dataObj) => {
this.sendObject(dataObj)
})
my.messageQueue = []
}
clearInterval(my.reconnecting) clearInterval(my.reconnecting)
delete my.reconnecting delete my.reconnecting
if (reconnect && uni.getStorageSync('_passtoken')) { // 前端断线重连时,并不会自动提供 _passtoken应当把_passtoken送给后台而后台则对_passtoken做验证后再加socketPool。
console.log('Reporting owner for reconnecting socket') 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.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) => { my.socket.onClose((res) => {
console.log('Websocket onClose: ', res) console.log({ _at: new Date().toJSON(), about: 'Websocket_onClose: ', res })
stateManager.socketAlive = false
if (!my.reconnecting) if (!my.reconnecting)
my.reconnecting = setInterval(() => { my.reconnecting = setInterval(() => {
console.log(new Date().toJSON(), 'WebSocket reconnecting...') console.log({ _at: new Date().toJSON(), about: 'Websocket_reconnecting...' })
this.initSocket(url, true) this.initSocket({ url, relogin: true, stateManager })
}, 5000) // 每5秒尝试重连 }, reconnectInterval || my.reconnectInterval) // 定时尝试重连
}) })
my.socket.onError((err) => { my.socket.onError((err) => {
console.log('Websocket onError: ', err) console.log({ _at: new Date().toJSON(), about: 'Websocket_onError: ', err })
stateManager.socketAlive = false
}) })
my.socket.onMessage(({ data }) => { my.socket.onMessage(({ data }) => {
// 在这里统一分发消息(用户端通常不需要返回结果给服务器,因此不用 rpc 模式,而用 event 模式。 // 在这里统一分发消息(用户端通常不需要返回结果给服务器,因此不用 rpc 模式,而用 event 模式。
try { try {
let { skevent, ...apiWhat } = JSON.parse(data) let { skevent, ...apiWhat } = JSON.parse(data)
console.log('WebSocket onMessage for skevent: ', skevent) console.log({ _at: new Date().toJSON(), about: 'Websocket_onMessage', skevent, apiWhat })
let listeners = my.listeners[skevent] || [] let listeners = my.listeners[skevent] || []
for (let listener of listeners) { for (let listener of listeners) {
listener(apiWhat) listener(apiWhat)
} }
} catch (exception) { } catch (exception) {
console.log(new Date().toJSON(), 'unknown message', data, exception) console.log({ _at: new Date().toJSON(), about: 'Websocket_onMessage unknown data format', data, exception })
return return
} }
}) })
@@ -76,11 +110,18 @@ export default {
} }
return 0 return 0
}, },
sendObject (dataObj) { sendObject (dataObj = {}) {
console.log({ _at: new Date().toJSON(), 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) { if (my.socket && my.socket.readyState === my.socket.OPEN) {
my.socket.send({ my.socket.send({
data: typeof dataObj !== 'string' ? JSON.stringify(dataObj) : dataObj, data: typeof dataObj !== 'string' ? JSON.stringify(dataObj) : dataObj,
}) })
} else {
my.messageQueue.push(dataObj)
} }
}, },
} }