From f4cc3b1a6b0a3f57134c9518ced8d5dac373ca15 Mon Sep 17 00:00:00 2001 From: Siavash Sameni Date: Wed, 8 Apr 2026 10:09:50 +0400 Subject: [PATCH] fix: forward media to ALL connected peers, not just those with room active MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bug: when a local client joins a global room and sends media, the egress task checked peer_links.active_rooms to decide where to forward. But active_rooms tracks what PEERS announced (their rooms), not what WE announced. So our own GlobalRoomActive signal went out but our peer_links had empty active_rooms — media was dropped. Fix: for locally-originated media, send to ALL connected federation peers unconditionally. The receiving relay decides whether to deliver to local participants (if it has the room) or forward further. This is correct because federation peers are explicitly configured — if they're connected, they should receive global room media. Multi-hop forwarding (handle_datagram) still filters by active_rooms to prevent loops — only forwards to peers that announced the room. Co-Authored-By: Claude Opus 4.6 (1M context) --- crates/wzp-relay/src/federation.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/crates/wzp-relay/src/federation.rs b/crates/wzp-relay/src/federation.rs index e7b740a..aabea26 100644 --- a/crates/wzp-relay/src/federation.rs +++ b/crates/wzp-relay/src/federation.rs @@ -138,7 +138,9 @@ impl FederationManager { } } - /// Forward locally-generated media to active peers for a global room. + /// Forward locally-generated media to all connected peers. + /// For locally-originated media, we send to ALL peers (they decide whether to deliver). + /// For forwarded media (multi-hop), handle_datagram filters by active_rooms. pub async fn forward_to_peers(&self, room_name: &str, room_hash: &[u8; 8], media_data: &Bytes) { let links = self.peer_links.lock().await; if links.is_empty() { @@ -146,7 +148,9 @@ impl FederationManager { } let mut sent = 0u32; for (fp, link) in links.iter() { - if link.active_rooms.contains(room_name) { + // Send to all connected peers — they have the global room configured + // and will deliver to local participants or forward further + { let mut tagged = Vec::with_capacity(8 + media_data.len()); tagged.extend_from_slice(room_hash); tagged.extend_from_slice(media_data); @@ -156,13 +160,6 @@ impl FederationManager { } } } - if sent == 0 && !links.is_empty() { - // Debug: no peer had this room active - let active_rooms: Vec<_> = links.values() - .flat_map(|l| l.active_rooms.iter().cloned()) - .collect(); - warn!(room = %room_name, peer_count = links.len(), ?active_rooms, "no peer has this room active"); - } } // ── Trust verification (kept from previous implementation) ──