mirror of
https://github.com/natsukagami/youmubot.git
synced 2025-04-19 16:58:55 +00:00
Composed framework (#43)
Composed poise and serenity into a composed framework. This will help the migration towards slash-commands in the future.
This commit is contained in:
parent
f3c062f417
commit
a2f0684509
6 changed files with 201 additions and 2 deletions
89
Cargo.lock
generated
89
Cargo.lock
generated
|
@ -440,6 +440,41 @@ dependencies = [
|
|||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.20.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.20.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.20.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dashmap"
|
||||
version = "5.5.3"
|
||||
|
@ -481,6 +516,17 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derivative"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
|
@ -1013,6 +1059,12 @@ dependencies = [
|
|||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.5.0"
|
||||
|
@ -1543,6 +1595,35 @@ version = "0.3.29"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb"
|
||||
|
||||
[[package]]
|
||||
name = "poise"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1819d5a45e3590ef33754abce46432570c54a120798bdbf893112b4211fa09a6"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"derivative",
|
||||
"futures-util",
|
||||
"parking_lot",
|
||||
"poise_macros",
|
||||
"regex",
|
||||
"serenity",
|
||||
"tokio",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "poise_macros"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fa2c123c961e78315cd3deac7663177f12be4460f5440dbf62a7ed37b1effea"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "powerfmt"
|
||||
version = "0.2.0"
|
||||
|
@ -2346,6 +2427,12 @@ dependencies = [
|
|||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.5.0"
|
||||
|
@ -3106,6 +3193,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"dotenv",
|
||||
"env_logger",
|
||||
"poise",
|
||||
"serenity",
|
||||
"tokio",
|
||||
"youmubot-cf",
|
||||
|
@ -3209,6 +3297,7 @@ dependencies = [
|
|||
"dashmap",
|
||||
"flume 0.10.14",
|
||||
"futures-util",
|
||||
"poise",
|
||||
"reqwest",
|
||||
"serenity",
|
||||
"thiserror",
|
||||
|
|
|
@ -18,6 +18,7 @@ chrono = "0.4.19"
|
|||
flume = "0.10.13"
|
||||
dashmap = "5.3.4"
|
||||
thiserror = "1"
|
||||
poise = "0.6"
|
||||
|
||||
[dependencies.serenity]
|
||||
version = "0.12"
|
||||
|
|
|
@ -33,6 +33,9 @@ pub mod table_format;
|
|||
/// The global app data.
|
||||
pub type AppData = Arc<RwLock<TypeMap>>;
|
||||
|
||||
/// The global context type for app commands
|
||||
pub type CmdContext<'a, Env> = poise::Context<'a, Env, anyhow::Error>;
|
||||
|
||||
/// The HTTP client.
|
||||
pub struct HTTPClient;
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ codeforces = ["youmubot-cf"]
|
|||
|
||||
[dependencies]
|
||||
serenity = "0.12"
|
||||
poise = "0.6"
|
||||
tokio = { version = "1.19.2", features = ["rt-multi-thread"] }
|
||||
dotenv = "0.15.0"
|
||||
env_logger = "0.9.0"
|
||||
|
|
54
youmubot/src/compose_framework.rs
Normal file
54
youmubot/src/compose_framework.rs
Normal file
|
@ -0,0 +1,54 @@
|
|||
use std::{future::Future, pin::Pin};
|
||||
|
||||
use serenity::{client::FullEvent, framework::Framework};
|
||||
|
||||
use youmubot_prelude::*;
|
||||
|
||||
/// A Framework to compose other frameworks.
|
||||
pub(crate) struct ComposedFramework {
|
||||
frameworks: Box<[Box<dyn Framework>]>,
|
||||
}
|
||||
|
||||
impl ComposedFramework {
|
||||
/// Create a new composed framework.
|
||||
pub fn new(frameworks: Vec<Box<dyn Framework>>) -> Self {
|
||||
Self {
|
||||
frameworks: frameworks.into_boxed_slice(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Framework for ComposedFramework {
|
||||
async fn dispatch(&self, ctx: Context, msg: FullEvent) -> () {
|
||||
if !self.frameworks.is_empty() {
|
||||
self.dispatch_loop(self.frameworks.len() - 1, ctx, msg)
|
||||
.await
|
||||
}
|
||||
}
|
||||
async fn init(&mut self, client: &Client) {
|
||||
for f in self.frameworks.iter_mut() {
|
||||
f.init(&client).await
|
||||
}
|
||||
}
|
||||
}
|
||||
impl ComposedFramework {
|
||||
/// Dispatch to all inner frameworks in a loop. Returns a `Pin<Box<Future>>` because rust.
|
||||
fn dispatch_loop<'a>(
|
||||
&'a self,
|
||||
index: usize,
|
||||
ctx: Context,
|
||||
msg: FullEvent,
|
||||
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||
Box::pin(async move {
|
||||
if index == 0 {
|
||||
self.frameworks[index].dispatch(ctx, msg).await
|
||||
} else {
|
||||
self.frameworks[index]
|
||||
.dispatch(ctx.clone(), msg.clone())
|
||||
.await;
|
||||
self.dispatch_loop(index - 1, ctx, msg).await
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -13,6 +13,10 @@ use serenity::{
|
|||
use youmubot_prelude::announcer::AnnouncerHandler;
|
||||
use youmubot_prelude::*;
|
||||
|
||||
use crate::compose_framework::ComposedFramework;
|
||||
|
||||
mod compose_framework;
|
||||
|
||||
struct Handler {
|
||||
hooks: Vec<RwLock<Box<dyn Hook>>>,
|
||||
ready_hooks: Vec<fn(&Context) -> CommandResult>,
|
||||
|
@ -172,7 +176,7 @@ async fn main() {
|
|||
}
|
||||
};
|
||||
|
||||
data.insert::<Env>(env);
|
||||
data.insert::<Env>(env.clone());
|
||||
|
||||
#[cfg(feature = "core")]
|
||||
println!("Core enabled.");
|
||||
|
@ -184,6 +188,41 @@ async fn main() {
|
|||
// Set up base framework
|
||||
let fw = setup_framework(&token[..]).await;
|
||||
|
||||
// Poise for application commands
|
||||
let poise_fw = poise::Framework::builder()
|
||||
.setup(|_, _, _| Box::pin(async { Ok(env) as Result<_> }))
|
||||
.options(poise::FrameworkOptions {
|
||||
prefix_options: poise::PrefixFrameworkOptions {
|
||||
prefix: None,
|
||||
mention_as_prefix: true,
|
||||
execute_untracked_edits: true,
|
||||
execute_self_messages: false,
|
||||
ignore_thread_creation: true,
|
||||
case_insensitive_commands: true,
|
||||
..Default::default()
|
||||
},
|
||||
on_error: |err| {
|
||||
Box::pin(async move {
|
||||
if let poise::FrameworkError::Command { error, ctx, .. } = err {
|
||||
let reply = format!(
|
||||
"Command '{}' returned error {:?}",
|
||||
ctx.invoked_command_name(),
|
||||
error
|
||||
);
|
||||
ctx.reply(&reply).await.pls_ok();
|
||||
println!("{}", reply)
|
||||
} else {
|
||||
eprintln!("Poise error: {:?}", err)
|
||||
}
|
||||
})
|
||||
},
|
||||
commands: vec![poise_register()],
|
||||
..Default::default()
|
||||
})
|
||||
.build();
|
||||
|
||||
let composed = ComposedFramework::new(vec![Box::new(fw), Box::new(poise_fw)]);
|
||||
|
||||
// Sets up a client
|
||||
let mut client = {
|
||||
// Attempt to connect and set up a framework
|
||||
|
@ -198,7 +237,7 @@ async fn main() {
|
|||
| GatewayIntents::DIRECT_MESSAGE_REACTIONS;
|
||||
Client::builder(token, intents)
|
||||
.type_map(data)
|
||||
.framework(fw)
|
||||
.framework(composed)
|
||||
.event_handler(handler)
|
||||
.await
|
||||
.unwrap()
|
||||
|
@ -276,6 +315,18 @@ async fn setup_framework(token: &str) -> StandardFramework {
|
|||
fw
|
||||
}
|
||||
|
||||
// Poise command to register
|
||||
#[poise::command(
|
||||
prefix_command,
|
||||
rename = "register",
|
||||
required_permissions = "MANAGE_GUILD"
|
||||
)]
|
||||
async fn poise_register(ctx: CmdContext<'_, Env>) -> Result<()> {
|
||||
// TODO: make this work for guild owners too
|
||||
poise::builtins::register_application_commands_buttons(ctx).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Hooks!
|
||||
|
||||
#[hook]
|
||||
|
|
Loading…
Add table
Reference in a new issue