feat(signal): PresenceList broadcast for lobby user discovery
Some checks failed
Build Release Binaries / build-amd64 (push) Failing after 7m21s
Mirror to GitHub / mirror (push) Failing after 27s

New signal infrastructure for the lobby-first UI:

- PresenceUser struct: { fingerprint, alias }
- SignalMessage::PresenceList: relay broadcasts full user list
  to all signal clients on every register/deregister
- SignalHub::presence_list(): builds the list from connected clients
- SignalHub::broadcast(): sends to ALL signal clients
- Relay calls broadcast on register + unregister
- Desktop emits "presence_list" signal-event to JS frontend

This gives clients real-time visibility of who's online via the
signal channel, without needing to join a voice room first.

603 tests pass, 0 regressions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Siavash Sameni
2026-04-14 18:12:47 +04:00
parent bb23976076
commit 1120c7b579
6 changed files with 64 additions and 1 deletions

View File

@@ -1016,6 +1016,13 @@ async fn main() -> anyhow::Result<()> {
info!(%addr, fingerprint = %client_fp, alias = ?client_alias, "signal client registered");
// Broadcast updated presence to all signal clients
{
let hub = signal_hub.lock().await;
let presence = hub.presence_list();
hub.broadcast(&presence).await;
}
// Signal recv loop
loop {
match transport.recv_signal().await {
@@ -1560,6 +1567,9 @@ async fn main() -> anyhow::Result<()> {
{
let mut hub = signal_hub.lock().await;
hub.unregister(&client_fp);
// Broadcast updated presence to remaining clients
let presence_msg = hub.presence_list();
hub.broadcast(&presence_msg).await;
}
{
let mut reg = presence.lock().await;

View File

@@ -86,6 +86,26 @@ impl SignalHub {
pub fn alias(&self, fp: &str) -> Option<&str> {
self.clients.get(fp).and_then(|c| c.alias.as_deref())
}
/// Build a PresenceList message with all online users.
pub fn presence_list(&self) -> SignalMessage {
let users: Vec<wzp_proto::PresenceUser> = self
.clients
.values()
.map(|c| wzp_proto::PresenceUser {
fingerprint: c.fingerprint.clone(),
alias: c.alias.clone(),
})
.collect();
SignalMessage::PresenceList { users }
}
/// Broadcast a message to ALL connected signal clients.
pub async fn broadcast(&self, msg: &SignalMessage) {
for client in self.clients.values() {
let _ = client.transport.send_signal(msg).await;
}
}
}
#[cfg(test)]