1pub mod extractors;
2pub mod handlers;
3pub mod responses;
4pub mod router;
5
6use std::net::SocketAddr;
7
8use notmad::{Component, ComponentInfo, MadError};
9use post3::StorageBackend;
10use tokio::net::TcpListener;
11use tokio_util::sync::CancellationToken;
12
13use crate::state::State;
14
15pub struct S3Server<B: StorageBackend> {
16 pub host: SocketAddr,
17 pub state: State<B>,
18}
19
20impl<B: StorageBackend> Component for S3Server<B> {
21 fn info(&self) -> ComponentInfo {
22 "post3/s3".into()
23 }
24
25 async fn run(&self, cancellation_token: CancellationToken) -> Result<(), MadError> {
26 let app = router::build_router(self.state.clone());
27
28 tracing::info!("post3 s3-compatible server listening on {}", self.host);
29 let listener = TcpListener::bind(&self.host).await.map_err(|e| {
30 MadError::Inner(anyhow::anyhow!("failed to bind: {e}"))
31 })?;
32
33 axum::serve(listener, app.into_make_service())
34 .with_graceful_shutdown(async move {
35 cancellation_token.cancelled().await;
36 })
37 .await
38 .map_err(|e| MadError::Inner(anyhow::anyhow!("server error: {e}")))?;
39
40 Ok(())
41 }
42}