moq-rs/moq-warp/src/relay/broker.rs
2023-08-03 13:57:33 -07:00

77 lines
2.0 KiB
Rust

use crate::model::{broadcast, track, watch};
use crate::relay::contribute;
use std::collections::hash_map::HashMap;
use std::sync::{Arc, Mutex};
use anyhow::Context;
#[derive(Clone, Default)]
pub struct Broker {
// Operate on the inner struct so we can share/clone the outer struct.
inner: Arc<Mutex<BrokerInner>>,
}
#[derive(Default)]
struct BrokerInner {
// TODO Automatically reclaim dropped sources.
lookup: HashMap<String, Arc<contribute::Broadcast>>,
updates: watch::Publisher<BrokerUpdate>,
}
#[derive(Clone)]
pub enum BrokerUpdate {
// Broadcast was announced
Insert(String), // TODO include source?
// Broadcast was unannounced
Remove(String, broadcast::Error),
}
impl Broker {
pub fn new() -> Self {
Default::default()
}
// Return the list of available broadcasts, and a subscriber that will return updates (add/remove).
pub fn available(&self) -> (Vec<String>, watch::Subscriber<BrokerUpdate>) {
// Grab the lock.
let this = self.inner.lock().unwrap();
// Get the list of all available tracks.
let keys = this.lookup.keys().cloned().collect();
// Get a subscriber that will return future updates.
let updates = this.updates.subscribe();
(keys, updates)
}
pub fn announce(&self, namespace: &str, source: Arc<contribute::Broadcast>) -> anyhow::Result<()> {
let mut this = self.inner.lock().unwrap();
if let Some(_existing) = this.lookup.get(namespace) {
anyhow::bail!("namespace already registered");
}
this.lookup.insert(namespace.to_string(), source);
this.updates.push(BrokerUpdate::Insert(namespace.to_string()));
Ok(())
}
pub fn unannounce(&self, namespace: &str, error: broadcast::Error) -> anyhow::Result<()> {
let mut this = self.inner.lock().unwrap();
this.lookup.remove(namespace).context("namespace was not published")?;
this.updates.push(BrokerUpdate::Remove(namespace.to_string(), error));
Ok(())
}
pub fn subscribe(&self, namespace: &str, name: &str) -> Option<track::Subscriber> {
let this = self.inner.lock().unwrap();
this.lookup.get(namespace).and_then(|v| v.subscribe(name))
}
}