fix: clear stale federated presence on GlobalRoomInactive
When a remote relay's room goes inactive (all participants left), the receiving relay now: 1. Clears remote_participants for that peer+room 2. Broadcasts updated RoomUpdate to local clients with the remote participant removed 3. Updates federation_active_rooms metric Previously, remote participants lingered in the participant list after disconnect, causing ghost entries and stale media forwarding. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -597,9 +597,18 @@ async fn handle_signal(
|
|||||||
let mut links = fm.peer_links.lock().await;
|
let mut links = fm.peer_links.lock().await;
|
||||||
if let Some(link) = links.get_mut(peer_fp) {
|
if let Some(link) = links.get_mut(peer_fp) {
|
||||||
link.active_rooms.remove(&room);
|
link.active_rooms.remove(&room);
|
||||||
|
// Clear remote participants for this peer+room
|
||||||
|
link.remote_participants.remove(&room);
|
||||||
|
// Also try canonical name
|
||||||
|
if let Some(canonical) = fm.resolve_global_room(&room) {
|
||||||
|
link.remote_participants.remove(canonical);
|
||||||
}
|
}
|
||||||
// Update active rooms gauge
|
}
|
||||||
|
|
||||||
|
// Update active rooms metric
|
||||||
let total: usize = links.values().map(|l| l.active_rooms.len()).sum();
|
let total: usize = links.values().map(|l| l.active_rooms.len()).sum();
|
||||||
|
fm.metrics.federation_active_rooms.set(total as i64);
|
||||||
|
|
||||||
// Check if any other peer still has this room — if none, propagate inactive
|
// Check if any other peer still has this room — if none, propagate inactive
|
||||||
let any_other_active = links.iter()
|
let any_other_active = links.iter()
|
||||||
.any(|(fp, l)| fp != peer_fp && l.active_rooms.contains(&room));
|
.any(|(fp, l)| fp != peer_fp && l.active_rooms.contains(&room));
|
||||||
@@ -614,6 +623,37 @@ async fn handle_signal(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
drop(links);
|
||||||
|
|
||||||
|
// Broadcast updated RoomUpdate to local clients (remote participant removed)
|
||||||
|
let mgr = fm.room_mgr.lock().await;
|
||||||
|
for local_room in mgr.active_rooms() {
|
||||||
|
if fm.is_global_room(&local_room) && fm.resolve_global_room(&local_room) == fm.resolve_global_room(&room) {
|
||||||
|
let mut all_participants = mgr.local_participant_list(&local_room);
|
||||||
|
// Merge remaining remote participants from other peers
|
||||||
|
let links = fm.peer_links.lock().await;
|
||||||
|
for link in links.values() {
|
||||||
|
if let Some(canonical) = fm.resolve_global_room(&local_room) {
|
||||||
|
if let Some(remote) = link.remote_participants.get(canonical) {
|
||||||
|
all_participants.extend(remote.iter().cloned());
|
||||||
|
}
|
||||||
|
if let Some(remote) = link.remote_participants.get(&local_room) {
|
||||||
|
all_participants.extend(remote.iter().cloned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let update = SignalMessage::RoomUpdate {
|
||||||
|
count: all_participants.len() as u32,
|
||||||
|
participants: all_participants,
|
||||||
|
};
|
||||||
|
let senders = mgr.local_senders(&local_room);
|
||||||
|
drop(links);
|
||||||
|
drop(mgr);
|
||||||
|
room::broadcast_signal(&senders, &update).await;
|
||||||
|
info!(room = %room, "broadcast updated presence (remote participant removed)");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {} // ignore other signals
|
_ => {} // ignore other signals
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user