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.

224 lines
5.6 KiB

5 months ago
  1. /*
  2. * @description: socket方法
  3. * @date: 2023-01-20
  4. * @author:
  5. */
  6. import { ElMessage } from 'element-plus'
  7. import { ref } from 'vue'
  8. export const isClose = ref(true)
  9. interface socket {
  10. appKey: any
  11. websocket: any
  12. connectURL: string
  13. socket_open: boolean
  14. hearBeat_timer: any
  15. hearBeat_interval: number
  16. is_reconnect: boolean
  17. reconnect_count: number
  18. reconnect_current: number
  19. reconnect_number: number
  20. reconnect_timer: any
  21. reconnect_interval: number
  22. receiveMessageCallBackObj: any
  23. initCallBacks: any
  24. // eslint-disable-next-line ts/no-unsafe-function-type
  25. receiveMessage: Function
  26. // eslint-disable-next-line ts/no-unsafe-function-type
  27. registerCallback: Function
  28. // eslint-disable-next-line ts/no-unsafe-function-type
  29. registerInitCallback: Function
  30. // eslint-disable-next-line ts/no-unsafe-function-type
  31. init: (receiveMessage?: Function | null, type?: string, connectURL?: string) => any
  32. heartbeat: () => void
  33. heartSend: () => void
  34. send: (data: any, callback?: any) => void
  35. close: () => void
  36. reconnect: () => void
  37. sendAppJoin: () => void
  38. }
  39. // eslint-disable-next-line ts/no-redeclare
  40. export const socket: socket = {
  41. appKey: null,
  42. websocket: null,
  43. connectURL: import.meta.env.FT_WS_URL,
  44. // 开启标识
  45. socket_open: false,
  46. // 心跳timer
  47. hearBeat_timer: null,
  48. // 心跳发送频率
  49. hearBeat_interval: 500,
  50. // 是否需要重连
  51. is_reconnect: true,
  52. // 重连次数
  53. reconnect_count: 10,
  54. // 已发起重连次数
  55. reconnect_current: 1,
  56. // 网络错误提示此时
  57. reconnect_number: 0,
  58. // 重连timer
  59. reconnect_timer: null,
  60. // 重连频率
  61. reconnect_interval: 1000,
  62. receiveMessageCallBackObj: {},
  63. initCallBacks: [],
  64. // eslint-disable-next-line ts/no-unsafe-function-type
  65. registerInitCallback: (fn: Function, ...args: any) => {
  66. // socket 连接成功后的回调
  67. socket.initCallBacks.push({
  68. fn,
  69. args,
  70. })
  71. },
  72. // 接收消息的方法
  73. receiveMessage: (e: any) => {
  74. const message = JSON.parse(e.data)
  75. const fn = socket.receiveMessageCallBackObj[message.type]
  76. if (fn) {
  77. fn(message)
  78. }
  79. else {
  80. console.error('请注册当前类型的回调函数', message)
  81. }
  82. },
  83. registerCallback: (fn: any, type: any) => {
  84. // 接收消息的回调
  85. socket.receiveMessageCallBackObj[type] = fn
  86. },
  87. init: async (
  88. receiveMessageCallBack: any,
  89. type?: string,
  90. connectURL?: string,
  91. reconnection?: boolean,
  92. ) => {
  93. if (!('WebSocket' in window)) {
  94. ElMessage.warning('浏览器不支持WebSocket')
  95. return null
  96. }
  97. // 注册回调函数
  98. if (receiveMessageCallBack && type) {
  99. socket.registerCallback(receiveMessageCallBack, type)
  100. }
  101. // 已经创建过连接无需重复创建
  102. if (socket.websocket && !reconnection) {
  103. return socket.websocket
  104. }
  105. await new Promise((rs) => {
  106. socket.websocket = new WebSocket(connectURL || socket.connectURL)
  107. // 消息接收
  108. socket.websocket.onmessage = (e: any) => {
  109. socket.receiveMessage(e)
  110. }
  111. // socket关闭
  112. socket.websocket.onclose = () => {
  113. console.error('onclose')
  114. clearInterval(socket.hearBeat_interval)
  115. socket.socket_open = false
  116. isClose.value = true
  117. // 需要重新连接
  118. if (socket.is_reconnect) {
  119. socket.reconnect_timer = setTimeout(() => {
  120. // 超过重连次数
  121. // if (socket.reconnect_current > socket.reconnect_count) {
  122. // clearTimeout(socket.reconnect_timer);
  123. // socket.is_reconnect = false;
  124. // console.error('超出重连次数,不再重连', new Date());
  125. // return;
  126. // }
  127. // 记录重连次数
  128. socket.reconnect_current++
  129. socket.reconnect()
  130. }, socket.reconnect_interval)
  131. }
  132. }
  133. // 连接发生错误
  134. socket.websocket.onerror = function () {
  135. console.error('onerror')
  136. isClose.value = true
  137. socket.socket_open = false
  138. }
  139. // 连接成功
  140. socket.websocket.onopen = function () {
  141. socket.socket_open = true
  142. socket.is_reconnect = true
  143. // 开启心跳
  144. socket.heartbeat()
  145. // 连接成功后发起app加入消息
  146. socket.sendAppJoin()
  147. for (const fnItem of socket.initCallBacks) {
  148. fnItem.fn(...fnItem.args)
  149. }
  150. isClose.value = false
  151. rs(true) // socket 已连接
  152. }
  153. })
  154. },
  155. send: (data, callback = null) => {
  156. // 开启状态直接发送
  157. if (socket.websocket.readyState === socket.websocket.OPEN) {
  158. socket.websocket.send(JSON.stringify(data))
  159. if (callback) {
  160. callback()
  161. }
  162. }
  163. else {
  164. clearInterval(socket.hearBeat_timer)
  165. socket.reconnect_number++
  166. }
  167. },
  168. heartbeat: () => {
  169. if (socket.hearBeat_timer) {
  170. clearInterval(socket.hearBeat_timer)
  171. }
  172. socket.hearBeat_timer = setInterval(() => {
  173. socket.heartSend()
  174. }, socket.hearBeat_interval)
  175. },
  176. heartSend: () => {
  177. socket.send({
  178. type: 'ping', // ping
  179. })
  180. },
  181. close: () => {
  182. clearInterval(socket.hearBeat_timer)
  183. socket.is_reconnect = false
  184. socket.websocket && socket.websocket.close()
  185. socket.websocket = null
  186. },
  187. /**
  188. *
  189. */
  190. reconnect: () => {
  191. if (socket.websocket) {
  192. // 需要重连
  193. if (socket.is_reconnect) {
  194. socket.websocket.close()
  195. socket.websocket = null
  196. socket.init()
  197. }
  198. else {
  199. socket.close()
  200. }
  201. }
  202. },
  203. sendAppJoin: () => {
  204. socket.send({
  205. appKey: socket.appKey,
  206. type: 1, // appJoin
  207. })
  208. },
  209. }