diff --git a/CHANGELOG.md b/CHANGELOG.md index 07fc9ee..48a05a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - build time and size by [@Alch-Emi] ### Changed - Added route API [@Alch-Emi](https://github.com/Alch-Emi) +- API for adding handlers now accepts async handlers [@Alch-Emi](https://github.com/Alch-Emi) ## [0.3.0] - 2020-11-14 ### Added diff --git a/Cargo.toml b/Cargo.toml index 9ad991d..0f004c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,6 @@ tokio = { version = "0.3.1", features = ["io-util","net","time", "rt"] } mime = "0.3.16" uriparse = "0.6.3" percent-encoding = "2.1.0" -futures-core = "0.3.7" log = "0.4.11" webpki = "0.21.0" lazy_static = "1.4.0" @@ -28,5 +27,4 @@ mime_guess = { version = "2.0.3", optional = true } [dev-dependencies] env_logger = "0.8.1" -futures-util = "0.3.7" tokio = { version = "0.3.1", features = ["macros", "rt-multi-thread", "sync"] } diff --git a/examples/certificates.rs b/examples/certificates.rs index 143c71c..6fdcafe 100644 --- a/examples/certificates.rs +++ b/examples/certificates.rs @@ -1,6 +1,4 @@ use anyhow::*; -use futures_core::future::BoxFuture; -use futures_util::FutureExt; use log::LevelFilter; use tokio::sync::RwLock; use northstar::{Certificate, GEMINI_MIME, GEMINI_PORT, Request, Response, Server}; @@ -31,44 +29,42 @@ async fn main() -> Result<()> { /// selecting a username. They'll then get a message confirming their account creation. /// Any time this user visits the site in the future, they'll get a personalized welcome /// message. -fn handle_request(users: Arc>>, request: Request) -> BoxFuture<'static, Result> { - async move { - if let Some(Certificate(cert_bytes)) = request.certificate() { - // The user provided a certificate - let users_read = users.read().await; - if let Some(user) = users_read.get(cert_bytes) { - // The user has already registered +async fn handle_request(users: Arc>>, request: Request) -> Result { + if let Some(Certificate(cert_bytes)) = request.certificate() { + // The user provided a certificate + let users_read = users.read().await; + if let Some(user) = users_read.get(cert_bytes) { + // The user has already registered + Ok( + Response::success_with_body( + &GEMINI_MIME, + format!("Welcome {}!", user) + ) + ) + } else { + // The user still needs to register + drop(users_read); + if let Some(query_part) = request.uri().query() { + // The user provided some input (a username request) + let username = query_part.as_str(); + let mut users_write = users.write().await; + users_write.insert(cert_bytes.clone(), username.to_owned()); Ok( Response::success_with_body( &GEMINI_MIME, - format!("Welcome {}!", user) + format!( + "Your account has been created {}! Welcome!", + username + ) ) ) } else { - // The user still needs to register - drop(users_read); - if let Some(query_part) = request.uri().query() { - // The user provided some input (a username request) - let username = query_part.as_str(); - let mut users_write = users.write().await; - users_write.insert(cert_bytes.clone(), username.to_owned()); - Ok( - Response::success_with_body( - &GEMINI_MIME, - format!( - "Your account has been created {}! Welcome!", - username - ) - ) - ) - } else { - // The user didn't provide input, and should be prompted - Response::input("What username would you like?") - } + // The user didn't provide input, and should be prompted + Response::input("What username would you like?") } - } else { - // The user didn't provide a certificate - Ok(Response::client_certificate_required()) } - }.boxed() + } else { + // The user didn't provide a certificate + Ok(Response::client_certificate_required()) + } } diff --git a/examples/document.rs b/examples/document.rs index 3135c5f..9d4bdc2 100644 --- a/examples/document.rs +++ b/examples/document.rs @@ -1,6 +1,4 @@ use anyhow::*; -use futures_core::future::BoxFuture; -use futures_util::FutureExt; use log::LevelFilter; use northstar::{Server, Request, Response, GEMINI_PORT, Document}; use northstar::document::HeadingLevel::*; @@ -17,34 +15,31 @@ async fn main() -> Result<()> { .await } -fn handle_request(_request: Request) -> BoxFuture<'static, Result> { - async move { - let response = Document::new() - .add_preformatted(include_str!("northstar_logo.txt")) - .add_blank_line() - .add_link("https://docs.rs/northstar", "Documentation") - .add_link("https://github.com/panicbit/northstar", "GitHub") - .add_blank_line() - .add_heading(H1, "Usage") - .add_blank_line() - .add_text("Add the latest version of northstar to your `Cargo.toml`.") - .add_blank_line() - .add_heading(H2, "Manually") - .add_blank_line() - .add_preformatted_with_alt("toml", r#"northstar = "0.3.0" # check crates.io for the latest version"#) - .add_blank_line() - .add_heading(H2, "Automatically") - .add_blank_line() - .add_preformatted_with_alt("sh", "cargo add northstar") - .add_blank_line() - .add_heading(H1, "Generating a key & certificate") - .add_blank_line() - .add_preformatted_with_alt("sh", concat!( - "mkdir cert && cd cert\n", - "openssl req -x509 -nodes -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365", - )) - .into(); - Ok(response) - } - .boxed() +async fn handle_request(_request: Request) -> Result { + let response = Document::new() + .add_preformatted(include_str!("northstar_logo.txt")) + .add_blank_line() + .add_link("https://docs.rs/northstar", "Documentation") + .add_link("https://github.com/panicbit/northstar", "GitHub") + .add_blank_line() + .add_heading(H1, "Usage") + .add_blank_line() + .add_text("Add the latest version of northstar to your `Cargo.toml`.") + .add_blank_line() + .add_heading(H2, "Manually") + .add_blank_line() + .add_preformatted_with_alt("toml", r#"northstar = "0.3.0" # check crates.io for the latest version"#) + .add_blank_line() + .add_heading(H2, "Automatically") + .add_blank_line() + .add_preformatted_with_alt("sh", "cargo add northstar") + .add_blank_line() + .add_heading(H1, "Generating a key & certificate") + .add_blank_line() + .add_preformatted_with_alt("sh", concat!( + "mkdir cert && cd cert\n", + "openssl req -x509 -nodes -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365", + )) + .into(); + Ok(response) } diff --git a/examples/routing.rs b/examples/routing.rs index 04bded6..3f732d5 100644 --- a/examples/routing.rs +++ b/examples/routing.rs @@ -1,6 +1,4 @@ use anyhow::*; -use futures_core::future::BoxFuture; -use futures_util::FutureExt; use log::LevelFilter; use northstar::{Document, document::HeadingLevel, Request, Response, GEMINI_PORT}; @@ -18,25 +16,19 @@ async fn main() -> Result<()> { .await } -fn handle_base(req: Request) -> BoxFuture<'static, Result> { +async fn handle_base(req: Request) -> Result { let doc = generate_doc("base", &req); - async move { - Ok(Response::document(doc)) - }.boxed() + Ok(Response::document(doc)) } -fn handle_short(req: Request) -> BoxFuture<'static, Result> { +async fn handle_short(req: Request) -> Result { let doc = generate_doc("short", &req); - async move { - Ok(Response::document(doc)) - }.boxed() + Ok(Response::document(doc)) } -fn handle_long(req: Request) -> BoxFuture<'static, Result> { +async fn handle_long(req: Request) -> Result { let doc = generate_doc("long", &req); - async move { - Ok(Response::document(doc)) - }.boxed() + Ok(Response::document(doc)) } fn generate_doc(route_name: &str, req: &Request) -> Document { diff --git a/examples/serve_dir.rs b/examples/serve_dir.rs index de3e0b0..bb81add 100644 --- a/examples/serve_dir.rs +++ b/examples/serve_dir.rs @@ -1,6 +1,4 @@ use anyhow::*; -use futures_core::future::BoxFuture; -use futures_util::FutureExt; use log::LevelFilter; use northstar::{Server, Request, Response, GEMINI_PORT}; @@ -16,12 +14,9 @@ async fn main() -> Result<()> { .await } -fn handle_request(request: Request) -> BoxFuture<'static, Result> { - async move { - let path = request.path_segments(); - let response = northstar::util::serve_dir("public", &path).await?; +async fn handle_request(request: Request) -> Result { + let path = request.path_segments(); + let response = northstar::util::serve_dir("public", &path).await?; - Ok(response) - } - .boxed() + Ok(response) } diff --git a/src/lib.rs b/src/lib.rs index 87d923f..1926bfe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,8 +7,9 @@ use std::{ sync::Arc, path::PathBuf, time::Duration, + pin::Pin, }; -use futures_core::future::BoxFuture; +use std::future::Future; use tokio::{ prelude::*, io::{self, BufStream}, @@ -36,13 +37,12 @@ pub use types::*; pub const REQUEST_URI_MAX_LEN: usize = 1024; pub const GEMINI_PORT: u16 = 1965; -type Handler = Arc HandlerResponse + Send + Sync>; -pub (crate) type HandlerResponse = BoxFuture<'static, Result>; +type Handler = Box HandlerResponse + Send + Sync>; +pub (crate) type HandlerResponse = Pin> + Send>>; #[derive(Clone)] pub struct Server { tls_acceptor: TlsAcceptor, - listener: Arc, routes: Arc>, timeout: Duration, complex_timeout: Option, @@ -53,9 +53,9 @@ impl Server { Builder::bind(addr) } - async fn serve(self) -> Result<()> { + async fn serve(self, listener: TcpListener) -> Result<()> { loop { - let (stream, _addr) = self.listener.accept().await + let (stream, _addr) = listener.accept().await .context("Failed to accept client")?; let this = self.clone(); @@ -293,11 +293,13 @@ impl Builder { /// "endpoint". Entering a relative or malformed path will result in a panic. /// /// For more information about routing mechanics, see the docs for [`RoutingNode`]. - pub fn add_route(mut self, path: &'static str, handler: H) -> Self + pub fn add_route(mut self, path: &'static str, handler: H) -> Self where - H: Fn(Request) -> HandlerResponse + Send + Sync + 'static, + H: Send + Sync + 'static + Fn(Request) -> F, + F: Send + Sync + 'static + Future> { - self.routes.add_route(path, Arc::new(handler)); + let wrapped = Box::new(move|req| Box::pin((handler)(req)) as HandlerResponse); + self.routes.add_route(path, wrapped); self } @@ -312,13 +314,12 @@ impl Builder { let server = Server { tls_acceptor: TlsAcceptor::from(config), - listener: Arc::new(listener), routes: Arc::new(self.routes), timeout: self.timeout, complex_timeout: self.complex_body_timeout_override, }; - server.serve().await + server.serve(listener).await } } diff --git a/src/util.rs b/src/util.rs index 5c623aa..33ca6d6 100644 --- a/src/util.rs +++ b/src/util.rs @@ -13,7 +13,7 @@ use crate::types::{Document, document::HeadingLevel::*}; use crate::types::Response; use std::panic::{catch_unwind, AssertUnwindSafe}; use std::task::Poll; -use futures_core::future::Future; +use std::future::Future; use tokio::time; #[cfg(feature="serve_dir")]