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();