From 1508523ca9a59db1edf73fb79ac01db71734179c Mon Sep 17 00:00:00 2001 From: Natsu Kagami Date: Mon, 7 Sep 2020 02:09:36 -0400 Subject: [PATCH] Main: Is now running with `--no-default-features --features core` --- Cargo.lock | 61 +++++++++++- youmubot/Cargo.toml | 4 +- youmubot/src/main.rs | 218 ++++++++++++++++++++++++------------------- 3 files changed, 184 insertions(+), 99 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 448a7d6..394a80d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -75,6 +75,16 @@ dependencies = [ "tungstenite 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hermit-abi 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "autocfg" version = "1.0.0" @@ -351,6 +361,18 @@ dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "env_logger" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "fake-simd" version = "0.1.2" @@ -563,6 +585,14 @@ name = "httparse" version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "hyper" version = "0.13.5" @@ -1002,6 +1032,11 @@ dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "quote" version = "1.0.6" @@ -1466,6 +1501,14 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "termcolor" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "thiserror" version = "1.0.20" @@ -1858,6 +1901,14 @@ name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -1893,7 +1944,9 @@ name = "youmubot" version = "0.1.0" dependencies = [ "dotenv 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serenity 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serenity 0.9.0-rc.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "youmubot-cf 0.1.0", "youmubot-core 0.1.0", "youmubot-db 0.1.0", @@ -1991,6 +2044,7 @@ dependencies = [ "checksum async-tls 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce6977f57fa68da77ffe5542950d47e9c23d65f5bc7cb0a9f8700996913eec7" "checksum async-trait 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "687c230d85c0a52504709705fc8a53e4a692b83a2184f03dae73e38e1e93a783" "checksum async-tungstenite 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4187bb446c8ecb8849f17cef7553db8bdb09e482e806257130189958fb42dca7" +"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" "checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" @@ -2027,6 +2081,7 @@ dependencies = [ "checksum dtoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4358a9e11b9a09cf52383b451b49a169e8d797b68aa02301ff586d70d9661ea3" "checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" "checksum encoding_rs 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "e8ac63f94732332f44fe654443c46f6375d1939684c17b0afb6cb56b0456e171" +"checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" "checksum flate2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2cfff41391129e0a856d6d822600b8d71179d46879e310417eb9c762eb178b42" "checksum fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" @@ -2051,6 +2106,7 @@ dependencies = [ "checksum http 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "28d569972648b2c512421b5f2a405ad6ac9666547189d0c5477a3f200f3e02f9" "checksum http-body 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b" "checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" +"checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" "checksum hyper 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96816e1d921eca64d208a85aab4f7798455a8e34229ee5a88c935bdee1b78b14" "checksum hyper-rustls 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac965ea399ec3a25ac7d13b8affd4b8f39325cca00858ddf5eb29b79e6b14b08" "checksum hyper-tls 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3adcd308402b9553630734e9c36b77a7e48b3821251ca2493e8cd596763aafaa" @@ -2102,6 +2158,7 @@ dependencies = [ "checksum proc-macro-hack 0.5.15 (registry+https://github.com/rust-lang/crates.io-index)" = "0d659fe7c6d27f25e9d80a1a094c223f5246f6a6596453e09d7229bf42750b63" "checksum proc-macro-nested 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8e946095f9d3ed29ec38de908c22f95d9ac008e424c7bcae54c75a79c527c694" "checksum proc-macro2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "de40dd4ff82d9c9bab6dae29dbab1167e515f8df9ed17d2987cb6012db206933" +"checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" "checksum quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea" "checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" "checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" @@ -2146,6 +2203,7 @@ dependencies = [ "checksum static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" "checksum syn 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)" = "95b5f192649e48a5302a13f2feb224df883b98933222369e4b3b0fe2a5447269" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" +"checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" "checksum thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "7dfdd070ccd8ccb78f4ad66bf1982dc37f620ef696c6b5028fe2ed83dd3d0d08" "checksum thiserror-impl 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793" "checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" @@ -2192,6 +2250,7 @@ dependencies = [ "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum winreg 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" diff --git a/youmubot/Cargo.toml b/youmubot/Cargo.toml index c20d200..3280a04 100644 --- a/youmubot/Cargo.toml +++ b/youmubot/Cargo.toml @@ -12,8 +12,10 @@ osu = ["youmubot-osu"] codeforces = ["youmubot-cf"] [dependencies] -serenity = "0.8" +serenity = "0.9.0-rc.0" +tokio = "0.2" dotenv = "0.15" +env_logger = "0.7" youmubot-db = { path = "../youmubot-db" } youmubot-prelude = { path = "../youmubot-prelude" } youmubot-core = { path = "../youmubot-core" } diff --git a/youmubot/src/main.rs b/youmubot/src/main.rs index cb21aa0..67345e9 100644 --- a/youmubot/src/main.rs +++ b/youmubot/src/main.rs @@ -1,9 +1,10 @@ use dotenv; use dotenv::var; use serenity::{ - framework::standard::{DispatchError, StandardFramework}, + client::bridge::gateway::GatewayIntents, + framework::standard::{macros::hook, CommandResult, DispatchError, StandardFramework}, model::{ - channel::{Channel, Message, Reaction}, + channel::{Channel, Message}, gateway, id::{ChannelId, GuildId, UserId}, permissions::Permissions, @@ -21,78 +22,80 @@ impl Handler { } } +#[async_trait] impl EventHandler for Handler { - fn ready(&self, _: Context, ready: gateway::Ready) { + async fn ready(&self, _: Context, ready: gateway::Ready) { println!("{} is connected!", ready.user.name); } - fn message(&self, mut ctx: Context, message: Message) { + async fn message(&self, mut ctx: Context, message: Message) { self.hooks.iter().for_each(|f| f(&mut ctx, &message)); } - - fn reaction_add(&self, ctx: Context, reaction: Reaction) { - ctx.data - .get_cloned::() - .send(reaction, true); - } - - fn reaction_remove(&self, ctx: Context, reaction: Reaction) { - ctx.data - .get_cloned::() - .send(reaction, false); - } } /// Returns whether the user has "MANAGE_MESSAGES" permission in the channel. -fn is_channel_mod(ctx: &mut Context, _: Option, ch: ChannelId, u: UserId) -> bool { - match ch.to_channel(&ctx) { - Ok(Channel::Guild(gc)) => { - let gc = gc.read(); - gc.permissions_for_user(&ctx, u) - .map(|perms| perms.contains(Permissions::MANAGE_MESSAGES)) - .unwrap_or(false) - } +async fn is_channel_mod(ctx: &Context, _: Option, ch: ChannelId, u: UserId) -> bool { + match ch.to_channel(&ctx).await { + Ok(Channel::Guild(gc)) => gc + .permissions_for_user(&ctx, u) + .await + .map(|perms| perms.contains(Permissions::MANAGE_MESSAGES)) + .unwrap_or(false), _ => false, } } -fn main() { +#[tokio::main] +async fn main() { + env_logger::init(); // Setup dotenv if let Ok(path) = dotenv::dotenv() { println!("Loaded dotenv from {:?}", path); } - let mut handler = Handler::new(); + let handler = Handler::new(); // Set up hooks #[cfg(feature = "osu")] handler.hooks.push(youmubot_osu::discord::hook); #[cfg(feature = "codeforces")] handler.hooks.push(youmubot_cf::codeforces_info_hook); + // Collect the token + let token = var("TOKEN").expect("Please set TOKEN as the Discord Bot's token to be used."); + // Set up base framework + let fw = setup_framework(&token[..]).await; + // Sets up a client let mut client = { - // Collect the token - let token = var("TOKEN").expect("Please set TOKEN as the Discord Bot's token to be used."); // Attempt to connect and set up a framework - Client::new(token, handler).expect("Cannot connect") + Client::new(token) + .framework(fw) + .event_handler(handler) + .intents( + GatewayIntents::GUILDS + | GatewayIntents::GUILD_BANS + | GatewayIntents::GUILD_MESSAGES + | GatewayIntents::GUILD_MESSAGE_REACTIONS + | GatewayIntents::DIRECT_MESSAGES + | GatewayIntents::DIRECT_MESSAGE_REACTIONS, + ) + .await + .unwrap() }; - // Set up base framework - let mut fw = setup_framework(&client); - // Set up announcer handler let mut announcers = AnnouncerHandler::new(&client); // Setup each package starting from the prelude. { - let mut data = client.data.write(); + let mut data = client.data.write().await; let db_path = var("DBPATH") .map(|v| std::path::PathBuf::from(v)) .unwrap_or_else(|e| { println!("No DBPATH set up ({:?}), using `/data`", e); std::path::PathBuf::from("data") }); - youmubot_prelude::setup::setup_prelude(&db_path, &mut data, &mut fw); + youmubot_prelude::setup::setup_prelude(&db_path, &mut data); // Setup core #[cfg(feature = "core")] youmubot_core::setup(&db_path, &client, &mut data).expect("Setup db should succeed"); @@ -112,11 +115,10 @@ fn main() { #[cfg(feature = "codeforces")] println!("codeforces enabled."); - client.with_framework(fw); - announcers.scan(std::time::Duration::from_secs(120)); + tokio::spawn(announcers.scan(std::time::Duration::from_secs(120))); println!("Starting..."); - if let Err(v) = client.start() { + if let Err(v) = client.start().await { panic!(v) } @@ -124,71 +126,43 @@ fn main() { } // Sets up a framework for a client -fn setup_framework(client: &Client) -> StandardFramework { +async fn setup_framework(token: &str) -> StandardFramework { + let http = serenity::http::Http::new_with_token(token); // Collect owners - let owner = client - .cache_and_http - .http + let owner = http .get_current_application_info() + .await .expect("Should be able to get app info") .owner; - let fw = StandardFramework::new() - .configure(|c| { - c.with_whitespace(false) - .prefix(&var("PREFIX").unwrap_or("y!".to_owned())) - .delimiters(vec![" / ", "/ ", " /", "/"]) - .owners([owner.id].iter().cloned().collect()) - }) - .help(&youmubot_core::HELP) - .before(|_, msg, command_name| { - println!( - "Got command '{}' by user '{}'", - command_name, msg.author.name - ); - true - }) - .after(|ctx, msg, command_name, error| match error { - Ok(()) => println!("Processed command '{}'", command_name), - Err(why) => { - let reply = format!("Command '{}' returned error {:?}", command_name, why); - if let Err(_) = msg.reply(&ctx, &reply) {} - println!("{}", reply) - } - }) - .on_dispatch_error(|ctx, msg, error| { - msg.reply( - &ctx, - &match error { - DispatchError::Ratelimited(seconds) => format!( - "⏳ You are being rate-limited! Try this again in **{} seconds**.", - seconds - ), - DispatchError::NotEnoughArguments { min, given } => format!("😕 The command needs at least **{}** arguments, I only got **{}**!\nDid you know command arguments are separated with a slash (`/`)?", min, given), - DispatchError::TooManyArguments { max, given } => format!("😕 I can only handle at most **{}** arguments, but I got **{}**!", max, given), - DispatchError::OnlyForGuilds => format!("🔇 This command cannot be used in DMs."), - _ => return, - }, - ) - .unwrap(); // Invoke - }) - // Set a function that's called whenever an attempted command-call's - // command could not be found. - .unrecognised_command(|_, _, unknown_command_name| { - println!("Could not find command named '{}'", unknown_command_name); - }) - // Set a function that's called whenever a message is not a command. - .normal_message(|_, _| { - // println!("Message is not a command '{}'", message.content); - }) - .bucket("voting", |c| { - c.check(|ctx, g, ch, u| !is_channel_mod(ctx, g, ch, u)).delay(120 /* 2 minutes */).time_span(120).limit(1) - }) - .bucket("images", |c| c.time_span(60).limit(2)) - .bucket("community", |c| { - c.check(|ctx, g, ch, u| !is_channel_mod(ctx, g, ch, u)).delay(30).time_span(30).limit(1) - }) - .group(&prelude_commands::PRELUDE_GROUP); + let fw = StandardFramework::new() + .configure(|c| { + c.with_whitespace(false) + .prefix(&var("PREFIX").unwrap_or("y!".to_owned())) + .delimiters(vec![" / ", "/ ", " /", "/"]) + .owners([owner.id].iter().cloned().collect()) + }) + .help(&youmubot_core::HELP) + .before(before_hook) + .after(after_hook) + .on_dispatch_error(on_dispatch_error) + .bucket("voting", |c| { + c.check(|ctx, g, ch, u| Box::pin(async move { !is_channel_mod(ctx, g, ch, u).await })) + .delay(120 /* 2 minutes */) + .time_span(120) + .limit(1) + }) + .await + .bucket("images", |c| c.time_span(60).limit(2)) + .await + .bucket("community", |c| { + c.check(|ctx, g, ch, u| Box::pin(async move { !is_channel_mod(ctx, g, ch, u).await })) + .delay(30) + .time_span(30) + .limit(1) + }) + .await + .group(&prelude_commands::PRELUDE_GROUP); // groups here #[cfg(feature = "core")] let fw = fw @@ -201,3 +175,53 @@ fn setup_framework(client: &Client) -> StandardFramework { let fw = fw.group(&youmubot_cf::CODEFORCES_GROUP); fw } + +// Hooks! + +#[hook] +async fn before_hook(_: &Context, msg: &Message, command_name: &str) -> bool { + println!( + "Got command '{}' by user '{}'", + command_name, msg.author.name + ); + true +} + +#[hook] +async fn after_hook(ctx: &Context, msg: &Message, command_name: &str, error: CommandResult) { + match error { + Ok(()) => println!("Processed command '{}'", command_name), + Err(why) => { + let reply = format!("Command '{}' returned error {:?}", command_name, why); + msg.reply(&ctx, &reply).await.ok(); + println!("{}", reply) + } + } +} + +#[hook] +async fn on_dispatch_error(ctx: &Context, msg: &Message, error: DispatchError) { + msg.reply( + &ctx, + &match error { + DispatchError::Ratelimited(seconds) => format!( + "⏳ You are being rate-limited! Try this again in **{} seconds**.", + seconds + ), + DispatchError::NotEnoughArguments { min, given } => { + format!( + "😕 The command needs at least **{}** arguments, I only got **{}**!", + min, given + ) + "\nDid you know command arguments are separated with a slash (`/`)?" + } + DispatchError::TooManyArguments { max, given } => format!( + "😕 I can only handle at most **{}** arguments, but I got **{}**!", + max, given + ), + DispatchError::OnlyForGuilds => format!("🔇 This command cannot be used in DMs."), + _ => return, + }, + ) + .await + .ok(); // Invoke +}