├── src ├── utils.rs ├── builtin │ ├── mod.rs │ ├── echo.rs │ ├── rule.rs │ ├── pre_handle.rs │ └── extract.rs ├── bot.rs ├── config.rs ├── matcher │ ├── hook.rs │ ├── mod.rs │ ├── rule.rs │ ├── pre_handle.rs │ ├── matchers.rs │ ├── handle.rs │ └── session.rs ├── scheduler.rs ├── lib.rs └── caller │ └── mod.rs ├── .gitignore ├── plugins └── walle-plugin-roulette │ ├── Cargo.toml │ └── src │ └── lib.rs ├── examples ├── echo.rs ├── schedule.rs └── api_test.rs ├── Cargo.toml ├── LICENSE ├── README.md └── Cargo.lock /src/utils.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | .vscode 3 | /test 4 | wakatime.json -------------------------------------------------------------------------------- /src/builtin/mod.rs: -------------------------------------------------------------------------------- 1 | mod echo; 2 | mod extract; 3 | mod pre_handle; 4 | mod rule; 5 | 6 | pub use echo::*; 7 | pub use extract::*; 8 | pub use pre_handle::*; 9 | pub use rule::*; 10 | -------------------------------------------------------------------------------- /src/bot.rs: -------------------------------------------------------------------------------- 1 | use crate::ActionCaller; 2 | 3 | use std::sync::Arc; 4 | use walle_core::structs::Selft; 5 | 6 | #[derive(Clone)] 7 | pub struct Bot { 8 | pub selft: Selft, 9 | pub caller: Arc, 10 | } 11 | -------------------------------------------------------------------------------- /src/config.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | pub use walle_core::config::*; 3 | 4 | /// Matchers 可配置项 5 | #[derive(Serialize, Deserialize, Debug, Clone, Default)] 6 | pub struct MatchersConfig { 7 | #[serde(default = "Vec::default")] 8 | pub nicknames: Vec, 9 | } 10 | -------------------------------------------------------------------------------- /src/builtin/echo.rs: -------------------------------------------------------------------------------- 1 | use crate::{matcher, on_command}; 2 | use crate::{MatcherHandler, Session}; 3 | 4 | on_command!(Echo, "echo", crate); 5 | 6 | pub fn echo() -> impl MatcherHandler { 7 | matcher(|Echo(segs): Echo, session: Session| async move { 8 | session.reply(segs).await.ok(); 9 | }) 10 | } 11 | -------------------------------------------------------------------------------- /src/matcher/hook.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use crate::ActionCaller; 4 | 5 | #[async_trait::async_trait] 6 | pub trait MatchersHook: Sync { 7 | async fn on_start(&self, _caller: &Arc) {} 8 | async fn on_shutdown(&self, _caller: &Arc) {} 9 | } 10 | -------------------------------------------------------------------------------- /plugins/walle-plugin-roulette/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "walle-plugin-roulette" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | walle = { path = "../../" } 10 | tokio = "*" 11 | rand = "*" 12 | 13 | [dev-dependencies] 14 | tokio = { version = "*", features = ["full"] } 15 | -------------------------------------------------------------------------------- /examples/echo.rs: -------------------------------------------------------------------------------- 1 | use walle::{builtin::echo, new_walle, MatcherHandler, Matchers, MatchersConfig}; 2 | use walle_core::config::AppConfig; 3 | 4 | #[tokio::main] 5 | async fn main() { 6 | let matchers = Matchers::default().add_matcher(echo().boxed()); 7 | let walle = new_walle(matchers, "debug"); 8 | let joins = walle 9 | .start(AppConfig::default(), MatchersConfig::default(), true) 10 | .await 11 | .unwrap(); 12 | for join in joins { 13 | join.await.ok(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /examples/schedule.rs: -------------------------------------------------------------------------------- 1 | use walle::{ 2 | new_walle, walle_core::config::AppConfig, Matchers, MatchersConfig, OneMinutePassed, Scheduler, 3 | }; 4 | 5 | #[tokio::main] 6 | async fn main() { 7 | let matchers = Matchers::default(); 8 | let walle = new_walle(matchers, "debug"); 9 | let mut scheduler = Scheduler::new(walle.clone()); 10 | scheduler.add(OneMinutePassed); 11 | scheduler.start(); 12 | let joins = walle 13 | .start(AppConfig::default(), MatchersConfig::default(), true) 14 | .await 15 | .unwrap(); 16 | for join in joins { 17 | join.await.ok(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/matcher/mod.rs: -------------------------------------------------------------------------------- 1 | use walle_core::prelude::{async_trait, Event}; 2 | 3 | mod handle; 4 | mod hook; 5 | mod matchers; 6 | mod pre_handle; 7 | mod rule; 8 | mod session; 9 | 10 | pub use handle::*; 11 | pub use hook::*; 12 | pub use matchers::*; 13 | pub use pre_handle::*; 14 | pub use rule::*; 15 | pub use session::*; 16 | 17 | struct TempMatcher { 18 | pub tx: tokio::sync::mpsc::UnboundedSender, 19 | } 20 | 21 | #[async_trait] 22 | impl MatcherHandler for TempMatcher { 23 | async fn handle(&self, session: Session) -> Signal { 24 | self.tx.send(session.event).ok(); 25 | Signal::MatchAndBlock 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "walle" 3 | version = "0.1.0" 4 | edition = "2021" 5 | authors = ["Abrahum<307887491@qq.com>"] 6 | license = "MIT" 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [features] 11 | scheduler = ["tokio-cron-scheduler"] 12 | 13 | [dependencies] 14 | async-trait = "0.1" 15 | tokio = "1.17" 16 | tracing-subscriber = { version = "0.3.9", features = [ 17 | "env-filter", 18 | "fmt", 19 | "time", 20 | ] } 21 | tracing = "0.1" 22 | time = { version = "0.3", features = ["macros"] } 23 | tokio-cron-scheduler = { version = "0.7", optional = true } 24 | serde = { version = "1.0", features = ["derive"] } 25 | dashmap = "5.3" 26 | 27 | [dependencies.walle-core] 28 | version = "0.7.0" 29 | # git = "https://github.com/abrahum/walle-core.git" 30 | features = ["websocket", "app-obc", "http", "alt"] 31 | 32 | [[example]] 33 | name = "echo" 34 | required-features = ["scheduler"] 35 | 36 | [dev-dependencies] 37 | tokio = { version = "1.17", features = ["full"] } 38 | 39 | [workspace] 40 | members = ["plugins/walle-plugin-roulette"] 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 [abrahum<307887491@qq.com>] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/scheduler.rs: -------------------------------------------------------------------------------- 1 | use std::{future::Future, pin::Pin, sync::Arc}; 2 | 3 | use crate::{ActionCaller, Walle}; 4 | use tokio_cron_scheduler::{Job, JobScheduler}; 5 | 6 | /// 定时任务 trait 7 | pub trait ScheduledJob { 8 | fn cron(&self) -> &'static str; 9 | fn call(&self, walle: Walle) -> Pin + Send + 'static>>; 10 | } 11 | 12 | /// 定时任务执行器 13 | pub struct Scheduler { 14 | inner: JobScheduler, 15 | walle: Walle, 16 | } 17 | 18 | impl Scheduler { 19 | pub fn new(walle: Walle) -> Self { 20 | Self { 21 | inner: JobScheduler::new().unwrap(), 22 | walle, 23 | } 24 | } 25 | 26 | /// 向定时任务执行器中添加一个定时任务 27 | pub fn add(&mut self, job: impl ScheduledJob + Send + Sync + 'static) { 28 | let walle = self.walle.clone(); 29 | let job = Job::new_async(job.cron(), move |_, _| job.call(walle.clone())).unwrap(); 30 | self.inner.add(job).unwrap(); 31 | } 32 | 33 | /// 启动定时任务执行器 34 | pub fn start(&self) { 35 | self.inner.start().unwrap(); 36 | } 37 | } 38 | 39 | /// just for test 40 | pub struct OneMinutePassed; 41 | 42 | impl ScheduledJob for OneMinutePassed { 43 | fn cron(&self) -> &'static str { 44 | "0 * * * * *" 45 | } 46 | fn call(&self, walle: Walle) -> Pin + Send + 'static>> { 47 | Box::pin(async move { 48 | for bot in walle.get_bots().await.iter() { 49 | println!("One minute passed with bot: {:?}", bot.selft); 50 | } 51 | }) 52 | } 53 | } 54 | 55 | pub trait ArcScheduledJob { 56 | fn cron(&self) -> &'static str; 57 | fn call(self: &Arc, walle: Walle) -> Pin + Send + 'static>>; 58 | } 59 | 60 | impl ScheduledJob for Arc { 61 | fn cron(&self) -> &'static str { 62 | ::cron(&self) 63 | } 64 | fn call(&self, walle: Walle) -> Pin + Send + 'static>> { 65 | ::call(&self, walle) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use tracing_subscriber::EnvFilter; 4 | use walle_core::{action::Action, obc::AppOBC, prelude::Event, resp::Resp, OneBot}; 5 | 6 | mod bot; 7 | mod caller; 8 | pub mod matcher; 9 | #[cfg(feature = "scheduler")] 10 | mod scheduler; 11 | mod utils; 12 | 13 | // pub mod builtin; 14 | pub mod config; 15 | 16 | pub use bot::Bot; 17 | pub use caller::{ActionCaller, ActionCallerExt}; 18 | pub use config::*; 19 | pub use matcher::*; 20 | #[cfg(feature = "scheduler")] 21 | pub use scheduler::*; 22 | #[doc(hidden)] 23 | pub use tokio; 24 | #[doc(hidden)] 25 | pub use tracing; 26 | pub use walle_core; 27 | 28 | pub mod builtin; 29 | 30 | pub type Walle = Arc, Matchers>>; 31 | 32 | /// 构造一个新的 Walle 实例 33 | pub fn new_walle(matchers: Matchers, env: &str) -> Walle { 34 | let timer = tracing_subscriber::fmt::time::OffsetTime::new( 35 | time::UtcOffset::from_hms(8, 0, 0).unwrap(), 36 | time::format_description::parse( 37 | "[year repr:last_two]-[month]-[day] [hour]:[minute]:[second]", 38 | ) 39 | .unwrap(), 40 | ); 41 | let env = EnvFilter::from(env); 42 | tracing_subscriber::fmt() 43 | .with_env_filter(env) 44 | .with_timer(timer) 45 | .init(); 46 | Arc::new(walle_core::OneBot::new(AppOBC::new(), matchers)) 47 | } 48 | 49 | pub fn test_walle( 50 | matchers: Matchers, 51 | ) -> Arc, Matchers>> { 52 | let timer = tracing_subscriber::fmt::time::OffsetTime::new( 53 | time::UtcOffset::from_hms(8, 0, 0).unwrap(), 54 | time::format_description::parse( 55 | "[year repr:last_two]-[month]-[day] [hour]:[minute]:[second]", 56 | ) 57 | .unwrap(), 58 | ); 59 | let env = tracing_subscriber::EnvFilter::from("debug"); 60 | 61 | tracing_subscriber::fmt() 62 | .with_env_filter(env) 63 | .with_timer(timer) 64 | .init(); 65 | Arc::new(walle_core::OneBot::new( 66 | walle_core::alt::TracingHandler::default(), 67 | matchers, 68 | )) 69 | } 70 | -------------------------------------------------------------------------------- /src/matcher/rule.rs: -------------------------------------------------------------------------------- 1 | use crate::{JoinedRulePreHandler, MatcherHandler, PreHandler, Session, Signal}; 2 | 3 | use walle_core::{prelude::async_trait, WalleResult}; 4 | 5 | pub trait Rule { 6 | fn rule(&self, session: &Session) -> Signal; 7 | fn layer(self, handler: H) -> LayeredRule 8 | where 9 | Self: Sized, 10 | H: MatcherHandler, 11 | { 12 | LayeredRule { 13 | rule: self, 14 | handler, 15 | } 16 | } 17 | fn with(self, rule: R) -> JoinedRule 18 | where 19 | Self: Sized, 20 | R: Rule, 21 | { 22 | JoinedRule(self, rule) 23 | } 24 | fn with_pre_handler(self, pre_handler: PH) -> JoinedRulePreHandler 25 | where 26 | Self: Sized, 27 | PH: PreHandler, 28 | { 29 | JoinedRulePreHandler(self, pre_handler) 30 | } 31 | } 32 | 33 | impl Rule for () { 34 | fn rule(&self, _: &Session) -> Signal { 35 | Signal::Matched 36 | } 37 | } 38 | 39 | pub struct LayeredRule { 40 | pub rule: R, 41 | pub handler: H, 42 | } 43 | 44 | #[async_trait] 45 | impl MatcherHandler for LayeredRule 46 | where 47 | R: Rule + Send + Sync, 48 | H: MatcherHandler + Send + Sync, 49 | { 50 | async fn handle(&self, session: Session) -> Signal { 51 | let mut sig = self.rule.rule(&session); 52 | if sig != Signal::NotMatch { 53 | sig = self.handler.handle(session).await & sig 54 | } 55 | sig 56 | } 57 | } 58 | 59 | pub struct JoinedRule(pub R0, pub R1); 60 | 61 | impl Rule for JoinedRule 62 | where 63 | R0: Rule + Send + Sync, 64 | R1: Rule + Send + Sync, 65 | { 66 | fn rule(&self, session: &Session) -> Signal { 67 | self.0.rule(session) & self.1.rule(session) 68 | } 69 | } 70 | 71 | pub struct RuleFn(F); 72 | 73 | impl Rule for RuleFn 74 | where 75 | F: Fn(&Session) -> Signal + Send + Sync, 76 | { 77 | fn rule(&self, session: &Session) -> Signal { 78 | self.0(session) 79 | } 80 | } 81 | 82 | pub fn rule_fn(rule: F) -> RuleFn 83 | where 84 | F: Fn(&Session) -> Signal + 'static, 85 | { 86 | RuleFn(rule) 87 | } 88 | 89 | pub struct RuleFnUnwarp(F); 90 | 91 | pub fn rule_fn_unwarp(rule: F) -> RuleFnUnwarp 92 | where 93 | F: Fn(&Session) -> WalleResult + 'static, 94 | { 95 | RuleFnUnwarp(rule) 96 | } 97 | 98 | impl Rule for RuleFnUnwarp 99 | where 100 | F: Fn(&Session) -> WalleResult + Send + Sync, 101 | { 102 | fn rule(&self, session: &Session) -> Signal { 103 | self.0(session).into() 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/matcher/pre_handle.rs: -------------------------------------------------------------------------------- 1 | use crate::{MatcherHandler, Rule, Session, Signal}; 2 | 3 | use walle_core::{prelude::async_trait, WalleResult}; 4 | 5 | pub trait PreHandler { 6 | fn pre_handle(&self, session: &mut Session) -> Signal; 7 | fn layer(self, handler: H) -> LayeredPreHandler 8 | where 9 | Self: Sized, 10 | H: MatcherHandler, 11 | { 12 | LayeredPreHandler { pre: self, handler } 13 | } 14 | fn with(self, pr: PR) -> JoinedPreHandler 15 | where 16 | Self: Sized, 17 | PR: PreHandler, 18 | { 19 | JoinedPreHandler(self, pr) 20 | } 21 | fn with_rule(self, rule: R) -> JoinedPreHandlerRule 22 | where 23 | Self: Sized, 24 | R: Rule, 25 | { 26 | JoinedPreHandlerRule(self, rule) 27 | } 28 | } 29 | 30 | impl PreHandler for () { 31 | fn pre_handle(&self, _: &mut Session) -> Signal { 32 | Signal::Matched 33 | } 34 | } 35 | 36 | pub struct LayeredPreHandler { 37 | pub pre: PR, 38 | pub handler: H, 39 | } 40 | 41 | #[async_trait] 42 | impl MatcherHandler for LayeredPreHandler 43 | where 44 | PR: PreHandler + Send + Sync, 45 | H: MatcherHandler + Send + Sync, 46 | { 47 | async fn handle(&self, mut session: Session) -> Signal { 48 | let mut sig = self.pre.pre_handle(&mut session); 49 | if sig != Signal::NotMatch { 50 | sig = self.handler.handle(session).await & sig; 51 | } 52 | sig 53 | } 54 | } 55 | 56 | pub struct JoinedPreHandler(pub PR0, pub PR1); 57 | 58 | impl PreHandler for JoinedPreHandler 59 | where 60 | PR0: PreHandler + Sync, 61 | PR1: PreHandler + Sync, 62 | { 63 | fn pre_handle(&self, session: &mut Session) -> Signal { 64 | self.0.pre_handle(session) & self.1.pre_handle(session) 65 | } 66 | } 67 | 68 | pub struct JoinedPreHandlerRule(pub PH, pub R); 69 | 70 | impl PreHandler for JoinedPreHandlerRule 71 | where 72 | PH: PreHandler, 73 | R: Rule, 74 | { 75 | fn pre_handle(&self, session: &mut Session) -> Signal { 76 | self.0.pre_handle(session) & self.1.rule(session) 77 | } 78 | } 79 | 80 | pub struct JoinedRulePreHandler(pub R, pub PH); 81 | 82 | impl PreHandler for JoinedRulePreHandler 83 | where 84 | R: Rule + Sync, 85 | PH: PreHandler + Sync, 86 | { 87 | fn pre_handle(&self, session: &mut Session) -> Signal { 88 | self.0.rule(session) & self.1.pre_handle(session) 89 | } 90 | } 91 | 92 | pub struct PreHandleFn(F); 93 | 94 | impl PreHandler for PreHandleFn 95 | where 96 | F: Fn(&mut Session) -> Signal + Sync, 97 | { 98 | fn pre_handle(&self, session: &mut Session) -> Signal { 99 | self.0(session) 100 | } 101 | } 102 | 103 | pub fn pre_handle_fn(pre: F) -> PreHandleFn 104 | where 105 | F: Fn(&mut Session) -> Signal + Sync, 106 | { 107 | PreHandleFn(pre) 108 | } 109 | 110 | pub struct PreHandleFnUnwarp(F); 111 | 112 | impl PreHandler for PreHandleFnUnwarp 113 | where 114 | F: Fn(&mut Session) -> WalleResult + Sync, 115 | { 116 | fn pre_handle(&self, session: &mut Session) -> Signal { 117 | self.0(session).into() 118 | } 119 | } 120 | 121 | pub fn pre_handle_fn_unwarp(pre: F) -> PreHandleFnUnwarp 122 | where 123 | F: Fn(&mut Session) -> WalleResult + Sync, 124 | { 125 | PreHandleFnUnwarp(pre) 126 | } 127 | -------------------------------------------------------------------------------- /src/builtin/rule.rs: -------------------------------------------------------------------------------- 1 | use crate::{rule_fn, Rule, Session}; 2 | use crate::{rule_fn_unwarp, Signal}; 3 | use walle_core::segment::MsgSegmentRef; 4 | use walle_core::util::{Value, ValueMapExt}; 5 | use walle_core::WalleResult; 6 | 7 | pub struct UserIdChecker { 8 | pub user_id: String, 9 | } 10 | 11 | impl Rule for UserIdChecker { 12 | fn rule(&self, session: &Session) -> Signal { 13 | if session 14 | .event 15 | .extra 16 | .try_get_as_ref::<&str>("user_id") 17 | .unwrap_or_default() 18 | == self.user_id.as_str() 19 | { 20 | Signal::Matched 21 | } else { 22 | Signal::NotMatch 23 | } 24 | } 25 | } 26 | 27 | pub fn user_id_check(user_id: S) -> UserIdChecker 28 | where 29 | S: ToString, 30 | { 31 | UserIdChecker { 32 | user_id: user_id.to_string(), 33 | } 34 | } 35 | 36 | pub struct GroupIdChecker { 37 | pub group_id: String, 38 | } 39 | 40 | impl Rule for GroupIdChecker { 41 | fn rule(&self, session: &Session) -> Signal { 42 | if session 43 | .event 44 | .extra 45 | .try_get_as_ref::<&str>("group_id") 46 | .unwrap_or_default() 47 | == self.group_id.as_str() 48 | { 49 | Signal::Matched 50 | } else { 51 | Signal::NotMatch 52 | } 53 | } 54 | } 55 | 56 | pub fn group_id_check(group_id: S) -> GroupIdChecker 57 | where 58 | S: ToString, 59 | { 60 | GroupIdChecker { 61 | group_id: group_id.to_string(), 62 | } 63 | } 64 | 65 | pub fn channel_id_check(guild_id: &str, channel_id: &str) -> impl Rule { 66 | let guild_id2 = guild_id.to_string(); 67 | let channel_id2 = channel_id.to_string(); 68 | rule_fn_unwarp(move |session| { 69 | if session.event.extra.try_get_as_ref::<&str>("guild_id")? == guild_id2.as_str() 70 | && session.event.extra.try_get_as_ref::<&str>("channel_id")? == channel_id2.as_str() 71 | { 72 | Ok(Signal::Matched) 73 | } else { 74 | Ok(Signal::NotMatch) 75 | } 76 | }) 77 | } 78 | 79 | pub fn start_with(pat: &str) -> impl Rule { 80 | let word = pat.to_string(); 81 | rule_fn(move |session: &Session| { 82 | if let Some(MsgSegmentRef::Text { text, .. }) = session 83 | .event 84 | .extra 85 | .try_get_as_ref::<&Vec>("message") 86 | .ok() 87 | .and_then(|v| v.first()) 88 | .and_then(|v| v.try_as_ref::>().ok()) 89 | { 90 | if text.starts_with(&word) { 91 | return Signal::Matched; 92 | } 93 | } 94 | Signal::NotMatch 95 | }) 96 | } 97 | 98 | fn _mention_me(session: &Session) -> WalleResult { 99 | let alt = &session.event.extra.try_get_as_ref::<&str>("alt_message")?; 100 | for nickname in &session.config.nicknames { 101 | if alt.starts_with(nickname) { 102 | return Ok(Signal::Matched); 103 | } 104 | } 105 | for user_id in session 106 | .event 107 | .extra 108 | .try_get_as_ref::<&Vec>("message")? 109 | .iter() 110 | .filter_map(|v| match v.try_as_ref::>() { 111 | Ok(MsgSegmentRef::Mention { user_id, .. }) => Some(user_id), 112 | _ => None, 113 | }) 114 | { 115 | if user_id == session.event.selft().unwrap_or_default().user_id { 116 | return Ok(Signal::Matched); 117 | } 118 | } 119 | Ok(Signal::NotMatch) 120 | } 121 | 122 | pub fn mention_me_rule() -> impl Rule { 123 | rule_fn_unwarp(_mention_me) 124 | } 125 | 126 | pub fn to_me_rule() -> impl Rule { 127 | rule_fn_unwarp(|session: &Session| { 128 | if session.event.detail_type.as_str() == "private" { 129 | Ok(Signal::Matched) 130 | } else { 131 | _mention_me(session) 132 | } 133 | }) 134 | } 135 | -------------------------------------------------------------------------------- /plugins/walle-plugin-roulette/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::sync::Arc; 3 | 4 | use tokio::sync::Mutex; 5 | 6 | use walle::builtin::{mention_user, start_with, trim}; 7 | use walle::walle_core::event::GroupMessageEvent; 8 | use walle::walle_core::util::ValueMapExt; 9 | use walle::walle_core::WalleResult; 10 | use walle::{matcher, on_command, MatcherHandler, Session}; 11 | 12 | on_command!(Roulette, Start => "轮盘赌", Shot => "shot"); 13 | 14 | pub struct RouletteMatcher(Mutex>>); 15 | 16 | impl RouletteMatcher { 17 | pub async fn roalette( 18 | &self, 19 | ro: Roulette, 20 | event: GroupMessageEvent, 21 | mut s: Session, 22 | ) -> WalleResult<()> { 23 | match ro { 24 | Roulette::Start(_seg) => { 25 | s.getter() 26 | .with_pre_handler(mention_user(event.ty.user_id.clone())) 27 | .with_pre_handler(trim(true)) 28 | .with_rule(start_with("接受赌局")) 29 | .timeout(60) 30 | .timeout_callback(|s| { 31 | Box::pin(async move { 32 | s.reply("轮盘赌邀请已过期").await.ok(); 33 | }) 34 | }) 35 | .get("开始轮盘赌局,哪位英雄接受挑战?") 36 | .await?; 37 | self.0 38 | .lock() 39 | .await 40 | .entry(event.detail_type.group_id) 41 | .or_default() 42 | .push(( 43 | event.ty.user_id, 44 | s.event.extra.get_downcast("user_id")?, 45 | 0, 46 | 6, 47 | { 48 | use rand::Rng; 49 | let mut rng = rand::thread_rng(); 50 | rng.gen_range(0..6) 51 | }, 52 | )); 53 | s.reply("开始赌局,发送shot发射子弹").await?; 54 | } 55 | Roulette::Shot(_seg) => { 56 | let mut locked = self.0.lock().await; 57 | if let Some(v) = locked.get_mut(&event.detail_type.group_id) { 58 | let mut need_remove = None; 59 | for (index, (a, b, count, all, shot)) in v.into_iter().enumerate() { 60 | if a == event.ty.user_id.as_str() || b == event.ty.user_id.as_str() { 61 | if count == shot { 62 | s.reply("嘣!正中靶心!").await?; 63 | need_remove = Some(index); 64 | } else { 65 | *count += 1; 66 | s.reply(format!("咔哒,逃过一劫\n剩余子弹{}发", *all - *count)) 67 | .await?; 68 | } 69 | } 70 | } 71 | if let Some(index) = need_remove { 72 | v.remove(index); 73 | if v.is_empty() { 74 | drop(v); 75 | locked.remove(&event.detail_type.group_id); 76 | } 77 | } 78 | } 79 | } 80 | } 81 | Ok(()) 82 | } 83 | } 84 | 85 | matcher!( 86 | failable: RouletteMatcher, 87 | roalette, 88 | ro: Roulette, 89 | event: GroupMessageEvent 90 | ); 91 | 92 | pub fn roulette() -> impl MatcherHandler { 93 | Arc::new(RouletteMatcher(Mutex::default())) 94 | } 95 | 96 | #[tokio::test] 97 | async fn t() { 98 | let matchers = walle::Matchers::default().add_matcher(roulette().boxed()); 99 | let walle = walle::new_walle(matchers, "debug"); 100 | for join in walle 101 | .start( 102 | walle::config::AppConfig::default(), 103 | walle::MatchersConfig::default(), 104 | true, 105 | ) 106 | .await 107 | .unwrap() 108 | { 109 | join.await.ok(); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/matcher/matchers.rs: -------------------------------------------------------------------------------- 1 | use super::MatcherHandler; 2 | use crate::{ActionCaller, Session, Signal}; 3 | use crate::{MatchersConfig, MatchersHook}; 4 | use async_trait::async_trait; 5 | use std::collections::HashMap; 6 | use std::sync::Arc; 7 | use tokio::{ 8 | sync::{Mutex, RwLock}, 9 | task::JoinHandle, 10 | }; 11 | use tracing::info; 12 | use walle_core::prelude::WalleError; 13 | use walle_core::{ 14 | action::Action, error::WalleResult, event::Event, resp::Resp, ActionHandler, EventHandler, 15 | OneBot, 16 | }; 17 | 18 | pub type Matcher = Box; 19 | pub type TempMatchers = Arc>>; 20 | 21 | #[derive(Default)] 22 | pub struct Matchers { 23 | pub inner: Vec, 24 | pub config: RwLock>, 25 | temps: TempMatchers, 26 | hooks: Vec>, 27 | ob: RwLock>>, 28 | } 29 | 30 | impl Matchers { 31 | pub fn add_matcher(mut self, matcher: Matcher) -> Self { 32 | self.inner.push(matcher); 33 | self 34 | } 35 | async fn temp_call( 36 | &self, 37 | event: &Event, 38 | config: &Arc, 39 | ob: &Arc, 40 | ) -> bool { 41 | let mut matched_temp_key: Option = None; 42 | let mut temps = self.temps.lock().await; 43 | for temp in temps.iter() { 44 | let session = Session::new( 45 | event.clone(), 46 | ob.clone(), 47 | config.clone(), 48 | self.temps.clone(), 49 | ); 50 | if temp.1.handle(session).await != Signal::NotMatch { 51 | matched_temp_key = Some(temp.0.to_owned()); 52 | break; 53 | } 54 | } 55 | if let Some(key) = matched_temp_key { 56 | temps.remove(&key); 57 | true 58 | } else { 59 | false 60 | } 61 | } 62 | } 63 | 64 | #[async_trait] 65 | impl EventHandler for Matchers { 66 | type Config = MatchersConfig; 67 | async fn start( 68 | &self, 69 | ob: &Arc>, 70 | config: MatchersConfig, 71 | ) -> WalleResult>> 72 | where 73 | AH: ActionHandler + Send + Sync + 'static, 74 | EH: EventHandler + Send + Sync + 'static, 75 | { 76 | *self.ob.write().await = Some(Arc::new(ob.clone())); 77 | *self.config.write().await = Arc::new(config); 78 | let ob = self.ob.read().await.clone().unwrap(); 79 | for hook in self.hooks.iter() { 80 | hook.on_start(&ob).await 81 | } 82 | Ok(vec![]) 83 | } 84 | async fn call(&self, event: Event, _: &Arc>) -> WalleResult<()> 85 | where 86 | AH: ActionHandler + Send + Sync + 'static, 87 | EH: EventHandler + Send + Sync + 'static, 88 | { 89 | use walle_core::alt::ColoredAlt; 90 | if event.ty.as_str() == "meta" { 91 | return Ok(()); 92 | } 93 | info!(target: "Walle", "{}", event.colored_alt()); 94 | let ob: Arc = 95 | self.ob.read().await.clone().ok_or(WalleError::NotStarted)?; 96 | let config = self.config.read().await.clone(); 97 | if self.temp_call(&event, &config, &ob).await { 98 | return Ok(()); 99 | } 100 | for matcher in &self.inner { 101 | let session = Session::new( 102 | event.clone(), 103 | ob.clone(), 104 | config.clone(), 105 | self.temps.clone(), 106 | ); 107 | if matcher.handle(session).await == Signal::MatchAndBlock { 108 | return Ok(()); 109 | } 110 | } 111 | Ok(()) 112 | } 113 | async fn shutdown(&self) { 114 | let ob = self.ob.read().await.clone().unwrap(); 115 | for hook in self.hooks.iter() { 116 | hook.on_shutdown(&ob).await; 117 | } 118 | *self.ob.write().await = None; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/builtin/pre_handle.rs: -------------------------------------------------------------------------------- 1 | use crate::{pre_handle_fn, MatchersConfig, PreHandler, Session, Signal}; 2 | use walle_core::{ 3 | segment::{MessageMutExt, MsgSegmentMut}, 4 | util::{Value, ValueMapExt}, 5 | }; 6 | 7 | pub struct StripPrefix { 8 | pub prefix: String, 9 | } 10 | 11 | impl PreHandler for StripPrefix { 12 | fn pre_handle(&self, session: &mut Session) -> Signal { 13 | if let Some(text) = session 14 | .event 15 | .extra 16 | .try_get_as_mut::<&mut Vec>("message") 17 | .ok() 18 | .and_then(|v| v.try_first_text_mut().ok()) 19 | { 20 | if let Some(s) = text.strip_prefix(&self.prefix) { 21 | *text = s.to_string(); 22 | return Signal::Matched; 23 | } 24 | } 25 | Signal::NotMatch 26 | } 27 | } 28 | 29 | pub fn strip_prefix(prefix: S) -> StripPrefix 30 | where 31 | S: ToString, 32 | { 33 | StripPrefix { 34 | prefix: prefix.to_string(), 35 | } 36 | } 37 | 38 | pub fn trim(always_match: bool) -> impl PreHandler { 39 | pre_handle_fn(move |session| { 40 | let mut sig = if always_match { 41 | Signal::Matched 42 | } else { 43 | Signal::NotMatch 44 | }; 45 | let Ok(segs) = session 46 | .event 47 | .extra 48 | .try_get_as_mut::<&mut Vec>("message") else { 49 | return sig; 50 | }; 51 | if let Ok(text) = segs.try_first_text_mut() { 52 | if text.starts_with(' ') { 53 | sig = Signal::Matched; 54 | } 55 | *text = text.trim_start().to_owned(); 56 | } 57 | if let Ok(text) = segs.try_last_text_mut() { 58 | if text.ends_with(' ') { 59 | sig = Signal::Matched; 60 | } 61 | *text = text.trim_end().to_owned(); 62 | } 63 | sig 64 | }) 65 | } 66 | 67 | fn _mention_me(session: &mut Session) -> Signal { 68 | let self_id = session.event.selft().unwrap_or_default().user_id; 69 | let Ok(segs) = session.event.extra.try_get_as_mut::<&mut Vec>("message") else { 70 | return Signal::NotMatch 71 | }; 72 | _mention_user(segs, self_id) | _nickname(&session.config, segs) 73 | } 74 | 75 | fn _mention_user(segs: &mut Vec, user_id: String) -> Signal { 76 | let mut mentioned_index = None; 77 | let Ok(seg_muts) = segs.try_as_mut() else { return Signal::NotMatch }; 78 | for (index, seg) in seg_muts.into_iter().enumerate() { 79 | match seg { 80 | MsgSegmentMut::Mention { 81 | user_id: mention_id, 82 | } if mention_id.as_str() == &user_id => { 83 | mentioned_index = Some(index); 84 | break; 85 | } 86 | _ => {} 87 | } 88 | } 89 | if let Some(index) = mentioned_index { 90 | segs.remove(index); 91 | Signal::Matched 92 | } else { 93 | Signal::NotMatch 94 | } 95 | } 96 | 97 | fn _nickname(config: &MatchersConfig, segs: &mut Vec) -> Signal { 98 | if let Ok(text) = segs.try_first_text_mut() { 99 | for nickname in &config.nicknames { 100 | if let Some(s) = text.strip_prefix(nickname) { 101 | if !s.is_empty() { 102 | *text = s.to_owned(); 103 | } else { 104 | segs.remove(0); 105 | } 106 | return Signal::Matched; 107 | } 108 | } 109 | } 110 | Signal::NotMatch 111 | } 112 | 113 | pub fn mention_user(user_id: String) -> impl PreHandler { 114 | pre_handle_fn(move |session| { 115 | let Ok(segs) = session.event.extra.try_get_as_mut::<&mut Vec>("message") else { 116 | return Signal::NotMatch 117 | }; 118 | _mention_user(segs, user_id.clone()) 119 | }) 120 | } 121 | 122 | pub fn mention_me() -> impl PreHandler { 123 | pre_handle_fn(_mention_me) 124 | } 125 | 126 | pub fn to_me() -> impl PreHandler { 127 | pre_handle_fn(|session| { 128 | let sig = if &session.event.detail_type == "private" { 129 | Signal::Matched 130 | } else { 131 | Signal::NotMatch 132 | }; 133 | sig | _mention_me(session) 134 | }) 135 | } 136 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | # Walle 5 | 6 | ![OneBot12](https://img.shields.io/badge/OneBot-12-black?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHAAAABwCAMAAADxPgR5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAxQTFRF////29vbr6+vAAAAk1hCcwAAAAR0Uk5T////AEAqqfQAAAKcSURBVHja7NrbctswDATQXfD//zlpO7FlmwAWIOnOtNaTM5JwDMa8E+PNFz7g3waJ24fviyDPgfhz8fHP39cBcBL9KoJbQUxjA2iYqHL3FAnvzhL4GtVNUcoSZe6eSHizBcK5LL7dBr2AUZlev1ARRHCljzRALIEog6H3U6bCIyqIZdAT0eBuJYaGiJaHSjmkYIZd+qSGWAQnIaz2OArVnX6vrItQvbhZJtVGB5qX9wKqCMkb9W7aexfCO/rwQRBzsDIsYx4AOz0nhAtWu7bqkEQBO0Pr+Ftjt5fFCUEbm0Sbgdu8WSgJ5NgH2iu46R/o1UcBXJsFusWF/QUaz3RwJMEgngfaGGdSxJkE/Yg4lOBryBiMwvAhZrVMUUvwqU7F05b5WLaUIN4M4hRocQQRnEedgsn7TZB3UCpRrIJwQfqvGwsg18EnI2uSVNC8t+0QmMXogvbPg/xk+Mnw/6kW/rraUlvqgmFreAA09xW5t0AFlHrQZ3CsgvZm0FbHNKyBmheBKIF2cCA8A600aHPmFtRB1XvMsJAiza7LpPog0UJwccKdzw8rdf8MyN2ePYF896LC5hTzdZqxb6VNXInaupARLDNBWgI8spq4T0Qb5H4vWfPmHo8OyB1ito+AysNNz0oglj1U955sjUN9d41LnrX2D/u7eRwxyOaOpfyevCWbTgDEoilsOnu7zsKhjRCsnD/QzhdkYLBLXjiK4f3UWmcx2M7PO21CKVTH84638NTplt6JIQH0ZwCNuiWAfvuLhdrcOYPVO9eW3A67l7hZtgaY9GZo9AFc6cryjoeFBIWeU+npnk/nLE0OxCHL1eQsc1IciehjpJv5mqCsjeopaH6r15/MrxNnVhu7tmcslay2gO2Z1QfcfX0JMACG41/u0RrI9QAAAABJRU5ErkJggg==) 7 | 8 | license 9 | 10 | 11 |
12 | 13 | 14 | 15 | A Onebot application SDK 16 | 17 | Onebot 应用端开发框架,基于 [Walle-core](https://github.com/abrahum/walle-core) 18 | 19 | ## 最小实例 20 | 21 | ```rust 22 | use walle::{builtin::Echo, Plugins, Walle}; 23 | use walle_core::AppConfig; 24 | 25 | #[tokio::main] 26 | async fn main() { 27 | let plugins = Plugins::new().add_message_plugin(Echo::new()); 28 | let walle = Walle::new(AppConfig::default(), plugins); 29 | walle.start().await.unwrap(); 30 | } 31 | ``` 32 | 33 | ## Plugin 34 | 35 | Walle 以 Plugin 为各个独立组件作为开发,并提供一些常用可复用组件。 36 | 37 | 一个插件实例 38 | 39 | ```rust 40 | pub struct Echo; 41 | 42 | #[async_trait] 43 | impl Handler for Echo { 44 | async fn handle(&self, session: Session) { 45 | let _ = session.send(session.event.message().clone()).await; 46 | } 47 | } 48 | 49 | impl Echo { 50 | pub fn new() -> Plugin { 51 | Plugin::new("echo", "echo description", on_command("echo", Echo)) 52 | } 53 | } 54 | ``` 55 | 56 | 使用闭包构建插件 57 | 58 | ```rust 59 | pub fn echo2() -> Plugin { 60 | Plugin::new( 61 | "echo2", 62 | "echo2 description", 63 | on_command( 64 | "echo2", 65 | handler_fn(|mut session: Session| async move { 66 | let _ = session 67 | .get("input message", std::time::Duration::from_secs(10)) 68 | .await; 69 | let _ = session.send(session.event.message().clone()).await; 70 | }), 71 | ), 72 | ) 73 | } 74 | ``` 75 | 76 | ## 组件 77 | 78 | Walle 使用了类似 Tower 的 Service Layer 模式,提供了一些组件,供开发者使用。 79 | 80 | Handler 可以类比为 Service 组件,它是一个消息处理器,接收一个 Session,并返回一个消息。 81 | 82 | Rule 和 PreHandler 可以类比为 Layer 组件,它们是一个消息规则匹配和预处理器,前者接收一个 &Session,后者接受一个 &mut Session。 83 | 84 | 需要注意的是所有以上所有 trait 和 Session 都具有一个泛型参数,用于约定其处理的消息类型。 85 | 86 | Handler 最终需要被包裹为一个 Plugin,然后添加至 Plugins 中。 87 | 88 | ## Handler 89 | 90 | ```rust 91 | pub struct Echo; 92 | 93 | #[async_trait] 94 | impl Handler for Echo { 95 | async fn handle(&self, session: Session) { 96 | let _ = session.send(session.event.message().clone()).await; 97 | } 98 | } 99 | 100 | // or 101 | 102 | let echo2 = handler_fn(|mut session: Session| async move { 103 | let _ = session 104 | .get("input message", std::time::Duration::from_secs(10)) 105 | .await; 106 | let _ = session.send(session.event.message().clone()).await; 107 | }); 108 | ``` 109 | 110 | ## Rule 111 | 112 | ```rust 113 | pub struct UserIdChecker { 114 | pub user_id: String, 115 | } 116 | 117 | impl Rule for UserIdChecker { 118 | fn rule(&self, session: &Session) -> bool { 119 | session.event.user_id() == self.user_id 120 | } 121 | } 122 | 123 | pub fn user_id_check(user_id: S) -> UserIdChecker 124 | where 125 | S: ToString, 126 | { 127 | UserIdChecker { 128 | user_id: user_id.to_string(), 129 | } 130 | } 131 | 132 | // or 133 | 134 | pub fn start_with(word: &str) -> impl Rule { 135 | let word = word.to_string(); 136 | rule_fn(move |session: &Session| { 137 | session.event.content.alt_message.starts_with(&word) 138 | }) 139 | } 140 | ``` 141 | 142 | ## PreHandler 143 | 144 | ```rust 145 | pub struct StripPrefix { 146 | pub prefix: String, 147 | } 148 | 149 | impl PreHandler for StripPrefix { 150 | fn pre_handle(&self, session: &mut Session) { 151 | let _ = session.event.content.alt_message.strip_prefix(&self.prefix); 152 | } 153 | } 154 | 155 | pub fn strip_prefix(prefix: S) -> StripPrefix 156 | where 157 | S: ToString, 158 | { 159 | StripPrefix { 160 | prefix: prefix.to_string(), 161 | } 162 | } 163 | ``` 164 | 165 | ## Matcher 166 | 167 | ```rust 168 | pub fn on_command(command: &str, handler: H) -> impl Handler 169 | where 170 | H: Handler + Sync, 171 | { 172 | handler 173 | .rule(start_with(command)) 174 | .pre_handle(strip_prefix(command)) 175 | } 176 | ``` -------------------------------------------------------------------------------- /src/builtin/extract.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod test { 3 | pub struct Command(walle_core::segment::Segments); 4 | 5 | #[walle_core::prelude::async_trait] 6 | impl crate::FromSessionPart for Command { 7 | async fn from_session_part(session: &mut crate::Session) -> walle_core::WalleResult { 8 | use walle_core::{segment::MessageMutExt, util::ValueMapExt}; 9 | let mut segs = session 10 | .event 11 | .extra 12 | .try_get_as_mut::<&mut Vec>("message") 13 | .map(|v| std::mem::take(v))? 14 | .into_iter() 15 | .map(|seg| seg.downcast()) 16 | .collect::>()?; 17 | if let Ok(text) = segs.try_first_text_mut() { 18 | if let Some(mut rest) = text.strip_prefix("command") { 19 | rest = rest.trim_start(); 20 | if !rest.is_empty() { 21 | *text = rest.to_string(); 22 | } else { 23 | segs.remove(0); 24 | } 25 | return Ok(Self(segs)); 26 | } 27 | } 28 | Err(walle_core::WalleError::Other(format!( 29 | "Command not match with {}", 30 | "command" 31 | ))) 32 | } 33 | } 34 | 35 | pub enum Commands { 36 | A(crate::walle_core::segment::Segments), 37 | B(crate::walle_core::segment::Segments), 38 | } 39 | 40 | #[crate::walle_core::prelude::async_trait] 41 | impl crate::FromSessionPart for Commands { 42 | async fn from_session_part( 43 | session: &mut crate::Session, 44 | ) -> crate::walle_core::WalleResult { 45 | use crate::walle_core::{segment::MessageMutExt, util::ValueMapExt}; 46 | 47 | let mut segs = session 48 | .event 49 | .extra 50 | .try_get_as_mut::<&mut Vec>("message") 51 | .map(std::mem::take)? 52 | .into_iter() 53 | .map(|seg| seg.downcast()) 54 | .collect::>()?; 55 | if let Ok(text) = segs.try_first_text_mut() { 56 | if let Some(mut rest) = text.strip_prefix("a") { 57 | rest = rest.trim_start(); 58 | if !rest.is_empty() { 59 | *text = rest.to_string(); 60 | } else { 61 | segs.remove(0); 62 | } 63 | return Ok(Self::A(segs)); 64 | } else if let Some(mut rest) = text.strip_prefix("b") { 65 | rest = rest.trim_start(); 66 | if !rest.is_empty() { 67 | *text = rest.to_string(); 68 | } else { 69 | segs.remove(0); 70 | } 71 | return Ok(Self::B(segs)); 72 | } 73 | } 74 | Err(crate::walle_core::WalleError::Other(format!( 75 | "Command not match with {}", 76 | ["a", "b"].join(" or ") 77 | ))) 78 | } 79 | } 80 | 81 | pub struct StartWith(walle_core::segment::Segments); 82 | 83 | #[walle_core::prelude::async_trait] 84 | impl crate::FromSessionPart for StartWith { 85 | async fn from_session_part(session: &mut crate::Session) -> walle_core::WalleResult { 86 | use walle_core::util::ValueMapExt; 87 | let segs = session 88 | .event 89 | .extra 90 | .try_get_as_mut::<&mut Vec>("message") 91 | .map(|v| std::mem::take(v))? 92 | .into_iter() 93 | .map(|seg| seg.downcast()) 94 | .collect::>()?; 95 | if let Some(Ok(text)) = segs 96 | .first() 97 | .map(|seg| seg.data.try_get_as_ref::<&str>("text")) 98 | { 99 | if text.starts_with("started") { 100 | return Ok(Self(segs)); 101 | } 102 | } 103 | Err(walle_core::WalleError::Other(format!( 104 | "Message not start with {}", 105 | "started" 106 | ))) 107 | } 108 | } 109 | } 110 | 111 | #[macro_export] 112 | macro_rules! on_command { 113 | ($cid: ident, $command: expr) => { 114 | on_command!($cid, $command, walle); 115 | }; 116 | ($cid: ident, $command: expr, $span: tt) => { 117 | pub struct $cid($span::walle_core::segment::Segments); 118 | 119 | #[$span::walle_core::prelude::async_trait] 120 | impl $span::FromSessionPart for $cid { 121 | async fn from_session_part( 122 | session: &mut $span::Session, 123 | ) -> $span::walle_core::WalleResult { 124 | use $span::walle_core::{segment::MessageMutExt, util::ValueMapExt}; 125 | let mut segs = session 126 | .event 127 | .extra 128 | .try_get_as_mut::<&mut Vec<$span::walle_core::util::Value>>("message") 129 | .map(|v| std::mem::take(v))? 130 | .into_iter() 131 | .map(|seg| seg.downcast()) 132 | .collect::<$span::walle_core::WalleResult<$span::walle_core::segment::Segments>>()?; 133 | if let Ok(text) = segs.try_first_text_mut() { 134 | if let Some(mut rest) = text.strip_prefix($command) { 135 | rest = rest.trim_start(); 136 | if !rest.is_empty() { 137 | *text = rest.to_string(); 138 | } else { 139 | segs.remove(0); 140 | } 141 | return Ok(Self(segs)); 142 | } 143 | } 144 | Err($span::walle_core::WalleError::Other(format!( 145 | "Command not match with {}", 146 | $command 147 | ))) 148 | } 149 | } 150 | }; 151 | ($cid: ident, $($subids: ident => $commands: expr),*) => { 152 | pub enum $cid { 153 | $($subids(walle::walle_core::segment::Segments)),* 154 | } 155 | 156 | #[walle::walle_core::prelude::async_trait] 157 | impl walle::FromSessionPart for $cid { 158 | async fn from_session_part( 159 | session: &mut walle::Session, 160 | ) -> walle::walle_core::WalleResult { 161 | use walle::walle_core::{segment::MessageMutExt, util::ValueMapExt}; 162 | 163 | let mut segs = session 164 | .event 165 | .extra 166 | .try_get_as_mut::<&mut Vec>("message") 167 | .map(std::mem::take)? 168 | .into_iter() 169 | .map(|seg| seg.downcast()) 170 | .collect::>()?; 171 | if let Ok(text) = segs.try_first_text_mut() { 172 | $(if let Some(mut rest) = text.strip_prefix($commands) { 173 | rest = rest.trim_start(); 174 | if !rest.is_empty() { 175 | *text = rest.to_string(); 176 | } else { 177 | segs.remove(0); 178 | } 179 | return Ok(Self::$subids(segs)); 180 | })* 181 | } 182 | Err(walle::walle_core::WalleError::Other(format!( 183 | "Command not match with {}", 184 | [$($commands,)*].join(" or ") 185 | ))) 186 | } 187 | } 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /examples/api_test.rs: -------------------------------------------------------------------------------- 1 | use tracing::info; 2 | use walle::{ 3 | matcher, on_command, ActionCaller, ActionCallerExt, MatcherHandler, Matchers, MatchersConfig, 4 | Session, 5 | }; 6 | use walle_core::{ 7 | event::GroupMessageEvent, 8 | prelude::Action, 9 | segment::{Mention, MessageExt}, 10 | value_map, 11 | }; 12 | 13 | #[tokio::main] 14 | async fn main() { 15 | let matchers = Matchers::default() 16 | .add_matcher(recall_test_plugin().boxed()) 17 | .add_matcher(mute_test().boxed()) 18 | .add_matcher(unmute_test().boxed()); 19 | // .add_matcher(member_test()) 20 | // .add_matcher(forward_test_plugin()); 21 | let walle = walle::new_walle(matchers, "debug"); 22 | let joins = walle 23 | .start( 24 | walle::config::AppConfig::default(), 25 | MatchersConfig::default(), 26 | true, 27 | ) 28 | .await 29 | .unwrap(); 30 | // let walle = test_walle(matchers); 31 | // let joins = walle 32 | // .start((), MatchersConfig::default(), true) 33 | // .await 34 | // .unwrap(); 35 | // walle 36 | // .handle_event(Event { 37 | // id: "".to_owned(), 38 | // time: 0.0, 39 | // ty: "message".to_owned(), 40 | // detail_type: "group".to_owned(), 41 | // sub_type: "".to_owned(), 42 | // extra: value_map! { 43 | // "group_id": "", 44 | // "user_id": "", 45 | // "message": [{ 46 | // "type": "text", 47 | // "data": { 48 | // "text": "呼叫全体干员" 49 | // } 50 | // }] 51 | // }, 52 | // }) 53 | // .await 54 | // .ok(); 55 | for join in joins { 56 | join.await.ok(); 57 | } 58 | } 59 | 60 | fn recall_test_plugin() -> impl MatcherHandler { 61 | on_command!(Recall, "./recall"); 62 | matcher(|Recall(_): Recall, s: Session| async move { 63 | info!(target: "api_test", "recall test"); 64 | let m = s.reply("hello world").await.unwrap(); 65 | tokio::time::sleep(std::time::Duration::from_secs(1)).await; 66 | s.delete_message(m.message_id).await.unwrap(); 67 | }) 68 | } 69 | 70 | fn mute_test() -> impl MatcherHandler { 71 | on_command!(Mute, "./mute"); 72 | matcher( 73 | |Mute(segs): Mute, event: GroupMessageEvent, s: Session| async move { 74 | for seg in segs.extract::() { 75 | s.call_action(Action { 76 | action: "ban_group_member".to_string(), 77 | params: value_map! { 78 | "group_id": event.detail_type.group_id, 79 | "user_id": seg.user_id, 80 | "duration": 60, 81 | }, 82 | selft: None, 83 | }) 84 | .await 85 | .unwrap() 86 | .as_result() 87 | .unwrap(); 88 | } 89 | }, 90 | ) 91 | } 92 | 93 | fn unmute_test() -> impl MatcherHandler { 94 | on_command!(Unmute, "./unmute"); 95 | matcher( 96 | |Unmute(segs): Unmute, event: GroupMessageEvent, s: Session| async move { 97 | for seg in segs.extract::() { 98 | s.call_action(Action { 99 | action: "unban_group_member".to_string(), 100 | params: value_map! { 101 | "group_id": event.detail_type.group_id, 102 | "user_id": seg.user_id, 103 | }, 104 | selft: None, 105 | }) 106 | .await 107 | .unwrap(); 108 | } 109 | }, 110 | ) 111 | } 112 | 113 | // fn member_test() -> Matcher { 114 | // strip_prefix("./get_no_member") 115 | // .layer(handler_fn(|s: Session| async move { 116 | // let r = s 117 | // .call_action(walle_core::action::Action { 118 | // action: "get_group_member_info".to_string(), 119 | // selft: Some(s.event.ty.selft.clone()), 120 | // params: value_map! { 121 | // "group_id": s.event.detail_type.group_id, 122 | // "user_id": "80000001" 123 | // }, 124 | // }) 125 | // .await; 126 | // println!("{:?}", r); 127 | // })) 128 | // .boxed() 129 | // } 130 | 131 | // #[allow(dead_code)] 132 | // fn flash_test_plugin() -> Matcher { 133 | // handler_fn(|s: Session| async move { 134 | // let mut messages = s.event.message().into_iter(); 135 | // while let Some(MessageSegment::Image { file_id, .. }) = messages.next() { 136 | // s.send(vec![MessageSegment::image_with_extend( 137 | // file_id.to_string(), 138 | // extended_map! {"flash":true}, 139 | // )]) 140 | // .await 141 | // .unwrap(); 142 | // } 143 | // }) 144 | // .boxed() 145 | // } 146 | 147 | // fn reply_test_plugin() -> Matcher { 148 | // handler_fn(|s: Session| async move { 149 | // s.send(vec![MessageSegment::Reply { 150 | // message_id: s.event.message_id().to_string(), 151 | // user_id: s.event.user_id().to_string(), 152 | // extra: extended_map! {}, 153 | // }]) 154 | // .await 155 | // .unwrap(); 156 | // }) 157 | // .with_rule(strip_prefix("./reply")) 158 | // .boxed() 159 | // } 160 | 161 | // fn forward_test_plugin() -> Matcher { 162 | // handler_fn(|s: Session| async move { 163 | // s.send(vec![ 164 | // MsgSegment { 165 | // ty: "node".to_string(), 166 | // data: value_map! { 167 | // "user_id": "80000000", 168 | // "time": 1654654105527.0, 169 | // "user_name": "mht", 170 | // "message": [ 171 | // { 172 | // "type": "text", 173 | // "data": { 174 | // "text": "hello world" 175 | // } 176 | // } 177 | // ] 178 | // }, 179 | // }, 180 | // // MsgSegment { 181 | // // ty: "text".to_string(), 182 | // // data: value_map! { 183 | // // "text": "this segemnt will break the nodes" 184 | // // }, 185 | // // }, 186 | // MsgSegment { 187 | // ty: "node".to_string(), 188 | // data: value_map! { 189 | // "user_id": "80000001", 190 | // "time": 1654654190000.0, 191 | // "user_name": "mht2", 192 | // "message": [ 193 | // { 194 | // "type": "node", 195 | // "data": { 196 | // "user_id": "80000000", 197 | // "time": 1654654105527.0, 198 | // "user_name": "mht", 199 | // "message": [ 200 | // { 201 | // "type": "text", 202 | // "data": { 203 | // "text": "hello world" 204 | // } 205 | // } 206 | // ] 207 | // } 208 | // } 209 | // ] 210 | // }, 211 | // }, 212 | // ]) 213 | // .await 214 | // .unwrap(); 215 | // }) 216 | // .with_pre_handler(strip_prefix("./forward")) 217 | // .boxed() 218 | // } 219 | 220 | // fn url_image_plugin() -> MessageMatcher { 221 | // handler_fn(|s| async move { 222 | // let r = s 223 | // .bot 224 | // .upload_file_by_url( 225 | // "test".to_string(), 226 | // "https://avatars.githubusercontent.com/u/18395948?s=40&v=4".to_string(), 227 | // HashMap::default(), 228 | // None, 229 | // ) 230 | // .await 231 | // .unwrap(); 232 | // s.send(MessageSegment::image(r.data.file_id)).await.unwrap(); 233 | // }) 234 | // .with_pre_handler(strip_prefix("./url_image")) 235 | // .boxed() 236 | // } 237 | 238 | // fn delete_friend_plugin() -> MessageMatcher { 239 | // handler_fn(|s: Session| async move { 240 | // let r = s 241 | // .bot 242 | // .call_action( 243 | // walle::ext::WalleExtraAction::DeleteFriend(DeleteFriend { 244 | // user_id: s.event.content.user_id, 245 | // }) 246 | // .into(), 247 | // ) 248 | // .await; 249 | // println!("{r:?}"); 250 | // }) 251 | // .with_pre_handler(strip_prefix("./delete_me")) 252 | // .boxed() 253 | // } 254 | 255 | // fn group_temp_plugin() -> MessageMatcher { 256 | // handler_fn(|s| async move { 257 | // let r = s 258 | // .bot 259 | // .send_message_ex( 260 | // "private".to_string(), 261 | // s.event.group_id().map(ToString::to_string), 262 | // Some(s.event.user_id().to_string()), 263 | // None, 264 | // None, 265 | // vec![MessageSegment::text("hello stranger".to_string())], 266 | // extended_map! { 267 | // "sub_type": "group_temp", 268 | // }, 269 | // ) 270 | // .await; 271 | // println!("{r:?}"); 272 | // tokio::time::sleep(std::time::Duration::from_secs(2)).await; 273 | // s.bot.delete_message(r.unwrap().data.message_id).await.ok(); 274 | // }) 275 | // .with_pre_handler(strip_prefix("./temp_me")) 276 | // .boxed() 277 | // } 278 | 279 | // fn voice_test_plugin() -> MessageMatcher { 280 | // handler_fn(|s: Session| async move { 281 | // if let Ok(file) = s 282 | // .bot 283 | // .upload_file_by_path_ex( 284 | // "name".to_string(), 285 | // "E:/walle/test/test.mp3".to_string(), 286 | // None, 287 | // extended_map! { 288 | // "file_type": "voice", 289 | // }, 290 | // ) 291 | // .await 292 | // { 293 | // s.send(MessageSegment::voice(file.data.file_id)) 294 | // .await 295 | // .unwrap(); 296 | // } 297 | // }) 298 | // .with_pre_handler(strip_prefix("./voice")) 299 | // .boxed() 300 | // } 301 | -------------------------------------------------------------------------------- /src/matcher/handle.rs: -------------------------------------------------------------------------------- 1 | use crate::{FromSession, FromSessionPart}; 2 | 3 | use super::Session; 4 | use std::{future::Future, sync::Arc}; 5 | 6 | use async_trait::async_trait; 7 | use walle_core::WalleResult; 8 | 9 | #[derive(Default, Debug, PartialEq, Eq)] 10 | pub enum Signal { 11 | MatchAndBlock, 12 | Matched, 13 | #[default] 14 | NotMatch, 15 | } 16 | 17 | impl core::ops::BitOr for Signal { 18 | type Output = Self; 19 | fn bitor(self, rhs: Self) -> Self::Output { 20 | match (self, rhs) { 21 | (_, Self::MatchAndBlock) | (Self::MatchAndBlock, _) => Self::MatchAndBlock, 22 | (_, Self::Matched) | (Self::Matched, _) => Self::Matched, 23 | _ => Self::NotMatch, 24 | } 25 | } 26 | } 27 | 28 | impl core::ops::BitAnd for Signal { 29 | type Output = Self; 30 | fn bitand(self, rhs: Self) -> Self::Output { 31 | match (self, rhs) { 32 | (Self::MatchAndBlock, Self::MatchAndBlock) => Self::MatchAndBlock, 33 | (Self::MatchAndBlock, Self::Matched) 34 | | (Self::Matched, Self::MatchAndBlock) 35 | | (Self::Matched, Self::Matched) => Self::Matched, 36 | _ => Self::NotMatch, 37 | } 38 | } 39 | } 40 | 41 | impl From> for Signal { 42 | fn from(r: WalleResult) -> Self { 43 | r.unwrap_or(Self::NotMatch) 44 | } 45 | } 46 | 47 | #[async_trait] 48 | pub trait MatcherHandler { 49 | async fn handle(&self, session: Session) -> Signal; 50 | fn boxed(self) -> Box 51 | where 52 | Self: Sized, 53 | { 54 | Box::new(self) 55 | } 56 | } 57 | 58 | #[doc(hidden)] 59 | #[async_trait] 60 | pub trait ArcMatcherHandler { 61 | async fn handle(self: &Arc, session: Session) -> Signal; 62 | } 63 | 64 | impl MatcherHandler for Arc { 65 | fn handle<'life0, 'async_trait>( 66 | &'life0 self, 67 | session: Session, 68 | ) -> core::pin::Pin< 69 | Box + core::marker::Send + 'async_trait>, 70 | > 71 | where 72 | 'life0: 'async_trait, 73 | Self: 'async_trait, 74 | { 75 | self.handle(session) 76 | } 77 | } 78 | 79 | #[async_trait] 80 | pub trait _MatcherHandler { 81 | async fn _handle(&self, session: Session) -> Signal; 82 | } 83 | 84 | pub fn matcher(h: H) -> BoxedMatcherHandler 85 | where 86 | H: _MatcherHandler, 87 | { 88 | BoxedMatcherHandler(h, std::marker::PhantomData::default()) 89 | } 90 | 91 | pub struct BoxedMatcherHandler(H, std::marker::PhantomData); 92 | 93 | impl MatcherHandler for BoxedMatcherHandler 94 | where 95 | H: _MatcherHandler, 96 | { 97 | fn handle<'life0, 'async_trait>( 98 | &'life0 self, 99 | session: Session, 100 | ) -> core::pin::Pin< 101 | Box + core::marker::Send + 'async_trait>, 102 | > 103 | where 104 | 'life0: 'async_trait, 105 | Self: 'async_trait, 106 | { 107 | self.0._handle(session) 108 | } 109 | } 110 | 111 | impl _MatcherHandler<()> for F 112 | where 113 | F: Fn() -> Fut + Send + Sync + 'static, 114 | Fut: Future + Send + 'static, 115 | { 116 | fn _handle<'a, 't>( 117 | &'a self, 118 | _session: Session, 119 | ) -> core::pin::Pin + core::marker::Send + 't>> 120 | where 121 | 'a: 't, 122 | Self: 't, 123 | { 124 | Box::pin(async move { 125 | tokio::spawn(self()); 126 | Signal::Matched 127 | }) 128 | } 129 | } 130 | 131 | impl _MatcherHandler for F 132 | where 133 | F: Fn(T) -> Fut + Send + Sync + 'static, 134 | Fut: Future + Send + 'static, 135 | T: FromSession + Send, 136 | { 137 | fn _handle<'a, 't>( 138 | &'a self, 139 | session: Session, 140 | ) -> core::pin::Pin + core::marker::Send + 't>> 141 | where 142 | 'a: 't, 143 | Self: 't, 144 | { 145 | Box::pin(async move { 146 | let t = match T::from_session(session).await { 147 | Ok(t) => t, 148 | Err(e) => { 149 | tracing::debug!(target: "Walle", "from session failed: {}", e); 150 | return Signal::NotMatch; 151 | } 152 | }; 153 | tokio::spawn(self(t)); 154 | Signal::Matched 155 | }) 156 | } 157 | } 158 | 159 | macro_rules! impl_matcher_handler { 160 | ($($ty: ident),*) => { 161 | #[allow(non_snake_case)] 162 | impl _MatcherHandler<($($ty,)* T)> for F 163 | where 164 | F: Fn($($ty,)* T) -> Fut + Send + Sync + 'static, 165 | Fut: Future + Send + 'static, 166 | $($ty: FromSessionPart + Send,)* 167 | T: FromSession + Send, 168 | { 169 | fn _handle<'a, 't>( 170 | &'a self, 171 | mut session: Session, 172 | ) -> core::pin::Pin + core::marker::Send + 't>> 173 | where 174 | 'a: 't, 175 | Self: 't, 176 | { 177 | Box::pin(async move { 178 | $(let $ty = match $ty::from_session_part(&mut session).await { 179 | Ok(t) => t, 180 | Err(e) => { 181 | tracing::debug!(target: "Walle", "from session part failed: {}", e); 182 | return Signal::NotMatch; 183 | } 184 | };)* 185 | let t = match T::from_session(session).await { 186 | Ok(t) => t, 187 | Err(e) => { 188 | tracing::debug!(target: "Walle", "from session failed: {}", e); 189 | return Signal::NotMatch; 190 | } 191 | }; 192 | tokio::spawn(self($($ty,)* t)); 193 | Signal::Matched 194 | }) 195 | } 196 | } 197 | }; 198 | } 199 | 200 | impl_matcher_handler!(T0); 201 | impl_matcher_handler!(T0, T1); 202 | impl_matcher_handler!(T0, T1, T2); 203 | impl_matcher_handler!(T0, T1, T2, T3); 204 | impl_matcher_handler!(T0, T1, T2, T3, T4); 205 | impl_matcher_handler!(T0, T1, T2, T3, T4, T5); 206 | impl_matcher_handler!(T0, T1, T2, T3, T4, T5, T6); 207 | impl_matcher_handler!(T0, T1, T2, T3, T4, T5, T6, T7); 208 | impl_matcher_handler!(T0, T1, T2, T3, T4, T5, T6, T7, T8); 209 | 210 | #[cfg(test)] 211 | mod test { 212 | pub struct StructMatcher; 213 | 214 | impl StructMatcher { 215 | async fn method( 216 | &self, 217 | _event: crate::walle_core::event::GroupMessageEvent, 218 | _session: crate::Session, 219 | ) { 220 | () 221 | } 222 | #[allow(dead_code)] 223 | async fn failable_method( 224 | self: &std::sync::Arc, 225 | _event: crate::walle_core::event::GroupMessageEvent, 226 | _session: crate::Session, 227 | ) -> crate::walle_core::WalleResult<()> { 228 | Ok(()) 229 | } 230 | } 231 | 232 | #[crate::walle_core::prelude::async_trait] 233 | impl crate::ArcMatcherHandler for StructMatcher { 234 | async fn handle(self: &std::sync::Arc, mut session: crate::Session) -> crate::Signal { 235 | use crate::{FromSession, FromSessionPart}; 236 | let event = 237 | match walle_core::event::GroupMessageEvent::from_session_part(&mut session).await { 238 | Ok(e) => e, 239 | Err(e) => { 240 | tracing::debug!(target: "Walle", "from session part failed: {}", e); 241 | return crate::Signal::NotMatch; 242 | } 243 | }; 244 | let session = match crate::Session::from_session(session).await { 245 | Ok(e) => e, 246 | Err(e) => { 247 | tracing::debug!(target: "Walle", "from session failed: {}", e); 248 | return crate::Signal::NotMatch; 249 | } 250 | }; 251 | let new = self.clone(); 252 | crate::tokio::spawn(async move { new.method(event, session).await }); 253 | crate::Signal::Matched 254 | } 255 | } 256 | } 257 | 258 | #[macro_export] 259 | macro_rules! matcher { 260 | ($s: ident, $m: ident, $($i: ident: $t: ty),*) => { 261 | #[walle::walle_core::prelude::async_trait] 262 | impl walle::ArcMatcherHandler for $s { 263 | async fn handle(self: &std::sync::Arc, mut session: walle::Session) -> walle::Signal { 264 | use walle::{FromSession, FromSessionPart}; 265 | $(let $i = 266 | match <$t>::from_session_part(&mut session).await { 267 | Ok(e) => e, 268 | Err(e) => { 269 | walle::tracing::debug!(target: "Walle", "from session part failed: {}", e); 270 | return walle::Signal::NotMatch; 271 | } 272 | };)* 273 | let session = match walle::Session::from_session(session).await { 274 | Ok(e) => e, 275 | Err(e) => { 276 | walle::tracing::debug!(target: "Walle", "from session failed: {}", e); 277 | return walle::Signal::NotMatch; 278 | } 279 | }; 280 | let new = self.clone(); 281 | walle::tokio::spawn(async move { new.$m($($i,)* session).await }); 282 | walle::Signal::Matched 283 | } 284 | } 285 | }; 286 | (failable: $s: ident, $m: ident, $($i: ident: $t: ty),*) => { 287 | #[walle::walle_core::prelude::async_trait] 288 | impl walle::ArcMatcherHandler for $s { 289 | async fn handle(self: &std::sync::Arc, mut session: walle::Session) -> walle::Signal { 290 | use walle::{FromSession, FromSessionPart}; 291 | $(let $i = 292 | match <$t>::from_session_part(&mut session).await { 293 | Ok(e) => e, 294 | Err(e) => { 295 | walle::tracing::debug!(target: "Walle", "from session part failed: {}", e); 296 | return walle::Signal::NotMatch; 297 | } 298 | };)* 299 | let session = match walle::Session::from_session(session).await { 300 | Ok(e) => e, 301 | Err(e) => { 302 | walle::tracing::debug!(target: "Walle", "from session failed: {}", e); 303 | return walle::Signal::NotMatch; 304 | } 305 | }; 306 | let new = self.clone(); 307 | walle::tokio::spawn(async move { if let Err(e) = new.$m($($i,)* session).await { 308 | walle::tracing::warn!(target: "Walle", "matcher failed: {}", e); 309 | } }); 310 | walle::Signal::Matched 311 | } 312 | } 313 | }; 314 | } 315 | -------------------------------------------------------------------------------- /src/matcher/session.rs: -------------------------------------------------------------------------------- 1 | use super::TempMatcher; 2 | use crate::{ 3 | ActionCaller, ActionCallerExt, MatcherHandler, MatchersConfig, PreHandler, Rule, TempMatchers, 4 | }; 5 | use std::{pin::Pin, sync::Arc, time::Duration}; 6 | use walle_core::{ 7 | event::{ 8 | BaseEvent, DetailTypeLevel, ImplLevel, ParseEvent, PlatformLevel, SubTypeLevel, 9 | TryFromEvent, TypeLevel, 10 | }, 11 | prelude::{async_trait, Event}, 12 | segment::{IntoMessage, MsgSegment, Segments}, 13 | structs::{Selft, SendMessageResp}, 14 | util::{Value, ValueMap, ValueMapExt}, 15 | WalleError, WalleResult, 16 | }; 17 | 18 | /// Matcher 使用的 Session 19 | #[derive(Clone)] 20 | pub struct Session { 21 | pub event: Event, 22 | pub config: Arc, 23 | pub caller: Arc, 24 | reply_sign: ReplySign, 25 | temps: TempMatchers, 26 | pub(crate) selft: Option, 27 | } 28 | 29 | impl Session { 30 | pub fn new( 31 | event: Event, 32 | caller: Arc, 33 | config: Arc, 34 | temps: TempMatchers, 35 | ) -> Self { 36 | let reply_sign = ReplySign::new(&event); 37 | Self { 38 | selft: event.selft(), 39 | event, 40 | config, 41 | caller, 42 | reply_sign, 43 | temps, 44 | } 45 | } 46 | } 47 | 48 | #[derive(Clone)] 49 | enum ReplySign { 50 | Private(String), 51 | Group(String, String), 52 | Channel(String, String, String), 53 | UnReplyAble, 54 | } 55 | 56 | impl ReplySign { 57 | fn new(event: &Event) -> Self { 58 | if let (Ok(guild_id), Ok(channel_id), Ok(user_id)) = ( 59 | event.extra.get_downcast("guild_id"), 60 | event.extra.get_downcast("channel_id"), 61 | event.extra.get_downcast("user_id"), 62 | ) { 63 | ReplySign::Channel(guild_id, channel_id, user_id) 64 | } else if let (Ok(group_id), Ok(user_id)) = ( 65 | event.extra.get_downcast("group_id"), 66 | event.extra.get_downcast("user_id"), 67 | ) { 68 | ReplySign::Group(group_id, user_id) 69 | } else if let Ok(user_id) = event.extra.get_downcast("user_id") { 70 | ReplySign::Private(user_id) 71 | } else { 72 | ReplySign::UnReplyAble 73 | } 74 | } 75 | 76 | fn ruled( 77 | &self, 78 | handler: H, 79 | extra_pre_handler: PH, 80 | this_user_only: bool, 81 | ) -> WalleResult> 82 | where 83 | H: MatcherHandler + Send + Sync + 'static, 84 | PH: PreHandler + Send + Sync + 'static, 85 | { 86 | use crate::builtin::*; 87 | Ok(match self { 88 | ReplySign::Private(user_id) => extra_pre_handler 89 | .with_rule(user_id_check(user_id)) 90 | .layer(handler) 91 | .boxed(), 92 | ReplySign::Group(group_id, user_id) => { 93 | if this_user_only { 94 | extra_pre_handler 95 | .with_rule(user_id_check(user_id)) 96 | .with_rule(group_id_check(group_id)) 97 | .layer(handler) 98 | .boxed() 99 | } else { 100 | extra_pre_handler 101 | .with_rule(group_id_check(group_id)) 102 | .layer(handler) 103 | .boxed() 104 | } 105 | } 106 | ReplySign::Channel(guild_id, channel_id, user_id) => { 107 | if this_user_only { 108 | extra_pre_handler 109 | .with_rule(user_id_check(user_id)) 110 | .with_rule(channel_id_check(guild_id, channel_id)) 111 | .layer(handler) 112 | .boxed() 113 | } else { 114 | extra_pre_handler 115 | .with_rule(channel_id_check(guild_id, channel_id)) 116 | .layer(handler) 117 | .boxed() 118 | } 119 | } 120 | ReplySign::UnReplyAble => { 121 | return Err(WalleError::Other("unreplyable session".to_string())) 122 | } 123 | }) 124 | } 125 | } 126 | 127 | impl Session { 128 | pub async fn reply(&self, message: M) -> WalleResult { 129 | match &self.reply_sign { 130 | ReplySign::Private(user_id) => { 131 | self.send_private_message(user_id.clone(), message).await 132 | } 133 | ReplySign::Group(group_id, ..) => { 134 | self.send_group_message(group_id.clone(), message).await 135 | } 136 | ReplySign::Channel(guild_id, channel_id, ..) => { 137 | self.send_channel_message(guild_id.clone(), channel_id.clone(), message) 138 | .await 139 | } 140 | ReplySign::UnReplyAble => Err(WalleError::Other("unreplyable session".to_string())), 141 | } 142 | } 143 | pub fn getter<'a>(&'a mut self) -> SessionGetter<'a, (), ()> { 144 | SessionGetter { 145 | session: self, 146 | rule: (), 147 | pre_handler: (), 148 | this_user_only: false, 149 | timeout: 60, 150 | timeout_callback: |_: &Session| Box::pin(async move {}), 151 | } 152 | } 153 | pub async fn get(&mut self, message: M) -> WalleResult 154 | where 155 | M: IntoMessage + Send, 156 | { 157 | self.getter().get(message).await 158 | } 159 | } 160 | 161 | pub struct SessionGetter<'a, R, PH> { 162 | session: &'a mut Session, 163 | rule: R, 164 | pre_handler: PH, 165 | this_user_only: bool, 166 | timeout: u64, 167 | timeout_callback: 168 | for<'b> fn(&'b Session) -> Pin + Send + 'b>>, 169 | } 170 | 171 | impl<'a, R, PH> SessionGetter<'a, R, PH> 172 | where 173 | R: Rule + Send + Sync + 'static, 174 | PH: PreHandler + Send + Sync + 'static, 175 | { 176 | pub fn with_rule(self, rule: R0) -> SessionGetter<'a, crate::JoinedRule, PH> 177 | where 178 | R0: Rule + Send + Sync + 'static, 179 | { 180 | SessionGetter { 181 | session: self.session, 182 | rule: self.rule.with(rule), 183 | pre_handler: self.pre_handler, 184 | this_user_only: self.this_user_only, 185 | timeout: self.timeout, 186 | timeout_callback: self.timeout_callback, 187 | } 188 | } 189 | 190 | pub fn with_pre_handler( 191 | self, 192 | pre_handler: PH0, 193 | ) -> SessionGetter<'a, R, crate::JoinedPreHandler> 194 | where 195 | PH0: PreHandler + Send + Sync + 'static, 196 | { 197 | SessionGetter { 198 | session: self.session, 199 | rule: self.rule, 200 | pre_handler: self.pre_handler.with(pre_handler), 201 | this_user_only: self.this_user_only, 202 | timeout: self.timeout, 203 | timeout_callback: self.timeout_callback, 204 | } 205 | } 206 | 207 | pub fn this_user_only(self) -> Self { 208 | Self { 209 | this_user_only: true, 210 | ..self 211 | } 212 | } 213 | 214 | pub fn timeout(self, timeout: u64) -> Self { 215 | Self { timeout, ..self } 216 | } 217 | 218 | pub fn timeout_callback( 219 | self, 220 | callback: for<'b> fn( 221 | &'b Session, 222 | ) 223 | -> Pin + Send + 'b>>, 224 | ) -> SessionGetter<'a, R, PH> { 225 | SessionGetter { 226 | session: self.session, 227 | rule: self.rule, 228 | pre_handler: self.pre_handler, 229 | this_user_only: self.this_user_only, 230 | timeout: self.timeout, 231 | timeout_callback: callback, 232 | } 233 | } 234 | 235 | pub async fn get(self, message: M) -> WalleResult { 236 | let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel(); 237 | let temp = self.session.reply_sign.ruled( 238 | TempMatcher { tx }, 239 | self.pre_handler.with_rule(self.rule), 240 | self.this_user_only, 241 | )?; 242 | self.session 243 | .temps 244 | .lock() 245 | .await 246 | .insert(self.session.event.id.clone(), temp); 247 | let resp = self.session.reply(message).await?; 248 | if let Ok(Some(event)) = 249 | tokio::time::timeout(Duration::from_secs(self.timeout), rx.recv()).await 250 | { 251 | self.session.event = event; 252 | } else { 253 | self.session 254 | .temps 255 | .lock() 256 | .await 257 | .remove(&self.session.event.id); 258 | (self.timeout_callback)(self.session).await; 259 | return Err(WalleError::Other("session get timeout".to_owned())); 260 | } 261 | Ok(resp) 262 | } 263 | } 264 | 265 | #[async_trait] 266 | pub trait FromSessionPart: Sized { 267 | async fn from_session_part(session: &mut Session) -> WalleResult; 268 | } 269 | 270 | #[async_trait] 271 | pub trait FromSession: Sized { 272 | async fn from_session(session: Session) -> WalleResult; 273 | } 274 | 275 | impl FromSessionPart for Segments { 276 | fn from_session_part<'life0, 'async_trait>( 277 | session: &'life0 mut Session, 278 | ) -> core::pin::Pin< 279 | Box< 280 | dyn core::future::Future> 281 | + core::marker::Send 282 | + 'async_trait, 283 | >, 284 | > 285 | where 286 | 'life0: 'async_trait, 287 | Self: 'async_trait, 288 | { 289 | Box::pin(async move { 290 | let segments = session 291 | .event 292 | .extra 293 | .try_get_as_mut::<&mut Vec>("message")?; 294 | let segments = std::mem::replace(segments, vec![]); 295 | segments 296 | .into_iter() 297 | .map(|v| MsgSegment::try_from(v)) 298 | .collect() 299 | }) 300 | } 301 | } 302 | 303 | impl FromSessionPart for BaseEvent 304 | where 305 | T: TryFromEvent, 306 | D: TryFromEvent, 307 | S: TryFromEvent, 308 | P: TryFromEvent, 309 | I: TryFromEvent, 310 | { 311 | fn from_session_part<'life0, 'async_trait>( 312 | session: &'life0 mut Session, 313 | ) -> core::pin::Pin< 314 | Box< 315 | dyn core::future::Future> 316 | + core::marker::Send 317 | + 'async_trait, 318 | >, 319 | > 320 | where 321 | 'life0: 'async_trait, 322 | Self: 'async_trait, 323 | { 324 | Box::pin(async move { 325 | let event = std::mem::replace( 326 | &mut session.event, 327 | Event { 328 | id: String::default(), 329 | time: 0.0, 330 | ty: String::default(), 331 | detail_type: String::default(), 332 | sub_type: String::default(), 333 | extra: ValueMap::default(), 334 | }, 335 | ); 336 | let implt = "todo"; //todo 337 | Self::parse(event, implt) 338 | }) 339 | } 340 | } 341 | 342 | impl FromSession for Session { 343 | fn from_session<'async_trait>( 344 | session: Session, 345 | ) -> core::pin::Pin< 346 | Box< 347 | dyn core::future::Future> 348 | + core::marker::Send 349 | + 'async_trait, 350 | >, 351 | > 352 | where 353 | Self: 'async_trait, 354 | { 355 | Box::pin(async move { Ok(session) }) 356 | } 357 | } 358 | 359 | #[async_trait] 360 | impl FromSession for T { 361 | async fn from_session(mut session: Session) -> WalleResult { 362 | Self::from_session_part(&mut session).await 363 | } 364 | } 365 | -------------------------------------------------------------------------------- /src/caller/mod.rs: -------------------------------------------------------------------------------- 1 | use std::{future::Future, pin::Pin, sync::Arc}; 2 | use walle_core::{ 3 | action::Action, 4 | event::Event, 5 | prelude::{async_trait, GetSelfs}, 6 | resp::Resp, 7 | structs::Selft, 8 | util::Value, 9 | ActionHandler, EventHandler, OneBot, WalleError, WalleResult, 10 | }; 11 | 12 | use crate::{Bot, Session}; 13 | 14 | #[async_trait] 15 | pub trait ActionCaller: GetSelfs + Sync { 16 | async fn call_action(&self, action: Action) -> WalleResult; 17 | async fn get_bots(&self) -> Vec; 18 | } 19 | 20 | #[async_trait] 21 | impl ActionCaller for Arc> 22 | where 23 | AH: ActionHandler + Send + Sync + 'static, 24 | EH: EventHandler + Send + Sync + 'static, 25 | { 26 | async fn call_action(&self, action: Action) -> WalleResult { 27 | self.handle_action(action).await 28 | } 29 | 30 | async fn get_bots(&self) -> Vec { 31 | self.get_selfs() 32 | .await 33 | .into_iter() 34 | .map(|id| Bot { 35 | selft: id, 36 | caller: Arc::new(self.clone()), 37 | }) 38 | .collect() 39 | } 40 | } 41 | 42 | impl GetSelfs for Bot { 43 | fn get_impl<'life0, 'life1, 'async_trait>( 44 | &'life0 self, 45 | selft: &'life1 Selft, 46 | ) -> core::pin::Pin + Send + 'async_trait>> 47 | where 48 | 'life0: 'async_trait, 49 | 'life1: 'async_trait, 50 | Self: 'async_trait, 51 | { 52 | self.caller.get_impl(selft) 53 | } 54 | fn get_selfs<'life0, 'async_trait>( 55 | &'life0 self, 56 | ) -> core::pin::Pin> + Send + 'async_trait>> 57 | where 58 | 'life0: 'async_trait, 59 | Self: 'async_trait, 60 | { 61 | self.caller.get_selfs() 62 | } 63 | } 64 | 65 | impl ActionCaller for Bot { 66 | fn call_action<'a, 't>( 67 | &'a self, 68 | mut action: Action, 69 | ) -> Pin> + Send + 't>> 70 | where 71 | 'a: 't, 72 | Self: 't, 73 | { 74 | action.selft = Some(self.selft.clone()); 75 | self.caller.call_action(action) 76 | } 77 | fn get_bots<'a, 't>(&'a self) -> Pin> + Send + 't>> 78 | where 79 | 'a: 't, 80 | Self: 't, 81 | { 82 | self.caller.get_bots() 83 | } 84 | } 85 | 86 | impl GetSelfs for Session { 87 | fn get_impl<'life0, 'life1, 'async_trait>( 88 | &'life0 self, 89 | selft: &'life1 Selft, 90 | ) -> core::pin::Pin + Send + 'async_trait>> 91 | where 92 | 'life0: 'async_trait, 93 | 'life1: 'async_trait, 94 | Self: 'async_trait, 95 | { 96 | self.caller.get_impl(selft) 97 | } 98 | fn get_selfs<'life0, 'async_trait>( 99 | &'life0 self, 100 | ) -> core::pin::Pin> + Send + 'async_trait>> 101 | where 102 | 'life0: 'async_trait, 103 | Self: 'async_trait, 104 | { 105 | self.caller.get_selfs() 106 | } 107 | } 108 | 109 | impl ActionCaller for Session 110 | { 111 | fn call_action<'a, 't>( 112 | &'a self, 113 | mut action: Action, 114 | ) -> Pin> + Send + 't>> 115 | where 116 | 'a: 't, 117 | Self: 't, 118 | { 119 | action.selft = self.selft.clone(); 120 | self.caller.call_action(action) 121 | } 122 | fn get_bots<'a, 't>(&'a self) -> Pin> + Send + 't>> 123 | where 124 | 'a: 't, 125 | Self: 't, 126 | { 127 | self.caller.get_bots() 128 | } 129 | } 130 | 131 | macro_rules! action_ext { 132 | ($fname: ident, $aty: expr => $rty: ty) => { 133 | fn $fname<'a, 't>(&'a self) -> Pin> + Send + 't>> 134 | where 135 | 'a: 't, 136 | Self: 't, 137 | { 138 | self.call(walle_core::action::Action { 139 | action: $aty.to_string(), 140 | params: walle_core::prelude::ValueMap::default(), 141 | selft: None, 142 | }) 143 | } 144 | }; 145 | ($fname: ident, $a: expr => $rty: ty, $($f: ident: $fty: ty),*) => { 146 | fn $fname<'a, 't>(&'a self, $($f: $fty),*) -> Pin> + Send + 't>> 147 | where 148 | 'a: 't, 149 | Self: 't, 150 | { 151 | self.call($a) 152 | } 153 | }; 154 | } 155 | 156 | #[async_trait] 157 | pub trait ActionCallerExt: ActionCaller { 158 | async fn call(&self, action: A) -> WalleResult 159 | where 160 | A: Into + Send, 161 | R: TryFrom, 162 | { 163 | self.call_action(action.into()) 164 | .await? 165 | .as_result() 166 | .map_err(WalleError::RespError)? 167 | .try_into() 168 | } 169 | fn get_latest_events<'a, 't>( 170 | &'a self, 171 | limit: i64, 172 | timeout: i64, 173 | ) -> Pin>> + Send + 't>> 174 | where 175 | 'a: 't, 176 | Self: 't, 177 | { 178 | self.call(walle_core::action::GetLatestEvents { limit, timeout }) 179 | } 180 | action_ext!(get_supported_actions, "get_supported_actions" => Vec); 181 | action_ext!(get_status, "get_status" => walle_core::structs::Status); 182 | action_ext!(get_version, "get_version" => walle_core::structs::Version); 183 | fn send_message<'a, 't, M>( 184 | &'a self, 185 | detail_type: String, 186 | user_id: Option, 187 | group_id: Option, 188 | guild_id: Option, 189 | channel_id: Option, 190 | message: M, 191 | ) -> Pin> + Send + 't>> 192 | where 193 | 'a: 't, 194 | Self: 't, 195 | M: walle_core::segment::IntoMessage, 196 | { 197 | self.call(walle_core::action::SendMessage { 198 | detail_type, 199 | user_id, 200 | group_id, 201 | guild_id, 202 | channel_id, 203 | message:message.into_message() 204 | }) 205 | } 206 | fn send_private_message<'a, 't, M>( 207 | &'a self, 208 | user_id: String, 209 | message: M, 210 | ) -> Pin> + Send + 't>> 211 | where 212 | 'a: 't, 213 | Self: 't, 214 | M: walle_core::segment::IntoMessage, 215 | { 216 | self.call(walle_core::action::SendMessage { 217 | detail_type: "private".to_owned(), 218 | user_id: Some(user_id), 219 | group_id: None, 220 | guild_id: None, 221 | channel_id: None, 222 | message:message.into_message() 223 | }) 224 | } 225 | fn send_group_message<'a, 't, M>( 226 | &'a self, 227 | group_id: String, 228 | message: M, 229 | ) -> Pin> + Send + 't>> 230 | where 231 | 'a: 't, 232 | Self: 't, 233 | M: walle_core::segment::IntoMessage, 234 | { 235 | self.call(walle_core::action::SendMessage { 236 | detail_type: "group".to_owned(), 237 | user_id: None, 238 | group_id: Some(group_id), 239 | guild_id: None, 240 | channel_id: None, 241 | message:message.into_message() 242 | }) 243 | } 244 | fn send_channel_message<'a, 't, M>( 245 | &'a self, 246 | guild_id: String, 247 | channel_id: String, 248 | message: M, 249 | ) -> Pin> + Send + 't>> 250 | where 251 | 'a: 't, 252 | Self: 't, 253 | M: walle_core::segment::IntoMessage, 254 | { 255 | self.call(walle_core::action::SendMessage { 256 | detail_type: "channel".to_owned(), 257 | user_id: None, 258 | group_id: None, 259 | guild_id: Some(guild_id), 260 | channel_id: Some(channel_id), 261 | message:message.into_message() 262 | }) 263 | } 264 | action_ext!( 265 | delete_message, 266 | walle_core::action::DeleteMessage { message_id } => (), 267 | message_id: String 268 | ); 269 | action_ext!( 270 | get_self_info, 271 | "get_self_info" => walle_core::structs::UserInfo 272 | ); 273 | action_ext!( 274 | get_user_info, 275 | walle_core::action::GetUserInfo { user_id } => walle_core::structs::UserInfo, 276 | user_id: String 277 | ); 278 | action_ext!( 279 | get_friend_list, 280 | "get_friend_list" => Vec 281 | ); 282 | action_ext!( 283 | get_group_info, 284 | walle_core::action::GetGroupInfo { group_id } => walle_core::structs::GroupInfo, 285 | group_id: String 286 | ); 287 | action_ext!( 288 | get_group_list, 289 | "get_group_list" => Vec 290 | ); 291 | action_ext!( 292 | get_group_member_info, 293 | walle_core::action::GetGroupMemberInfo { group_id, user_id } => 294 | walle_core::structs::UserInfo, 295 | group_id: String, 296 | user_id: String 297 | ); 298 | action_ext!( 299 | get_group_member_list, 300 | walle_core::action::GetGroupMemberList {group_id} => 301 | Vec, 302 | group_id: String); 303 | action_ext!( 304 | set_group_name, 305 | walle_core::action::SetGroupName {group_id, group_name} => (), 306 | group_id: String, 307 | group_name: String 308 | ); 309 | action_ext!( 310 | leave_group, 311 | walle_core::action::LeaveGroup {group_id} => (), 312 | group_id: String 313 | ); 314 | action_ext!( 315 | get_guild_info, 316 | walle_core::action::GetGuildInfo { guild_id } => 317 | walle_core::structs::GuildInfo, 318 | guild_id: String 319 | ); 320 | action_ext!( 321 | get_guild_list, 322 | "get_guild_list" => Vec 323 | ); 324 | action_ext!( 325 | set_guild_name, 326 | walle_core::action::SetGuildName { guild_id, guild_name } => (), 327 | guild_id: String, 328 | guild_name: String 329 | ); 330 | action_ext!( 331 | get_guild_member_info, 332 | walle_core::action::GetGuildMemberInfo { guild_id, user_id } => 333 | walle_core::structs::UserInfo, 334 | guild_id: String, 335 | user_id: String 336 | ); 337 | action_ext!( 338 | get_guild_member_list, 339 | walle_core::action::GetGuildMemberList { guild_id } => 340 | Vec, 341 | guild_id: String 342 | ); 343 | action_ext!( 344 | leave_guild, 345 | walle_core::action::LeaveGuild { guild_id } => (), 346 | guild_id: String 347 | ); 348 | action_ext!( 349 | get_channel_info, 350 | walle_core::action::GetChannelInfo { guild_id, channel_id } => 351 | walle_core::structs::ChannelInfo, 352 | guild_id: String, 353 | channel_id: String 354 | ); 355 | action_ext!( 356 | get_channel_list, 357 | walle_core::action::GetChannelList { guild_id, joined_only } => 358 | Vec, 359 | guild_id: String, 360 | joined_only: bool 361 | ); 362 | action_ext!( 363 | set_channel_name, 364 | walle_core::action::SetChannelName { guild_id, channel_id, channel_name } => (), 365 | guild_id: String, 366 | channel_id: String, 367 | channel_name: String 368 | ); 369 | action_ext!( 370 | get_channel_member_info, 371 | walle_core::action::GetChannelMemberInfo { guild_id, channel_id, user_id } => 372 | walle_core::structs::UserInfo, 373 | guild_id: String, 374 | channel_id: String, 375 | user_id: String 376 | ); 377 | action_ext!( 378 | get_channel_member_list, 379 | walle_core::action::GetChannelMemberList { guild_id, channel_id } => 380 | Vec, 381 | guild_id: String, 382 | channel_id: String 383 | ); 384 | action_ext!( 385 | leave_channel, 386 | walle_core::action::LeaveChannel { guild_id, channel_id } => (), 387 | guild_id: String, 388 | channel_id: String 389 | ); 390 | 391 | // file 392 | action_ext!( 393 | upload_file, 394 | walle_core::action::UploadFile { ty, name, url, headers, path, data, sha256 } => 395 | walle_core::structs::FileId, 396 | ty: String, 397 | name: String, 398 | url: Option, 399 | headers: Option>, 400 | path: Option, 401 | data: Option, 402 | sha256: Option 403 | ); 404 | action_ext!( 405 | upload_file_by_url, 406 | walle_core::action::UploadFile { 407 | ty: "url".to_owned(), 408 | name, 409 | url: Some(url), 410 | headers, 411 | path: None, 412 | data: None, 413 | sha256 414 | } => walle_core::structs::FileId, 415 | name: String, 416 | url: String, 417 | headers: Option>, 418 | sha256: Option 419 | ); 420 | action_ext!( 421 | upload_file_by_path, 422 | walle_core::action::UploadFile { 423 | ty: "path".to_owned(), 424 | name, 425 | url: None, 426 | headers: None, 427 | path: Some(path), 428 | data: None, 429 | sha256 430 | } => walle_core::structs::FileId, 431 | name: String, 432 | path: String, 433 | sha256: Option 434 | ); 435 | action_ext!( 436 | upload_file_by_data, 437 | walle_core::action::UploadFile { 438 | ty: "data".to_owned(), 439 | name, 440 | url: None, 441 | headers: None, 442 | path: None, 443 | data: Some(walle_core::util::OneBotBytes(data)), 444 | sha256 445 | } => walle_core::structs::FileId, 446 | name: String, 447 | data: Vec, 448 | sha256: Option 449 | ); 450 | // async fn upload_file_fragmented_by_path( 451 | // &self, 452 | // path: &str, 453 | // size: Option, 454 | // ) -> WalleResult 455 | // { 456 | // let path = std::path::PathBuf::from(path); 457 | // let file = std::fs::File::open(&path)?; 458 | // let size = file.metadata()?.len(); 459 | // self.call(walle_core::action::UploadFileFragmented::Prepare { 460 | // name: path 461 | // .file_name() 462 | // .unwrap_or_default(), 463 | // total_size: size as i64 }).await?; 464 | // todo!() 465 | // } 466 | } 467 | 468 | impl ActionCallerExt for T {} 469 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "android_system_properties" 7 | version = "0.1.5" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 10 | dependencies = [ 11 | "libc", 12 | ] 13 | 14 | [[package]] 15 | name = "async-trait" 16 | version = "0.1.59" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "31e6e93155431f3931513b243d371981bb2770112b370c82745a1d19d2f99364" 19 | dependencies = [ 20 | "proc-macro2", 21 | "quote", 22 | "syn", 23 | ] 24 | 25 | [[package]] 26 | name = "atty" 27 | version = "0.2.14" 28 | source = "registry+https://github.com/rust-lang/crates.io-index" 29 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 30 | dependencies = [ 31 | "hermit-abi", 32 | "libc", 33 | "winapi", 34 | ] 35 | 36 | [[package]] 37 | name = "autocfg" 38 | version = "1.1.0" 39 | source = "registry+https://github.com/rust-lang/crates.io-index" 40 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 41 | 42 | [[package]] 43 | name = "base64" 44 | version = "0.13.1" 45 | source = "registry+https://github.com/rust-lang/crates.io-index" 46 | checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" 47 | 48 | [[package]] 49 | name = "bitflags" 50 | version = "1.3.2" 51 | source = "registry+https://github.com/rust-lang/crates.io-index" 52 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 53 | 54 | [[package]] 55 | name = "block-buffer" 56 | version = "0.10.3" 57 | source = "registry+https://github.com/rust-lang/crates.io-index" 58 | checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" 59 | dependencies = [ 60 | "generic-array", 61 | ] 62 | 63 | [[package]] 64 | name = "bumpalo" 65 | version = "3.11.1" 66 | source = "registry+https://github.com/rust-lang/crates.io-index" 67 | checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" 68 | 69 | [[package]] 70 | name = "byteorder" 71 | version = "1.4.3" 72 | source = "registry+https://github.com/rust-lang/crates.io-index" 73 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 74 | 75 | [[package]] 76 | name = "bytes" 77 | version = "1.3.0" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" 80 | 81 | [[package]] 82 | name = "cc" 83 | version = "1.0.77" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" 86 | 87 | [[package]] 88 | name = "cfg-if" 89 | version = "1.0.0" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 92 | 93 | [[package]] 94 | name = "chrono" 95 | version = "0.4.23" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" 98 | dependencies = [ 99 | "iana-time-zone", 100 | "js-sys", 101 | "num-integer", 102 | "num-traits", 103 | "time 0.1.45", 104 | "wasm-bindgen", 105 | "winapi", 106 | ] 107 | 108 | [[package]] 109 | name = "codespan-reporting" 110 | version = "0.11.1" 111 | source = "registry+https://github.com/rust-lang/crates.io-index" 112 | checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" 113 | dependencies = [ 114 | "termcolor", 115 | "unicode-width", 116 | ] 117 | 118 | [[package]] 119 | name = "colored" 120 | version = "2.0.0" 121 | source = "registry+https://github.com/rust-lang/crates.io-index" 122 | checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" 123 | dependencies = [ 124 | "atty", 125 | "lazy_static", 126 | "winapi", 127 | ] 128 | 129 | [[package]] 130 | name = "core-foundation-sys" 131 | version = "0.8.3" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" 134 | 135 | [[package]] 136 | name = "cpufeatures" 137 | version = "0.2.5" 138 | source = "registry+https://github.com/rust-lang/crates.io-index" 139 | checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" 140 | dependencies = [ 141 | "libc", 142 | ] 143 | 144 | [[package]] 145 | name = "cron" 146 | version = "0.10.1" 147 | source = "registry+https://github.com/rust-lang/crates.io-index" 148 | checksum = "4ee7e5cc3c6b73959cef3412d3a185225eefd926286b4ea55be8bea0bd27d10f" 149 | dependencies = [ 150 | "chrono", 151 | "nom", 152 | "once_cell", 153 | ] 154 | 155 | [[package]] 156 | name = "crypto-common" 157 | version = "0.1.6" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 160 | dependencies = [ 161 | "generic-array", 162 | "typenum", 163 | ] 164 | 165 | [[package]] 166 | name = "cxx" 167 | version = "1.0.83" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | checksum = "bdf07d07d6531bfcdbe9b8b739b104610c6508dcc4d63b410585faf338241daf" 170 | dependencies = [ 171 | "cc", 172 | "cxxbridge-flags", 173 | "cxxbridge-macro", 174 | "link-cplusplus", 175 | ] 176 | 177 | [[package]] 178 | name = "cxx-build" 179 | version = "1.0.83" 180 | source = "registry+https://github.com/rust-lang/crates.io-index" 181 | checksum = "d2eb5b96ecdc99f72657332953d4d9c50135af1bac34277801cc3937906ebd39" 182 | dependencies = [ 183 | "cc", 184 | "codespan-reporting", 185 | "once_cell", 186 | "proc-macro2", 187 | "quote", 188 | "scratch", 189 | "syn", 190 | ] 191 | 192 | [[package]] 193 | name = "cxxbridge-flags" 194 | version = "1.0.83" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | checksum = "ac040a39517fd1674e0f32177648334b0f4074625b5588a64519804ba0553b12" 197 | 198 | [[package]] 199 | name = "cxxbridge-macro" 200 | version = "1.0.83" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | checksum = "1362b0ddcfc4eb0a1f57b68bd77dd99f0e826958a96abd0ae9bd092e114ffed6" 203 | dependencies = [ 204 | "proc-macro2", 205 | "quote", 206 | "syn", 207 | ] 208 | 209 | [[package]] 210 | name = "dashmap" 211 | version = "5.4.0" 212 | source = "registry+https://github.com/rust-lang/crates.io-index" 213 | checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" 214 | dependencies = [ 215 | "cfg-if", 216 | "hashbrown", 217 | "lock_api", 218 | "once_cell", 219 | "parking_lot_core", 220 | ] 221 | 222 | [[package]] 223 | name = "digest" 224 | version = "0.10.6" 225 | source = "registry+https://github.com/rust-lang/crates.io-index" 226 | checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" 227 | dependencies = [ 228 | "block-buffer", 229 | "crypto-common", 230 | ] 231 | 232 | [[package]] 233 | name = "fnv" 234 | version = "1.0.7" 235 | source = "registry+https://github.com/rust-lang/crates.io-index" 236 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 237 | 238 | [[package]] 239 | name = "form_urlencoded" 240 | version = "1.1.0" 241 | source = "registry+https://github.com/rust-lang/crates.io-index" 242 | checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" 243 | dependencies = [ 244 | "percent-encoding", 245 | ] 246 | 247 | [[package]] 248 | name = "futures-channel" 249 | version = "0.3.25" 250 | source = "registry+https://github.com/rust-lang/crates.io-index" 251 | checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" 252 | dependencies = [ 253 | "futures-core", 254 | ] 255 | 256 | [[package]] 257 | name = "futures-core" 258 | version = "0.3.25" 259 | source = "registry+https://github.com/rust-lang/crates.io-index" 260 | checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" 261 | 262 | [[package]] 263 | name = "futures-macro" 264 | version = "0.3.25" 265 | source = "registry+https://github.com/rust-lang/crates.io-index" 266 | checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" 267 | dependencies = [ 268 | "proc-macro2", 269 | "quote", 270 | "syn", 271 | ] 272 | 273 | [[package]] 274 | name = "futures-sink" 275 | version = "0.3.25" 276 | source = "registry+https://github.com/rust-lang/crates.io-index" 277 | checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" 278 | 279 | [[package]] 280 | name = "futures-task" 281 | version = "0.3.25" 282 | source = "registry+https://github.com/rust-lang/crates.io-index" 283 | checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" 284 | 285 | [[package]] 286 | name = "futures-util" 287 | version = "0.3.25" 288 | source = "registry+https://github.com/rust-lang/crates.io-index" 289 | checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" 290 | dependencies = [ 291 | "futures-core", 292 | "futures-macro", 293 | "futures-sink", 294 | "futures-task", 295 | "pin-project-lite", 296 | "pin-utils", 297 | "slab", 298 | ] 299 | 300 | [[package]] 301 | name = "generic-array" 302 | version = "0.14.6" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" 305 | dependencies = [ 306 | "typenum", 307 | "version_check", 308 | ] 309 | 310 | [[package]] 311 | name = "getrandom" 312 | version = "0.2.8" 313 | source = "registry+https://github.com/rust-lang/crates.io-index" 314 | checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" 315 | dependencies = [ 316 | "cfg-if", 317 | "libc", 318 | "wasi 0.11.0+wasi-snapshot-preview1", 319 | ] 320 | 321 | [[package]] 322 | name = "h2" 323 | version = "0.3.15" 324 | source = "registry+https://github.com/rust-lang/crates.io-index" 325 | checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" 326 | dependencies = [ 327 | "bytes", 328 | "fnv", 329 | "futures-core", 330 | "futures-sink", 331 | "futures-util", 332 | "http", 333 | "indexmap", 334 | "slab", 335 | "tokio", 336 | "tokio-util", 337 | "tracing", 338 | ] 339 | 340 | [[package]] 341 | name = "hashbrown" 342 | version = "0.12.3" 343 | source = "registry+https://github.com/rust-lang/crates.io-index" 344 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 345 | 346 | [[package]] 347 | name = "hermit-abi" 348 | version = "0.1.19" 349 | source = "registry+https://github.com/rust-lang/crates.io-index" 350 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 351 | dependencies = [ 352 | "libc", 353 | ] 354 | 355 | [[package]] 356 | name = "hex" 357 | version = "0.4.3" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 360 | 361 | [[package]] 362 | name = "http" 363 | version = "0.2.8" 364 | source = "registry+https://github.com/rust-lang/crates.io-index" 365 | checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" 366 | dependencies = [ 367 | "bytes", 368 | "fnv", 369 | "itoa", 370 | ] 371 | 372 | [[package]] 373 | name = "http-body" 374 | version = "0.4.5" 375 | source = "registry+https://github.com/rust-lang/crates.io-index" 376 | checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" 377 | dependencies = [ 378 | "bytes", 379 | "http", 380 | "pin-project-lite", 381 | ] 382 | 383 | [[package]] 384 | name = "httparse" 385 | version = "1.8.0" 386 | source = "registry+https://github.com/rust-lang/crates.io-index" 387 | checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" 388 | 389 | [[package]] 390 | name = "httpdate" 391 | version = "1.0.2" 392 | source = "registry+https://github.com/rust-lang/crates.io-index" 393 | checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" 394 | 395 | [[package]] 396 | name = "hyper" 397 | version = "0.14.23" 398 | source = "registry+https://github.com/rust-lang/crates.io-index" 399 | checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c" 400 | dependencies = [ 401 | "bytes", 402 | "futures-channel", 403 | "futures-core", 404 | "futures-util", 405 | "h2", 406 | "http", 407 | "http-body", 408 | "httparse", 409 | "httpdate", 410 | "itoa", 411 | "pin-project-lite", 412 | "socket2", 413 | "tokio", 414 | "tower-service", 415 | "tracing", 416 | "want", 417 | ] 418 | 419 | [[package]] 420 | name = "iana-time-zone" 421 | version = "0.1.53" 422 | source = "registry+https://github.com/rust-lang/crates.io-index" 423 | checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" 424 | dependencies = [ 425 | "android_system_properties", 426 | "core-foundation-sys", 427 | "iana-time-zone-haiku", 428 | "js-sys", 429 | "wasm-bindgen", 430 | "winapi", 431 | ] 432 | 433 | [[package]] 434 | name = "iana-time-zone-haiku" 435 | version = "0.1.1" 436 | source = "registry+https://github.com/rust-lang/crates.io-index" 437 | checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" 438 | dependencies = [ 439 | "cxx", 440 | "cxx-build", 441 | ] 442 | 443 | [[package]] 444 | name = "idna" 445 | version = "0.3.0" 446 | source = "registry+https://github.com/rust-lang/crates.io-index" 447 | checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" 448 | dependencies = [ 449 | "unicode-bidi", 450 | "unicode-normalization", 451 | ] 452 | 453 | [[package]] 454 | name = "indexmap" 455 | version = "1.9.2" 456 | source = "registry+https://github.com/rust-lang/crates.io-index" 457 | checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" 458 | dependencies = [ 459 | "autocfg", 460 | "hashbrown", 461 | ] 462 | 463 | [[package]] 464 | name = "itoa" 465 | version = "1.0.4" 466 | source = "registry+https://github.com/rust-lang/crates.io-index" 467 | checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" 468 | 469 | [[package]] 470 | name = "js-sys" 471 | version = "0.3.60" 472 | source = "registry+https://github.com/rust-lang/crates.io-index" 473 | checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" 474 | dependencies = [ 475 | "wasm-bindgen", 476 | ] 477 | 478 | [[package]] 479 | name = "lazy_static" 480 | version = "1.4.0" 481 | source = "registry+https://github.com/rust-lang/crates.io-index" 482 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 483 | 484 | [[package]] 485 | name = "libc" 486 | version = "0.2.138" 487 | source = "registry+https://github.com/rust-lang/crates.io-index" 488 | checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" 489 | 490 | [[package]] 491 | name = "link-cplusplus" 492 | version = "1.0.7" 493 | source = "registry+https://github.com/rust-lang/crates.io-index" 494 | checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" 495 | dependencies = [ 496 | "cc", 497 | ] 498 | 499 | [[package]] 500 | name = "lock_api" 501 | version = "0.4.9" 502 | source = "registry+https://github.com/rust-lang/crates.io-index" 503 | checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" 504 | dependencies = [ 505 | "autocfg", 506 | "scopeguard", 507 | ] 508 | 509 | [[package]] 510 | name = "log" 511 | version = "0.4.17" 512 | source = "registry+https://github.com/rust-lang/crates.io-index" 513 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" 514 | dependencies = [ 515 | "cfg-if", 516 | ] 517 | 518 | [[package]] 519 | name = "matchers" 520 | version = "0.1.0" 521 | source = "registry+https://github.com/rust-lang/crates.io-index" 522 | checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" 523 | dependencies = [ 524 | "regex-automata", 525 | ] 526 | 527 | [[package]] 528 | name = "memchr" 529 | version = "2.5.0" 530 | source = "registry+https://github.com/rust-lang/crates.io-index" 531 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 532 | 533 | [[package]] 534 | name = "minimal-lexical" 535 | version = "0.2.1" 536 | source = "registry+https://github.com/rust-lang/crates.io-index" 537 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 538 | 539 | [[package]] 540 | name = "mio" 541 | version = "0.8.5" 542 | source = "registry+https://github.com/rust-lang/crates.io-index" 543 | checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" 544 | dependencies = [ 545 | "libc", 546 | "log", 547 | "wasi 0.11.0+wasi-snapshot-preview1", 548 | "windows-sys", 549 | ] 550 | 551 | [[package]] 552 | name = "nom" 553 | version = "7.1.1" 554 | source = "registry+https://github.com/rust-lang/crates.io-index" 555 | checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" 556 | dependencies = [ 557 | "memchr", 558 | "minimal-lexical", 559 | ] 560 | 561 | [[package]] 562 | name = "nu-ansi-term" 563 | version = "0.46.0" 564 | source = "registry+https://github.com/rust-lang/crates.io-index" 565 | checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" 566 | dependencies = [ 567 | "overload", 568 | "winapi", 569 | ] 570 | 571 | [[package]] 572 | name = "num-derive" 573 | version = "0.3.3" 574 | source = "registry+https://github.com/rust-lang/crates.io-index" 575 | checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" 576 | dependencies = [ 577 | "proc-macro2", 578 | "quote", 579 | "syn", 580 | ] 581 | 582 | [[package]] 583 | name = "num-integer" 584 | version = "0.1.45" 585 | source = "registry+https://github.com/rust-lang/crates.io-index" 586 | checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" 587 | dependencies = [ 588 | "autocfg", 589 | "num-traits", 590 | ] 591 | 592 | [[package]] 593 | name = "num-traits" 594 | version = "0.2.15" 595 | source = "registry+https://github.com/rust-lang/crates.io-index" 596 | checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" 597 | dependencies = [ 598 | "autocfg", 599 | ] 600 | 601 | [[package]] 602 | name = "num_cpus" 603 | version = "1.14.0" 604 | source = "registry+https://github.com/rust-lang/crates.io-index" 605 | checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" 606 | dependencies = [ 607 | "hermit-abi", 608 | "libc", 609 | ] 610 | 611 | [[package]] 612 | name = "once_cell" 613 | version = "1.16.0" 614 | source = "registry+https://github.com/rust-lang/crates.io-index" 615 | checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" 616 | 617 | [[package]] 618 | name = "overload" 619 | version = "0.1.1" 620 | source = "registry+https://github.com/rust-lang/crates.io-index" 621 | checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" 622 | 623 | [[package]] 624 | name = "parking_lot" 625 | version = "0.12.1" 626 | source = "registry+https://github.com/rust-lang/crates.io-index" 627 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" 628 | dependencies = [ 629 | "lock_api", 630 | "parking_lot_core", 631 | ] 632 | 633 | [[package]] 634 | name = "parking_lot_core" 635 | version = "0.9.5" 636 | source = "registry+https://github.com/rust-lang/crates.io-index" 637 | checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" 638 | dependencies = [ 639 | "cfg-if", 640 | "libc", 641 | "redox_syscall", 642 | "smallvec", 643 | "windows-sys", 644 | ] 645 | 646 | [[package]] 647 | name = "paste" 648 | version = "1.0.9" 649 | source = "registry+https://github.com/rust-lang/crates.io-index" 650 | checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" 651 | 652 | [[package]] 653 | name = "percent-encoding" 654 | version = "2.2.0" 655 | source = "registry+https://github.com/rust-lang/crates.io-index" 656 | checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" 657 | 658 | [[package]] 659 | name = "pin-project-lite" 660 | version = "0.2.9" 661 | source = "registry+https://github.com/rust-lang/crates.io-index" 662 | checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" 663 | 664 | [[package]] 665 | name = "pin-utils" 666 | version = "0.1.0" 667 | source = "registry+https://github.com/rust-lang/crates.io-index" 668 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 669 | 670 | [[package]] 671 | name = "ppv-lite86" 672 | version = "0.2.17" 673 | source = "registry+https://github.com/rust-lang/crates.io-index" 674 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 675 | 676 | [[package]] 677 | name = "proc-macro2" 678 | version = "1.0.47" 679 | source = "registry+https://github.com/rust-lang/crates.io-index" 680 | checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" 681 | dependencies = [ 682 | "unicode-ident", 683 | ] 684 | 685 | [[package]] 686 | name = "quote" 687 | version = "1.0.21" 688 | source = "registry+https://github.com/rust-lang/crates.io-index" 689 | checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" 690 | dependencies = [ 691 | "proc-macro2", 692 | ] 693 | 694 | [[package]] 695 | name = "rand" 696 | version = "0.8.5" 697 | source = "registry+https://github.com/rust-lang/crates.io-index" 698 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 699 | dependencies = [ 700 | "libc", 701 | "rand_chacha", 702 | "rand_core", 703 | ] 704 | 705 | [[package]] 706 | name = "rand_chacha" 707 | version = "0.3.1" 708 | source = "registry+https://github.com/rust-lang/crates.io-index" 709 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 710 | dependencies = [ 711 | "ppv-lite86", 712 | "rand_core", 713 | ] 714 | 715 | [[package]] 716 | name = "rand_core" 717 | version = "0.6.4" 718 | source = "registry+https://github.com/rust-lang/crates.io-index" 719 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 720 | dependencies = [ 721 | "getrandom", 722 | ] 723 | 724 | [[package]] 725 | name = "redox_syscall" 726 | version = "0.2.16" 727 | source = "registry+https://github.com/rust-lang/crates.io-index" 728 | checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" 729 | dependencies = [ 730 | "bitflags", 731 | ] 732 | 733 | [[package]] 734 | name = "regex" 735 | version = "1.7.0" 736 | source = "registry+https://github.com/rust-lang/crates.io-index" 737 | checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" 738 | dependencies = [ 739 | "regex-syntax", 740 | ] 741 | 742 | [[package]] 743 | name = "regex-automata" 744 | version = "0.1.10" 745 | source = "registry+https://github.com/rust-lang/crates.io-index" 746 | checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" 747 | dependencies = [ 748 | "regex-syntax", 749 | ] 750 | 751 | [[package]] 752 | name = "regex-syntax" 753 | version = "0.6.28" 754 | source = "registry+https://github.com/rust-lang/crates.io-index" 755 | checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" 756 | 757 | [[package]] 758 | name = "rmp" 759 | version = "0.8.11" 760 | source = "registry+https://github.com/rust-lang/crates.io-index" 761 | checksum = "44519172358fd6d58656c86ab8e7fbc9e1490c3e8f14d35ed78ca0dd07403c9f" 762 | dependencies = [ 763 | "byteorder", 764 | "num-traits", 765 | "paste", 766 | ] 767 | 768 | [[package]] 769 | name = "rmp-serde" 770 | version = "1.1.1" 771 | source = "registry+https://github.com/rust-lang/crates.io-index" 772 | checksum = "c5b13be192e0220b8afb7222aa5813cb62cc269ebb5cac346ca6487681d2913e" 773 | dependencies = [ 774 | "byteorder", 775 | "rmp", 776 | "serde", 777 | ] 778 | 779 | [[package]] 780 | name = "ryu" 781 | version = "1.0.11" 782 | source = "registry+https://github.com/rust-lang/crates.io-index" 783 | checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" 784 | 785 | [[package]] 786 | name = "scopeguard" 787 | version = "1.1.0" 788 | source = "registry+https://github.com/rust-lang/crates.io-index" 789 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 790 | 791 | [[package]] 792 | name = "scratch" 793 | version = "1.0.2" 794 | source = "registry+https://github.com/rust-lang/crates.io-index" 795 | checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" 796 | 797 | [[package]] 798 | name = "serde" 799 | version = "1.0.150" 800 | source = "registry+https://github.com/rust-lang/crates.io-index" 801 | checksum = "e326c9ec8042f1b5da33252c8a37e9ffbd2c9bef0155215b6e6c80c790e05f91" 802 | dependencies = [ 803 | "serde_derive", 804 | ] 805 | 806 | [[package]] 807 | name = "serde_derive" 808 | version = "1.0.150" 809 | source = "registry+https://github.com/rust-lang/crates.io-index" 810 | checksum = "42a3df25b0713732468deadad63ab9da1f1fd75a48a15024b50363f128db627e" 811 | dependencies = [ 812 | "proc-macro2", 813 | "quote", 814 | "syn", 815 | ] 816 | 817 | [[package]] 818 | name = "serde_json" 819 | version = "1.0.89" 820 | source = "registry+https://github.com/rust-lang/crates.io-index" 821 | checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" 822 | dependencies = [ 823 | "itoa", 824 | "ryu", 825 | "serde", 826 | ] 827 | 828 | [[package]] 829 | name = "sha-1" 830 | version = "0.10.1" 831 | source = "registry+https://github.com/rust-lang/crates.io-index" 832 | checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" 833 | dependencies = [ 834 | "cfg-if", 835 | "cpufeatures", 836 | "digest", 837 | ] 838 | 839 | [[package]] 840 | name = "sha2" 841 | version = "0.10.6" 842 | source = "registry+https://github.com/rust-lang/crates.io-index" 843 | checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" 844 | dependencies = [ 845 | "cfg-if", 846 | "cpufeatures", 847 | "digest", 848 | ] 849 | 850 | [[package]] 851 | name = "sharded-slab" 852 | version = "0.1.4" 853 | source = "registry+https://github.com/rust-lang/crates.io-index" 854 | checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" 855 | dependencies = [ 856 | "lazy_static", 857 | ] 858 | 859 | [[package]] 860 | name = "signal-hook-registry" 861 | version = "1.4.0" 862 | source = "registry+https://github.com/rust-lang/crates.io-index" 863 | checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" 864 | dependencies = [ 865 | "libc", 866 | ] 867 | 868 | [[package]] 869 | name = "slab" 870 | version = "0.4.7" 871 | source = "registry+https://github.com/rust-lang/crates.io-index" 872 | checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" 873 | dependencies = [ 874 | "autocfg", 875 | ] 876 | 877 | [[package]] 878 | name = "smallvec" 879 | version = "1.10.0" 880 | source = "registry+https://github.com/rust-lang/crates.io-index" 881 | checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" 882 | 883 | [[package]] 884 | name = "snake_cased" 885 | version = "0.1.0" 886 | source = "registry+https://github.com/rust-lang/crates.io-index" 887 | checksum = "4586c5a1e13fd7b00552c861116077f2f60ec4b94092671bf1998e6adb462d25" 888 | dependencies = [ 889 | "snake_cased_derive", 890 | ] 891 | 892 | [[package]] 893 | name = "snake_cased_derive" 894 | version = "0.1.1" 895 | source = "registry+https://github.com/rust-lang/crates.io-index" 896 | checksum = "3c859c1484dd123a8b2913cef1e031794051845509bb9b149a84492d19779c47" 897 | dependencies = [ 898 | "proc-macro2", 899 | "quote", 900 | "syn", 901 | ] 902 | 903 | [[package]] 904 | name = "socket2" 905 | version = "0.4.7" 906 | source = "registry+https://github.com/rust-lang/crates.io-index" 907 | checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" 908 | dependencies = [ 909 | "libc", 910 | "winapi", 911 | ] 912 | 913 | [[package]] 914 | name = "syn" 915 | version = "1.0.105" 916 | source = "registry+https://github.com/rust-lang/crates.io-index" 917 | checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908" 918 | dependencies = [ 919 | "proc-macro2", 920 | "quote", 921 | "unicode-ident", 922 | ] 923 | 924 | [[package]] 925 | name = "termcolor" 926 | version = "1.1.3" 927 | source = "registry+https://github.com/rust-lang/crates.io-index" 928 | checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" 929 | dependencies = [ 930 | "winapi-util", 931 | ] 932 | 933 | [[package]] 934 | name = "thiserror" 935 | version = "1.0.37" 936 | source = "registry+https://github.com/rust-lang/crates.io-index" 937 | checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" 938 | dependencies = [ 939 | "thiserror-impl", 940 | ] 941 | 942 | [[package]] 943 | name = "thiserror-impl" 944 | version = "1.0.37" 945 | source = "registry+https://github.com/rust-lang/crates.io-index" 946 | checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" 947 | dependencies = [ 948 | "proc-macro2", 949 | "quote", 950 | "syn", 951 | ] 952 | 953 | [[package]] 954 | name = "thread_local" 955 | version = "1.1.4" 956 | source = "registry+https://github.com/rust-lang/crates.io-index" 957 | checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" 958 | dependencies = [ 959 | "once_cell", 960 | ] 961 | 962 | [[package]] 963 | name = "time" 964 | version = "0.1.45" 965 | source = "registry+https://github.com/rust-lang/crates.io-index" 966 | checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" 967 | dependencies = [ 968 | "libc", 969 | "wasi 0.10.0+wasi-snapshot-preview1", 970 | "winapi", 971 | ] 972 | 973 | [[package]] 974 | name = "time" 975 | version = "0.3.17" 976 | source = "registry+https://github.com/rust-lang/crates.io-index" 977 | checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" 978 | dependencies = [ 979 | "itoa", 980 | "serde", 981 | "time-core", 982 | "time-macros", 983 | ] 984 | 985 | [[package]] 986 | name = "time-core" 987 | version = "0.1.0" 988 | source = "registry+https://github.com/rust-lang/crates.io-index" 989 | checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" 990 | 991 | [[package]] 992 | name = "time-macros" 993 | version = "0.2.6" 994 | source = "registry+https://github.com/rust-lang/crates.io-index" 995 | checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" 996 | dependencies = [ 997 | "time-core", 998 | ] 999 | 1000 | [[package]] 1001 | name = "tinyvec" 1002 | version = "1.6.0" 1003 | source = "registry+https://github.com/rust-lang/crates.io-index" 1004 | checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" 1005 | dependencies = [ 1006 | "tinyvec_macros", 1007 | ] 1008 | 1009 | [[package]] 1010 | name = "tinyvec_macros" 1011 | version = "0.1.0" 1012 | source = "registry+https://github.com/rust-lang/crates.io-index" 1013 | checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" 1014 | 1015 | [[package]] 1016 | name = "tokio" 1017 | version = "1.23.0" 1018 | source = "registry+https://github.com/rust-lang/crates.io-index" 1019 | checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46" 1020 | dependencies = [ 1021 | "autocfg", 1022 | "bytes", 1023 | "libc", 1024 | "memchr", 1025 | "mio", 1026 | "num_cpus", 1027 | "parking_lot", 1028 | "pin-project-lite", 1029 | "signal-hook-registry", 1030 | "socket2", 1031 | "tokio-macros", 1032 | "windows-sys", 1033 | ] 1034 | 1035 | [[package]] 1036 | name = "tokio-cron-scheduler" 1037 | version = "0.7.6" 1038 | source = "registry+https://github.com/rust-lang/crates.io-index" 1039 | checksum = "7234a86e3b6c9b889c0f0fda06199cf166db3089419ea4134d7ed457d351c946" 1040 | dependencies = [ 1041 | "chrono", 1042 | "cron", 1043 | "num-derive", 1044 | "num-traits", 1045 | "time 0.1.45", 1046 | "tokio", 1047 | "tracing", 1048 | "uuid", 1049 | ] 1050 | 1051 | [[package]] 1052 | name = "tokio-macros" 1053 | version = "1.8.2" 1054 | source = "registry+https://github.com/rust-lang/crates.io-index" 1055 | checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" 1056 | dependencies = [ 1057 | "proc-macro2", 1058 | "quote", 1059 | "syn", 1060 | ] 1061 | 1062 | [[package]] 1063 | name = "tokio-tungstenite" 1064 | version = "0.17.2" 1065 | source = "registry+https://github.com/rust-lang/crates.io-index" 1066 | checksum = "f714dd15bead90401d77e04243611caec13726c2408afd5b31901dfcdcb3b181" 1067 | dependencies = [ 1068 | "futures-util", 1069 | "log", 1070 | "tokio", 1071 | "tungstenite", 1072 | ] 1073 | 1074 | [[package]] 1075 | name = "tokio-util" 1076 | version = "0.7.4" 1077 | source = "registry+https://github.com/rust-lang/crates.io-index" 1078 | checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" 1079 | dependencies = [ 1080 | "bytes", 1081 | "futures-core", 1082 | "futures-sink", 1083 | "pin-project-lite", 1084 | "tokio", 1085 | "tracing", 1086 | ] 1087 | 1088 | [[package]] 1089 | name = "tower-service" 1090 | version = "0.3.2" 1091 | source = "registry+https://github.com/rust-lang/crates.io-index" 1092 | checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" 1093 | 1094 | [[package]] 1095 | name = "tracing" 1096 | version = "0.1.37" 1097 | source = "registry+https://github.com/rust-lang/crates.io-index" 1098 | checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" 1099 | dependencies = [ 1100 | "cfg-if", 1101 | "pin-project-lite", 1102 | "tracing-attributes", 1103 | "tracing-core", 1104 | ] 1105 | 1106 | [[package]] 1107 | name = "tracing-attributes" 1108 | version = "0.1.23" 1109 | source = "registry+https://github.com/rust-lang/crates.io-index" 1110 | checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" 1111 | dependencies = [ 1112 | "proc-macro2", 1113 | "quote", 1114 | "syn", 1115 | ] 1116 | 1117 | [[package]] 1118 | name = "tracing-core" 1119 | version = "0.1.30" 1120 | source = "registry+https://github.com/rust-lang/crates.io-index" 1121 | checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" 1122 | dependencies = [ 1123 | "once_cell", 1124 | "valuable", 1125 | ] 1126 | 1127 | [[package]] 1128 | name = "tracing-log" 1129 | version = "0.1.3" 1130 | source = "registry+https://github.com/rust-lang/crates.io-index" 1131 | checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" 1132 | dependencies = [ 1133 | "lazy_static", 1134 | "log", 1135 | "tracing-core", 1136 | ] 1137 | 1138 | [[package]] 1139 | name = "tracing-subscriber" 1140 | version = "0.3.16" 1141 | source = "registry+https://github.com/rust-lang/crates.io-index" 1142 | checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" 1143 | dependencies = [ 1144 | "matchers", 1145 | "nu-ansi-term", 1146 | "once_cell", 1147 | "regex", 1148 | "sharded-slab", 1149 | "smallvec", 1150 | "thread_local", 1151 | "time 0.3.17", 1152 | "tracing", 1153 | "tracing-core", 1154 | "tracing-log", 1155 | ] 1156 | 1157 | [[package]] 1158 | name = "try-lock" 1159 | version = "0.2.3" 1160 | source = "registry+https://github.com/rust-lang/crates.io-index" 1161 | checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" 1162 | 1163 | [[package]] 1164 | name = "tungstenite" 1165 | version = "0.17.3" 1166 | source = "registry+https://github.com/rust-lang/crates.io-index" 1167 | checksum = "e27992fd6a8c29ee7eef28fc78349aa244134e10ad447ce3b9f0ac0ed0fa4ce0" 1168 | dependencies = [ 1169 | "base64", 1170 | "byteorder", 1171 | "bytes", 1172 | "http", 1173 | "httparse", 1174 | "log", 1175 | "rand", 1176 | "sha-1", 1177 | "thiserror", 1178 | "url", 1179 | "utf-8", 1180 | ] 1181 | 1182 | [[package]] 1183 | name = "typenum" 1184 | version = "1.16.0" 1185 | source = "registry+https://github.com/rust-lang/crates.io-index" 1186 | checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" 1187 | 1188 | [[package]] 1189 | name = "unicode-bidi" 1190 | version = "0.3.8" 1191 | source = "registry+https://github.com/rust-lang/crates.io-index" 1192 | checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" 1193 | 1194 | [[package]] 1195 | name = "unicode-ident" 1196 | version = "1.0.5" 1197 | source = "registry+https://github.com/rust-lang/crates.io-index" 1198 | checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" 1199 | 1200 | [[package]] 1201 | name = "unicode-normalization" 1202 | version = "0.1.22" 1203 | source = "registry+https://github.com/rust-lang/crates.io-index" 1204 | checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" 1205 | dependencies = [ 1206 | "tinyvec", 1207 | ] 1208 | 1209 | [[package]] 1210 | name = "unicode-width" 1211 | version = "0.1.10" 1212 | source = "registry+https://github.com/rust-lang/crates.io-index" 1213 | checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" 1214 | 1215 | [[package]] 1216 | name = "url" 1217 | version = "2.3.1" 1218 | source = "registry+https://github.com/rust-lang/crates.io-index" 1219 | checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" 1220 | dependencies = [ 1221 | "form_urlencoded", 1222 | "idna", 1223 | "percent-encoding", 1224 | ] 1225 | 1226 | [[package]] 1227 | name = "utf-8" 1228 | version = "0.7.6" 1229 | source = "registry+https://github.com/rust-lang/crates.io-index" 1230 | checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" 1231 | 1232 | [[package]] 1233 | name = "uuid" 1234 | version = "1.2.2" 1235 | source = "registry+https://github.com/rust-lang/crates.io-index" 1236 | checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c" 1237 | dependencies = [ 1238 | "getrandom", 1239 | ] 1240 | 1241 | [[package]] 1242 | name = "valuable" 1243 | version = "0.1.0" 1244 | source = "registry+https://github.com/rust-lang/crates.io-index" 1245 | checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" 1246 | 1247 | [[package]] 1248 | name = "version_check" 1249 | version = "0.9.4" 1250 | source = "registry+https://github.com/rust-lang/crates.io-index" 1251 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 1252 | 1253 | [[package]] 1254 | name = "walle" 1255 | version = "0.1.0" 1256 | dependencies = [ 1257 | "async-trait", 1258 | "dashmap", 1259 | "serde", 1260 | "time 0.3.17", 1261 | "tokio", 1262 | "tokio-cron-scheduler", 1263 | "tracing", 1264 | "tracing-subscriber", 1265 | "walle-core", 1266 | ] 1267 | 1268 | [[package]] 1269 | name = "walle-core" 1270 | version = "0.7.0" 1271 | source = "registry+https://github.com/rust-lang/crates.io-index" 1272 | checksum = "ab007509bdde5895c946931b010575963865c61df80414f3f57b7aa0e763a239" 1273 | dependencies = [ 1274 | "async-trait", 1275 | "base64", 1276 | "colored", 1277 | "dashmap", 1278 | "futures-util", 1279 | "hex", 1280 | "hyper", 1281 | "rmp-serde", 1282 | "serde", 1283 | "serde_json", 1284 | "sha2", 1285 | "snake_cased", 1286 | "thiserror", 1287 | "tokio", 1288 | "tokio-tungstenite", 1289 | "tracing", 1290 | "walle-macro", 1291 | ] 1292 | 1293 | [[package]] 1294 | name = "walle-macro" 1295 | version = "0.7.0-a2" 1296 | source = "registry+https://github.com/rust-lang/crates.io-index" 1297 | checksum = "565c75d3305a5208f56c894000130185c81568407d0777f72860bba9cf26b285" 1298 | dependencies = [ 1299 | "proc-macro2", 1300 | "quote", 1301 | "syn", 1302 | ] 1303 | 1304 | [[package]] 1305 | name = "walle-plugin-roulette" 1306 | version = "0.1.0" 1307 | dependencies = [ 1308 | "rand", 1309 | "tokio", 1310 | "walle", 1311 | ] 1312 | 1313 | [[package]] 1314 | name = "want" 1315 | version = "0.3.0" 1316 | source = "registry+https://github.com/rust-lang/crates.io-index" 1317 | checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" 1318 | dependencies = [ 1319 | "log", 1320 | "try-lock", 1321 | ] 1322 | 1323 | [[package]] 1324 | name = "wasi" 1325 | version = "0.10.0+wasi-snapshot-preview1" 1326 | source = "registry+https://github.com/rust-lang/crates.io-index" 1327 | checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" 1328 | 1329 | [[package]] 1330 | name = "wasi" 1331 | version = "0.11.0+wasi-snapshot-preview1" 1332 | source = "registry+https://github.com/rust-lang/crates.io-index" 1333 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1334 | 1335 | [[package]] 1336 | name = "wasm-bindgen" 1337 | version = "0.2.83" 1338 | source = "registry+https://github.com/rust-lang/crates.io-index" 1339 | checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" 1340 | dependencies = [ 1341 | "cfg-if", 1342 | "wasm-bindgen-macro", 1343 | ] 1344 | 1345 | [[package]] 1346 | name = "wasm-bindgen-backend" 1347 | version = "0.2.83" 1348 | source = "registry+https://github.com/rust-lang/crates.io-index" 1349 | checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" 1350 | dependencies = [ 1351 | "bumpalo", 1352 | "log", 1353 | "once_cell", 1354 | "proc-macro2", 1355 | "quote", 1356 | "syn", 1357 | "wasm-bindgen-shared", 1358 | ] 1359 | 1360 | [[package]] 1361 | name = "wasm-bindgen-macro" 1362 | version = "0.2.83" 1363 | source = "registry+https://github.com/rust-lang/crates.io-index" 1364 | checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" 1365 | dependencies = [ 1366 | "quote", 1367 | "wasm-bindgen-macro-support", 1368 | ] 1369 | 1370 | [[package]] 1371 | name = "wasm-bindgen-macro-support" 1372 | version = "0.2.83" 1373 | source = "registry+https://github.com/rust-lang/crates.io-index" 1374 | checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" 1375 | dependencies = [ 1376 | "proc-macro2", 1377 | "quote", 1378 | "syn", 1379 | "wasm-bindgen-backend", 1380 | "wasm-bindgen-shared", 1381 | ] 1382 | 1383 | [[package]] 1384 | name = "wasm-bindgen-shared" 1385 | version = "0.2.83" 1386 | source = "registry+https://github.com/rust-lang/crates.io-index" 1387 | checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" 1388 | 1389 | [[package]] 1390 | name = "winapi" 1391 | version = "0.3.9" 1392 | source = "registry+https://github.com/rust-lang/crates.io-index" 1393 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1394 | dependencies = [ 1395 | "winapi-i686-pc-windows-gnu", 1396 | "winapi-x86_64-pc-windows-gnu", 1397 | ] 1398 | 1399 | [[package]] 1400 | name = "winapi-i686-pc-windows-gnu" 1401 | version = "0.4.0" 1402 | source = "registry+https://github.com/rust-lang/crates.io-index" 1403 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1404 | 1405 | [[package]] 1406 | name = "winapi-util" 1407 | version = "0.1.5" 1408 | source = "registry+https://github.com/rust-lang/crates.io-index" 1409 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 1410 | dependencies = [ 1411 | "winapi", 1412 | ] 1413 | 1414 | [[package]] 1415 | name = "winapi-x86_64-pc-windows-gnu" 1416 | version = "0.4.0" 1417 | source = "registry+https://github.com/rust-lang/crates.io-index" 1418 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1419 | 1420 | [[package]] 1421 | name = "windows-sys" 1422 | version = "0.42.0" 1423 | source = "registry+https://github.com/rust-lang/crates.io-index" 1424 | checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" 1425 | dependencies = [ 1426 | "windows_aarch64_gnullvm", 1427 | "windows_aarch64_msvc", 1428 | "windows_i686_gnu", 1429 | "windows_i686_msvc", 1430 | "windows_x86_64_gnu", 1431 | "windows_x86_64_gnullvm", 1432 | "windows_x86_64_msvc", 1433 | ] 1434 | 1435 | [[package]] 1436 | name = "windows_aarch64_gnullvm" 1437 | version = "0.42.0" 1438 | source = "registry+https://github.com/rust-lang/crates.io-index" 1439 | checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" 1440 | 1441 | [[package]] 1442 | name = "windows_aarch64_msvc" 1443 | version = "0.42.0" 1444 | source = "registry+https://github.com/rust-lang/crates.io-index" 1445 | checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" 1446 | 1447 | [[package]] 1448 | name = "windows_i686_gnu" 1449 | version = "0.42.0" 1450 | source = "registry+https://github.com/rust-lang/crates.io-index" 1451 | checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" 1452 | 1453 | [[package]] 1454 | name = "windows_i686_msvc" 1455 | version = "0.42.0" 1456 | source = "registry+https://github.com/rust-lang/crates.io-index" 1457 | checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" 1458 | 1459 | [[package]] 1460 | name = "windows_x86_64_gnu" 1461 | version = "0.42.0" 1462 | source = "registry+https://github.com/rust-lang/crates.io-index" 1463 | checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" 1464 | 1465 | [[package]] 1466 | name = "windows_x86_64_gnullvm" 1467 | version = "0.42.0" 1468 | source = "registry+https://github.com/rust-lang/crates.io-index" 1469 | checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" 1470 | 1471 | [[package]] 1472 | name = "windows_x86_64_msvc" 1473 | version = "0.42.0" 1474 | source = "registry+https://github.com/rust-lang/crates.io-index" 1475 | checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" 1476 | --------------------------------------------------------------------------------