From 8a06f53ec0cb3019b9000490ac8598b5ea84f267 Mon Sep 17 00:00:00 2001 From: Jordan Doyle Date: Tue, 31 Aug 2021 20:04:35 +0100 Subject: [PATCH] Define cargo API routes in chartered-web --- Cargo.lock | 1 + chartered-web/Cargo.toml | 1 + test-using-chartered/.gitignore | 2 -- test-using-chartered/Cargo.toml | 9 --------- chartered-git/src/main.rs | 24 +++++++++++------------- chartered-web/src/main.rs | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ test-using-chartered/.cargo/config.toml | 2 -- test-using-chartered/src/lib.rs | 7 ------- chartered-web/src/endpoints/mod.rs | 1 + chartered-web/src/middleware/auth.rs | 43 +++++++++++++++++++++++++++++++++++++++++++ chartered-web/src/middleware/mod.rs | 1 + chartered-web/src/endpoints/cargo_api/download.rs | 3 +++ chartered-web/src/endpoints/cargo_api/mod.rs | 3 +++ 13 files changed, 124 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ddfce59..80939a3 100644 --- a/Cargo.lock +++ a/Cargo.lock @@ -210,6 +210,7 @@ version = "0.1.0" dependencies = [ "axum", + "futures", "tokio", "tower", "tower-http", diff --git a/chartered-web/Cargo.toml b/chartered-web/Cargo.toml index e50ae48..d1ac7f5 100644 --- a/chartered-web/Cargo.toml +++ a/chartered-web/Cargo.toml @@ -7,6 +7,7 @@ [dependencies] axum = "0.2" +futures = "0.3" tokio = { version = "1", features = ["full"] } tower = { version = "0.4", features = ["util", "filter"] } tower-http = { version = "0.1", features = ["trace"] } diff --git a/test-using-chartered/.gitignore b/test-using-chartered/.gitignore deleted file mode 100644 index 2c96eb1..0000000 100644 --- a/test-using-chartered/.gitignore +++ /dev/null @@ -1,2 +1,0 @@ -target/ -Cargo.lock diff --git a/test-using-chartered/Cargo.toml b/test-using-chartered/Cargo.toml deleted file mode 100644 index 471bf5c..0000000 100644 --- a/test-using-chartered/Cargo.toml +++ /dev/null @@ -1,9 +1,0 @@ -[package] -name = "test-using-chartered" -version = "0.1.0" -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -charteredtest = { version = "1", registry = "chartered" } diff --git a/chartered-git/src/main.rs b/chartered-git/src/main.rs index 92529cc..fb358e6 100644 --- a/chartered-git/src/main.rs +++ a/chartered-git/src/main.rs @@ -177,21 +177,17 @@ }"#, ); - let ch_ar_tree = PackFileEntry::Tree(vec![ - TreeItem { - kind: TreeItemKind::File, - name: "charteredtest", - hash: test_crate_file.hash()?, - } - ]); + let ch_ar_tree = PackFileEntry::Tree(vec![TreeItem { + kind: TreeItemKind::File, + name: "charteredtest", + hash: test_crate_file.hash()?, + }]); - let ch_tree = PackFileEntry::Tree(vec![ - TreeItem { - kind: TreeItemKind::Directory, - name: "ar", - hash: ch_ar_tree.hash()?, - } - ]); + let ch_tree = PackFileEntry::Tree(vec![TreeItem { + kind: TreeItemKind::Directory, + name: "ar", + hash: ch_ar_tree.hash()?, + }]); let root_tree = PackFileEntry::Tree(vec![ TreeItem { diff --git a/chartered-web/src/main.rs b/chartered-web/src/main.rs index 7e3d561..ad7525f 100644 --- a/chartered-web/src/main.rs +++ a/chartered-web/src/main.rs @@ -1,4 +1,64 @@ +mod endpoints; +mod middleware; + +use axum::{ + handler::{delete, get, put}, + Router, +}; +use tower::{filter::AsyncFilterLayer, ServiceBuilder}; + +async fn hello_world() -> &'static str { + "hello, world!" +} + +// there's some sort of issue with monomorphization of axum routes +// which causes compile times to increase exponentially with every +// new route, the workaround is to box the router down to a +// dynamically dispatched version with every new route. +macro_rules! axum_box_after_every_route { + (Router::new()$(.route($path:expr, $svc:expr$(,)?))*) => { + Router::new() + $( + .route($path, $svc) + .boxed() + )* + }; +} + #[tokio::main] async fn main() { - println!("Hello, world!"); + let api_authenticated = axum_box_after_every_route!(Router::new() + .route("/crates/new", put(hello_world)) + .route("/crates/search", get(hello_world)) + .route("/crates/:crate/owners", get(hello_world)) + .route("/crates/:crate/owners", put(hello_world)) + .route("/crates/:crate/owners", delete(hello_world)) + .route("/crates/:crate/:version/yank", delete(hello_world)) + .route("/crates/:crate/:version/unyank", put(hello_world)) + .route( + "/crates/:crate/:version/download", + get(endpoints::cargo_api::download), + )) + .layer( + ServiceBuilder::new() + .layer_fn(middleware::auth::AuthMiddleware) + .into_inner(), + ); + + let middleware_stack = ServiceBuilder::new() + .layer(AsyncFilterLayer::new(|req| async { + eprintln!("{:#?}", req); + Ok::<_, std::convert::Infallible>(req) + })) + .into_inner(); + + let app = Router::new() + .route("/", get(hello_world)) + .nest("/a/:key/api/v1", api_authenticated) + .layer(middleware_stack); + + axum::Server::bind(&"0.0.0.0:8888".parse().unwrap()) + .serve(app.into_make_service()) + .await + .unwrap(); } diff --git a/test-using-chartered/.cargo/config.toml b/test-using-chartered/.cargo/config.toml deleted file mode 100644 index 37f88f8..0000000 100644 --- a/test-using-chartered/.cargo/config.toml +++ /dev/null @@ -1,2 +1,0 @@ -[registries] -chartered = { index = "ssh://127.0.0.1:2233/" } diff --git a/test-using-chartered/src/lib.rs b/test-using-chartered/src/lib.rs deleted file mode 100644 index 31e1bb2..0000000 100644 --- a/test-using-chartered/src/lib.rs +++ /dev/null @@ -1,7 +1,0 @@ -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} diff --git a/chartered-web/src/endpoints/mod.rs b/chartered-web/src/endpoints/mod.rs new file mode 100644 index 0000000..168c1af 100644 --- /dev/null +++ a/chartered-web/src/endpoints/mod.rs @@ -1,0 +1,1 @@ +pub mod cargo_api; diff --git a/chartered-web/src/middleware/auth.rs b/chartered-web/src/middleware/auth.rs new file mode 100644 index 0000000..a6a6154 100644 --- /dev/null +++ a/chartered-web/src/middleware/auth.rs @@ -1,0 +1,43 @@ +use axum::http::{Request, Response, StatusCode}; +use futures::future::BoxFuture; +use std::task::{Context, Poll}; +use tower::Service; + +#[derive(Clone)] +pub struct AuthMiddleware(pub S); + +impl Service> for AuthMiddleware +where + S: Service, Response = Response> + Clone + Send + 'static, + S::Future: Send + 'static, + ReqBody: Send + 'static, + ResBody: Default + Send + 'static, +{ + type Response = S::Response; + type Error = S::Error; + type Future = BoxFuture<'static, Result>; + + fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { + self.0.poll_ready(cx) + } + + fn call(&mut self, req: Request) -> Self::Future { + // best practice is to clone the inner service like this + // see https://github.com/tower-rs/tower/issues/547 for details + let clone = self.0.clone(); + let mut inner = std::mem::replace(&mut self.0, clone); + + Box::pin(async move { + if true { + return Ok(Response::builder() + .status(StatusCode::UNAUTHORIZED) + .body(ResBody::default()) + .unwrap()); + } + + let res: Response = inner.call(req).await?; + + Ok(res) + }) + } +} diff --git a/chartered-web/src/middleware/mod.rs b/chartered-web/src/middleware/mod.rs new file mode 100644 index 0000000..0e4a05d 100644 --- /dev/null +++ a/chartered-web/src/middleware/mod.rs @@ -1,0 +1,1 @@ +pub mod auth; diff --git a/chartered-web/src/endpoints/cargo_api/download.rs b/chartered-web/src/endpoints/cargo_api/download.rs new file mode 100644 index 0000000..a03b66a 100644 --- /dev/null +++ a/chartered-web/src/endpoints/cargo_api/download.rs @@ -1,0 +1,3 @@ +pub async fn handle() -> &'static str { + "download" +} diff --git a/chartered-web/src/endpoints/cargo_api/mod.rs b/chartered-web/src/endpoints/cargo_api/mod.rs new file mode 100644 index 0000000..4ca25db 100644 --- /dev/null +++ a/chartered-web/src/endpoints/cargo_api/mod.rs @@ -1,0 +1,3 @@ +mod download; + +pub use download::handle as download; -- rgit 0.1.3