liveWS.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. import CryptoJS from 'crypto-js'
  2. export class LiveWS {
  3. /**
  4. * @param {string} url - WebSocket 服务器地址
  5. * @param {number} liveId - 直播间ID
  6. * @param {number} userId - 用户ID
  7. * @param {string|null} tenantCode - 企业编号(可选)
  8. * @param {number} checkInterval - 检查连接状态的时间间隔,单位毫秒
  9. * @param {number} reconnectDelay - 连接断开后重连的延迟,单位毫秒
  10. */
  11. constructor(url, liveId, userId, tenantCode = null, checkInterval = 5000, reconnectDelay = 3000) {
  12. let timestamp = new Date().getTime()
  13. let userType = 1
  14. let signature = CryptoJS.HmacSHA256(
  15. CryptoJS.enc.Utf8.parse('' + liveId + userId + userType + timestamp),
  16. CryptoJS.enc.Utf8.parse(timestamp)).toString(CryptoJS.enc.Hex)
  17. let query = `?liveId=${liveId}&userId=${userId}&userType=${userType}&timestamp=${timestamp}&signature=${signature}`
  18. if (tenantCode) {
  19. query += `&tenantCode=${encodeURIComponent(tenantCode)}`
  20. }
  21. this.url = url + query;
  22. this.liveId = liveId;
  23. this.userId = userId;
  24. this.tenantCode = tenantCode;
  25. this.checkInterval = checkInterval;
  26. this.reconnectDelay = reconnectDelay;
  27. this.ws = null;
  28. this.reconnectTimer = null;
  29. this.heartbeatTimer = null;
  30. this.isManualClose = false;
  31. this.connect();
  32. this.startHeartbeat();
  33. }
  34. connect() {
  35. // 如果已经有一个连接处于 OPEN 或 CONNECTING 状态,则不再创建新连接
  36. if (this.ws && (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING)) {
  37. return;
  38. }
  39. this.ws = new WebSocket(this.url);
  40. // 绑定事件
  41. this.ws.onopen = (event) => {
  42. // 连接成功后,清除重连计时器
  43. if (this.reconnectTimer) {
  44. clearTimeout(this.reconnectTimer);
  45. this.reconnectTimer = null;
  46. }
  47. };
  48. this.ws.onmessage = (event) => {
  49. this.onmessage(event);
  50. };
  51. this.ws.onerror = (error) => {
  52. };
  53. this.ws.onclose = (event) => {
  54. // 如果不是主动关闭,则重连
  55. if (!this.isManualClose) {
  56. setTimeout(() => this.reconnect(), this.reconnectDelay);
  57. }
  58. };
  59. }
  60. onmessage(event) {}
  61. reconnect() {
  62. this.connect();
  63. }
  64. // 调度重连
  65. scheduleReconnect() {
  66. // 避免多次重连定时器同时存在
  67. if (this.reconnectTimer) return;
  68. this.reconnectTimer = setTimeout(() => {
  69. this.connect();
  70. }, this.reconnectDelay);
  71. }
  72. // 定时检查连接状态
  73. startHeartbeat() {
  74. this.heartbeatTimer = setInterval(() => {
  75. if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
  76. this.scheduleReconnect();
  77. } else {
  78. // 发送信息
  79. const heartbeat = { 'cmd': 'heartbeat', 'msg': 'ping', 'liveId': this.liveId, 'userId': this.userId };
  80. if (this.tenantCode) heartbeat.tenantCode = this.tenantCode;
  81. this.ws.send(JSON.stringify(heartbeat));
  82. }
  83. }, this.checkInterval);
  84. }
  85. // 主动关闭 WebSocket 连接,并清除定时任务
  86. close() {
  87. this.isManualClose = true;
  88. if (this.heartbeatTimer) {
  89. clearInterval(this.heartbeatTimer);
  90. }
  91. if (this.reconnectTimer) {
  92. clearTimeout(this.reconnectTimer);
  93. }
  94. if (this.ws) {
  95. this.ws.close();
  96. }
  97. }
  98. // 发送消息方法
  99. send(message) {
  100. if (this.ws && this.ws.readyState === WebSocket.OPEN) {
  101. this.ws.send(message);
  102. } else {
  103. console.error("WebSocket is not open. Message not sent.");
  104. }
  105. }
  106. }