40 lines
1.4 KiB
Rust
40 lines
1.4 KiB
Rust
pub mod grpc;
|
|
|
|
use std::net::SocketAddr;
|
|
|
|
use anyhow::{Result, anyhow};
|
|
use async_trait::async_trait;
|
|
use tokio::sync::broadcast::Receiver;
|
|
|
|
use crate::server::state::ServerState;
|
|
use crate::server::watcher::ChangeEvent;
|
|
|
|
/// Transport-agnostic musicfs server. A single implementation is wired in
|
|
/// today (`grpc`); the factory in [`build`] is the seam where additional
|
|
/// transports (HTTP/3, raw QUIC, in-process for tests, ...) get plugged in
|
|
/// without touching the binary.
|
|
///
|
|
/// `run` consumes `self` — a transport serves exactly once. It receives the
|
|
/// shared [`ServerState`] and a fresh broadcast receiver for change events.
|
|
#[async_trait]
|
|
pub trait MusicTransport: Send + Sync + 'static {
|
|
async fn run(self: Box<Self>, state: ServerState, events: Receiver<ChangeEvent>) -> Result<()>;
|
|
}
|
|
|
|
/// Arguments every transport understands. Transports may extend this with
|
|
/// their own configuration via their constructors.
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub struct TransportArgs {
|
|
pub listen: SocketAddr,
|
|
}
|
|
|
|
/// Construct the named transport. The list of accepted names is intentionally
|
|
/// discoverable (a single match arm) so adding a transport means adding an
|
|
/// arm here plus a module under `transport/`.
|
|
pub fn build(name: &str, args: TransportArgs) -> Result<Box<dyn MusicTransport>> {
|
|
return match name {
|
|
"grpc" => Ok(Box::new(grpc::GrpcTransport::new(args))),
|
|
other => Err(anyhow!("unknown transport: {other}")),
|
|
};
|
|
}
|