🏗️ 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: async-std support !!

Fuwn 49cd0660 513705a7

+106 -8
+6 -2
Cargo.toml
··· 18 18 logger = ["pretty_env_logger"] 19 19 auto-deduce-mime = ["tree_magic"] 20 20 response-macros = [] 21 + tokio = ["dep:tokio", "tokio-openssl"] 22 + async-std = ["dep:async-std", "async-std-openssl"] 21 23 22 24 [dependencies] 23 25 # SSL 24 26 openssl = "0.10.38" 25 - tokio-openssl = "0.6.3" 27 + tokio-openssl = { version = "0.6.3", optional = true } 28 + async-std-openssl = { version = "0.6.3", optional = true } 26 29 27 30 # Non-blocking I/O 28 - tokio = { version = "1.26.0", features = ["full"] } 31 + tokio = { version = "1.26.0", features = ["full"], optional = true } 29 32 async-trait = "0.1.68" 33 + async-std = { version = "1.12.0", features = ["attributes"], optional = true } 30 34 31 35 # Logging 32 36 pretty_env_logger = { version = "0.4.0", optional = true }
+2 -2
Makefile.toml
··· 4 4 toolchain = "nightly" 5 5 6 6 [tasks.check] 7 - args = ["check"] 7 + args = ["check", "--features", "logger,auto-deduce-mime,response-macros,${@}"] 8 8 command = "cargo" 9 9 toolchain = "nightly" 10 10 11 11 [tasks.clippy] 12 - args = ["clippy"] 12 + args = ["clippy", "--features", "logger,auto-deduce-mime,response-macros,${@}"] 13 13 command = "cargo" 14 14 toolchain = "nightly" 15 15
+2
README.md
··· 7 7 Windmark is an elegant and highly performant, async Gemini server framework for 8 8 the modern age! 9 9 10 + Now supporting both [Tokio](https://github.com/tokio-rs/tokio) and [`async-std`](https://github.com/async-rs/async-std)! 11 + 10 12 ## Usage 11 13 12 14 Check out an example starter project
+29
examples/simple_async_std.rs
··· 1 + // This file is part of Windmark <https://github.com/gemrest/windmark>. 2 + // Copyright (C) 2022-2022 Fuwn <contact@fuwn.me> 3 + // 4 + // This program is free software: you can redistribute it and/or modify 5 + // it under the terms of the GNU General Public License as published by 6 + // the Free Software Foundation, version 3. 7 + // 8 + // This program is distributed in the hope that it will be useful, but 9 + // WITHOUT ANY WARRANTY; without even the implied warranty of 10 + // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 + // General Public License for more details. 12 + // 13 + // You should have received a copy of the GNU General Public License 14 + // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 + // 16 + // Copyright (C) 2022-2022 Fuwn <contact@fuwn.me> 17 + // SPDX-License-Identifier: GPL-3.0-only 18 + 19 + //! `cargo run --example simple_async_std --features async-std` 20 + 21 + #[windmark::main] 22 + async fn main() -> Result<(), Box<dyn std::error::Error>> { 23 + windmark::Router::new() 24 + .set_private_key_file("windmark_private.pem") 25 + .set_certificate_file("windmark_public.pem") 26 + .mount("/", |_| windmark::Response::success("Hello, async-std!")) 27 + .run() 28 + .await 29 + }
+29
examples/simple_tokio.rs
··· 1 + // This file is part of Windmark <https://github.com/gemrest/windmark>. 2 + // Copyright (C) 2022-2022 Fuwn <contact@fuwn.me> 3 + // 4 + // This program is free software: you can redistribute it and/or modify 5 + // it under the terms of the GNU General Public License as published by 6 + // the Free Software Foundation, version 3. 7 + // 8 + // This program is distributed in the hope that it will be useful, but 9 + // WITHOUT ANY WARRANTY; without even the implied warranty of 10 + // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 + // General Public License for more details. 12 + // 13 + // You should have received a copy of the GNU General Public License 14 + // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 + // 16 + // Copyright (C) 2022-2022 Fuwn <contact@fuwn.me> 17 + // SPDX-License-Identifier: GPL-3.0-only 18 + 19 + //! `cargo run --example simple_tokio --features tokio` 20 + 21 + #[windmark::main] 22 + async fn main() -> Result<(), Box<dyn std::error::Error>> { 23 + windmark::Router::new() 24 + .set_private_key_file("windmark_private.pem") 25 + .set_certificate_file("windmark_public.pem") 26 + .mount("/", |_| windmark::Response::success("Hello, Tokio!")) 27 + .run() 28 + .await 29 + }
+3
src/lib.rs
··· 40 40 #[macro_use] 41 41 extern crate log; 42 42 43 + #[cfg(feature = "async-std")] 44 + pub use async_std::main; 43 45 pub use module::{AsyncModule, Module}; 44 46 pub use response::Response; 45 47 pub use router::Router; 48 + #[cfg(feature = "tokio")] 46 49 pub use tokio::main;
+1 -1
src/response.rs
··· 98 98 #[must_use] 99 99 pub fn binary_success_auto(content: &[u8]) -> Self { 100 100 Self::new(22, String::from_utf8_lossy(content)) 101 - .with_mime(&tree_magic::from_u8(&*content)) 101 + .with_mime(&tree_magic::from_u8(content)) 102 102 .clone() 103 103 } 104 104
+34 -3
src/router.rs
··· 25 25 time, 26 26 }; 27 27 28 + #[cfg(feature = "async-std")] 29 + use async_std::{ 30 + io::{ReadExt, WriteExt}, 31 + sync::Mutex as AsyncMutex, 32 + }; 28 33 use openssl::ssl::{self, SslAcceptor, SslMethod}; 34 + #[cfg(feature = "tokio")] 29 35 use tokio::{ 30 36 io::{AsyncReadExt, AsyncWriteExt}, 31 37 sync::Mutex as AsyncMutex, ··· 47 53 48 54 macro_rules! block { 49 55 ($body:expr) => { 56 + #[cfg(feature = "tokio")] 50 57 ::tokio::task::block_in_place(|| { 51 58 ::tokio::runtime::Handle::current().block_on(async { $body }); 52 59 }); 60 + #[cfg(feature = "async-std")] 61 + ::async_std::task::block_on(async { $body }); 53 62 }; 54 63 } 55 64 ··· 69 78 } 70 79 }; 71 80 } 81 + 82 + #[cfg(feature = "tokio")] 83 + type Stream = tokio_openssl::SslStream<tokio::net::TcpStream>; 84 + #[cfg(feature = "async-std")] 85 + type Stream = async_std_openssl::SslStream<async_std::net::TcpStream>; 72 86 73 87 /// A router which takes care of all tasks a Windmark server should handle: 74 88 /// response generation, panics, logging, and more. ··· 266 280 pretty_env_logger::init(); 267 281 } 268 282 283 + #[cfg(feature = "tokio")] 269 284 let listener = 270 285 tokio::net::TcpListener::bind(format!("0.0.0.0:{}", self.port)).await?; 286 + #[cfg(feature = "async-std")] 287 + let listener = 288 + async_std::net::TcpListener::bind(format!("0.0.0.0:{}", self.port)) 289 + .await?; 271 290 272 291 #[cfg(feature = "logger")] 273 292 info!("windmark is listening for connections"); ··· 277 296 Ok((stream, _)) => { 278 297 let mut self_clone = self.clone(); 279 298 let acceptor = self_clone.ssl_acceptor.clone(); 299 + #[cfg(feature = "tokio")] 300 + let spawner = tokio::spawn; 301 + #[cfg(feature = "async-std")] 302 + let spawner = async_std::task::spawn; 280 303 281 - tokio::spawn(async move { 304 + spawner(async move { 282 305 let ssl = match ssl::Ssl::new(acceptor.context()) { 283 306 Ok(ssl) => ssl, 284 307 Err(e) => { ··· 288 311 } 289 312 }; 290 313 291 - match tokio_openssl::SslStream::new(ssl, stream) { 314 + #[cfg(feature = "tokio")] 315 + let quick_stream = tokio_openssl::SslStream::new(ssl, stream); 316 + #[cfg(feature = "async-std")] 317 + let quick_stream = async_std_openssl::SslStream::new(ssl, stream); 318 + 319 + match quick_stream { 292 320 Ok(mut stream) => { 293 321 if let Err(e) = std::pin::Pin::new(&mut stream).accept().await { 294 322 println!("stream accept error: {e:?}"); ··· 312 340 #[allow(clippy::too_many_lines)] 313 341 async fn handle( 314 342 &mut self, 315 - stream: &mut tokio_openssl::SslStream<tokio::net::TcpStream>, 343 + stream: &mut Stream, 316 344 ) -> Result<(), Box<dyn Error>> { 317 345 let mut buffer = [0u8; 1024]; 318 346 let mut url = Url::parse("gemini://fuwn.me/")?; ··· 473 501 ) 474 502 .await?; 475 503 504 + #[cfg(feature = "tokio")] 476 505 stream.shutdown().await?; 506 + #[cfg(feature = "async-std")] 507 + stream.get_mut().shutdown(std::net::Shutdown::Both)?; 477 508 478 509 Ok(()) 479 510 }