websocket.js 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. /**
  2. * 骑手端WebSocket管理工具
  3. * 统一管理WebSocket连接、消息处理和状态维护
  4. *
  5. * @author kxmall
  6. * @date 2025-01-08
  7. */
  8. class RiderWebSocketManager {
  9. constructor() {
  10. this.websocket = null;
  11. this.heartbeatTimer = null;
  12. this.reconnectTimer = null;
  13. this.isManualClose = false; // 是否手动关闭
  14. this.reconnectAttempts = 0; // 重连尝试次数
  15. this.maxReconnectAttempts = 5; // 最大重连次数
  16. this.reconnectInterval = 5000; // 重连间隔
  17. this.heartbeatInterval = 30000; // 心跳间隔
  18. // 消息处理回调
  19. this.onMessageCallbacks = new Map();
  20. this.onStatusChangeCallback = null;
  21. // 绑定方法上下文
  22. this.connect = this.connect.bind(this);
  23. this.disconnect = this.disconnect.bind(this);
  24. this.send = this.send.bind(this);
  25. this.handleMessage = this.handleMessage.bind(this);
  26. }
  27. /**
  28. * 连接WebSocket
  29. * @param {Object} userInfo 用户信息
  30. * @param {String} baseUrl 基础URL
  31. */
  32. connect(userInfo, baseUrl) {
  33. if (!userInfo || !userInfo.id) {
  34. console.error('用户信息不存在,无法连接WebSocket');
  35. return;
  36. }
  37. if (this.websocket) {
  38. console.warn('WebSocket已存在,先断开再重连');
  39. this.disconnect();
  40. }
  41. // 构建WebSocket连接地址
  42. const socketUrl = `ws://${baseUrl.replace('http://', '').replace('https://', '')}/websocket/rider/${userInfo.id}`;
  43. console.log('连接WebSocket:', socketUrl);
  44. try {
  45. this.websocket = uni.connectSocket({
  46. url: socketUrl,
  47. success: () => {
  48. console.log('WebSocket连接请求发送成功');
  49. },
  50. fail: (err) => {
  51. console.error('WebSocket连接请求失败:', err);
  52. this._scheduleReconnect(userInfo, baseUrl);
  53. }
  54. });
  55. this._setupEventHandlers(userInfo, baseUrl);
  56. } catch (error) {
  57. console.error('创建WebSocket连接失败:', error);
  58. this._scheduleReconnect(userInfo, baseUrl);
  59. }
  60. }
  61. /**
  62. * 设置事件处理器
  63. * @private
  64. */
  65. _setupEventHandlers(userInfo, baseUrl) {
  66. if (!this.websocket) return;
  67. // 监听连接打开
  68. this.websocket.onOpen(() => {
  69. console.log('WebSocket连接已打开');
  70. this.reconnectAttempts = 0; // 重置重连次数
  71. this._startHeartbeat();
  72. this._notifyStatusChange('connected');
  73. });
  74. // 监听消息
  75. this.websocket.onMessage((res) => {
  76. console.log('收到WebSocket消息:', res.data);
  77. this.handleMessage(res.data);
  78. });
  79. // 监听错误
  80. this.websocket.onError((err) => {
  81. console.error('WebSocket发生错误:', err);
  82. this._notifyStatusChange('error', err);
  83. });
  84. // 监听关闭
  85. this.websocket.onClose((res) => {
  86. console.log('WebSocket连接关闭:', res);
  87. this._stopHeartbeat();
  88. this._notifyStatusChange('disconnected');
  89. // 如果不是手动关闭且用户仍然有效,则尝试重连
  90. if (!this.isManualClose && userInfo && userInfo.state) {
  91. this._scheduleReconnect(userInfo, baseUrl);
  92. }
  93. });
  94. }
  95. /**
  96. * 断开WebSocket连接
  97. */
  98. disconnect() {
  99. this.isManualClose = true;
  100. this._stopHeartbeat();
  101. this._stopReconnect();
  102. if (this.websocket) {
  103. this.websocket.close();
  104. this.websocket = null;
  105. }
  106. console.log('WebSocket手动断开');
  107. this._notifyStatusChange('disconnected');
  108. }
  109. /**
  110. * 发送消息
  111. * @param {String} message 消息内容
  112. */
  113. send(message) {
  114. if (!this.websocket) {
  115. console.warn('WebSocket未连接,无法发送消息');
  116. return false;
  117. }
  118. this.websocket.send({
  119. data: message,
  120. success: () => {
  121. console.log('WebSocket消息发送成功:', message);
  122. },
  123. fail: (err) => {
  124. console.error('WebSocket消息发送失败:', err);
  125. }
  126. });
  127. return true;
  128. }
  129. /**
  130. * 处理接收到的消息
  131. * @param {String} data 消息数据
  132. */
  133. handleMessage(data) {
  134. try {
  135. // 处理心跳响应
  136. if (data === '连接成功' || data === 'pong') {
  137. return;
  138. }
  139. // 解析JSON消息
  140. const message = typeof data === 'string' ? JSON.parse(data) : data;
  141. // 调用对应的消息处理回调
  142. const callback = this.onMessageCallbacks.get(message.type);
  143. if (callback && typeof callback === 'function') {
  144. callback(message);
  145. } else {
  146. console.warn('未找到消息类型处理器:', message.type);
  147. }
  148. } catch (error) {
  149. console.error('处理WebSocket消息失败:', error);
  150. }
  151. }
  152. /**
  153. * 注册消息处理回调
  154. * @param {String} messageType 消息类型
  155. * @param {Function} callback 回调函数
  156. */
  157. onMessage(messageType, callback) {
  158. this.onMessageCallbacks.set(messageType, callback);
  159. }
  160. /**
  161. * 注册状态变化回调
  162. * @param {Function} callback 回调函数
  163. */
  164. onStatusChange(callback) {
  165. this.onStatusChangeCallback = callback;
  166. }
  167. /**
  168. * 移除消息处理回调
  169. * @param {String} messageType 消息类型
  170. */
  171. offMessage(messageType) {
  172. this.onMessageCallbacks.delete(messageType);
  173. }
  174. /**
  175. * 清除所有回调
  176. */
  177. clearCallbacks() {
  178. this.onMessageCallbacks.clear();
  179. this.onStatusChangeCallback = null;
  180. }
  181. /**
  182. * 获取连接状态
  183. */
  184. isConnected() {
  185. return this.websocket !== null;
  186. }
  187. /**
  188. * 开始心跳
  189. * @private
  190. */
  191. _startHeartbeat() {
  192. this._stopHeartbeat();
  193. this.heartbeatTimer = setInterval(() => {
  194. this.send('ping');
  195. }, this.heartbeatInterval);
  196. }
  197. /**
  198. * 停止心跳
  199. * @private
  200. */
  201. _stopHeartbeat() {
  202. if (this.heartbeatTimer) {
  203. clearInterval(this.heartbeatTimer);
  204. this.heartbeatTimer = null;
  205. }
  206. }
  207. /**
  208. * 计划重连
  209. * @private
  210. */
  211. _scheduleReconnect(userInfo, baseUrl) {
  212. if (this.isManualClose || this.reconnectAttempts >= this.maxReconnectAttempts) {
  213. console.log('不再尝试重连');
  214. return;
  215. }
  216. this._stopReconnect();
  217. this.reconnectAttempts++;
  218. const delay = this.reconnectInterval * this.reconnectAttempts;
  219. console.log(`${delay/1000}秒后尝试第${this.reconnectAttempts}次重连`);
  220. this.reconnectTimer = setTimeout(() => {
  221. console.log(`开始第${this.reconnectAttempts}次重连`);
  222. this.connect(userInfo, baseUrl);
  223. }, delay);
  224. }
  225. /**
  226. * 停止重连
  227. * @private
  228. */
  229. _stopReconnect() {
  230. if (this.reconnectTimer) {
  231. clearTimeout(this.reconnectTimer);
  232. this.reconnectTimer = null;
  233. }
  234. }
  235. /**
  236. * 通知状态变化
  237. * @private
  238. */
  239. _notifyStatusChange(status, data = null) {
  240. if (this.onStatusChangeCallback && typeof this.onStatusChangeCallback === 'function') {
  241. this.onStatusChangeCallback(status, data);
  242. }
  243. }
  244. /**
  245. * 重置连接状态(用于手动重连)
  246. */
  247. reset() {
  248. this.isManualClose = false;
  249. this.reconnectAttempts = 0;
  250. }
  251. /**
  252. * 销毁实例
  253. */
  254. destroy() {
  255. this.disconnect();
  256. this.clearCallbacks();
  257. this._stopReconnect();
  258. }
  259. }
  260. // 消息类型常量
  261. export const MESSAGE_TYPES = {
  262. NEW_ORDER: 'NEW_ORDER',
  263. ORDER_CANCEL: 'ORDER_CANCEL',
  264. ORDER_STATUS_UPDATE: 'ORDER_STATUS_UPDATE',
  265. SYSTEM_MESSAGE: 'SYSTEM_MESSAGE'
  266. };
  267. // 连接状态常量
  268. export const CONNECTION_STATUS = {
  269. CONNECTING: 'connecting',
  270. CONNECTED: 'connected',
  271. DISCONNECTED: 'disconnected',
  272. ERROR: 'error'
  273. };
  274. // 导出单例实例
  275. const riderWebSocketManager = new RiderWebSocketManager();
  276. export default riderWebSocketManager;