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); 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}