HcSocket.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. import website from '~src/config/index'
  2. import { getObjValue, isNullES } from 'js-fast-way'
  3. // 长链接推送插件
  4. class HcSocket {
  5. constructor(data, change) {
  6. this.limit = website.socketLimit
  7. this.interval = website.socketInterval
  8. this.param = getObjValue(data)
  9. this.onChange = change
  10. this.socket = null
  11. this.isReconnecting = false
  12. this.connectionStatus = 'disconnected'
  13. this.isManualClosed = false
  14. if (this.validateParams()) {
  15. this.create()
  16. //this.handleMultipleTabs()
  17. }
  18. }
  19. validateParams() {
  20. const { projectId, contractId, userId } = this.param
  21. const { socket: socketUrl, clientId } = website
  22. return !(isNullES(socketUrl) || isNullES(clientId) || isNullES(projectId) || isNullES(contractId) || isNullES(userId))
  23. }
  24. //创建连接
  25. create() {
  26. const { projectId, contractId, userId } = this.param
  27. const { socket: socketUrl, clientId } = website
  28. const url = `${socketUrl}/${clientId}/${projectId}/${contractId}/${userId}`
  29. this.socket = new WebSocket(url)
  30. this.socket.onopen = this.handleOpen.bind(this)
  31. this.socket.onclose = this.handleClose.bind(this)
  32. this.socket.onmessage = this.handleMessage.bind(this)
  33. this.socket.onerror = this.handleError.bind(this)
  34. }
  35. handleOpen() {
  36. console.log('WebSocket 链接成功')
  37. this.connectionStatus = 'connected'
  38. this.isManualClosed = false
  39. }
  40. handleClose() {
  41. console.log('WebSocket 链接已断开')
  42. this.connectionStatus = 'disconnected'
  43. if (!this.isManualClosed) {
  44. this.reconnect()
  45. }
  46. }
  47. handleMessage({ data }) {
  48. try {
  49. const parsedData = JSON.parse(data)
  50. if (typeof this.onChange === 'function') {
  51. this.onChange(parsedData)
  52. }
  53. } catch (error) {
  54. console.error('解析 WebSocket 数据时出错:', error)
  55. }
  56. }
  57. handleError(error) {
  58. console.error('WebSocket 错误:', error)
  59. this.connectionStatus = 'error'
  60. }
  61. //发送消息
  62. send(data) {
  63. if (this.isSocket()) {
  64. this.socket.send(data)
  65. } else {
  66. console.warn('消息发送失败')
  67. }
  68. }
  69. //链接是否存在
  70. isSocket() {
  71. return !isNullES(this.socket) && (this.socket.readyState === WebSocket.OPEN)
  72. }
  73. //尝试重连
  74. async reconnect(attempts = 0) {
  75. if (this.isReconnecting || this.isManualClosed) return
  76. this.isReconnecting = true
  77. while (attempts < this.limit && !this.isSocket() && !this.isManualClosed) {
  78. console.log(`重新链接中... (${attempts + 1}/${this.limit})`)
  79. this.create()
  80. await new Promise(resolve => setTimeout(resolve, this.getReconnectInterval(attempts)))
  81. attempts++
  82. }
  83. this.isReconnecting = false
  84. if (!this.isSocket() && !this.isManualClosed) {
  85. console.error('达到最大重连次数后仍然失败')
  86. }
  87. }
  88. // 指数退避策略
  89. getReconnectInterval(attempt) {
  90. return Math.min(1000 * Math.pow(2, attempt), this.interval)
  91. }
  92. handleMultipleTabs() {
  93. document.addEventListener('visibilitychange', this.handleVisibilityChange.bind(this))
  94. }
  95. // 处理多标签页问题
  96. handleVisibilityChange() {
  97. if (document.visibilityState === 'visible' && !this.isSocket() && !this.isManualClosed) {
  98. this.create()
  99. } else if (document.visibilityState === 'hidden') {
  100. this.close()
  101. }
  102. }
  103. //关闭或断开连接
  104. close() {
  105. this.isManualClosed = true
  106. if (this.isSocket()) {
  107. this.socket.close()
  108. }
  109. this.connectionStatus = 'disconnected'
  110. }
  111. destroy() {
  112. this.close()
  113. //document.removeEventListener('visibilitychange', this.handleVisibilityChange)
  114. this.socket = null
  115. this.onChange = null
  116. }
  117. }
  118. export { HcSocket }