merge main: PresenceList signal for lobby
This commit is contained in:
@@ -138,6 +138,7 @@ pub fn signal_to_call_type(signal: &SignalMessage) -> CallSignalType {
|
|||||||
| SignalMessage::UpgradeResponse { .. }
|
| SignalMessage::UpgradeResponse { .. }
|
||||||
| SignalMessage::UpgradeConfirm { .. }
|
| SignalMessage::UpgradeConfirm { .. }
|
||||||
| SignalMessage::QualityCapability { .. } => CallSignalType::Offer, // quality negotiation
|
| SignalMessage::QualityCapability { .. } => CallSignalType::Offer, // quality negotiation
|
||||||
|
SignalMessage::PresenceList { .. } => CallSignalType::Offer, // lobby presence
|
||||||
SignalMessage::QualityDirective { .. } => CallSignalType::Offer, // relay-initiated
|
SignalMessage::QualityDirective { .. } => CallSignalType::Offer, // relay-initiated
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ pub use codec_id::{CodecId, QualityProfile};
|
|||||||
pub use error::*;
|
pub use error::*;
|
||||||
pub use packet::{
|
pub use packet::{
|
||||||
CallAcceptMode, HangupReason, MediaHeader, MediaPacket, MiniFrameContext, MiniHeader,
|
CallAcceptMode, HangupReason, MediaHeader, MediaPacket, MiniFrameContext, MiniHeader,
|
||||||
QualityReport, RoomParticipant, SignalMessage, TrunkEntry, TrunkFrame, FRAME_TYPE_FULL,
|
PresenceUser, QualityReport, RoomParticipant, SignalMessage, TrunkEntry, TrunkFrame, FRAME_TYPE_FULL,
|
||||||
FRAME_TYPE_MINI,
|
FRAME_TYPE_MINI,
|
||||||
};
|
};
|
||||||
pub use bandwidth::{BandwidthEstimator, CongestionState};
|
pub use bandwidth::{BandwidthEstimator, CongestionState};
|
||||||
|
|||||||
@@ -156,6 +156,14 @@ impl MediaHeader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A user visible in the signal presence list.
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct PresenceUser {
|
||||||
|
pub fingerprint: String,
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub alias: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
/// Quality report appended to a media packet when Q flag is set (4 bytes).
|
/// Quality report appended to a media packet when Q flag is set (4 bytes).
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct QualityReport {
|
pub struct QualityReport {
|
||||||
@@ -1020,6 +1028,16 @@ pub enum SignalMessage {
|
|||||||
reason: Option<String>,
|
reason: Option<String>,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// ── Signal presence ───────────────────────────────────────────
|
||||||
|
|
||||||
|
/// Relay broadcasts the list of currently registered signal
|
||||||
|
/// users to all connected clients. Sent on every register/
|
||||||
|
/// deregister so clients can maintain a live lobby user list.
|
||||||
|
PresenceList {
|
||||||
|
/// List of online users. Each entry is { fingerprint, alias }.
|
||||||
|
users: Vec<PresenceUser>,
|
||||||
|
},
|
||||||
|
|
||||||
// ── Quality upgrade negotiation (#28, #29) ──────────────────
|
// ── Quality upgrade negotiation (#28, #29) ──────────────────
|
||||||
|
|
||||||
/// Peer proposes upgrading to a higher quality profile.
|
/// Peer proposes upgrading to a higher quality profile.
|
||||||
|
|||||||
@@ -1016,6 +1016,13 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
info!(%addr, fingerprint = %client_fp, alias = ?client_alias, "signal client registered");
|
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
|
// Signal recv loop
|
||||||
loop {
|
loop {
|
||||||
match transport.recv_signal().await {
|
match transport.recv_signal().await {
|
||||||
@@ -1560,6 +1567,9 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
{
|
{
|
||||||
let mut hub = signal_hub.lock().await;
|
let mut hub = signal_hub.lock().await;
|
||||||
hub.unregister(&client_fp);
|
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;
|
let mut reg = presence.lock().await;
|
||||||
|
|||||||
@@ -86,6 +86,26 @@ impl SignalHub {
|
|||||||
pub fn alias(&self, fp: &str) -> Option<&str> {
|
pub fn alias(&self, fp: &str) -> Option<&str> {
|
||||||
self.clients.get(fp).and_then(|c| c.alias.as_deref())
|
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)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -1451,6 +1451,20 @@ fn do_register_signal(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(Some(SignalMessage::PresenceList { users })) => {
|
||||||
|
tracing::info!(count = users.len(), "signal: PresenceList received");
|
||||||
|
// Emit to JS frontend for lobby user list
|
||||||
|
let user_list: Vec<serde_json::Value> = users.iter().map(|u| {
|
||||||
|
serde_json::json!({
|
||||||
|
"fingerprint": u.fingerprint,
|
||||||
|
"alias": u.alias,
|
||||||
|
})
|
||||||
|
}).collect();
|
||||||
|
let _ = app_clone.emit("signal-event", serde_json::json!({
|
||||||
|
"type": "presence_list",
|
||||||
|
"users": user_list,
|
||||||
|
}));
|
||||||
|
}
|
||||||
Ok(Some(SignalMessage::UpgradeProposal { call_id, proposal_id, proposed_profile, local_loss_pct, local_rtt_ms })) => {
|
Ok(Some(SignalMessage::UpgradeProposal { call_id, proposal_id, proposed_profile, local_loss_pct, local_rtt_ms })) => {
|
||||||
tracing::info!(%call_id, %proposal_id, ?proposed_profile, "signal: UpgradeProposal from peer");
|
tracing::info!(%call_id, %proposal_id, ?proposed_profile, "signal: UpgradeProposal from peer");
|
||||||
emit_call_debug(&app_clone, "recv:UpgradeProposal", serde_json::json!({
|
emit_call_debug(&app_clone, "recv:UpgradeProposal", serde_json::json!({
|
||||||
|
|||||||
Reference in New Issue
Block a user