Files
quicproquo/crates/quicprochat-rpc/src/push.rs
Christian Nennemann a710037dde chore: rename quicproquo → quicprochat in Rust workspace
Rename all crate directories, package names, binary names, proto
package/module paths, ALPN strings, env var prefixes, config filenames,
mDNS service names, and plugin ABI symbols from quicproquo/qpq to
quicprochat/qpc.
2026-03-21 19:14:06 +01:00

115 lines
3.0 KiB
Rust

//! Server-push infrastructure — manages push connections per identity key.
use bytes::Bytes;
use dashmap::DashMap;
use quinn::Connection;
use tracing::{debug, warn};
use crate::error::RpcError;
/// Manages push connections per identity key.
pub struct PushBroker {
/// Map from identity_key to active QUIC connections.
connections: DashMap<Vec<u8>, Vec<Connection>>,
}
impl PushBroker {
pub fn new() -> Self {
Self {
connections: DashMap::new(),
}
}
/// Register a connection for an identity.
pub fn register(&self, identity_key: Vec<u8>, connection: Connection) {
self.connections
.entry(identity_key)
.or_default()
.push(connection);
}
/// Remove closed connections from the registry.
pub fn gc(&self) {
self.connections.alter_all(|_, mut conns| {
conns.retain(|c| c.close_reason().is_none());
conns
});
self.connections.retain(|_, conns| !conns.is_empty());
}
/// Send a push event to all connections for an identity.
/// Returns the number of successful sends.
pub async fn send_to(
&self,
identity_key: &[u8],
event_type: u16,
payload: Bytes,
) -> usize {
let conns = match self.connections.get(identity_key) {
Some(entry) => entry.clone(),
None => return 0,
};
let mut sent = 0usize;
for conn in &conns {
match crate::server::send_push(conn, event_type, payload.clone()).await {
Ok(()) => {
sent += 1;
debug!("push sent to connection {}", conn.remote_address());
}
Err(RpcError::Connection(e)) => {
warn!("push send failed to {}: {e}", conn.remote_address());
}
Err(e) => {
warn!("push send error: {e}");
}
}
}
sent
}
/// Send a push event to all members of a channel.
/// `member_keys` is the list of identity keys in the channel.
/// Returns the total number of successful sends.
pub async fn send_to_channel(
&self,
member_keys: &[Vec<u8>],
event_type: u16,
payload: Bytes,
) -> usize {
let mut total = 0usize;
for key in member_keys {
total += self.send_to(key, event_type, payload.clone()).await;
}
total
}
/// Number of identities with registered connections.
pub fn identity_count(&self) -> usize {
self.connections.len()
}
}
impl Default for PushBroker {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_broker_is_empty() {
let broker = PushBroker::new();
assert_eq!(broker.identity_count(), 0);
}
#[test]
fn default_broker_is_empty() {
let broker = PushBroker::default();
assert_eq!(broker.identity_count(), 0);
}
}