Skip to main content

syncweb_core/media/
server.rs

1use std::net::SocketAddr;
2use std::sync::Arc;
3
4use axum::{Router, routing::get};
5use tokio::sync::broadcast;
6use tokio::task::JoinHandle;
7
8use crate::node::blob_store::BlobStore;
9
10use super::serve::{MediaState, serve_media};
11
12pub const DEFAULT_MEDIA_PORT: u16 = 9193;
13
14pub struct MediaServer {
15    addr: SocketAddr,
16    state: Arc<MediaState>,
17}
18
19impl MediaServer {
20    #[must_use]
21    pub fn new(addr: SocketAddr, blob_store: BlobStore) -> Self {
22        Self {
23            addr,
24            state: Arc::new(MediaState { blob_store }),
25        }
26    }
27
28    /// Bind the TCP listener and run until the shutdown signal is received.
29    ///
30    /// # Errors
31    ///
32    /// Returns an error if the TCP listener cannot be bound.
33    pub async fn run(self, shutdown: broadcast::Sender<()>) -> Result<(), crate::SyncwebError> {
34        let app = Router::new()
35            .route("/media/{hash}", get(serve_media))
36            .with_state(self.state);
37
38        let listener = tokio::net::TcpListener::bind(self.addr)
39            .await
40            .map_err(|error| crate::SyncwebError::operation("failed to bind media server", error))?;
41
42        let local_addr = listener
43            .local_addr()
44            .map_err(|error| crate::SyncwebError::operation("failed to get media server local address", error))?;
45
46        tracing::info!(addr = %local_addr, "media server started");
47
48        axum::serve(listener, app)
49            .with_graceful_shutdown(async move {
50                let mut rx = shutdown.subscribe();
51                let _ = rx.recv().await;
52                tracing::debug!("media server shutdown signal received");
53            })
54            .await
55            .map_err(|error| crate::SyncwebError::operation("media server failed", error))?;
56
57        Ok(())
58    }
59
60    #[must_use]
61    pub fn spawn(self, shutdown: broadcast::Sender<()>) -> JoinHandle<Result<(), crate::SyncwebError>> {
62        tokio::spawn(async move { self.run(shutdown).await })
63    }
64}