Files
svc-gw/src/hub.rs
T

59 lines
1.5 KiB
Rust
Raw Normal View History

//! Fan-out to clients. Drop-only: each client has a bounded queue that loses its
//! oldest message when full, so a tablet with its screen off never stalls anything.
use std::collections::VecDeque;
use std::sync::{Arc, Condvar, Mutex};
use std::time::Duration;
const QUEUE: usize = 64;
pub struct Outbox {
q: Mutex<VecDeque<String>>,
cv: Condvar,
}
impl Outbox {
pub fn push(&self, msg: String) {
let mut q = self.q.lock().unwrap();
if q.len() >= QUEUE {
q.pop_front();
}
q.push_back(msg);
self.cv.notify_one();
}
/// Everything queued, waiting at most `wait` for something to arrive.
pub fn drain(&self, wait: Duration) -> Vec<String> {
let q = self.q.lock().unwrap();
let (mut q, _) = self.cv.wait_timeout_while(q, wait, |q| q.is_empty()).unwrap();
q.drain(..).collect()
}
}
#[derive(Default, Clone)]
pub struct Hub {
clients: Arc<Mutex<Vec<Arc<Outbox>>>>,
}
impl Hub {
pub fn join(&self) -> Arc<Outbox> {
let o = Arc::new(Outbox { q: Mutex::new(VecDeque::new()), cv: Condvar::new() });
self.clients.lock().unwrap().push(o.clone());
o
}
pub fn leave(&self, o: &Arc<Outbox>) {
self.clients.lock().unwrap().retain(|c| !Arc::ptr_eq(c, o));
}
pub fn broadcast(&self, msg: &str) {
for c in self.clients.lock().unwrap().iter() {
c.push(msg.to_string());
}
}
pub fn count(&self) -> usize {
self.clients.lock().unwrap().len()
}
}