use std::collections::HashMap;
use std::sync::Arc;
pub struct InputCtx {
pub name: String,
pub params: serde_json::Value,
pub store: Arc<crate::store::MediaStore>,
pub target_duration_secs: f64,
pub part_target_ms: u32,
pub shutdown_rx: tokio::sync::watch::Receiver<bool>,
}
pub type InputFactory =
Arc<dyn Fn(InputCtx) -> crate::Result<tokio::task::JoinHandle<()>> + Send + Sync>;
pub struct OutputCtx<'a> {
pub params: serde_json::Value,
pub playlist_name: &'a str,
}
pub type OutputFactory =
Arc<dyn Fn(&OutputCtx) -> crate::Result<Arc<dyn crate::output::Output>> + Send + Sync>;
pub struct AuthCtx<'a> {
pub params: serde_json::Value,
pub realm: &'a str,
}
pub type AuthFactory =
Arc<dyn Fn(&AuthCtx) -> crate::Result<broadcast_auth::Verifier> + Send + Sync>;
#[derive(Clone, Default)]
pub struct SchemeRegistry {
inputs: HashMap<String, InputFactory>,
outputs: HashMap<String, OutputFactory>,
auths: HashMap<String, AuthFactory>,
}
impl SchemeRegistry {
pub fn new() -> Self {
Self::default()
}
pub fn register_input(&mut self, tag: impl Into<String>, factory: InputFactory) -> &mut Self {
self.inputs.insert(tag.into(), factory);
self
}
pub fn register_output(&mut self, tag: impl Into<String>, factory: OutputFactory) -> &mut Self {
self.outputs.insert(tag.into(), factory);
self
}
pub fn register_auth(&mut self, tag: impl Into<String>, factory: AuthFactory) -> &mut Self {
self.auths.insert(tag.into(), factory);
self
}
pub fn input(&self, tag: &str) -> Option<&InputFactory> {
self.inputs.get(tag)
}
pub fn output(&self, tag: &str) -> Option<&OutputFactory> {
self.outputs.get(tag)
}
pub fn auth(&self, tag: &str) -> Option<&AuthFactory> {
self.auths.get(tag)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_registry_has_no_factories() {
let registry = SchemeRegistry::new();
assert!(registry.input("anything").is_none());
assert!(registry.output("anything").is_none());
assert!(registry.auth("anything").is_none());
}
#[test]
fn registered_input_factory_is_found_by_exact_tag_only() {
let mut registry = SchemeRegistry::new();
let factory: InputFactory =
Arc::new(|_ctx: InputCtx| unreachable!("factory is not invoked by this test"));
registry.register_input("silence", factory);
assert!(registry.input("silence").is_some());
assert!(registry.input("nope").is_none());
}
#[test]
fn registered_output_factory_is_found_by_exact_tag_only() {
let mut registry = SchemeRegistry::new();
let factory: OutputFactory =
Arc::new(|_ctx: &OutputCtx| unreachable!("factory is not invoked by this test"));
registry.register_output("webrtc", factory);
assert!(registry.output("webrtc").is_some());
assert!(registry.output("nope").is_none());
}
#[test]
fn registered_auth_factory_is_found_by_exact_tag_only() {
let mut registry = SchemeRegistry::new();
let factory: AuthFactory =
Arc::new(|_ctx: &AuthCtx| unreachable!("factory is not invoked by this test"));
registry.register_auth("hmac", factory);
assert!(registry.auth("hmac").is_some());
assert!(registry.auth("nope").is_none());
}
#[test]
fn register_calls_chain() {
let mut registry = SchemeRegistry::new();
registry
.register_input("a", Arc::new(|_ctx: InputCtx| unreachable!("not invoked")))
.register_input("b", Arc::new(|_ctx: InputCtx| unreachable!("not invoked")));
assert!(registry.input("a").is_some());
assert!(registry.input("b").is_some());
}
}