| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- import appSettings from '@/core/config/app-settings'
- const OPEN = 1
- const PING_INTERVAL = 30000
- const CONNECT_TIMEOUT = 8000
- export class SocketSession {
- constructor(handlers = {}) {
- this.handlers = handlers
- this.socket = null
- this.connecting = false
- this.connected = false
- this.allowReconnect = true
- this.paused = false
- this.reconnectAttempt = 0
- this.reconnecting = false
- this.heartbeatId = null
- this.connectTimer = null
- }
- open() {
- if (this.paused || !this.allowReconnect) return
- if (this.connecting) return
- if (this.connected && this.socket?.readyState === OPEN) return
- this.teardownSocket(false)
- this.connecting = true
- this.connected = false
- this.connectTimer = setTimeout(() => {
- if (!this.connected) this.handlers.onError?.()
- }, CONNECT_TIMEOUT)
- try {
- this.socket = uni.connectSocket({
- url: appSettings.socketurl,
- fail: () => {
- this.connecting = false
- this.clearConnectTimer()
- this.handlers.onError?.()
- }
- })
- this.socket.onOpen(() => {
- this.clearConnectTimer()
- this.connecting = false
- this.connected = true
- this.reconnectAttempt = 0
- this.startHeartbeat()
- this.handlers.onOpen?.()
- })
- this.socket.onMessage((msg) => {
- this.handlers.onMessage?.(msg)
- })
- this.socket.onClose((evt) => {
- this.onDisconnected(evt)
- })
- this.socket.onError(() => {
- this.clearConnectTimer()
- this.connecting = false
- this.connected = false
- this.handlers.onError?.()
- })
- } catch (err) {
- this.connecting = false
- this.clearConnectTimer()
- this.handlers.onError?.(err)
- }
- }
- send(data) {
- if (!this.socket || this.socket.readyState !== OPEN) return false
- try {
- const payload = typeof data === 'string' ? data : JSON.stringify(data)
- this.socket.send({ data: payload })
- return true
- } catch (_) {
- return false
- }
- }
- pause(temporary = true) {
- if (!temporary) {
- this.paused = true
- this.allowReconnect = false
- }
- this.stopHeartbeat()
- this.clearConnectTimer()
- if (this.socket) {
- try { this.socket.close() } catch (_) {}
- if (!temporary) this.socket = null
- }
- this.connecting = false
- this.connected = false
- }
- resume() {
- if (this.paused && !this.allowReconnect) {
- this.paused = false
- this.allowReconnect = true
- }
- this.open()
- }
- scheduleReconnect() {
- if (!this.allowReconnect || this.paused || this.reconnecting) return
- if (this.reconnectAttempt >= 10) {
- this.reconnectAttempt = 0
- return
- }
- this.reconnecting = true
- const delay = Math.min(1000 * Math.pow(1.5, this.reconnectAttempt), 5000)
- setTimeout(() => {
- this.reconnecting = false
- if (!this.allowReconnect || this.paused) return
- this.reconnectAttempt += 1
- this.open()
- }, delay)
- }
- startHeartbeat() {
- this.stopHeartbeat()
- this.heartbeatId = setInterval(() => {
- if (!this.socket || this.socket.readyState !== OPEN) return
- try {
- this.socket.send({
- data: '{"type":"ping"}',
- fail: () => this.handlers.onError?.()
- })
- } catch (_) {
- this.handlers.onError?.()
- }
- }, PING_INTERVAL)
- }
- stopHeartbeat() {
- if (this.heartbeatId) {
- clearInterval(this.heartbeatId)
- this.heartbeatId = null
- }
- }
- clearConnectTimer() {
- if (this.connectTimer) {
- clearTimeout(this.connectTimer)
- this.connectTimer = null
- }
- }
- onDisconnected(evt) {
- this.connecting = false
- this.connected = false
- this.stopHeartbeat()
- this.clearConnectTimer()
- this.handlers.onClose?.(evt)
- if (evt?.code === 1000 && this.paused) {
- this.socket = null
- return
- }
- this.scheduleReconnect()
- }
- teardownSocket(clearRef) {
- this.stopHeartbeat()
- this.clearConnectTimer()
- if (this.socket) {
- try { this.socket.close() } catch (_) {}
- if (clearRef) this.socket = null
- }
- }
- }
|