fix: make WS handler synchronous — async handler breaks socket.on('message') in @fastify/websocket v8

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Ai
2026-05-22 13:31:21 +03:00
parent 71b961ac2b
commit 21edd7f7a3

View File

@@ -52,7 +52,7 @@ async function sendPushToOfflineUsers(userIds: string[], payload: object) {
} }
export function setupWebSocket(app: FastifyInstance) { export function setupWebSocket(app: FastifyInstance) {
(app as any).get('/ws', { websocket: true }, async (socket: any, req: any) => { (app as any).get('/ws', { websocket: true }, (socket: any, req: any) => {
let userId: string | null = null; let userId: string | null = null;
try { try {
@@ -64,21 +64,20 @@ export function setupWebSocket(app: FastifyInstance) {
return; return;
} }
const uid = userId;
// Register connection // Register connection
if (!connections.has(userId)) connections.set(userId, new Set()); if (!connections.has(uid)) connections.set(uid, new Set());
connections.get(userId)!.add(socket); connections.get(uid)!.add(socket);
// Update last_seen // Update last_seen + notify online (fire-and-forget)
await pool.query('UPDATE users SET last_seen = NOW() WHERE id = $1', [userId]); pool.query('UPDATE users SET last_seen = NOW() WHERE id = $1', [uid]).catch(() => {});
pool.query('SELECT DISTINCT chat_id FROM chat_members WHERE user_id = $1', [uid]).then(async ({ rows: memberChats }) => {
// Notify others that user is online for (const row of memberChats) {
const { rows: memberChats } = await pool.query( const ids = await getChatMemberIds(row.chat_id);
'SELECT DISTINCT chat_id FROM chat_members WHERE user_id = $1', [userId] broadcast(ids.filter(id => id !== uid), { type: 'user_online', payload: { userId: uid, online: true } });
); }
for (const row of memberChats) { }).catch(() => {});
const ids = await getChatMemberIds(row.chat_id);
broadcast(ids.filter(id => id !== userId), { type: 'user_online', payload: { userId, online: true } });
}
socket.on('message', async (raw: any, isBinary: boolean) => { socket.on('message', async (raw: any, isBinary: boolean) => {
try { try {
@@ -199,20 +198,19 @@ export function setupWebSocket(app: FastifyInstance) {
}); });
socket.on('close', async () => { socket.on('close', async () => {
if (!userId) return; const set = connections.get(uid);
const set = connections.get(userId);
if (set) { if (set) {
set.delete(socket); set.delete(socket);
if (set.size === 0) { if (set.size === 0) {
connections.delete(userId); connections.delete(uid);
await pool.query('UPDATE users SET last_seen = NOW() WHERE id = $1', [userId]); await pool.query('UPDATE users SET last_seen = NOW() WHERE id = $1', [uid]);
const { rows: memberChats } = await pool.query( const { rows: memberChats } = await pool.query(
'SELECT DISTINCT chat_id FROM chat_members WHERE user_id = $1', [userId] 'SELECT DISTINCT chat_id FROM chat_members WHERE user_id = $1', [uid]
); );
for (const row of memberChats) { for (const row of memberChats) {
const ids = await getChatMemberIds(row.chat_id); const ids = await getChatMemberIds(row.chat_id);
broadcast(ids, { type: 'user_online', payload: { userId, online: false } }); broadcast(ids, { type: 'user_online', payload: { userId: uid, online: false } });
} }
} }
} }