59 lines
1.5 KiB
Rust
59 lines
1.5 KiB
Rust
|
|
//! 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()
|
||
|
|
}
|
||
|
|
}
|