diff options
| author | Fuwn <[email protected]> | 2023-04-18 21:29:47 +0000 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2023-04-18 21:29:47 +0000 |
| commit | 49cd06600431bc314e9c1cebfc73ecfbe5d9f894 (patch) | |
| tree | 214acfd8abe32069f6af5001f54bf8c6fa4dab24 | |
| parent | feat: improve macro hygiene (diff) | |
| download | windmark-49cd06600431bc314e9c1cebfc73ecfbe5d9f894.tar.xz windmark-49cd06600431bc314e9c1cebfc73ecfbe5d9f894.zip | |
feat: async-std support !!
| -rw-r--r-- | Cargo.toml | 8 | ||||
| -rw-r--r-- | Makefile.toml | 4 | ||||
| -rw-r--r-- | README.md | 2 | ||||
| -rw-r--r-- | examples/simple_async_std.rs | 29 | ||||
| -rw-r--r-- | examples/simple_tokio.rs | 29 | ||||
| -rw-r--r-- | src/lib.rs | 3 | ||||
| -rw-r--r-- | src/response.rs | 2 | ||||
| -rw-r--r-- | src/router.rs | 37 |
8 files changed, 106 insertions, 8 deletions
@@ -18,15 +18,19 @@ categories = ["web-programming"] logger = ["pretty_env_logger"] auto-deduce-mime = ["tree_magic"] response-macros = [] +tokio = ["dep:tokio", "tokio-openssl"] +async-std = ["dep:async-std", "async-std-openssl"] [dependencies] # SSL openssl = "0.10.38" -tokio-openssl = "0.6.3" +tokio-openssl = { version = "0.6.3", optional = true } +async-std-openssl = { version = "0.6.3", optional = true } # Non-blocking I/O -tokio = { version = "1.26.0", features = ["full"] } +tokio = { version = "1.26.0", features = ["full"], optional = true } async-trait = "0.1.68" +async-std = { version = "1.12.0", features = ["attributes"], optional = true } # Logging pretty_env_logger = { version = "0.4.0", optional = true } diff --git a/Makefile.toml b/Makefile.toml index 525424a..0b44382 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -4,12 +4,12 @@ command = "cargo" toolchain = "nightly" [tasks.check] -args = ["check"] +args = ["check", "--features", "logger,auto-deduce-mime,response-macros,${@}"] command = "cargo" toolchain = "nightly" [tasks.clippy] -args = ["clippy"] +args = ["clippy", "--features", "logger,auto-deduce-mime,response-macros,${@}"] command = "cargo" toolchain = "nightly" @@ -7,6 +7,8 @@ Windmark is an elegant and highly performant, async Gemini server framework for the modern age! +Now supporting both [Tokio](https://github.com/tokio-rs/tokio) and [`async-std`](https://github.com/async-rs/async-std)! + ## Usage Check out an example starter project diff --git a/examples/simple_async_std.rs b/examples/simple_async_std.rs new file mode 100644 index 0000000..cc2b498 --- /dev/null +++ b/examples/simple_async_std.rs @@ -0,0 +1,29 @@ +// This file is part of Windmark <https://github.com/gemrest/windmark>. +// Copyright (C) 2022-2022 Fuwn <[email protected]> +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 3. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +// Copyright (C) 2022-2022 Fuwn <[email protected]> +// SPDX-License-Identifier: GPL-3.0-only + +//! `cargo run --example simple_async_std --features async-std` + +#[windmark::main] +async fn main() -> Result<(), Box<dyn std::error::Error>> { + windmark::Router::new() + .set_private_key_file("windmark_private.pem") + .set_certificate_file("windmark_public.pem") + .mount("/", |_| windmark::Response::success("Hello, async-std!")) + .run() + .await +} diff --git a/examples/simple_tokio.rs b/examples/simple_tokio.rs new file mode 100644 index 0000000..21b2a98 --- /dev/null +++ b/examples/simple_tokio.rs @@ -0,0 +1,29 @@ +// This file is part of Windmark <https://github.com/gemrest/windmark>. +// Copyright (C) 2022-2022 Fuwn <[email protected]> +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 3. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +// Copyright (C) 2022-2022 Fuwn <[email protected]> +// SPDX-License-Identifier: GPL-3.0-only + +//! `cargo run --example simple_tokio --features tokio` + +#[windmark::main] +async fn main() -> Result<(), Box<dyn std::error::Error>> { + windmark::Router::new() + .set_private_key_file("windmark_private.pem") + .set_certificate_file("windmark_public.pem") + .mount("/", |_| windmark::Response::success("Hello, Tokio!")) + .run() + .await +} @@ -40,7 +40,10 @@ pub mod utilities; #[macro_use] extern crate log; +#[cfg(feature = "async-std")] +pub use async_std::main; pub use module::{AsyncModule, Module}; pub use response::Response; pub use router::Router; +#[cfg(feature = "tokio")] pub use tokio::main; diff --git a/src/response.rs b/src/response.rs index 9a8efb8..90950da 100644 --- a/src/response.rs +++ b/src/response.rs @@ -98,7 +98,7 @@ impl Response { #[must_use] pub fn binary_success_auto(content: &[u8]) -> Self { Self::new(22, String::from_utf8_lossy(content)) - .with_mime(&tree_magic::from_u8(&*content)) + .with_mime(&tree_magic::from_u8(content)) .clone() } diff --git a/src/router.rs b/src/router.rs index 1bb295c..8df8c03 100644 --- a/src/router.rs +++ b/src/router.rs @@ -25,7 +25,13 @@ use std::{ time, }; +#[cfg(feature = "async-std")] +use async_std::{ + io::{ReadExt, WriteExt}, + sync::Mutex as AsyncMutex, +}; use openssl::ssl::{self, SslAcceptor, SslMethod}; +#[cfg(feature = "tokio")] use tokio::{ io::{AsyncReadExt, AsyncWriteExt}, sync::Mutex as AsyncMutex, @@ -47,9 +53,12 @@ use crate::{ macro_rules! block { ($body:expr) => { + #[cfg(feature = "tokio")] ::tokio::task::block_in_place(|| { ::tokio::runtime::Handle::current().block_on(async { $body }); }); + #[cfg(feature = "async-std")] + ::async_std::task::block_on(async { $body }); }; } @@ -70,6 +79,11 @@ macro_rules! or_error { }; } +#[cfg(feature = "tokio")] +type Stream = tokio_openssl::SslStream<tokio::net::TcpStream>; +#[cfg(feature = "async-std")] +type Stream = async_std_openssl::SslStream<async_std::net::TcpStream>; + /// A router which takes care of all tasks a Windmark server should handle: /// response generation, panics, logging, and more. #[derive(Clone)] @@ -266,8 +280,13 @@ impl Router { pretty_env_logger::init(); } + #[cfg(feature = "tokio")] let listener = tokio::net::TcpListener::bind(format!("0.0.0.0:{}", self.port)).await?; + #[cfg(feature = "async-std")] + let listener = + async_std::net::TcpListener::bind(format!("0.0.0.0:{}", self.port)) + .await?; #[cfg(feature = "logger")] info!("windmark is listening for connections"); @@ -277,8 +296,12 @@ impl Router { Ok((stream, _)) => { let mut self_clone = self.clone(); let acceptor = self_clone.ssl_acceptor.clone(); + #[cfg(feature = "tokio")] + let spawner = tokio::spawn; + #[cfg(feature = "async-std")] + let spawner = async_std::task::spawn; - tokio::spawn(async move { + spawner(async move { let ssl = match ssl::Ssl::new(acceptor.context()) { Ok(ssl) => ssl, Err(e) => { @@ -288,7 +311,12 @@ impl Router { } }; - match tokio_openssl::SslStream::new(ssl, stream) { + #[cfg(feature = "tokio")] + let quick_stream = tokio_openssl::SslStream::new(ssl, stream); + #[cfg(feature = "async-std")] + let quick_stream = async_std_openssl::SslStream::new(ssl, stream); + + match quick_stream { Ok(mut stream) => { if let Err(e) = std::pin::Pin::new(&mut stream).accept().await { println!("stream accept error: {e:?}"); @@ -312,7 +340,7 @@ impl Router { #[allow(clippy::too_many_lines)] async fn handle( &mut self, - stream: &mut tokio_openssl::SslStream<tokio::net::TcpStream>, + stream: &mut Stream, ) -> Result<(), Box<dyn Error>> { let mut buffer = [0u8; 1024]; let mut url = Url::parse("gemini://fuwn.me/")?; @@ -473,7 +501,10 @@ impl Router { ) .await?; + #[cfg(feature = "tokio")] stream.shutdown().await?; + #[cfg(feature = "async-std")] + stream.get_mut().shutdown(std::net::Shutdown::Both)?; Ok(()) } |