aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFuwn <[email protected]>2023-04-04 09:12:11 +0000
committerFuwn <[email protected]>2023-04-04 09:12:11 +0000
commitbda843b8f911f379fd8d3af526b9e6619f6a5ca9 (patch)
treee297caaf07d84f2ba9351cc440ffd0c1ec45aa69
parentfeat(cargo): bump 0.2.5 -> 0.3.0 (diff)
downloadwindmark-bda843b8f911f379fd8d3af526b9e6619f6a5ca9.tar.xz
windmark-bda843b8f911f379fd8d3af526b9e6619f6a5ca9.zip
feat(route): native async route support !!
-rw-r--r--examples/windmark.rs15
-rw-r--r--rust-toolchain.toml2
-rw-r--r--src/handler/response/route.rs24
-rw-r--r--src/router.rs55
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!")),
/// );