From 7db7b700b5574da5e79b8c39fae6f146bb8c7305 Mon Sep 17 00:00:00 2001 From: kana-rus Date: Sun, 4 Aug 2024 00:39:35 +0900 Subject: [PATCH 1/2] rough support on rt_tokio --- ohkami/Cargo.toml | 2 +- ohkami/src/ohkami/mod.rs | 35 +++++++++++++++++++----- ohkami/src/ohkami/router/radix.rs | 15 +--------- ohkami_lib/src/serde_urlencoded/_test.rs | 16 ----------- 4 files changed, 30 insertions(+), 38 deletions(-) diff --git a/ohkami/Cargo.toml b/ohkami/Cargo.toml index 0145ff65..c6ee706e 100644 --- a/ohkami/Cargo.toml +++ b/ohkami/Cargo.toml @@ -21,7 +21,7 @@ features = ["rt_tokio", "nightly", "sse", "ws"] ohkami_lib = { version = "=0.2.5", path = "../ohkami_lib" } ohkami_macros = { version = "=0.8.0", path = "../ohkami_macros" } -tokio = { version = "1", optional = true, features = ["net", "rt", "io-util", "sync", "time"] } +tokio = { version = "1", optional = true, features = ["net", "rt", "io-util", "sync", "time", "signal"] } async-std = { version = "1", optional = true } worker = { version = "0.3", optional = true } diff --git a/ohkami/src/ohkami/mod.rs b/ohkami/src/ohkami/mod.rs index 3e7d181c..6dbff56d 100644 --- a/ohkami/src/ohkami/mod.rs +++ b/ohkami/src/ohkami/mod.rs @@ -273,15 +273,36 @@ impl Ohkami { }; #[cfg(feature="rt_tokio")] { + let ctrl_c = tokio::signal::ctrl_c(); + let (ctrl_c_tx, ctrl_c_rx) = tokio::sync::watch::channel(()); + __rt__::task::spawn(async move { + ctrl_c.await.expect("something was unexpected around Ctrl-C"); + drop(ctrl_c_rx); + }); + + let (close_tx, close_rx) = tokio::sync::watch::channel(()); loop { - let Ok((connection, _)) = listener.accept().await else {continue}; + tokio::select! { + accept = listener.accept() => { + crate::DEBUG!("Accepted {accept:#?}"); + let Ok((connection, _)) = accept else {continue}; + let session = Session::new(router.clone(), connection); + let close_rx = close_rx.clone(); + __rt__::task::spawn(async { + session.manage().await; + drop(close_rx) + }); + }, + _ = ctrl_c_tx.closed() => { + crate::DEBUG!("Recieved Ctrl-C, trying graceful shutdown"); + + crate::DEBUG!("Waiting {} session(s) to finish...", close_tx.receiver_count()); + drop(close_rx); + close_tx.closed().await; - __rt__::task::spawn({ - Session::new( - router.clone(), - connection, - ).manage() - }); + break + } + } } } #[cfg(feature="rt_async-std")] { diff --git a/ohkami/src/ohkami/router/radix.rs b/ohkami/src/ohkami/router/radix.rs index 947a8abf..e543763e 100644 --- a/ohkami/src/ohkami/router/radix.rs +++ b/ohkami/src/ohkami/router/radix.rs @@ -1,6 +1,6 @@ use crate::request::Path; use crate::{Method, Request, Response}; -use crate::fangs::{FangProcCaller, BoxedFPC, Handler}; +use crate::fangs::{FangProcCaller, BoxedFPC}; use ohkami_lib::Slice; use std::fmt::Write as _; @@ -30,21 +30,8 @@ pub(super) struct Node { } } - enum HandlerMarker { None, Some } - impl From> for HandlerMarker { - fn from(h: Option<&Handler>) -> Self { - match h {Some(_) => Self::Some, None => Self::None} - } - } - impl std::fmt::Debug for HandlerMarker { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self {Self::Some => f.write_char('@'), Self::None => f.write_str("None")} - } - } - f.debug_struct("") .field("patterns", &PatternsMarker(self.patterns)) - // .field("proc", &HandlerMarker::from(self.handler.as_ref())) .field("children", &self.children) .finish() } diff --git a/ohkami_lib/src/serde_urlencoded/_test.rs b/ohkami_lib/src/serde_urlencoded/_test.rs index 8cabdfc3..07957da8 100644 --- a/ohkami_lib/src/serde_urlencoded/_test.rs +++ b/ohkami_lib/src/serde_urlencoded/_test.rs @@ -16,15 +16,6 @@ enum Gender { Other, } -#[derive(Serialize, Deserialize, PartialEq, Debug)] -enum Difficulty { - Low, - Middle, - High, - Ultimate, -} - - #[derive(Serialize, Deserialize, PartialEq, Debug)] struct User<'s> { name: Cow<'s, str>, @@ -32,13 +23,6 @@ struct User<'s> { gender: Option, } -#[derive(Serialize, Deserialize, PartialEq, Debug)] -struct Problem<'s> { - title: Cow<'s, str>, - content: String, - difficulty: Option, -} - #[derive(Deserialize, PartialEq, Debug)] struct URLRequest<'req> { url: Cow<'req, str>, From d8fce9ccc3a20892a7ac9e7489642a1b66edf73a Mon Sep 17 00:00:00 2001 From: kana-rus Date: Sun, 4 Aug 2024 01:26:57 +0900 Subject: [PATCH 2/2] organize features & update README --- README.md | 5 +++++ Taskfile.yaml | 2 ++ ohkami/Cargo.toml | 3 ++- ohkami/src/lib.rs | 17 ++++++++++++----- ohkami/src/ohkami/mod.rs | 14 +++++++++++++- 5 files changed, 34 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index d694fec9..4a9df9f7 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,11 @@ Then your project directory has `wrangler.toml`, `package.json` and a Rust libra See README of the [template](https://github.com/ohkami-rs/ohkami-templates/tree/main/worker) for details. +### `"graceful"`:Graceful Shutdown + +Automatically catch Ctrl-C ( SIGINT ) and perform graceful shutdown.\ +Currently, only supported on `rt_tokio`. + ### `"sse"`:Server-Sent Events Ohkami responds with HTTP/1.1 `Transfer-Encoding: chunked`.\ diff --git a/Taskfile.yaml b/Taskfile.yaml index 24293cb1..cfdca353 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -59,6 +59,7 @@ tasks: cmds: - cargo test --lib --features rt_tokio,DEBUG,{{.MAYBE_NIGHTLY}} - cargo test --lib --features rt_tokio,DEBUG,sse,ws,{{.MAYBE_NIGHTLY}} + - cargo test --lib --features rt_tokio,DEBUG,graceful,{{.MAYBE_NIGHTLY}} test_rt_async-std: vars: @@ -101,6 +102,7 @@ tasks: - cargo check --lib --features rt_tokio,{{.MAYBE_NIGHTLY}} - cargo check --lib --features rt_tokio,sse,{{.MAYBE_NIGHTLY}} - cargo check --lib --features rt_tokio,sse,ws,{{.MAYBE_NIGHTLY}} + - cargo check --lib --features rt_tokio,graceful,{{.MAYBE_NIGHTLY}} check_rt_async-std: vars: diff --git a/ohkami/Cargo.toml b/ohkami/Cargo.toml index c6ee706e..079bd2f6 100644 --- a/ohkami/Cargo.toml +++ b/ohkami/Cargo.toml @@ -21,7 +21,7 @@ features = ["rt_tokio", "nightly", "sse", "ws"] ohkami_lib = { version = "=0.2.5", path = "../ohkami_lib" } ohkami_macros = { version = "=0.8.0", path = "../ohkami_macros" } -tokio = { version = "1", optional = true, features = ["net", "rt", "io-util", "sync", "time", "signal"] } +tokio = { version = "1", optional = true, features = ["net", "rt", "io-util", "sync", "time"] } async-std = { version = "1", optional = true } worker = { version = "0.3", optional = true } @@ -47,6 +47,7 @@ nightly = [] testing = [] sse = ["ohkami_lib/stream"] ws = ["dep:sha1"] +graceful = ["rt_tokio", "tokio/signal", "tokio/macros"] ##### DEBUG ##### DEBUG = [ diff --git a/ohkami/src/lib.rs b/ohkami/src/lib.rs index 1104f18f..c5aa7e91 100644 --- a/ohkami/src/lib.rs +++ b/ohkami/src/lib.rs @@ -24,16 +24,23 @@ all(feature="rt_tokio", feature="rt_async-std"), all(feature="rt_async-std", feature="rt_worker"), all(feature="rt_worker", feature="rt_tokio"), -))] compile_error!(" - Can't activate multiple `rt_*` features! -"); +))] compile_error! {" + Can't activate multiple `rt_*` features at once! +"} + +#[cfg(any( + all(feature="graceful", not(feature="rt_tokio")), +))] compile_error! {" + In current versoin, `graceful` feature is only supported on `rt_tokio`. + Please wait for future development for other runtimes... +"} #[cfg(not(feature="DEBUG"))] const _: () = { #[cfg(all(feature="rt_worker", not(target_arch="wasm32")))] - compile_error!(" + compile_error! {" `rt_worker` must be activated on `wasm32` target! (We recommend to touch `.cargo/config.toml`: `[build] target = \"wasm32-unknown-unknown\"`) - "); + "} }; diff --git a/ohkami/src/ohkami/mod.rs b/ohkami/src/ohkami/mod.rs index 6dbff56d..68d53b15 100644 --- a/ohkami/src/ohkami/mod.rs +++ b/ohkami/src/ohkami/mod.rs @@ -272,7 +272,7 @@ impl Ohkami { Err(e) => panic!("Failed to bind TCP listener: {e}"), }; - #[cfg(feature="rt_tokio")] { + #[cfg(all(feature="rt_tokio", feature="graceful"))] { let ctrl_c = tokio::signal::ctrl_c(); let (ctrl_c_tx, ctrl_c_rx) = tokio::sync::watch::channel(()); __rt__::task::spawn(async move { @@ -305,6 +305,18 @@ impl Ohkami { } } } + #[cfg(all(feature="rt_tokio", not(feature="graceful")))] { + loop { + let Ok((connection, _)) = listener.accept().await else {continue}; + + __rt__::task::spawn({ + Session::new( + router.clone(), + connection, + ).manage() + }); + } + } #[cfg(feature="rt_async-std")] { use async_std::stream::StreamExt as _/* .next() */;