···2424openssl = "0.10.38"
2525tokio-openssl = "0.6.3"
26262727-tokio = { version = "1.26.0", features = ["full"] } # Non-blocking I/O
2727+# Non-blocking I/O
2828+tokio = { version = "1.26.0", features = ["full"] }
2929+async-trait = "0.1.68"
28302931# Logging
3032pretty_env_logger = { version = "0.4.0", optional = true }
+6-5
examples/windmark.rs
···3333 clicks: isize,
3434}
35353636-impl windmark::Module for Clicker {
3737- fn on_attach(&mut self, _: &mut Router) {
3636+#[async_trait::async_trait]
3737+impl windmark::AsyncModule for Clicker {
3838+ async fn on_attach(&mut self, _: &mut Router) {
3839 println!("clicker has been attached!");
3940 }
40414141- fn on_pre_route(&mut self, context: HookContext<'_>) {
4242+ async fn on_pre_route(&mut self, context: HookContext<'_>) {
4243 self.clicks += 1;
43444445 info!(
···4849 );
4950 }
50515151- fn on_post_route(&mut self, context: HookContext<'_>) {
5252+ async fn on_post_route(&mut self, context: HookContext<'_>) {
5253 info!(
5354 "clicker has been called post-route on {} with {} clicks!",
5455 context.url.path(),
···7879 router.attach_stateless(|r| {
7980 r.mount("/module", success!("This is a module!"));
8081 });
8181- router.attach(Clicker::default());
8282+ router.attach_async(Clicker::default());
8283 router.set_pre_route_callback(|context| {
8384 info!(
8485 "accepted connection from {} to {}",
+1-1
src/lib.rs
···4040#[macro_use]
4141extern crate log;
42424343-pub use module::Module;
4343+pub use module::{AsyncModule, Module};
4444pub use response::Response;
4545pub use router::Router;
4646pub use tokio::main;
+5-11
src/module.rs
···1616// Copyright (C) 2022-2022 Fuwn <contact@fuwn.me>
1717// SPDX-License-Identifier: GPL-3.0-only
18181919-use crate::{context::HookContext, Router};
2020-2121-pub trait Module {
2222- /// Called right after the module is attached.
2323- fn on_attach(&mut self, _: &mut Router) {}
2424-2525- /// Called before a route is mounted.
2626- fn on_pre_route(&mut self, _: HookContext<'_>) {}
1919+mod asynchronous;
2020+mod sync;
27212828- /// Called after a route is mounted.
2929- fn on_post_route(&mut self, _: HookContext<'_>) {}
3030-}
2222+#[allow(clippy::module_name_repetitions)]
2323+pub use asynchronous::AsyncModule;
2424+pub use sync::Module;
+94-2
src/router.rs
···2525};
26262727use openssl::ssl::{self, SslAcceptor, SslMethod};
2828-use tokio::io::{AsyncReadExt, AsyncWriteExt};
2828+use tokio::{
2929+ io::{AsyncReadExt, AsyncWriteExt},
3030+ sync::Mutex as AsyncMutex,
3131+};
2932use url::Url;
30333134use crate::{
···3740 PreRouteHook,
3841 RouteResponse,
3942 },
4040- module::Module,
4343+ module::{AsyncModule, Module},
4144 response::Response,
4245};
4346···7679 character_set: String,
7780 languages: Vec<String>,
7881 port: i32,
8282+ async_modules: Arc<AsyncMutex<Vec<Box<dyn AsyncModule + Send>>>>,
7983 modules: Arc<Mutex<Vec<Box<dyn Module + Send>>>>,
8084 fix_path: bool,
8185}
···352356 };
353357 let route = &mut self.routes.at(&fixed_path);
354358359359+ for module in &mut *self.async_modules.lock().await {
360360+ module
361361+ .on_pre_route(HookContext::new(
362362+ stream.get_ref(),
363363+ &url,
364364+ route.as_ref().map_or(None, |route| Some(&route.params)),
365365+ &stream.ssl().peer_certificate(),
366366+ ))
367367+ .await;
368368+ }
369369+355370 for module in &mut *self.modules.lock().unwrap() {
356371 module.on_pre_route(HookContext::new(
357372 stream.get_ref(),
···420435 ))
421436 };
422437438438+ for module in &mut *self.async_modules.lock().await {
439439+ module
440440+ .on_post_route(HookContext::new(
441441+ stream.get_ref(),
442442+ &url,
443443+ route.as_ref().map_or(None, |route| Some(&route.params)),
444444+ &stream.ssl().peer_certificate(),
445445+ ))
446446+ .await;
447447+ }
448448+423449 for module in &mut *self.modules.lock().unwrap() {
424450 module.on_post_route(HookContext::new(
425451 stream.get_ref(),
···678704 self
679705 }
680706707707+ /// Attach a stateful module to a `Router`; with async support
708708+ ///
709709+ /// Like a stateless module is an extension or middleware to a `Router`.
710710+ /// Modules get full access to the `Router` and can be extended by a third
711711+ /// party, but also, can create hooks will be executed through various parts
712712+ /// of a routes' lifecycle. Stateful modules also have state, so variables can
713713+ /// be stored for further access.
714714+ ///
715715+ /// # Panics
716716+ ///
717717+ /// May panic if the stateful module cannot be attached.
718718+ ///
719719+ /// # Examples
720720+ ///
721721+ /// ```rust
722722+ /// use log::info;
723723+ /// use windmark::{context::HookContext, Response, Router};
724724+ ///
725725+ /// #[derive(Default)]
726726+ /// struct Clicker {
727727+ /// clicks: isize,
728728+ /// }
729729+ ///
730730+ /// #[async_trait::async_trait]
731731+ /// impl windmark::AsyncModule for Clicker {
732732+ /// async fn on_attach(&mut self, _: &mut Router) {
733733+ /// info!("clicker has been attached!");
734734+ /// }
735735+ ///
736736+ /// async fn on_pre_route(&mut self, context: HookContext<'_>) {
737737+ /// self.clicks += 1;
738738+ ///
739739+ /// info!(
740740+ /// "clicker has been called pre-route on {} with {} clicks!",
741741+ /// context.url.path(),
742742+ /// self.clicks
743743+ /// );
744744+ /// }
745745+ ///
746746+ /// async fn on_post_route(&mut self, context: HookContext<'_>) {
747747+ /// info!(
748748+ /// "clicker has been called post-route on {} with {} clicks!",
749749+ /// context.url.path(),
750750+ /// self.clicks
751751+ /// );
752752+ /// }
753753+ /// }
754754+ ///
755755+ /// Router::new().attach_async(Clicker::default());
756756+ /// ```
757757+ pub fn attach_async(
758758+ &mut self,
759759+ mut module: impl AsyncModule + 'static + Send,
760760+ ) -> &mut Self {
761761+ tokio::task::block_in_place(|| {
762762+ tokio::runtime::Handle::current().block_on(async {
763763+ module.on_attach(self).await;
764764+765765+ (*self.async_modules.lock().await).push(Box::new(module));
766766+ });
767767+ });
768768+769769+ self
770770+ }
771771+681772 /// Attach a stateful module to a `Router`.
682773 ///
683774 /// Like a stateless module is an extension or middleware to a `Router`.
···835926 languages: vec!["en".to_string()],
836927 port: 1965,
837928 modules: Arc::new(Mutex::new(vec![])),
929929+ async_modules: Arc::new(AsyncMutex::new(vec![])),
838930 fix_path: false,
839931 }
840932 }