forked from datawhale/whale-town-end
- 更新location_broadcast网关以支持原生WebSocket - 修改WebSocket认证守卫和中间件 - 更新相关的测试文件和规范 - 添加WebSocket测试工具 - 完善Zulip服务的测试覆盖 技术改进: - 统一WebSocket实现架构 - 优化性能监控和限流中间件 - 更新测试用例以适配新的WebSocket实现
118 lines
2.9 KiB
TypeScript
118 lines
2.9 KiB
TypeScript
/**
|
|
* 原生 WebSocket 客户端测试工具
|
|
*
|
|
* 用于替代 Socket.IO 客户端进行测试
|
|
*/
|
|
|
|
import WebSocket from 'ws';
|
|
|
|
export interface WebSocketTestClient {
|
|
connect(): Promise<void>;
|
|
disconnect(): void;
|
|
send(event: string, data: any): void;
|
|
on(event: string, callback: (data: any) => void): void;
|
|
off(event: string, callback?: (data: any) => void): void;
|
|
waitForEvent(event: string, timeout?: number): Promise<any>;
|
|
isConnected(): boolean;
|
|
}
|
|
|
|
export class WebSocketTestClientImpl implements WebSocketTestClient {
|
|
private ws: WebSocket | null = null;
|
|
private eventHandlers = new Map<string, Set<(data: any) => void>>();
|
|
private connected = false;
|
|
|
|
constructor(private url: string) {}
|
|
|
|
async connect(): Promise<void> {
|
|
return new Promise((resolve, reject) => {
|
|
this.ws = new WebSocket(this.url);
|
|
|
|
this.ws.on('open', () => {
|
|
this.connected = true;
|
|
resolve();
|
|
});
|
|
|
|
this.ws.on('error', (error) => {
|
|
reject(error);
|
|
});
|
|
|
|
this.ws.on('message', (data) => {
|
|
try {
|
|
const message = JSON.parse(data.toString());
|
|
const { event, data: eventData } = message;
|
|
|
|
const handlers = this.eventHandlers.get(event);
|
|
if (handlers) {
|
|
handlers.forEach(handler => handler(eventData));
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to parse WebSocket message:', error);
|
|
}
|
|
});
|
|
|
|
this.ws.on('close', () => {
|
|
this.connected = false;
|
|
});
|
|
});
|
|
}
|
|
|
|
disconnect(): void {
|
|
if (this.ws) {
|
|
this.ws.close();
|
|
this.ws = null;
|
|
this.connected = false;
|
|
}
|
|
}
|
|
|
|
send(event: string, data: any): void {
|
|
if (this.ws && this.connected) {
|
|
const message = JSON.stringify({ event, data });
|
|
this.ws.send(message);
|
|
} else {
|
|
throw new Error('WebSocket is not connected');
|
|
}
|
|
}
|
|
|
|
on(event: string, callback: (data: any) => void): void {
|
|
if (!this.eventHandlers.has(event)) {
|
|
this.eventHandlers.set(event, new Set());
|
|
}
|
|
this.eventHandlers.get(event)!.add(callback);
|
|
}
|
|
|
|
off(event: string, callback?: (data: any) => void): void {
|
|
const handlers = this.eventHandlers.get(event);
|
|
if (handlers) {
|
|
if (callback) {
|
|
handlers.delete(callback);
|
|
} else {
|
|
handlers.clear();
|
|
}
|
|
}
|
|
}
|
|
|
|
async waitForEvent(event: string, timeout: number = 5000): Promise<any> {
|
|
return new Promise((resolve, reject) => {
|
|
const timer = setTimeout(() => {
|
|
this.off(event, handler);
|
|
reject(new Error(`Timeout waiting for event: ${event}`));
|
|
}, timeout);
|
|
|
|
const handler = (data: any) => {
|
|
clearTimeout(timer);
|
|
this.off(event, handler);
|
|
resolve(data);
|
|
};
|
|
|
|
this.on(event, handler);
|
|
});
|
|
}
|
|
|
|
isConnected(): boolean {
|
|
return this.connected;
|
|
}
|
|
}
|
|
|
|
export function createWebSocketTestClient(url: string): WebSocketTestClient {
|
|
return new WebSocketTestClientImpl(url);
|
|
} |