diff --git a/src/main.rs b/src/main.rs index 8ac9dd1..348aabd 100755 --- a/src/main.rs +++ b/src/main.rs @@ -54,13 +54,14 @@ impl EventHandler for Handler { #[group] #[commands( - init, ping, halt, list_srv, host, ship, bottom_rng, headpat, uwu, gayculator, sausage, help, + init, ping, halt, servers, host, ship, bottom_rng, headpat, uwu, gayculator, sausage, help, embed, define, owo, info, echo, desc, pinned, brainfuck )] struct General; lazy_static! { static ref OWNERS: std::vec::Vec = + /* Agatha's Id Julia's Id */ vec![UserId(254310746450690048), UserId(687740609703706630)]; } @@ -75,6 +76,7 @@ fn main() { let mut client = Client::new(&env::var("DISCORD_TOKEN").expect("Invalid token"), Handler) .expect("Error creating client"); + // Updates stored data, used for ping command { let mut data = client.data.write(); data.insert::(Arc::clone(&client.shard_manager)); @@ -92,14 +94,22 @@ fn main() { }) .on_dispatch_error(|ctx, msg, error| { if let DispatchError::CheckFailed("Owner", Reason::Unknown) = error { + // triggers if user is not owner let _ = msg.channel_id.say(&ctx.http, "nyo"); - } else if let DispatchError::Ratelimited(seconds) = error { - let _ = msg - .channel_id - .say(&ctx.http, &format!("Try again in {} seconds.", seconds)); + } else if let DispatchError::Ratelimited(_) = error { + // triggers if rate limited + eprintln!( + "{}", + format!( + "Rate limited in {} with message {}", + msg.channel_id.to_string().purple().bold(), + msg.content.purple() + ) + ); } }) .after(|ctx, msg, cmd_name, error| { + // prints error in chat if let Err(why) = error { let _ = msg.channel_id.send_message(&ctx.http, |m| { m.embed(|e| { @@ -109,6 +119,7 @@ fn main() { .colour(0xff6961) }) }); + // prints error in console eprintln!( "{}", format!("Error in {}: {}", cmd_name.purple(), &why.0.red().bold()) @@ -191,9 +202,6 @@ fn ping(ctx: &mut Context, message: &Message) -> CommandResult { fn echo(ctx: &mut Context, message: &Message, args: Args) -> CommandResult { let input: String = args.rest().trim().to_string(); if args.is_empty() { - let _ = message - .channel_id - .say(&ctx.http, "Error: called without input!"); return Err(CommandError("Called without input".to_string())); } @@ -205,6 +213,7 @@ fn echo(ctx: &mut Context, message: &Message, args: Args) -> CommandResult { #[command] #[checks(Owner)] fn halt(ctx: &mut Context) -> CommandResult { + // Workaround for discord not doing this automatically ctx.set_presence(None, OnlineStatus::Offline); use std::{thread, time}; @@ -216,7 +225,7 @@ fn halt(ctx: &mut Context) -> CommandResult { #[command] #[checks(Owner)] -fn list_srv(ctx: &mut Context, message: &Message) -> CommandResult { +fn servers(ctx: &mut Context, message: &Message) -> CommandResult { let mut list = String::new(); let cache = ctx.cache.read(); for (index, guild_lock) in cache.guilds.values().enumerate() { @@ -225,6 +234,7 @@ fn list_srv(ctx: &mut Context, message: &Message) -> CommandResult { } let _ = message .channel_id + // Add zero width space to all mentions .say(&ctx.http, list.replace("@", "@\u{200B}")); Ok(()) @@ -269,6 +279,7 @@ fn embed(ctx: &mut Context, message: &Message, args: Args) -> CommandResult { url: Option, } + // print documentation from src/embed-docs.txt if &args.rest().trim().to_string() == "help" { let mut file = fs::File::open("./src/embed-docs.txt")?; let mut help_string = String::new(); @@ -362,10 +373,12 @@ fn embed(ctx: &mut Context, message: &Message, args: Args) -> CommandResult { Ok(()) } +// generate a random number using a keysmash as seed #[command] fn bottom_rng(ctx: &mut Context, message: &Message, mut args: Args) -> CommandResult { use rand::{rngs::StdRng, SeedableRng}; + // get N last messages, otherwise 10 let num = args.single::().unwrap_or(10); let messages = message .channel_id @@ -374,6 +387,7 @@ fn bottom_rng(ctx: &mut Context, message: &Message, mut args: Args) -> CommandRe let _ = message.channel_id.say(&ctx.http, format!("Error: {}", e)); } else { let mut messages = messages?; + // remove all messages by other users messages.retain(|v| v.author != message.mentions[0]); let mut input = String::new(); for msg in messages { @@ -411,6 +425,7 @@ fn ship(ctx: &mut Context, message: &Message, args: Args) -> CommandResult { .map(|x| x.to_owned()) .collect::>(); + // Concatenate names together let shipname: Result = match names.len() { 0 => Err("Invalid input!".to_string()), 1 => Ok(names[0].clone()), @@ -455,6 +470,7 @@ fn headpat(ctx: &mut Context, message: &Message, args: Args) -> CommandResult { return Err(CommandError("Please specify a username!".to_string())); } + // Get username from first mention, otherwise use input text let name = match message.mentions.len() { 0 => args, _ => message.mentions[0].name.as_str(), @@ -475,6 +491,7 @@ fn headpat(ctx: &mut Context, message: &Message, args: Args) -> CommandResult { Ok(()) } +// send a random uwu image #[command] fn uwu(ctx: &mut Context, message: &Message) -> CommandResult { let images = [ @@ -552,7 +569,7 @@ fn help(ctx: &mut Context, message: &Message) -> CommandResult { true, ), ( - "owo!embed ``[args]``", + "owo!embed ``[args]`` *OR* help", "Create an embed from a Toml object", true, ), @@ -562,13 +579,13 @@ fn help(ctx: &mut Context, message: &Message) -> CommandResult { "Display channel's Nth pinned message. Channel name is optional", true, ), - ("owo!brainfuck ``input``", "execute input code", true), + ("owo!brainfuck ``input``", "Execute input code", true), ("owo!ship ``[names]``", "*Shipping intensifies*", true), ("owo!headpat ``name``", "Headpat someone", true), ("owo!owo ``text``", "owoify input text", true), ("\u{200B}", "**Admin commands:**", false), ("owo!halt", "Kill the bot process", true), - ("owo!list_srv", "List my servers", true), + ("owo!servers", "List the servers I'm in", true), ("owo!host", "Display host info", true), ]) .color(0xffd1dc) @@ -585,13 +602,15 @@ fn info(ctx: &mut Context, message: &Message, args: Args) -> CommandResult { } let num = ctx.cache.read().guilds.len(); + // get developer's username let aganame = OWNERS.clone()[0].to_user(ctx.http.clone())?.tag(); let _ = message.channel_id.send_message(&ctx.http, |m| m .embed(|e| e .title("Discordinator9000's info:") .field("Author:", format!("{} / Agatha", aganame), false) .field("Server count:", num , false) - .field("Invite:", "[Invite link](https://discordapp.com/api/oauth2/authorize?client_id=470350233419907129&permissions=2048&scope=bot)", false ) + .field("Invite:", "[Invite link](https://discordapp.com/api/oauth2/authorize?client_id=470350233419907129&permissions=2048&scope=bot)", true ) + .field("source:", "[Gitlab](https://gitlab.com/agathasorceress/rustcord)", true) .footer(|f| f .text("Written in Rust using Serenity, OwOify and a few other libraries")) .thumbnail("https://cdn.discordapp.com/attachments/687011390434967621/704118007563157544/discordinator.png") @@ -600,6 +619,7 @@ fn info(ctx: &mut Context, message: &Message, args: Args) -> CommandResult { Ok(()) } +// Urban Dictionary lookup #[command] #[aliases("what's this")] fn define(ctx: &mut Context, message: &Message, args: Args) -> CommandResult { @@ -634,6 +654,7 @@ fn define(ctx: &mut Context, message: &Message, args: Args) -> CommandResult { Ok(()) } +// Text owoification #[command] fn owo(ctx: &mut Context, message: &Message, args: Args) -> CommandResult { use owoify::OwOifiable; @@ -644,6 +665,7 @@ fn owo(ctx: &mut Context, message: &Message, args: Args) -> CommandResult { Ok(()) } +// Prints channel topic #[command] #[aliases("description", "topic")] fn desc(ctx: &mut Context, message: &Message) -> CommandResult { @@ -678,9 +700,12 @@ fn desc(ctx: &mut Context, message: &Message) -> CommandResult { Ok(()) } +// Prints Nth pinned message #[command] fn pinned(ctx: &mut Context, message: &Message, mut args: Args) -> CommandResult { + // defaults to latest pinned message if no args are provided let mut idx = args.single::().unwrap_or(1); + // Makes pinned messages 1-indexed if idx != 0 { idx -= 1; } @@ -724,6 +749,7 @@ fn pinned(ctx: &mut Context, message: &Message, mut args: Args) -> CommandResult Ok(()) } +// brainfuck interpreter #[command] #[aliases("bf", "brainfrick")] fn brainfuck(ctx: &mut Context, message: &Message, args: Args) -> CommandResult { @@ -731,7 +757,7 @@ fn brainfuck(ctx: &mut Context, message: &Message, args: Args) -> CommandResult let input = match args.rest().trim() { "" => { - return Err(CommandError("Empty input!".to_string())); + return Err(CommandError("Called without input!".to_string())); } v @ _ => v, };