chore: 初始化仓库基线(AGENTS.md、git 规范、敏感文件排除)

This commit is contained in:
weijuesen
2026-08-10 22:30:53 +08:00
commit 84abf4454c
358 changed files with 75993 additions and 0 deletions
+155
View File
@@ -0,0 +1,155 @@
import Taro from '@tarojs/taro';
import { getWsUrl } from '@/api/config';
type MessageHandler = (data: unknown) => void;
class WebSocketManager {
private connected: boolean = false;
private handlers: Map<string, Set<MessageHandler>> = new Map();
private token: string = '';
private reconnectAttempts: number = 0;
private maxReconnectAttempts: number = 5;
private reconnectTimer: ReturnType<typeof setTimeout> | null = null;
private isManualClose: boolean = false;
connect(token: string): void {
this.token = token;
this.isManualClose = false;
this.doConnect();
}
private doConnect(): void {
if (!this.token) {
console.warn('[WS] 无 token,无法连接 WebSocket');
return;
}
// 先关闭旧连接
if (this.connected) {
try {
Taro.closeSocket();
} catch {
// ignore
}
this.connected = false;
}
const url = getWsUrl(this.token);
console.log('[WS] 正在连接:', url);
// 注册全局回调(每次调用会替换上一次的回调)
Taro.onSocketOpen(() => {
console.log('[WS] 连接已建立');
this.connected = true;
this.reconnectAttempts = 0;
});
Taro.onSocketMessage((res) => {
try {
const data = JSON.parse(res.data as string);
const type = (data.type || data.event || 'default') as string;
const handlers = this.handlers.get(type);
if (handlers) {
handlers.forEach((handler) => handler(data));
}
// 广播给通配符监听器
const wildcardHandlers = this.handlers.get('*');
if (wildcardHandlers) {
wildcardHandlers.forEach((handler) => handler(data));
}
} catch (e) {
console.error('[WS] 消息解析失败:', e, res.data);
}
});
Taro.onSocketClose(() => {
console.log('[WS] 连接已关闭');
this.connected = false;
if (!this.isManualClose) {
this.scheduleReconnect();
}
});
Taro.onSocketError((err) => {
console.error('[WS] 连接错误:', err);
});
Taro.connectSocket({
url,
fail: (err) => {
console.error('[WS] 连接失败:', err);
this.scheduleReconnect();
},
});
}
private scheduleReconnect(): void {
if (this.isManualClose) return;
if (this.reconnectAttempts >= this.maxReconnectAttempts) {
console.warn('[WS] 达到最大重连次数,停止重连');
return;
}
this.reconnectAttempts++;
const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000);
console.log(`[WS] ${delay}ms 后第 ${this.reconnectAttempts} 次重连...`);
if (this.reconnectTimer) {
clearTimeout(this.reconnectTimer);
}
this.reconnectTimer = setTimeout(() => {
this.doConnect();
}, delay);
}
on(type: string, handler: MessageHandler): () => void {
if (!this.handlers.has(type)) {
this.handlers.set(type, new Set());
}
this.handlers.get(type)!.add(handler);
return () => {
this.handlers.get(type)?.delete(handler);
};
}
off(type: string, handler?: MessageHandler): void {
if (handler) {
this.handlers.get(type)?.delete(handler);
} else {
this.handlers.delete(type);
}
}
send(data: unknown): void {
if (this.connected) {
Taro.sendSocketMessage({
data: typeof data === 'string' ? data : JSON.stringify(data),
fail: (err) => {
console.error('[WS] 发送失败:', err);
},
});
} else {
console.warn('[WS] WebSocket 未连接,无法发送消息');
}
}
close(): void {
this.isManualClose = true;
if (this.reconnectTimer) {
clearTimeout(this.reconnectTimer);
this.reconnectTimer = null;
}
if (this.connected) {
Taro.closeSocket();
this.connected = false;
}
this.handlers.clear();
this.reconnectAttempts = 0;
}
isConnected(): boolean {
return this.connected;
}
}
export const wsManager = new WebSocketManager();