fix: make server mute/deafen state survive page reload
- Client ready handler now builds restriction Sets atomically in a single setState call, eliminating intermediate empty-Set state that caused amber icons to flash rose on reload - buildReadyPayload queries all voice restrictions from DB across the user's spaces instead of relying on in-memory state (which is lost on disconnect timeout) - voice_join early-return path now re-broadcasts restrictions to the reconnecting user, covering fast reload where the user is still in the room
This commit is contained in:
@@ -875,34 +875,21 @@ function buildReadyPayload(userId: string): {
|
||||
}
|
||||
}
|
||||
|
||||
// Build server mute/deafen states for users currently in voice
|
||||
// Build server mute/deafen states from DB (authoritative source for all spaces the user belongs to)
|
||||
const serverVoiceStates: Record<string, { serverMuted: boolean; serverDeafened: boolean }> = {};
|
||||
for (const chId of Object.keys(voiceStates)) {
|
||||
const usersInChannel = voiceStates[chId];
|
||||
if (usersInChannel) {
|
||||
for (const uid of usersInChannel) {
|
||||
const sm = connectionManager.isServerMuted(uid);
|
||||
const sd = connectionManager.isServerDeafened(uid);
|
||||
if (sm || sd) {
|
||||
serverVoiceStates[uid] = { serverMuted: sm, serverDeafened: sd };
|
||||
}
|
||||
}
|
||||
if (spaceIds.length > 0) {
|
||||
const allRestrictions = db.select()
|
||||
.from(schema.voiceRestrictions)
|
||||
.where(inArray(schema.voiceRestrictions.spaceId, spaceIds))
|
||||
.all();
|
||||
for (const r of allRestrictions) {
|
||||
const existing = serverVoiceStates[r.userId] ?? { serverMuted: false, serverDeafened: false };
|
||||
if (r.restrictionType === 'mute') existing.serverMuted = true;
|
||||
if (r.restrictionType === 'deafen') existing.serverDeafened = true;
|
||||
serverVoiceStates[r.userId] = existing;
|
||||
}
|
||||
}
|
||||
|
||||
// Also include the connecting user's own DB-persisted restrictions
|
||||
// (covers reconnect after disconnect timeout cleared in-memory state)
|
||||
const myRestrictions = db.select()
|
||||
.from(schema.voiceRestrictions)
|
||||
.where(eq(schema.voiceRestrictions.userId, userId))
|
||||
.all();
|
||||
for (const r of myRestrictions) {
|
||||
const existing = serverVoiceStates[userId] ?? { serverMuted: false, serverDeafened: false };
|
||||
if (r.restrictionType === 'mute') existing.serverMuted = true;
|
||||
if (r.restrictionType === 'deafen') existing.serverDeafened = true;
|
||||
serverVoiceStates[userId] = existing;
|
||||
}
|
||||
|
||||
// Fetch read states for unread tracking
|
||||
const readStateRows = db.select()
|
||||
.from(schema.readStates)
|
||||
|
||||
Reference in New Issue
Block a user