diff options
| author | Fuwn <[email protected]> | 2023-04-04 09:12:11 +0000 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2023-04-04 09:12:11 +0000 |
| commit | bda843b8f911f379fd8d3af526b9e6619f6a5ca9 (patch) | |
| tree | e297caaf07d84f2ba9351cc440ffd0c1ec45aa69 | |
| parent | feat(cargo): bump 0.2.5 -> 0.3.0 (diff) | |
| download | windmark-bda843b8f911f379fd8d3af526b9e6619f6a5ca9.tar.xz windmark-bda843b8f911f379fd8d3af526b9e6619f6a5ca9.zip | |
feat(route): native async route support !!
| -rw-r--r-- | examples/windmark.rs | 15 | ||||
| -rw-r--r-- | rust-toolchain.toml | 2 | ||||
| -rw-r--r-- | src/handler/response/route.rs | 24 | ||||
| -rw-r--r-- | src/router.rs | 55 |
4 files changed, 81 insertions, 15 deletions
diff --git a/examples/windmark.rs b/examples/windmark.rs index f6857e5..5ddf7a3 100644 --- a/examples/windmark.rs +++ b/examples/windmark.rs @@ -61,6 +61,7 @@ impl windmark::Module for Clicker { async fn main() -> Result<(), Box<dyn std::error::Error>> { let mut error_count = 0; let mut router = Router::new(); + let async_clicks = std::sync::Arc::new(tokio::sync::Mutex::new(0)); router.set_private_key_file("windmark_private.pem"); router.set_certificate_file("windmark_public.pem"); @@ -198,6 +199,20 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { ) } }); + router.mount_async("/async", move |_| { + let async_clicks = async_clicks.clone(); + + async move { + let mut clicks = async_clicks.lock().await; + + *clicks += 1; + + Response::success(*clicks) + } + }); + router.mount_async("/async-nothing", |_| { + async { Response::success("This is an async route.") } + }); router.run().await } diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 776ddcd..864d3c4 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "nightly-2023-03-27" +channel = "1.68.2" diff --git a/src/handler/response/route.rs b/src/handler/response/route.rs index f480b02..91265a3 100644 --- a/src/handler/response/route.rs +++ b/src/handler/response/route.rs @@ -16,13 +16,27 @@ // Copyright (C) 2022-2022 Fuwn <[email protected]> // SPDX-License-Identifier: GPL-3.0-only +use std::{future::Future, pin::Pin}; + use crate::{context::RouteContext, Response}; #[allow(clippy::module_name_repetitions)] -pub trait RouteResponse: - FnMut(RouteContext<'_>) -> Response + Send + Sync -{ +pub trait RouteResponse: Send + Sync { + fn call( + &mut self, + context: RouteContext<'_>, + ) -> Pin<Box<dyn Future<Output = Response> + Send>>; } -impl<T> RouteResponse for T where T: FnMut(RouteContext<'_>) -> Response + Send + Sync -{} +impl<T, F> RouteResponse for T +where + T: FnMut(RouteContext<'_>) -> F + Send + Sync, + F: Future<Output = Response> + Send + 'static, +{ + fn call( + &mut self, + context: RouteContext<'_>, + ) -> Pin<Box<dyn Future<Output = Response> + Send>> { + Box::pin((*self)(context)) + } +} diff --git a/src/router.rs b/src/router.rs index 7761e3c..2744d4a 100644 --- a/src/router.rs +++ b/src/router.rs @@ -133,21 +133,56 @@ impl Router { /// /// ```rust /// windmark::Router::new() - /// .mount("/", |_| windmark::success!("This is the index page!")) - /// .mount("/test", |_| windmark::success!("This is a test page!")); + /// .mount("/", windmark::success!("This is the index page!")) + /// .mount("/test", windmark::success!("This is a test page!")); /// ``` /// /// # Panics /// - /// if the route cannot be mounted. + /// May panic if the route cannot be mounted. pub fn mount( &mut self, route: impl Into<String> + AsRef<str>, - handler: impl RouteResponse + 'static, + mut handler: impl FnMut(RouteContext<'_>) -> Response + Send + Sync + 'static, ) -> &mut Self { + self.mount_async(route, move |context| { + let response = handler(context); + + async move { response } + }); + + self + } + + /// Map routes to URL paths; with async support + /// + /// # Examples + /// + /// ```rust + /// windmark::Router::new().mount_async("/", |_| { + /// async { windmark::Response::success("This is the index page!") } + /// }); + /// ``` + /// + /// # Panics + /// + /// May panic if the route cannot be mounted. + pub fn mount_async<R>( + &mut self, + route: impl Into<String> + AsRef<str>, + mut handler: impl FnMut(RouteContext<'_>) -> R + Send + Sync + 'static, + ) -> &mut Self + where + R: std::future::Future<Output = Response> + Send + 'static, + { self .routes - .insert(route.into(), Arc::new(Mutex::new(Box::new(handler)))) + .insert( + route.into(), + Arc::new(Mutex::new(Box::new(move |context: RouteContext<'_>| { + Box::pin(handler(context)) + }))), + ) .unwrap(); self @@ -369,12 +404,14 @@ impl Router { )); } - (*route.value).lock().unwrap()(RouteContext::new( + let handler = (*route.value).lock().unwrap().call(RouteContext::new( stream.get_ref(), &url, &route.params, &peer_certificate, - )) + )); + + handler.await } else { (*self.error_handler).lock().unwrap()(ErrorContext::new( stream.get_ref(), @@ -606,7 +643,7 @@ impl Router { /// use windmark::Response; /// /// windmark::Router::new().attach_stateless(|r| { - /// r.mount( + /// r.mount_async( /// "/module", /// Box::new(|_| Response::success("This is a module!")), /// ); @@ -625,7 +662,7 @@ impl Router { /// /// mod windmark_example { /// pub fn module(router: &mut windmark::Router) { - /// router.mount( + /// router.mount_async( /// "/module", /// Box::new(|_| windmark::Response::success("This is a module!")), /// ); |