fix: comprehensive client-side session management for federated DM calls
Four fixes addressing the full state management problem: 1. Passive ready handler: no longer auto-connects to LiveKit on page refresh. Prevents identity conflicts when the same user has multiple sessions fighting for one LiveKit identity slot. The user must re-accept to join; state is shown but not acted on. 2. SoundController sync guard: incomingCallLoading/outgoingCallLoading refs prevent multiple playSound calls during async audio load. If call is cancelled while sound loads, stops it immediately on completion. Eliminates the "5 ringtones at once" bug. 3. Host dm_call_accepted broadcasts now include federatedCallId so all clients (including remote instances) can match the event. 4. Removed all diagnostic console.log statements.
This commit is contained in:
@@ -1444,8 +1444,6 @@ function handleDmCallStart(event: Record<string, unknown>, userId: string, usern
|
||||
function handleDmCallAccept(event: Record<string, unknown>, userId: string, ws: WebSocket): void {
|
||||
let dmChannelId = (event.dmChannelId as string) || null;
|
||||
const federatedCallId = (event.federatedCallId as string) || null;
|
||||
console.log(`[DM_CALL_ACCEPT] userId=${userId} dmChannelId=${dmChannelId} federatedCallId=${federatedCallId}`);
|
||||
|
||||
if (!dmChannelId && !federatedCallId) {
|
||||
connectionManager.sendToUser(userId, { type: 'error', message: 'dmChannelId or federatedCallId is required' });
|
||||
return;
|
||||
@@ -1462,22 +1460,17 @@ function handleDmCallAccept(event: Record<string, unknown>, userId: string, ws:
|
||||
.get();
|
||||
if (ch) {
|
||||
dmChannelId = ch.id;
|
||||
console.log(`[DM_CALL_ACCEPT] Resolved federatedId → dmChannelId=${ch.id}`);
|
||||
} else {
|
||||
console.log(`[DM_CALL_ACCEPT] No channel found for federatedId=${federatedCallId}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Path 1: Local room (we're the host) — only possible with dmChannelId
|
||||
if (dmChannelId) {
|
||||
if (!isDmMember(dmChannelId, userId)) {
|
||||
console.log(`[DM_CALL_ACCEPT] NOT a member of dmChannelId=${dmChannelId}`);
|
||||
connectionManager.sendToUser(userId, { type: 'error', message: 'You are not a member of this DM channel' });
|
||||
return;
|
||||
}
|
||||
|
||||
const room = connectionManager.getRoom(dmChannelId);
|
||||
console.log(`[DM_CALL_ACCEPT] Path1: getRoom(${dmChannelId}) → ${room ? `found (type=${room.roomType}, state=${(room.metadata as any).state})` : 'NOT FOUND'}`);
|
||||
if (room && room.roomType === 'dm') {
|
||||
const meta = room.metadata as DmRoomMeta;
|
||||
|
||||
@@ -1498,14 +1491,20 @@ function handleDmCallAccept(event: Record<string, unknown>, userId: string, ws:
|
||||
if (acceptorLeft) broadcastRoomLeave(acceptorLeft.roomId, acceptorLeft.room, userId);
|
||||
connectionManager.joinRoom(dmChannelId, userId);
|
||||
connectionManager.setVoiceWs(userId, ws);
|
||||
connectionManager.sendToDmMembers(dmChannelId, { type: 'dm_call_accepted', dmChannelId });
|
||||
// Look up federatedId for the broadcast so all clients (including remote) can match
|
||||
const fedIdRow = getDb().select({ federatedId: schema.dmChannels.federatedId })
|
||||
.from(schema.dmChannels).where(eq(schema.dmChannels.id, dmChannelId)).get();
|
||||
connectionManager.sendToDmMembers(dmChannelId, {
|
||||
type: 'dm_call_accepted',
|
||||
dmChannelId,
|
||||
federatedCallId: fedIdRow?.federatedId ?? undefined,
|
||||
} as ServerEvent);
|
||||
connectionManager.sendToDmMembers(dmChannelId, {
|
||||
type: 'voice_state_update',
|
||||
channelId: dmChannelId,
|
||||
userId,
|
||||
action: 'join',
|
||||
});
|
||||
console.log(`[DM_CALL_ACCEPT] Path1 HOST SUCCESS: room activated, dm_call_accepted broadcast`);
|
||||
sendFederatedCallAccept(dmChannelId, userId)
|
||||
.catch(err => console.error('[federation] sendFederatedCallAccept error:', err));
|
||||
return;
|
||||
@@ -1519,7 +1518,6 @@ function handleDmCallAccept(event: Record<string, unknown>, userId: string, ws:
|
||||
? connectionManager.getFederatedCallByDmChannel(dmChannelId)
|
||||
: undefined;
|
||||
|
||||
console.log(`[DM_CALL_ACCEPT] Path2: fedCall=${fedCall ? `found (host=${fedCall.federatedCallHost})` : 'NOT FOUND'}`);
|
||||
if (fedCall) {
|
||||
connectionManager.activateFederatedCall(fedCall.federatedId);
|
||||
connectionManager.sendToFederatedCallUsers(fedCall.federatedId, {
|
||||
@@ -1535,7 +1533,6 @@ function handleDmCallAccept(event: Record<string, unknown>, userId: string, ws:
|
||||
.get();
|
||||
const homeUserId = user?.homeUserId || userId;
|
||||
|
||||
console.log(`[DM_CALL_ACCEPT] Path2 RELAY to host ${fedCall.federatedCallHost}`);
|
||||
sendCallRelay(fedCall.federatedCallHost, [{
|
||||
eventType: 'dm_call_accept',
|
||||
messageId: generateSnowflake(),
|
||||
@@ -1545,13 +1542,10 @@ function handleDmCallAccept(event: Record<string, unknown>, userId: string, ws:
|
||||
call: {
|
||||
acceptor: { homeUserId, homeInstance: getOurOrigin() },
|
||||
},
|
||||
}]).then(result => {
|
||||
console.log(`[DM_CALL_ACCEPT] Relay result: ${JSON.stringify(result)}`);
|
||||
}).catch(err => console.error('[federation] Failed to send dm_call_accept:', err));
|
||||
}]).catch(err => console.error('[federation] Failed to send dm_call_accept:', err));
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[DM_CALL_ACCEPT] FALLTHROUGH — no call found for userId=${userId}`);
|
||||
connectionManager.sendToUser(userId, { type: 'error', message: 'No active call in this DM channel' });
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user