syncweb_core/media/
server.rs1use 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 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}