@jungjaehoon/mama-core 1.1.3 → 1.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -21,7 +21,9 @@ import type { Server as HTTPServer } from 'http';
|
|
|
21
21
|
* Message router interface
|
|
22
22
|
*/
|
|
23
23
|
interface MessageRouter {
|
|
24
|
-
process(message: NormalizedMessage
|
|
24
|
+
process(message: NormalizedMessage, options?: {
|
|
25
|
+
onQueued?: () => void;
|
|
26
|
+
}): Promise<RouterResult>;
|
|
25
27
|
}
|
|
26
28
|
/**
|
|
27
29
|
* Session store interface
|
|
@@ -81,6 +81,22 @@ function extractUserId(req) {
|
|
|
81
81
|
return `user_${Date.now()}`;
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Safe send helper - guards against closed socket with try-catch for race conditions
|
|
86
|
+
*/
|
|
87
|
+
function safeSend(ws, data) {
|
|
88
|
+
if (ws.readyState === ws_1.WebSocket.OPEN) {
|
|
89
|
+
try {
|
|
90
|
+
ws.send(data);
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// Socket may have closed between readyState check and send
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
84
100
|
/**
|
|
85
101
|
* Create WebSocket handler with MessageRouter integration
|
|
86
102
|
*/
|
|
@@ -269,19 +285,37 @@ async function handleClientMessage(clientId, message, clientInfo, messageRouter,
|
|
|
269
285
|
timestamp: Date.now(),
|
|
270
286
|
},
|
|
271
287
|
};
|
|
272
|
-
result = await messageRouter.process(normalizedMessage
|
|
288
|
+
result = await messageRouter.process(normalizedMessage, {
|
|
289
|
+
onQueued: () => {
|
|
290
|
+
// Guard: check if socket is still open before sending
|
|
291
|
+
if (clientInfo.ws.readyState !== ws_1.WebSocket.OPEN) {
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
// Notify client that message is queued (session busy)
|
|
295
|
+
try {
|
|
296
|
+
clientInfo.ws.send(JSON.stringify({
|
|
297
|
+
type: 'queued',
|
|
298
|
+
message: '⏳ 이전 요청 처리 중... 대기열에 추가되었습니다.',
|
|
299
|
+
}));
|
|
300
|
+
}
|
|
301
|
+
catch (err) {
|
|
302
|
+
logger.warn('Queued notification failed:', err instanceof Error ? err.message : String(err));
|
|
303
|
+
}
|
|
304
|
+
logger.info(`Message queued for ${clientId} (session busy)`);
|
|
305
|
+
},
|
|
306
|
+
});
|
|
273
307
|
}
|
|
274
308
|
finally {
|
|
275
309
|
clearInterval(keepAliveInterval);
|
|
276
310
|
}
|
|
277
311
|
// Send response as stream (for Chat tab compatibility)
|
|
278
|
-
clientInfo.ws
|
|
312
|
+
safeSend(clientInfo.ws, JSON.stringify({
|
|
279
313
|
type: 'stream',
|
|
280
314
|
content: result.response,
|
|
281
315
|
sessionId: result.sessionId,
|
|
282
316
|
}));
|
|
283
317
|
// Send stream end
|
|
284
|
-
clientInfo.ws
|
|
318
|
+
safeSend(clientInfo.ws, JSON.stringify({
|
|
285
319
|
type: 'stream_end',
|
|
286
320
|
sessionId: result.sessionId,
|
|
287
321
|
duration: result.duration,
|
|
@@ -291,7 +325,7 @@ async function handleClientMessage(clientId, message, clientInfo, messageRouter,
|
|
|
291
325
|
catch (error) {
|
|
292
326
|
const errMsg = error instanceof Error ? error.message : String(error);
|
|
293
327
|
logger.error(`Message processing error for ${clientId}:`, errMsg);
|
|
294
|
-
clientInfo.ws
|
|
328
|
+
safeSend(clientInfo.ws, JSON.stringify({
|
|
295
329
|
type: 'error',
|
|
296
330
|
error: 'Failed to process message',
|
|
297
331
|
// Don't expose internal error details to client for security
|