| | |
| | | import type { AxiosRequestConfig } from 'axios'; |
| | | |
| | | import { accessSessionKey } from '../request'; |
| | | import { SESSION_KEY } from '../request'; |
| | | import { Local } from '../storage'; |
| | | import { debounce } from 'lodash-es'; |
| | | export interface SSEOptions { |
| | | /** 重试次数 */ |
| | | retries?: number; |
| | | /** 重试延迟(ms) */ |
| | | retryDelay?: number; |
| | | /** 超时时间(ms) */ |
| | | timeout?: number; |
| | | /** 请求配置 */ |
| | | // requestConfig?: AxiosRequestConfig; |
| | | /** 是否自动重连 */ |
| | | autoReconnect?: boolean; |
| | | |
| | | /** 请求头 */ |
| | | headers?: Record<string, string>; |
| | | } |
| | | |
| | | export interface SSEEventCallbacks { |
| | |
| | | /** 连接关闭回调 */ |
| | | onClose?: () => void; |
| | | /** 重试回调 */ |
| | | onRetry?: (retryCount: number) => void; |
| | | onRetry?: () => void; |
| | | } |
| | | |
| | | export class SSEClient { |
| | | private eventSource: EventSource | null = null; |
| | | private retryCount = 0; |
| | | private isConnecting = false; |
| | | private reconnectTimeout: number | null = null; |
| | | private abortController: AbortController | null = null; |
| | | |
| | | constructor(private url: string, private options: SSEOptions = {}, private callbacks: SSEEventCallbacks = {}) { |
| | | // 设置默认值 |
| | | this.options = { |
| | | retries: 3, |
| | | retryDelay: 1000, |
| | | timeout: 30000, |
| | | autoReconnect: true, |
| | | timeout: 3000, |
| | | headers: { |
| | | [SESSION_KEY]: Local.get(accessSessionKey), |
| | | }, |
| | | ...options, |
| | | }; |
| | | } |
| | |
| | | * 建立连接 |
| | | */ |
| | | async connect(params?: Record<string, any>): Promise<void> { |
| | | if (this.isConnecting) return; |
| | | this.isConnecting = true; |
| | | |
| | | try { |
| | | // 构建 URL 和参数 |
| | | const queryString = params ? `?${new URLSearchParams(params).toString()}` : ''; |
| | | const queryString = params && Object.values(params).length ? `?${new URLSearchParams(params).toString()}` : ''; |
| | | const fullUrl = `${this.url}${queryString}`; |
| | | |
| | | // 创建 AbortController 用于超时控制 |
| | | this.abortController = new AbortController(); |
| | | |
| | | // 设置超时 |
| | | const timeoutId = setTimeout(() => { |
| | | this.abortController?.abort(); |
| | | throw new Error('Connection timeout'); |
| | | }, this.options.timeout); |
| | | |
| | | // 创建 EventSource |
| | | // this.abortController = new AbortController(); |
| | | // 创建 EventSource 并添加 headers |
| | | this.eventSource = new EventSource(fullUrl); |
| | | |
| | | // 清除超时 |
| | | clearTimeout(timeoutId); |
| | | |
| | | // 绑定事件处理 |
| | | this.bindEvents(); |
| | | |
| | | this.isConnecting = false; |
| | | } catch (error) { |
| | | this.isConnecting = false; |
| | | await this.handleError(error); |
| | | console.log('catch error'); |
| | | } |
| | | } |
| | | |
| | |
| | | if (!this.eventSource) return; |
| | | |
| | | this.eventSource.onopen = () => { |
| | | console.log('连接成功'); |
| | | this.callbacks.onOpen?.(); |
| | | }; |
| | | |
| | |
| | | }; |
| | | |
| | | this.eventSource.onerror = async (error) => { |
| | | await this.handleError(error); |
| | | }; |
| | | } |
| | | |
| | |
| | | */ |
| | | private async handleError(error: any): Promise<void> { |
| | | this.callbacks.onError?.(error); |
| | | |
| | | if (this.options.autoReconnect && this.retryCount < (this.options.retries || 0)) { |
| | | // debugger; |
| | | this.retryCount++; |
| | | this.callbacks.onRetry?.(this.retryCount); |
| | | |
| | | if (this.options.autoReconnect) { |
| | | this.callbacks.onRetry?.(); |
| | | // 延迟重试 |
| | | await new Promise((resolve) => { |
| | | this.reconnectTimeout = setTimeout(resolve, this.options.retryDelay); |
| | | }); |
| | | |
| | | // 重新连接 |
| | | await this.connect(); |
| | | } else { |
| | | this.disconnect(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 断开连接 |
| | |
| | | clearTimeout(this.reconnectTimeout); |
| | | this.reconnectTimeout = null; |
| | | } |
| | | |
| | | if (this.eventSource) { |
| | | this.eventSource.close(); |
| | | this.eventSource = null; |
| | | } |
| | | |
| | | if (this.abortController) { |
| | | this.abortController.abort(); |
| | | this.abortController = null; |
| | | } |
| | | // if (this.abortController) { |
| | | // this.abortController.abort(); |
| | | // this.abortController = null; |
| | | // } |
| | | |
| | | this.isConnecting = false; |
| | | this.callbacks.onClose?.(); |
| | | this.retryCount = 0; |
| | | } |
| | | |
| | | /** |