diff --git a/Cargo.lock b/Cargo.lock index af4acf0..ade9df1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -54,6 +54,7 @@ dependencies = [ "rayon", "regex", "serde_json", + "state", ] [[package]] @@ -90,7 +91,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -317,6 +318,19 @@ dependencies = [ "slab", ] +[[package]] +name = "generator" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" +dependencies = [ + "cc", + "libc", + "log", + "rustversion", + "windows", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -506,6 +520,30 @@ version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +[[package]] +name = "loom" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "serde", + "serde_json", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "memchr" version = "2.7.4" @@ -619,7 +657,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -802,8 +840,17 @@ checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", - "regex-automata", - "regex-syntax", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", ] [[package]] @@ -814,9 +861,15 @@ checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.8.4", ] +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + [[package]] name = "regex-syntax" version = "0.8.4" @@ -933,12 +986,24 @@ dependencies = [ "untrusted", ] +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + [[package]] name = "ryu" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + [[package]] name = "scopeguard" version = "1.2.0" @@ -1055,6 +1120,15 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +[[package]] +name = "state" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b8c4a4445d81357df8b1a650d0d0d6fbbbfe99d064aa5e02f3e4022061476d8" +dependencies = [ + "loom", +] + [[package]] name = "subtle" version = "2.6.1" @@ -1255,10 +1329,14 @@ version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ + "matchers", "nu-ansi-term", + "once_cell", + "regex", "sharded-slab", "smallvec", "thread_local", + "tracing", "tracing-core", "tracing-log", ] @@ -1472,6 +1550,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-registry" version = "0.2.0" @@ -1480,7 +1567,7 @@ checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" dependencies = [ "windows-result", "windows-strings", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -1489,7 +1576,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -1499,7 +1586,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ "windows-result", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -1508,7 +1595,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -1517,7 +1604,22 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -1526,28 +1628,46 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -1560,24 +1680,48 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" diff --git a/crates/aionbot-adapter-onebot/src/lib.rs b/crates/aionbot-adapter-onebot/src/lib.rs index cb642b6..2651f82 100644 --- a/crates/aionbot-adapter-onebot/src/lib.rs +++ b/crates/aionbot-adapter-onebot/src/lib.rs @@ -1,4 +1,8 @@ +use std::sync::Arc; + +use aionbot_core::runtime::{Runtime, StateManager}; use anyhow::Result; +use onebot_v11::connect::ws_reverse::ReverseWsConnect; pub extern crate aionbot_core; @@ -13,3 +17,45 @@ impl Adapter for aionbot_core::event::Event { unimplemented!() } } + +pub struct OnebotRuntime { + connect: Option>, + state: Arc, +} + +impl Default for OnebotRuntime { + fn default() -> Self { + Self { + connect: None, + state: Arc::new(StateManager::default()), + } + } +} + +impl Runtime for OnebotRuntime { + fn set_manager(mut self, manager: Arc) -> Self { + self.state = manager; + self + } + + fn manager(&self) -> &StateManager { + &self.state + } + + async fn prepare(&mut self) -> Result<()> { + self.connect = Some(ReverseWsConnect::new(Default::default()).await?); + Ok(()) + } + + fn setup(&mut self, setup: Box) { + setup(self); + } + + async fn finalize(&mut self) -> Result<()> { + Ok(()) + } + + async fn run(&self) -> Result<()> { + Ok(()) + } +} diff --git a/crates/aionbot-core/Cargo.toml b/crates/aionbot-core/Cargo.toml index eb875ae..0b8bde4 100644 --- a/crates/aionbot-core/Cargo.toml +++ b/crates/aionbot-core/Cargo.toml @@ -9,3 +9,4 @@ futures = "0.3.30" rayon = "1.10.0" regex = "1.10.6" serde_json = "1.0.128" +state = "0.6.0" diff --git a/crates/aionbot-core/src/event.rs b/crates/aionbot-core/src/event.rs index 3437f06..91cd955 100644 --- a/crates/aionbot-core/src/event.rs +++ b/crates/aionbot-core/src/event.rs @@ -4,9 +4,28 @@ use serde_json::Value; pub struct MessageSegment { pub text: String, - pub type_: String, + pub r#type: String, } +impl From<&str> for MessageSegment { + fn from(value: &str) -> Self { + Self { + text: value.to_string(), + r#type: "text".to_string(), + } + } +} + +impl From for MessageSegment { + fn from(value: String) -> Self { + Self { + text: value, + r#type: "text".to_string(), + } + } +} + +#[derive(Default)] pub struct Message { pub entity: Option, pub segments: Vec, @@ -21,6 +40,7 @@ impl fmt::Display for Message { } } +#[derive(Default)] pub struct Event { pub plain_data: Message, pub user_id: String, diff --git a/crates/aionbot-core/src/handler.rs b/crates/aionbot-core/src/handler.rs index 72fb2c8..3010308 100644 --- a/crates/aionbot-core/src/handler.rs +++ b/crates/aionbot-core/src/handler.rs @@ -4,6 +4,7 @@ use anyhow::Result; use crate::{entry::Entry, event::Event, queue::EventQueue}; +#[derive(Default)] pub struct Handler { pub entries: Vec, } diff --git a/crates/aionbot-core/src/lib.rs b/crates/aionbot-core/src/lib.rs index 9ae57fd..38bc095 100644 --- a/crates/aionbot-core/src/lib.rs +++ b/crates/aionbot-core/src/lib.rs @@ -4,4 +4,5 @@ pub mod handler; pub mod prelude; pub mod queue; pub mod router; +pub mod runtime; pub mod types; diff --git a/crates/aionbot-core/src/router.rs b/crates/aionbot-core/src/router.rs index d8ec1c0..ed764c1 100644 --- a/crates/aionbot-core/src/router.rs +++ b/crates/aionbot-core/src/router.rs @@ -200,115 +200,153 @@ impl Router for RegexRouter { // } // } -// #[cfg(test)] -// mod tests { -// use super::*; - -// #[test] -// fn test_exact_match_router() { -// let router = ExactMatchRouter::new("hello", false); -// assert!(router.matches("hello")); -// assert!(!router.matches("world")); -// assert!(!router.matches("hello world")); -// } - -// #[test] -// fn test_exact_match_router_ignore_spaces() { -// let router = ExactMatchRouter::new("hello world", true); -// assert!(router.matches("hello world")); -// assert!(!router.matches("hello")); -// assert!(!router.matches("world")); -// assert!(!router.matches("hello world!")); -// } - -// #[test] -// fn test_regex_router() { -// let router = RegexRouter::new(r"^hello.*$"); -// assert!(router.matches("hello world")); -// assert!(!router.matches("world")); -// assert!(router.matches("hello world!")); -// } - -// #[test] -// fn test_starts_with_router() { -// let router = StartsWithRouter::new("hello", false); -// assert!(router.matches("hello world")); -// assert!(!router.matches("world")); -// assert!(router.matches("hello world!")); -// } - -// #[test] -// fn test_starts_with_router_ignore_spaces() { -// let router = StartsWithRouter::new("hello world", true); -// assert!(router.matches("hello world")); -// assert!(!router.matches("hello")); -// assert!(!router.matches("world")); -// assert!(router.matches("hello world!")); -// } - -// #[test] -// fn test_contains_router() { -// let router = ContainsRouter::new("world", false); -// assert!(router.matches("hello world")); -// assert!(!router.matches("hello")); -// assert!(router.matches("world")); -// assert!(router.matches("hello world!")); -// } - -// #[test] -// fn test_contains_router_ignore_spaces() { -// let router = ContainsRouter::new("hello world", true); -// assert!(router.matches("hello world")); -// assert!(!router.matches("hello")); -// assert!(!router.matches("world")); -// assert!(router.matches("hello world!")); -// } - -// #[test] -// fn test_ends_with_router() { -// let router = EndsWithRouter::new("world", false); -// assert!(router.matches("hello world")); -// assert!(!router.matches("hello")); -// assert!(router.matches("world")); -// assert!(!router.matches("hello world!")); -// } - -// #[test] -// fn test_ends_with_router_ignore_spaces() { -// let router = EndsWithRouter::new("hello world", true); -// assert!(router.matches("hello world")); -// assert!(!router.matches("hello")); -// assert!(!router.matches("world")); -// assert!(!router.matches("hello world!")); -// } +#[cfg(test)] +mod tests { + #![allow(clippy::borrow_interior_mutable_const)] + #![allow(clippy::declare_interior_mutable_const)] + use std::cell::LazyCell; + + use crate::event::Message; + + use super::*; + + const HELLO_EVENT: LazyCell = LazyCell::new(|| Event { + plain_data: Message { + segments: vec!["hello".into()], + ..Default::default() + }, + ..Default::default() + }); + + const WORLD_EVENT: LazyCell = LazyCell::new(|| Event { + plain_data: Message { + segments: vec!["world".into()], + ..Default::default() + }, + ..Default::default() + }); + + const HELLO_WORLD_EVENT: LazyCell = LazyCell::new(|| Event { + plain_data: Message { + segments: vec!["hello".into(), " ".into(), "world".into()], + ..Default::default() + }, + ..Default::default() + }); + + const HAPPY_HELLO_WORLD_EVENT: LazyCell = LazyCell::new(|| Event { + plain_data: Message { + segments: vec!["hello".into(), " ".into(), "world!".into()], + ..Default::default() + }, + ..Default::default() + }); + + #[test] + fn test_exact_match_router() { + let router = ExactMatchRouter::new("hello", false); + assert!(router.matches(&HELLO_EVENT)); + assert!(!router.matches(&WORLD_EVENT)); + assert!(!router.matches(&HELLO_WORLD_EVENT)); + } -// #[test] -// fn test_or_router() { -// let router = OrRouter::new(vec![ -// Box::new(ExactMatchRouter::new("hello", false)), -// Box::new(ExactMatchRouter::new("world", false)), -// ]); -// assert!(router.matches("hello")); -// assert!(router.matches("world")); -// assert!(!router.matches("foo")); -// } + #[test] + fn test_exact_match_router_ignore_spaces() { + let router = ExactMatchRouter::new("hello world", true); + assert!(router.matches(&HELLO_WORLD_EVENT)); + assert!(!router.matches(&HELLO_EVENT)); + assert!(!router.matches(&WORLD_EVENT)); + assert!(!router.matches(&HAPPY_HELLO_WORLD_EVENT)); + } -// #[test] -// fn test_and_router() { -// let router = AndRouter::new(vec![ -// Box::new(ExactMatchRouter::new("hello", false)), -// Box::new(ExactMatchRouter::new("world", false)), -// ]); -// assert!(!router.matches("hello")); -// assert!(!router.matches("world")); -// assert!(!router.matches("foo")); -// assert!(!router.matches("hello world")); -// } + #[test] + fn test_regex_router() { + let router = RegexRouter::new(r"^hello.*$"); + assert!(router.matches(&HELLO_WORLD_EVENT)); + assert!(!router.matches(&WORLD_EVENT)); + assert!(router.matches(&HAPPY_HELLO_WORLD_EVENT)); + } -// #[test] -// fn test_not_router() { -// let router = NotRouter::new(Box::new(ExactMatchRouter::new("hello", false))); -// assert!(!router.matches("hello")); -// assert!(router.matches("world")); -// } -// } + // #[test] + // fn test_starts_with_router() { + // let router = StartsWithRouter::new("hello", false); + // assert!(router.matches("hello world")); + // assert!(!router.matches("world")); + // assert!(router.matches("hello world!")); + // } + + // #[test] + // fn test_starts_with_router_ignore_spaces() { + // let router = StartsWithRouter::new("hello world", true); + // assert!(router.matches("hello world")); + // assert!(!router.matches("hello")); + // assert!(!router.matches("world")); + // assert!(router.matches("hello world!")); + // } + + // #[test] + // fn test_contains_router() { + // let router = ContainsRouter::new("world", false); + // assert!(router.matches("hello world")); + // assert!(!router.matches("hello")); + // assert!(router.matches("world")); + // assert!(router.matches("hello world!")); + // } + + // #[test] + // fn test_contains_router_ignore_spaces() { + // let router = ContainsRouter::new("hello world", true); + // assert!(router.matches("hello world")); + // assert!(!router.matches("hello")); + // assert!(!router.matches("world")); + // assert!(router.matches("hello world!")); + // } + + // #[test] + // fn test_ends_with_router() { + // let router = EndsWithRouter::new("world", false); + // assert!(router.matches("hello world")); + // assert!(!router.matches("hello")); + // assert!(router.matches("world")); + // assert!(!router.matches("hello world!")); + // } + + // #[test] + // fn test_ends_with_router_ignore_spaces() { + // let router = EndsWithRouter::new("hello world", true); + // assert!(router.matches("hello world")); + // assert!(!router.matches("hello")); + // assert!(!router.matches("world")); + // assert!(!router.matches("hello world!")); + // } + + // #[test] + // fn test_or_router() { + // let router = OrRouter::new(vec![ + // Box::new(ExactMatchRouter::new("hello", false)), + // Box::new(ExactMatchRouter::new("world", false)), + // ]); + // assert!(router.matches("hello")); + // assert!(router.matches("world")); + // assert!(!router.matches("foo")); + // } + + // #[test] + // fn test_and_router() { + // let router = AndRouter::new(vec![ + // Box::new(ExactMatchRouter::new("hello", false)), + // Box::new(ExactMatchRouter::new("world", false)), + // ]); + // assert!(!router.matches("hello")); + // assert!(!router.matches("world")); + // assert!(!router.matches("foo")); + // assert!(!router.matches("hello world")); + // } + + // #[test] + // fn test_not_router() { + // let router = NotRouter::new(Box::new(ExactMatchRouter::new("hello", false))); + // assert!(!router.matches("hello")); + // assert!(router.matches("world")); + // } +} diff --git a/crates/aionbot-core/src/runtime.rs b/crates/aionbot-core/src/runtime.rs new file mode 100644 index 0000000..3caee81 --- /dev/null +++ b/crates/aionbot-core/src/runtime.rs @@ -0,0 +1,99 @@ +use std::sync::Arc; + +use anyhow::Result; +use state::TypeMap; + +use crate::{entry::Entry, handler::Handler, types::SetupFn}; + +#[derive(Default)] +pub struct StateManager(pub(crate) TypeMap!(Send + Sync)); + +impl StateManager { + pub fn new() -> Self { + StateManager(::new()) + } + + pub fn set(&mut self, state: T) { + self.0.set::(state); + } + + pub fn get(&self) -> &T { + self.0.get::() + } + + pub fn try_get(&self) -> Option<&T> { + self.0.try_get::() + } +} + +pub struct Builder { + handler: Arc>, + runtime: R, + state: Arc, + setup: Option>, +} + +impl Builder +where + R: Runtime + Default + Send + 'static, +{ + pub fn setup(&mut self, setup: SetupFn) { + self.setup = Some(setup); + } + + pub fn invoke_handler(mut self, entries: Vec) -> Self { + self.handler = Arc::new(Some(Handler::new(entries))); + self + } + + pub fn manage(self, state: T) -> Self { + self.state.0.set(state); + self + } + + pub async fn run(&mut self) -> Result<()> { + self.runtime.prepare().await?; + if let Some(setup) = self.setup.take() { + self.runtime.setup(setup); + } + self.runtime.finalize().await?; + self.runtime.run().await + } +} + +impl Default for Builder +where + R: Runtime + Default + Send + 'static, +{ + fn default() -> Self { + let manager = Arc::new(StateManager::new()); + let runtime = R::default().set_manager(manager.clone()); + Self { + handler: Arc::new(None), + runtime, + state: Arc::clone(&manager), + setup: None, + } + } +} + +pub trait Runtime { + #[must_use] + fn set_manager(self, manager: Arc) -> Self; + + fn manager(&self) -> &StateManager; + + fn prepare(&mut self) -> impl std::future::Future> + Send { + async move { Ok(()) } + } + + fn setup(&mut self, setup: SetupFn) { + setup(self) + } + + fn finalize(&mut self) -> impl std::future::Future> + Send { + async move { Ok(()) } + } + + fn run(&self) -> impl std::future::Future> + Send; +} diff --git a/crates/aionbot-core/src/types.rs b/crates/aionbot-core/src/types.rs index 425be50..ac9970d 100644 --- a/crates/aionbot-core/src/types.rs +++ b/crates/aionbot-core/src/types.rs @@ -7,3 +7,4 @@ use crate::event::Event; pub type HandlerCallback = BoxFuture<'static, Result<()>>; pub type Callback = fn(Arc) -> HandlerCallback; +pub type SetupFn = Box; diff --git a/crates/aionbot-macros/tests/macros.rs b/crates/aionbot-macros/tests/macros.rs index 546ead9..2e588a0 100644 --- a/crates/aionbot-macros/tests/macros.rs +++ b/crates/aionbot-macros/tests/macros.rs @@ -18,7 +18,7 @@ fn test_register_router() { entity: Some("test".to_string()), segments: vec![MessageSegment { text: "test_router".to_string(), - type_: "text".to_string(), + r#type: "text".to_string(), }], }, user_id: "test".to_string(), @@ -39,7 +39,7 @@ fn test_register_router_priority() { entity: Some("test".to_string()), segments: vec![MessageSegment { text: "test_router".to_string(), - type_: "text".to_string(), + r#type: "text".to_string(), }], }, user_id: "test".to_string(), diff --git a/crates/aionbot/src/main.rs b/crates/aionbot/src/main.rs index a101fe0..8d49404 100644 --- a/crates/aionbot/src/main.rs +++ b/crates/aionbot/src/main.rs @@ -1,8 +1,10 @@ use std::sync::Arc; -use aionbot_adapter_onebot::Adapter; +use aionbot_adapter_onebot::{Adapter, OnebotRuntime}; use aionbot_macros::register; +struct State {} + #[register(router = ExactMatchRouter::new("hello", false))] pub async fn hello_world(event: Arc) -> Result { println!("{}", &event.plain_data.to_string()); @@ -12,8 +14,10 @@ pub async fn hello_world(event: Arc) -> Result { #[tokio::main] async fn main() { - let entries = vec![hello_world()]; - for entry in entries { - println!("{}", entry.id); - } + aionbot_core::runtime::Builder::::default() + .invoke_handler(vec![hello_world()]) + .manage(State {}) + .run() + .await + .expect("Failed to start the bot runtime."); }