9433cfb9创建于 2025年12月31日历史提交
import { VITE_APP_HOST,VITE_APP_SOCKET_PORT} from '@/config/setting.uts'
 

// 1. 定义事件类型
type SocketEvent = 'open' | 'message' | 'close' | 'error' | 'reconnect_failed';

// 2. 定义通用的事件监听器接口
interface EventListener {
  (...args: any[]): void;
}

// 3. 定义事件发射器
class EventBus {
  private listeners: Map<SocketEvent, EventListener[]> = new Map();

  on(event: SocketEvent, listener: EventListener): void {
    if (!this.listeners.has(event)) {
      this.listeners.set(event, []);
    }
    this.listeners.get(event)!.push(listener);
  }

  off(event: SocketEvent, listener: EventListener): void {
    if (this.listeners.has(event)) {
      const listenerList = this.listeners.get(event)!;
      const index = listenerList.indexOf(listener);
      if (index !== -1) {
        listenerList.splice(index, 1);
      }
    }
  }

  emit(event: SocketEvent, ...args: any[]): void {
    if (this.listeners.has(event)) {
      const listenerList = [...this.listeners.get(event)!];
      listenerList.forEach(listener => listener(...args));
    }
  }
}

// 4. 定义 Socket 服务类
class SocketService {
  private static instance: SocketService;
  private socketTask: SocketTask | null = null;
  private baseUrl: string = 'wss://'+VITE_APP_HOST+':'+ '/ws'; // 替换为你的服务器地址
  private isConnected: boolean = false;
  private reconnectTimer: number | null = null;
  private heartbeatTimer: number | null = null;
  private readonly heartbeatInterval: number = 30000; // 30秒
  private reconnectCount: number = 0;
  private readonly maxReconnectCount: number = 5;
  private messageQueue: any[] = [];
  private emitter: EventBus = new EventBus();

  public static getInstance(): SocketService {
    if (!SocketService.instance) {
      SocketService.instance = new SocketService();
    }
    return SocketService.instance;
  }

  private constructor() {}

  // 连接
  public connect(): void {
    if (this.socketTask || this.isConnected) {
      console.log('Socket 已连接或正在连接中...');
      return;
    }

    this.socketTask = uni.connectSocket({
      url: this.baseUrl,
      success: () => console.log('Socket 连接请求已发送'),
      fail: (err) => {
        console.error('Socket 连接请求失败', err);
        this.isConnected = false;
        this.handleReconnect();
      }
    });

    // --- 最终正确的事件监听方式 ---

    // onOpen: 回调函数无参数
    this.socketTask.onOpen(() => {
      console.log('Socket 连接成功');
      this.isConnected = true;
      this.reconnectCount = 0;
      this.startHeartbeat();
      this.flushMessageQueue();
      this.emitter.emit('open');
    });

    // onMessage: 回调函数直接接收消息数据对象
    this.socketTask.onMessage((result: OnSocketMessageCallbackResult) => {
      console.log('收到消息:', result.data);
      let data = result.data;
      if (typeof data === 'string') {
        try {
          data = JSON.parse(data);
        } catch (e) {
          console.error('消息JSON解析失败', e);
        }
      }
      this.emitter.emit('message', data);
    });

    // onClose: 回调函数直接接收关闭数据对象
    this.socketTask.onClose((result: OnSocketCloseCallbackResult) => {
      console.log('Socket 连接关闭', result);
      this.isConnected = false;
      this.stopHeartbeat();
      this.socketTask = null;
      this.emitter.emit('close');

      if (result.code !== 1000) { // 非正常关闭
        this.handleReconnect();
      }
    });

    // onError: 回调函数直接接收错误数据对象
    this.socketTask.onError((result: OnSocketErrorCallbackResult) => {
      console.error('Socket 连接错误', result);
      this.isConnected = false;
      this.emitter.emit('error', result);
      // 错误通常会导致 close 事件,重连逻辑放在 close 中处理更健壮
    });
  }

  // 发送消息
  public send(data: any): void {
    if (this.isConnected && this.socketTask) {
      const sendData = typeof data === 'object' ? JSON.stringify(data) : data;
      this.socketTask.send({
        data: sendData,
        fail: (err) => console.error('消息发送失败', err)
      });
    } else {
      console.log('Socket 未连接,消息已加入队列');
      this.messageQueue.push(data);
    }
  }

  // 关闭连接
  public close(): void {
    if (this.socketTask) {
      console.log('正在关闭 Socket 连接...');
      this.socketTask.close({
        code: 1000,
        reason: 'Manual closure'
      });
    }
  }

  // --- 高级功能 ---

  private startHeartbeat(): void {
    this.stopHeartbeat();
    this.heartbeatTimer = setInterval(() => {
      this.send({ type: 10 });
    }, this.heartbeatInterval);
  }

  private stopHeartbeat(): void {
    if (this.heartbeatTimer) {
      clearInterval(this.heartbeatTimer);
      this.heartbeatTimer = null;
    }
  }

  private handleReconnect(): void {
    if (this.reconnectCount >= this.maxReconnectCount) {
      console.log(`已达到最大重连次数 (${this.maxReconnectCount}),停止重连`);
      this.emitter.emit('reconnect_failed');
      return;
    }
    if (this.reconnectTimer) return;

    const delay = Math.pow(2, this.reconnectCount) * 1000;
    console.log(`将在 ${delay / 1000} 秒后进行第 ${this.reconnectCount + 1} 次重连...`);

    this.reconnectTimer = setTimeout(() => {
      this.reconnectCount++;
      this.connect();
      this.reconnectTimer = null;
    }, delay);
  }

  private flushMessageQueue(): void {
    while (this.messageQueue.length > 0) {
      const msg = this.messageQueue.shift();
      if (msg) this.send(msg);
    }
  }

  // --- 事件监听接口 ---
  public on(event: SocketEvent, listener: EventListener): void {
    this.emitter.on(event, listener);
  }

  public off(event: SocketEvent, listener: EventListener): void {
    this.emitter.off(event, listener);
  }
}

// 导出单例实例
export default SocketService.getInstance();