//! Buffers, replays, broadcasts, and atomically closes downstream output. use bytes::Bytes; use tokio::sync::mpsc; #[derive(Default)] pub struct OutputHub { state: parking_lot::Mutex, } #[derive(Default)] struct OutputState { history: Vec, subscribers: Vec>, closed: bool, } impl OutputHub { pub fn emit(&self, frame: Bytes) -> bool { let mut state = self.state.lock(); if state.closed { return false; } state.history.push(frame.clone()); state .subscribers .retain(|subscriber| subscriber.send(frame.clone()).is_ok()); true } pub fn subscribe(&self) -> mpsc::UnboundedReceiver { let (sender, receiver) = mpsc::unbounded_channel(); let mut state = self.state.lock(); for frame in &state.history { let _ = sender.send(frame.clone()); } if !state.closed { state.subscribers.push(sender); } receiver } pub fn close(&self) -> bool { let mut state = self.state.lock(); if state.closed { return false; } state.closed = true; state.subscribers.clear(); drop(state); true } }