🏗️ Elegant & Highly Performant Async Gemini Server Framework for the Modern Age
async framework gemini-protocol protocol gemini rust
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat(route): native async route support !!

Fuwn bda843b8 dd796651

+81 -15
+15
examples/windmark.rs
··· 61 61 async fn main() -> Result<(), Box<dyn std::error::Error>> { 62 62 let mut error_count = 0; 63 63 let mut router = Router::new(); 64 + let async_clicks = std::sync::Arc::new(tokio::sync::Mutex::new(0)); 64 65 65 66 router.set_private_key_file("windmark_private.pem"); 66 67 router.set_certificate_file("windmark_public.pem"); ··· 197 198 "This is a secret route! Identify yourself!", 198 199 ) 199 200 } 201 + }); 202 + router.mount_async("/async", move |_| { 203 + let async_clicks = async_clicks.clone(); 204 + 205 + async move { 206 + let mut clicks = async_clicks.lock().await; 207 + 208 + *clicks += 1; 209 + 210 + Response::success(*clicks) 211 + } 212 + }); 213 + router.mount_async("/async-nothing", |_| { 214 + async { Response::success("This is an async route.") } 200 215 }); 201 216 202 217 router.run().await
+1 -1
rust-toolchain.toml
··· 1 1 [toolchain] 2 - channel = "nightly-2023-03-27" 2 + channel = "1.68.2"
+19 -5
src/handler/response/route.rs
··· 16 16 // Copyright (C) 2022-2022 Fuwn <contact@fuwn.me> 17 17 // SPDX-License-Identifier: GPL-3.0-only 18 18 19 + use std::{future::Future, pin::Pin}; 20 + 19 21 use crate::{context::RouteContext, Response}; 20 22 21 23 #[allow(clippy::module_name_repetitions)] 22 - pub trait RouteResponse: 23 - FnMut(RouteContext<'_>) -> Response + Send + Sync 24 - { 24 + pub trait RouteResponse: Send + Sync { 25 + fn call( 26 + &mut self, 27 + context: RouteContext<'_>, 28 + ) -> Pin<Box<dyn Future<Output = Response> + Send>>; 25 29 } 26 30 27 - impl<T> RouteResponse for T where T: FnMut(RouteContext<'_>) -> Response + Send + Sync 28 - {} 31 + impl<T, F> RouteResponse for T 32 + where 33 + T: FnMut(RouteContext<'_>) -> F + Send + Sync, 34 + F: Future<Output = Response> + Send + 'static, 35 + { 36 + fn call( 37 + &mut self, 38 + context: RouteContext<'_>, 39 + ) -> Pin<Box<dyn Future<Output = Response> + Send>> { 40 + Box::pin((*self)(context)) 41 + } 42 + }
+46 -9
src/router.rs
··· 133 133 /// 134 134 /// ```rust 135 135 /// windmark::Router::new() 136 - /// .mount("/", |_| windmark::success!("This is the index page!")) 137 - /// .mount("/test", |_| windmark::success!("This is a test page!")); 136 + /// .mount("/", windmark::success!("This is the index page!")) 137 + /// .mount("/test", windmark::success!("This is a test page!")); 138 138 /// ``` 139 139 /// 140 140 /// # Panics 141 141 /// 142 - /// if the route cannot be mounted. 142 + /// May panic if the route cannot be mounted. 143 143 pub fn mount( 144 144 &mut self, 145 145 route: impl Into<String> + AsRef<str>, 146 - handler: impl RouteResponse + 'static, 146 + mut handler: impl FnMut(RouteContext<'_>) -> Response + Send + Sync + 'static, 147 147 ) -> &mut Self { 148 + self.mount_async(route, move |context| { 149 + let response = handler(context); 150 + 151 + async move { response } 152 + }); 153 + 154 + self 155 + } 156 + 157 + /// Map routes to URL paths; with async support 158 + /// 159 + /// # Examples 160 + /// 161 + /// ```rust 162 + /// windmark::Router::new().mount_async("/", |_| { 163 + /// async { windmark::Response::success("This is the index page!") } 164 + /// }); 165 + /// ``` 166 + /// 167 + /// # Panics 168 + /// 169 + /// May panic if the route cannot be mounted. 170 + pub fn mount_async<R>( 171 + &mut self, 172 + route: impl Into<String> + AsRef<str>, 173 + mut handler: impl FnMut(RouteContext<'_>) -> R + Send + Sync + 'static, 174 + ) -> &mut Self 175 + where 176 + R: std::future::Future<Output = Response> + Send + 'static, 177 + { 148 178 self 149 179 .routes 150 - .insert(route.into(), Arc::new(Mutex::new(Box::new(handler)))) 180 + .insert( 181 + route.into(), 182 + Arc::new(Mutex::new(Box::new(move |context: RouteContext<'_>| { 183 + Box::pin(handler(context)) 184 + }))), 185 + ) 151 186 .unwrap(); 152 187 153 188 self ··· 369 404 )); 370 405 } 371 406 372 - (*route.value).lock().unwrap()(RouteContext::new( 407 + let handler = (*route.value).lock().unwrap().call(RouteContext::new( 373 408 stream.get_ref(), 374 409 &url, 375 410 &route.params, 376 411 &peer_certificate, 377 - )) 412 + )); 413 + 414 + handler.await 378 415 } else { 379 416 (*self.error_handler).lock().unwrap()(ErrorContext::new( 380 417 stream.get_ref(), ··· 606 643 /// use windmark::Response; 607 644 /// 608 645 /// windmark::Router::new().attach_stateless(|r| { 609 - /// r.mount( 646 + /// r.mount_async( 610 647 /// "/module", 611 648 /// Box::new(|_| Response::success("This is a module!")), 612 649 /// ); ··· 625 662 /// 626 663 /// mod windmark_example { 627 664 /// pub fn module(router: &mut windmark::Router) { 628 - /// router.mount( 665 + /// router.mount_async( 629 666 /// "/module", 630 667 /// Box::new(|_| windmark::Response::success("This is a module!")), 631 668 /// );