ai-websocket.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. /**
  2. * AI问答WebSocket工具函数
  3. */
  4. // AI WebSocket配置
  5. const AI_WS_CONFIG = {
  6. baseURL: 'ws://116.62.47.88:5003',
  7. timeout: 30000, // 30秒超时
  8. reconnectInterval: 3000, // 重连间隔
  9. maxReconnectAttempts: 3 // 最大重连次数
  10. };
  11. class AIWebSocket {
  12. constructor() {
  13. this.ws = null;
  14. this.url = '';
  15. this.connected = false;
  16. this.connecting = false;
  17. this.reconnectCount = 0;
  18. this.lockReconnect = false;
  19. this.messageCallback = null;
  20. this.errorCallback = null;
  21. this.closeCallback = null;
  22. this.reconnectTimer = null;
  23. this.heartbeatTimer = null;
  24. // 最近一次连接的参数,用于必要时重连
  25. this.lastQuestion = '';
  26. this.lastOnMessage = null;
  27. this.lastOnError = null;
  28. // 是否允许自动重连(默认不重连,避免重复消息)
  29. this.shouldReconnect = false;
  30. }
  31. /**
  32. * 连接WebSocket
  33. * @param {string} question - 用户问题
  34. * @param {Function} onMessage - 消息回调函数
  35. * @param {Function} onError - 错误回调函数
  36. */
  37. connect(question, onMessage, onError, onClose) {
  38. if (this.connecting || this.connected) {
  39. console.log('WebSocket已连接或正在连接中');
  40. return;
  41. }
  42. // 记录本次连接参数
  43. this.messageCallback = onMessage;
  44. this.errorCallback = onError;
  45. this.lastQuestion = question;
  46. this.lastOnMessage = onMessage;
  47. this.lastOnError = onError;
  48. this.closeCallback = onClose;
  49. // 默认不自动重连,除非调用方显式开启
  50. this.shouldReconnect = false;
  51. this.url = `${AI_WS_CONFIG.baseURL}/ws`;
  52. try {
  53. this.connecting = true;
  54. // 创建WebSocket连接
  55. this.ws = uni.connectSocket({
  56. url: this.url,
  57. success: (data) => {
  58. console.log('AI WebSocket连接创建成功');
  59. },
  60. fail: (error) => {
  61. console.error('AI WebSocket连接创建失败:', error);
  62. this.handleError('连接创建失败');
  63. }
  64. });
  65. // 监听连接打开
  66. this.ws.onOpen((res) => {
  67. console.log('AI WebSocket连接已打开');
  68. this.connecting = false;
  69. this.connected = true;
  70. this.reconnectCount = 0;
  71. // 发送问题
  72. this.sendQuestion(question);
  73. // 开始心跳检测
  74. this.startHeartbeat();
  75. });
  76. // 监听消息
  77. this.ws.onMessage((res) => {
  78. console.log('AI WebSocket收到消息:', res.data);
  79. try {
  80. const data = JSON.parse(res.data);
  81. if (this.messageCallback) {
  82. this.messageCallback(data);
  83. }
  84. } catch (error) {
  85. console.error('解析WebSocket消息失败:', error);
  86. }
  87. });
  88. // 监听错误
  89. this.ws.onError((res) => {
  90. console.error('AI WebSocket连接错误:', res);
  91. this.handleError('连接错误');
  92. });
  93. // 监听连接关闭
  94. this.ws.onClose((res) => {
  95. console.log('AI WebSocket连接已关闭');
  96. this.connected = false;
  97. this.connecting = false;
  98. this.ws = null;
  99. // 停止心跳
  100. this.stopHeartbeat();
  101. // 通知外部关闭事件
  102. if (this.closeCallback) {
  103. try { this.closeCallback(res); } catch (e) { console.error('关闭回调执行失败', e); }
  104. }
  105. // 仅在允许时才尝试重连
  106. if (this.shouldReconnect) {
  107. this.reconnect();
  108. }
  109. });
  110. } catch (error) {
  111. console.error('创建AI WebSocket失败:', error);
  112. this.handleError('创建连接失败');
  113. }
  114. }
  115. /**
  116. * 发送问题
  117. * @param {string} question - 用户问题
  118. */
  119. sendQuestion(question) {
  120. if (!this.connected || !this.ws) {
  121. console.error('WebSocket未连接,无法发送问题');
  122. return;
  123. }
  124. const message = {
  125. question: question
  126. };
  127. this.ws.send({
  128. data: JSON.stringify(message),
  129. success: () => {
  130. console.log('问题发送成功');
  131. },
  132. fail: (error) => {
  133. console.error('问题发送失败:', error);
  134. this.handleError('发送问题失败');
  135. }
  136. });
  137. }
  138. /**
  139. * 开始心跳检测
  140. */
  141. startHeartbeat() {
  142. this.heartbeatTimer = setInterval(() => {
  143. if (this.connected && this.ws) {
  144. this.ws.send({
  145. data: JSON.stringify({ type: 'ping' }),
  146. fail: (error) => {
  147. console.error('心跳发送失败:', error);
  148. this.reconnect();
  149. }
  150. });
  151. }
  152. }, 10000); // 每10秒发送一次心跳
  153. }
  154. /**
  155. * 停止心跳检测
  156. */
  157. stopHeartbeat() {
  158. if (this.heartbeatTimer) {
  159. clearInterval(this.heartbeatTimer);
  160. this.heartbeatTimer = null;
  161. }
  162. }
  163. /**
  164. * 重连
  165. */
  166. reconnect() {
  167. if (this.lockReconnect || this.reconnectCount >= AI_WS_CONFIG.maxReconnectAttempts) {
  168. console.log('达到最大重连次数或重连被锁定');
  169. return;
  170. }
  171. this.lockReconnect = true;
  172. this.reconnectCount++;
  173. console.log(`尝试重连 (${this.reconnectCount}/${AI_WS_CONFIG.maxReconnectAttempts})`);
  174. this.reconnectTimer = setTimeout(() => {
  175. this.lockReconnect = false;
  176. if (!this.connected) {
  177. // 使用最近一次的参数重连
  178. this.connect(this.lastQuestion, this.lastOnMessage, this.lastOnError);
  179. }
  180. }, AI_WS_CONFIG.reconnectInterval);
  181. }
  182. /**
  183. * 处理错误
  184. * @param {string} error - 错误信息
  185. */
  186. handleError(error) {
  187. console.error('AI WebSocket错误:', error);
  188. if (this.errorCallback) {
  189. this.errorCallback(error);
  190. }
  191. }
  192. /**
  193. * 关闭连接
  194. */
  195. close() {
  196. console.log('关闭AI WebSocket连接');
  197. // 停止重连
  198. if (this.reconnectTimer) {
  199. clearTimeout(this.reconnectTimer);
  200. this.reconnectTimer = null;
  201. }
  202. // 主动关闭时不再重连
  203. this.shouldReconnect = false;
  204. // 停止心跳
  205. this.stopHeartbeat();
  206. // 关闭WebSocket
  207. if (this.ws && this.connected) {
  208. this.ws.close();
  209. }
  210. // 重置状态
  211. this.connected = false;
  212. this.connecting = false;
  213. this.ws = null;
  214. this.lockReconnect = false;
  215. this.reconnectCount = 0;
  216. this.messageCallback = null;
  217. this.errorCallback = null;
  218. }
  219. /**
  220. * 启用或禁用自动重连
  221. * @param {boolean} enable 是否启用
  222. */
  223. setAutoReconnect(enable) {
  224. this.shouldReconnect = !!enable;
  225. }
  226. /**
  227. * 检查连接状态
  228. * @returns {boolean} 是否已连接
  229. */
  230. isConnected() {
  231. return this.connected;
  232. }
  233. }
  234. // 创建单例实例
  235. const aiWebSocket = new AIWebSocket();
  236. export default aiWebSocket;