|
|
@ -6,6 +6,10 @@ const socket = { |
|
|
heartbeatTimer: null, |
|
|
heartbeatTimer: null, |
|
|
subscriptions: {}, |
|
|
subscriptions: {}, |
|
|
connecting: false, |
|
|
connecting: false, |
|
|
|
|
|
manualClosed: false, |
|
|
|
|
|
reconnectTimer: null, |
|
|
|
|
|
reconnectAttempts: 0, |
|
|
|
|
|
roomIds: [], |
|
|
messageHandlers: [], |
|
|
messageHandlers: [], |
|
|
ackHandlers: [], |
|
|
ackHandlers: [], |
|
|
presenceHandlers: [], |
|
|
presenceHandlers: [], |
|
|
@ -66,7 +70,9 @@ function subscribe(destination, id) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function subscribeRoom(roomId) { |
|
|
function subscribeRoom(roomId) { |
|
|
if (!socket.connected || !socket.task || !roomId) return false |
|
|
if (!roomId) return false |
|
|
|
|
|
if (socket.roomIds.indexOf(roomId) < 0) socket.roomIds.push(roomId) |
|
|
|
|
|
if (!socket.connected || !socket.task) return false |
|
|
const id = 'ie-room-' + roomId |
|
|
const id = 'ie-room-' + roomId |
|
|
if (socket.subscriptions[id]) return true |
|
|
if (socket.subscriptions[id]) return true |
|
|
socket.subscriptions[id] = true |
|
|
socket.subscriptions[id] = true |
|
|
@ -74,6 +80,12 @@ function subscribeRoom(roomId) { |
|
|
return true |
|
|
return true |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function unsubscribeRoom(roomId) { |
|
|
|
|
|
const index = socket.roomIds.indexOf(roomId) |
|
|
|
|
|
if (index > -1) socket.roomIds.splice(index, 1) |
|
|
|
|
|
delete socket.subscriptions['ie-room-' + roomId] |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
function bindSubscriptions() { |
|
|
function bindSubscriptions() { |
|
|
subscribe('/user/queue/ie/ack', 'ie-ack') |
|
|
subscribe('/user/queue/ie/ack', 'ie-ack') |
|
|
subscribe('/user/queue/ie/message', 'ie-message') |
|
|
subscribe('/user/queue/ie/message', 'ie-message') |
|
|
@ -81,6 +93,25 @@ function bindSubscriptions() { |
|
|
subscribe('/user/queue/ie/room-end', 'ie-room-end') |
|
|
subscribe('/user/queue/ie/room-end', 'ie-room-end') |
|
|
subscribe('/user/queue/ie/offline', 'ie-offline') |
|
|
subscribe('/user/queue/ie/offline', 'ie-offline') |
|
|
send('/app/ie/connect') |
|
|
send('/app/ie/connect') |
|
|
|
|
|
// 重连后恢复房间订阅
|
|
|
|
|
|
socket.roomIds.forEach(roomId => { |
|
|
|
|
|
const id = 'ie-room-' + roomId |
|
|
|
|
|
if (!socket.subscriptions[id]) { |
|
|
|
|
|
socket.subscriptions[id] = true |
|
|
|
|
|
subscribe('/topic/ie/room/' + roomId, id) |
|
|
|
|
|
} |
|
|
|
|
|
}) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function scheduleReconnect() { |
|
|
|
|
|
if (socket.manualClosed || socket.reconnectTimer) return |
|
|
|
|
|
// 指数退避:2s/4s/8s/16s/30s 封顶
|
|
|
|
|
|
const delay = Math.min(2000 * Math.pow(2, socket.reconnectAttempts), 30000) |
|
|
|
|
|
socket.reconnectAttempts += 1 |
|
|
|
|
|
socket.reconnectTimer = setTimeout(() => { |
|
|
|
|
|
socket.reconnectTimer = null |
|
|
|
|
|
connect().catch(() => scheduleReconnect()) |
|
|
|
|
|
}, delay) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function handleMessage(raw) { |
|
|
function handleMessage(raw) { |
|
|
@ -88,6 +119,8 @@ function handleMessage(raw) { |
|
|
const data = parseFrame(raw) |
|
|
const data = parseFrame(raw) |
|
|
if (data.command === 'CONNECTED') { |
|
|
if (data.command === 'CONNECTED') { |
|
|
socket.connected = true |
|
|
socket.connected = true |
|
|
|
|
|
socket.reconnectAttempts = 0 |
|
|
|
|
|
socket.subscriptions = {} |
|
|
bindSubscriptions() |
|
|
bindSubscriptions() |
|
|
startHeartbeat() |
|
|
startHeartbeat() |
|
|
return |
|
|
return |
|
|
@ -113,6 +146,7 @@ function startHeartbeat() { |
|
|
function connect() { |
|
|
function connect() { |
|
|
if (socket.connected || socket.connecting) return Promise.resolve() |
|
|
if (socket.connected || socket.connecting) return Promise.resolve() |
|
|
socket.connecting = true |
|
|
socket.connecting = true |
|
|
|
|
|
socket.manualClosed = false |
|
|
return new Promise((resolve, reject) => { |
|
|
return new Promise((resolve, reject) => { |
|
|
socket.task = uni.connectSocket({ |
|
|
socket.task = uni.connectSocket({ |
|
|
url: wsUrl(), |
|
|
url: wsUrl(), |
|
|
@ -134,17 +168,27 @@ function connect() { |
|
|
socket.task.onClose(() => { |
|
|
socket.task.onClose(() => { |
|
|
socket.connected = false |
|
|
socket.connected = false |
|
|
socket.connecting = false |
|
|
socket.connecting = false |
|
|
|
|
|
socket.subscriptions = {} |
|
|
clearInterval(socket.heartbeatTimer) |
|
|
clearInterval(socket.heartbeatTimer) |
|
|
|
|
|
scheduleReconnect() |
|
|
}) |
|
|
}) |
|
|
socket.task.onError(() => { |
|
|
socket.task.onError(() => { |
|
|
socket.connected = false |
|
|
socket.connected = false |
|
|
socket.connecting = false |
|
|
socket.connecting = false |
|
|
|
|
|
socket.subscriptions = {} |
|
|
clearInterval(socket.heartbeatTimer) |
|
|
clearInterval(socket.heartbeatTimer) |
|
|
|
|
|
scheduleReconnect() |
|
|
}) |
|
|
}) |
|
|
}) |
|
|
}) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function close() { |
|
|
function close() { |
|
|
|
|
|
socket.manualClosed = true |
|
|
|
|
|
clearTimeout(socket.reconnectTimer) |
|
|
|
|
|
socket.reconnectTimer = null |
|
|
|
|
|
socket.reconnectAttempts = 0 |
|
|
|
|
|
socket.roomIds = [] |
|
|
|
|
|
socket.subscriptions = {} |
|
|
clearInterval(socket.heartbeatTimer) |
|
|
clearInterval(socket.heartbeatTimer) |
|
|
if (socket.task) socket.task.close() |
|
|
if (socket.task) socket.task.close() |
|
|
socket.connected = false |
|
|
socket.connected = false |
|
|
@ -164,6 +208,7 @@ export default { |
|
|
close, |
|
|
close, |
|
|
resetHandlers, |
|
|
resetHandlers, |
|
|
subscribeRoom, |
|
|
subscribeRoom, |
|
|
|
|
|
unsubscribeRoom, |
|
|
sendMessage(data) { return send('/app/ie/message', data) }, |
|
|
sendMessage(data) { return send('/app/ie/message', data) }, |
|
|
sendPresence(data) { return send('/app/ie/presence', data) }, |
|
|
sendPresence(data) { return send('/app/ie/presence', data) }, |
|
|
onAck(handler) { socket.ackHandlers.push(handler) }, |
|
|
onAck(handler) { socket.ackHandlers.push(handler) }, |
|
|
|