|
@@ -14,8 +14,8 @@ interface AuthenticatedWebSocket extends WebSocket {
|
|
|
class WebSocketManager {
|
|
class WebSocketManager {
|
|
|
private wss: WebSocketServer | null = null;
|
|
private wss: WebSocketServer | null = null;
|
|
|
private clients: Map<number, Set<AuthenticatedWebSocket>> = new Map();
|
|
private clients: Map<number, Set<AuthenticatedWebSocket>> = new Map();
|
|
|
- // 验证码回调监听器
|
|
|
|
|
- private captchaListeners: Map<string, (code: string) => void> = new Map();
|
|
|
|
|
|
|
+ // 修复: captchaListeners 存储 callback 和 timer,以便超时自动删除
|
|
|
|
|
+ private captchaListeners: Map<string, { callback: (code: string) => void; timer: NodeJS.Timeout }> = new Map();
|
|
|
// 心跳检测定时器
|
|
// 心跳检测定时器
|
|
|
private heartbeatTimer: NodeJS.Timeout | null = null;
|
|
private heartbeatTimer: NodeJS.Timeout | null = null;
|
|
|
|
|
|
|
@@ -100,7 +100,11 @@ class WebSocketManager {
|
|
|
const listener = this.captchaListeners.get(captchaTaskId);
|
|
const listener = this.captchaListeners.get(captchaTaskId);
|
|
|
if (listener) {
|
|
if (listener) {
|
|
|
logger.info(`[WS] Captcha submitted for task ${captchaTaskId}`);
|
|
logger.info(`[WS] Captcha submitted for task ${captchaTaskId}`);
|
|
|
- listener(code);
|
|
|
|
|
|
|
+ // 修复: 调用 listener.callback
|
|
|
|
|
+ listener.callback(code);
|
|
|
|
|
+ // 调用后删除监听器
|
|
|
|
|
+ clearTimeout(listener.timer);
|
|
|
|
|
+ this.captchaListeners.delete(captchaTaskId);
|
|
|
} else {
|
|
} else {
|
|
|
logger.warn(`[WS] No listener for captcha task ${captchaTaskId}`);
|
|
logger.warn(`[WS] No listener for captcha task ${captchaTaskId}`);
|
|
|
}
|
|
}
|
|
@@ -204,10 +208,20 @@ class WebSocketManager {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 注册验证码提交监听
|
|
|
|
|
|
|
+ * 注册验证码提交监听(5分钟超时后自动删除)
|
|
|
*/
|
|
*/
|
|
|
onCaptchaSubmit(captchaTaskId: string, callback: (code: string) => void): void {
|
|
onCaptchaSubmit(captchaTaskId: string, callback: (code: string) => void): void {
|
|
|
- this.captchaListeners.set(captchaTaskId, callback);
|
|
|
|
|
|
|
+ // 修复: 清除旧的定时器
|
|
|
|
|
+ const existing = this.captchaListeners.get(captchaTaskId);
|
|
|
|
|
+ if (existing) {
|
|
|
|
|
+ clearTimeout(existing.timer);
|
|
|
|
|
+ }
|
|
|
|
|
+ // 5分钟超时后自动删除
|
|
|
|
|
+ const timer = setTimeout(() => {
|
|
|
|
|
+ this.captchaListeners.delete(captchaTaskId);
|
|
|
|
|
+ logger.info(`[WS] Captcha listener timed out for ${captchaTaskId}`);
|
|
|
|
|
+ }, 5 * 60 * 1000);
|
|
|
|
|
+ this.captchaListeners.set(captchaTaskId, { callback, timer });
|
|
|
logger.info(`[WS] Registered captcha listener for ${captchaTaskId}`);
|
|
logger.info(`[WS] Registered captcha listener for ${captchaTaskId}`);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -215,14 +229,21 @@ class WebSocketManager {
|
|
|
* 移除验证码监听
|
|
* 移除验证码监听
|
|
|
*/
|
|
*/
|
|
|
removeCaptchaListener(captchaTaskId: string): void {
|
|
removeCaptchaListener(captchaTaskId: string): void {
|
|
|
- this.captchaListeners.delete(captchaTaskId);
|
|
|
|
|
- logger.info(`[WS] Removed captcha listener for ${captchaTaskId}`);
|
|
|
|
|
|
|
+ const existing = this.captchaListeners.get(captchaTaskId);
|
|
|
|
|
+ if (existing) {
|
|
|
|
|
+ clearTimeout(existing.timer);
|
|
|
|
|
+ this.captchaListeners.delete(captchaTaskId);
|
|
|
|
|
+ logger.info(`[WS] Removed captcha listener for ${captchaTaskId}`);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 清理所有监听器
|
|
* 清理所有监听器
|
|
|
*/
|
|
*/
|
|
|
clearAllCaptchaListeners(): void {
|
|
clearAllCaptchaListeners(): void {
|
|
|
|
|
+ for (const { timer } of this.captchaListeners.values()) {
|
|
|
|
|
+ clearTimeout(timer);
|
|
|
|
|
+ }
|
|
|
this.captchaListeners.clear();
|
|
this.captchaListeners.clear();
|
|
|
logger.info('[WS] Cleared all captcha listeners');
|
|
logger.info('[WS] Cleared all captcha listeners');
|
|
|
}
|
|
}
|