You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
175 lines
4.7 KiB
175 lines
4.7 KiB
|
3 weeks ago
|
import tui from './httpRequest'
|
||
|
|
|
||
|
|
const socket = {
|
||
|
|
connected: false,
|
||
|
|
task: null,
|
||
|
|
heartbeatTimer: null,
|
||
|
|
subscriptions: {},
|
||
|
|
connecting: false,
|
||
|
|
messageHandlers: [],
|
||
|
|
ackHandlers: [],
|
||
|
|
presenceHandlers: [],
|
||
|
|
roomEndHandlers: [],
|
||
|
|
offlineHandlers: []
|
||
|
|
}
|
||
|
|
|
||
|
|
function wsUrl() {
|
||
|
|
return tui.interfaceUrl().replace(/^http/, 'ws') + '/ws/websocket'
|
||
|
|
}
|
||
|
|
|
||
|
|
function frame(command, headers = {}, body = '') {
|
||
|
|
const lines = [command]
|
||
|
|
Object.keys(headers).forEach(key => {
|
||
|
|
lines.push(`${key}:${headers[key]}`)
|
||
|
|
})
|
||
|
|
lines.push('')
|
||
|
|
lines.push(body)
|
||
|
|
return lines.join('\n') + '\u0000'
|
||
|
|
}
|
||
|
|
|
||
|
|
function parseFrame(raw) {
|
||
|
|
const text = raw.replace(/\u0000/g, '')
|
||
|
|
const splitIndex = text.indexOf('\n\n')
|
||
|
|
const head = splitIndex >= 0 ? text.slice(0, splitIndex) : text
|
||
|
|
const body = splitIndex >= 0 ? text.slice(splitIndex + 2) : ''
|
||
|
|
const lines = head.split('\n')
|
||
|
|
const command = lines.shift()
|
||
|
|
const headers = {}
|
||
|
|
lines.forEach(line => {
|
||
|
|
const index = line.indexOf(':')
|
||
|
|
if (index > -1) headers[line.slice(0, index)] = line.slice(index + 1)
|
||
|
|
})
|
||
|
|
return { command, headers, body }
|
||
|
|
}
|
||
|
|
|
||
|
|
function emit(list, payload) {
|
||
|
|
list.forEach(handler => {
|
||
|
|
try { handler(payload) } catch (e) { console.warn('ie socket handler error', e) }
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
function send(destination, body = {}) {
|
||
|
|
if (!socket.connected || !socket.task) return false
|
||
|
|
socket.task.send({
|
||
|
|
data: frame('SEND', {
|
||
|
|
destination,
|
||
|
|
'content-type': 'application/json'
|
||
|
|
}, JSON.stringify(body))
|
||
|
|
})
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
|
||
|
|
function subscribe(destination, id) {
|
||
|
|
socket.task.send({
|
||
|
|
data: frame('SUBSCRIBE', { id, destination, ack: 'auto' })
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
function subscribeRoom(roomId) {
|
||
|
|
if (!socket.connected || !socket.task || !roomId) return false
|
||
|
|
const id = 'ie-room-' + roomId
|
||
|
|
if (socket.subscriptions[id]) return true
|
||
|
|
socket.subscriptions[id] = true
|
||
|
|
subscribe('/topic/ie/room/' + roomId, id)
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
|
||
|
|
function bindSubscriptions() {
|
||
|
|
subscribe('/user/queue/ie/ack', 'ie-ack')
|
||
|
|
subscribe('/user/queue/ie/message', 'ie-message')
|
||
|
|
subscribe('/user/queue/ie/presence', 'ie-presence')
|
||
|
|
subscribe('/user/queue/ie/room-end', 'ie-room-end')
|
||
|
|
subscribe('/user/queue/ie/offline', 'ie-offline')
|
||
|
|
send('/app/ie/connect')
|
||
|
|
}
|
||
|
|
|
||
|
|
function handleMessage(raw) {
|
||
|
|
if (raw === 'h') return
|
||
|
|
const data = parseFrame(raw)
|
||
|
|
if (data.command === 'CONNECTED') {
|
||
|
|
socket.connected = true
|
||
|
|
bindSubscriptions()
|
||
|
|
startHeartbeat()
|
||
|
|
return
|
||
|
|
}
|
||
|
|
if (data.command !== 'MESSAGE') return
|
||
|
|
let payload = data.body
|
||
|
|
try { payload = JSON.parse(data.body) } catch (e) {}
|
||
|
|
const dest = data.headers.destination || ''
|
||
|
|
if (dest.indexOf('/queue/ie/ack') > -1) emit(socket.ackHandlers, payload)
|
||
|
|
if (dest.indexOf('/queue/ie/message') > -1 || dest.indexOf('/topic/ie/room/') > -1) emit(socket.messageHandlers, payload)
|
||
|
|
if (dest.indexOf('/queue/ie/presence') > -1) emit(socket.presenceHandlers, payload)
|
||
|
|
if (dest.indexOf('/queue/ie/room-end') > -1) emit(socket.roomEndHandlers, payload)
|
||
|
|
if (dest.indexOf('/queue/ie/offline') > -1) emit(socket.offlineHandlers, payload)
|
||
|
|
}
|
||
|
|
|
||
|
|
function startHeartbeat() {
|
||
|
|
clearInterval(socket.heartbeatTimer)
|
||
|
|
socket.heartbeatTimer = setInterval(() => {
|
||
|
|
send('/app/ie/heartbeat')
|
||
|
|
}, 25000)
|
||
|
|
}
|
||
|
|
|
||
|
|
function connect() {
|
||
|
|
if (socket.connected || socket.connecting) return Promise.resolve()
|
||
|
|
socket.connecting = true
|
||
|
|
return new Promise((resolve, reject) => {
|
||
|
|
socket.task = uni.connectSocket({
|
||
|
|
url: wsUrl(),
|
||
|
|
header: { accessToken: tui.getToken() },
|
||
|
|
success: resolve,
|
||
|
|
fail: reject
|
||
|
|
})
|
||
|
|
socket.task.onOpen(() => {
|
||
|
|
socket.connecting = false
|
||
|
|
socket.task.send({
|
||
|
|
data: frame('CONNECT', {
|
||
|
|
'accept-version': '1.2',
|
||
|
|
'heart-beat': '10000,10000',
|
||
|
|
accessToken: tui.getToken()
|
||
|
|
})
|
||
|
|
})
|
||
|
|
})
|
||
|
|
socket.task.onMessage(res => handleMessage(res.data || ''))
|
||
|
|
socket.task.onClose(() => {
|
||
|
|
socket.connected = false
|
||
|
|
socket.connecting = false
|
||
|
|
clearInterval(socket.heartbeatTimer)
|
||
|
|
})
|
||
|
|
socket.task.onError(() => {
|
||
|
|
socket.connected = false
|
||
|
|
socket.connecting = false
|
||
|
|
clearInterval(socket.heartbeatTimer)
|
||
|
|
})
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
function close() {
|
||
|
|
clearInterval(socket.heartbeatTimer)
|
||
|
|
if (socket.task) socket.task.close()
|
||
|
|
socket.connected = false
|
||
|
|
socket.task = null
|
||
|
|
}
|
||
|
|
|
||
|
|
function resetHandlers() {
|
||
|
|
socket.messageHandlers = []
|
||
|
|
socket.ackHandlers = []
|
||
|
|
socket.presenceHandlers = []
|
||
|
|
socket.roomEndHandlers = []
|
||
|
|
socket.offlineHandlers = []
|
||
|
|
}
|
||
|
|
|
||
|
|
export default {
|
||
|
|
connect,
|
||
|
|
close,
|
||
|
|
resetHandlers,
|
||
|
|
subscribeRoom,
|
||
|
|
sendMessage(data) { return send('/app/ie/message', data) },
|
||
|
|
sendPresence(data) { return send('/app/ie/presence', data) },
|
||
|
|
onAck(handler) { socket.ackHandlers.push(handler) },
|
||
|
|
onMessage(handler) { socket.messageHandlers.push(handler) },
|
||
|
|
onPresence(handler) { socket.presenceHandlers.push(handler) },
|
||
|
|
onRoomEnd(handler) { socket.roomEndHandlers.push(handler) },
|
||
|
|
onOffline(handler) { socket.offlineHandlers.push(handler) }
|
||
|
|
}
|