cargolifter_web/
lib.rs

1mod endpoints;
2
3use hyper::body::Buf;
4
5pub struct WebService {
6    backend: tokio::sync::mpsc::Sender<cargolifter_core::BackendCommand>,
7    storage: tokio::sync::mpsc::Sender<cargolifter_core::StorageCommand>,
8    config: cargolifter_core::config::WebServiceConfig,
9}
10
11pub struct RequestExtractor(cargolifter_core::models::PublishRequest);
12
13#[axum::async_trait]
14impl axum::extract::FromRequest for RequestExtractor {
15    type Rejection = axum::http::StatusCode;
16
17    async fn from_request(req: &mut axum::extract::RequestParts) -> Result<Self, Self::Rejection> {
18        let mut data = hyper::body::to_bytes(req.body_mut().unwrap())
19            .await
20            .unwrap();
21        let json_length = data.get_u32_le() as usize;
22        let json_data = &data[0..json_length].to_vec();
23        data.advance(json_length);
24        let data_length = data.get_u32_le() as usize;
25
26        Ok(Self {
27            0: cargolifter_core::models::PublishRequest {
28                meta: serde_json::from_slice(json_data).unwrap(),
29                data: data[0..data_length].to_vec(),
30            },
31        })
32    }
33}
34
35impl WebService {
36    pub fn new(
37        backend: tokio::sync::mpsc::Sender<cargolifter_core::BackendCommand>,
38        storage: tokio::sync::mpsc::Sender<cargolifter_core::StorageCommand>,
39        config: cargolifter_core::config::WebServiceConfig,
40    ) -> Self {
41        Self {
42            backend,
43            storage,
44            config,
45        }
46    }
47
48    pub async fn run(&self) {
49        let host = format!("0.0.0.0:{}", self.config.port); // TODO: confiure port
50        tracing::info!("starting web service at: {}", host);
51
52        let app = axum::Router::new()
53            .route(
54                "/api/v1/crates/:crate_name/:crate_version/download",
55                axum::handler::get(endpoints::download),
56            )
57            .route("/api/v1/crates/new", axum::handler::put(endpoints::publish))
58            .route(
59                "/api/v1/crates/:name/:version/yank",
60                axum::handler::delete(endpoints::yank),
61            )
62            .route(
63                "/api/v1/crates/:name/:version/unyank",
64                axum::handler::put(endpoints::unyank),
65            )
66            .layer(axum::AddExtensionLayer::new(self.backend.clone()))
67            .layer(axum::AddExtensionLayer::new(self.storage.clone()));
68
69        axum::Server::bind(&host.parse().unwrap())
70            .serve(app.into_make_service())
71            .await
72            .unwrap();
73    }
74}