socket.service.ts 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import useStore from '@/pages/store'
  2. import { injectable, Service } from './service'
  3. @injectable
  4. export default class SocketService extends Service {
  5. private _socket: WebSocket | null = null
  6. private _reconnectTimeout: string | number | NodeJS.Timeout | undefined = undefined
  7. private _ping = JSON.stringify({ event: 'heartbeat', content: 'ping' })
  8. private _reconnectTime = 3000
  9. private _heartInterval: string | number | NodeJS.Timeout | undefined = undefined
  10. private _messageTime = 0
  11. private _store = useStore()
  12. /**
  13. * 连接
  14. */
  15. private _connect() {
  16. const { token } = this._store
  17. if (!token) return null
  18. const url = `${import.meta.env.VITE_SOCKET_API}/${token}`
  19. const socket = new WebSocket(url)
  20. socket.onerror = this._onError.bind(this)
  21. socket.onopen = this._onOpen.bind(this)
  22. socket.onmessage = this._onMessage.bind(this)
  23. socket.onclose = this._onClose.bind(this)
  24. this._socket = socket
  25. return socket
  26. }
  27. /**
  28. * 重连
  29. */
  30. private _reConnect() {
  31. this._onClose()
  32. this._reconnectTimeout = setTimeout(() => {
  33. this._socket = this._connect()
  34. console.log('网络连接已断开,正在尝试重新连接...')
  35. }, this._reconnectTime)
  36. }
  37. /**
  38. * 连接错误,重连
  39. */
  40. private _onError() {
  41. this._reConnect()
  42. }
  43. /**
  44. * 连接打开,心跳检测
  45. */
  46. private _onOpen() {
  47. this._socket?.send(this._ping)
  48. }
  49. /**
  50. * 心跳检测
  51. */
  52. private _heartbeat(iTime: number, pTime: number) {
  53. const t = new Date().getTime()
  54. if (this._heartInterval) clearInterval(this._heartInterval)
  55. return setTimeout(() => {
  56. if ((t - this._messageTime) > pTime) {
  57. this._reConnect()
  58. }
  59. this._socket?.send(this._ping)
  60. }, iTime)
  61. }
  62. /**
  63. * 接收消息
  64. */
  65. private _onMessage(evt: Any) {
  66. this._messageTime = new Date().getTime()
  67. const data = JSON.parse(evt.data)
  68. if (data.event === 'connect') {
  69. const iTime = data.content.ping_interval * 1000
  70. const pTime = data.content.ping_timeout * 1000
  71. this._heartInterval = this._heartbeat(iTime, pTime)
  72. } else {
  73. this._store.setSocketData(data)
  74. }
  75. }
  76. /**
  77. * 关闭连接
  78. */
  79. private _onClose() {
  80. clearTimeout(this._reconnectTimeout)
  81. clearInterval(this._heartInterval)
  82. this._socket = null
  83. }
  84. /** 链接 */
  85. public connect() {
  86. return this._connect()
  87. }
  88. /** 关闭 */
  89. public close() {
  90. if (this._socket) this._socket.close()
  91. this._store.setSocketData(null)
  92. this._onClose()
  93. }
  94. /**
  95. * 推送消息
  96. *
  97. */
  98. public emit(event: string, data: object) {
  99. const content = JSON.stringify({ event, data })
  100. if (!this._socket && this._socket!.readyState !== 1) return
  101. this._socket?.send(content)
  102. }
  103. }