diff --git a/src/command/devel.rs b/src/command/devel.rs new file mode 100644 index 0000000..9c517e3 --- /dev/null +++ b/src/command/devel.rs @@ -0,0 +1,11 @@ +use crate::Context; +use crate::Error; + +#[poise::command(slash_command, owners_only, hide_in_help)] +pub async fn shutdown(ctx: Context<'_>) -> Result<(), Error> { + ctx.defer_ephemeral().await?; + ctx.say("Shutting down...").await?; + info!("Received `shutdown` command, shutting down all shards"); + ctx.framework().shard_manager().shutdown_all().await; + Ok(()) +} diff --git a/src/command/fun.rs b/src/command/fun.rs index b3365ef..e69de29 100644 --- a/src/command/fun.rs +++ b/src/command/fun.rs @@ -1,6 +0,0 @@ -use rand::seq::SliceRandom; -use rand::Rng; - -use crate::Context; -use crate::Error; - diff --git a/src/command/mod.rs b/src/command/mod.rs index 9a7b277..1ba8b87 100644 --- a/src/command/mod.rs +++ b/src/command/mod.rs @@ -1,2 +1,2 @@ -pub mod fun; +pub mod devel; pub mod util; diff --git a/src/command/util.rs b/src/command/util.rs index 6448363..d044e39 100644 --- a/src/command/util.rs +++ b/src/command/util.rs @@ -20,7 +20,7 @@ pub async fn age( #[poise::command(slash_command)] pub async fn info(ctx: Context<'_>) -> Result<(), Error> { ctx.say(format!( - "DeerBot ReBleated v{} was created by Shibe Drill (@shibedrill) using Rust and Poise.\nVisit her website: https://riverdev.carrd.co\nCheck out her Github: https://github.com/shibedrill\nPoise: https://docs.rs/poise/latest/poise/\nRust: https://www.rust-lang.org/", + "Shibe Bot v{} was created by Shibe Drill (@shibedrill) using Rust and Poise.\nVisit her website: https://riverdev.carrd.co\nCheck out her Github: https://github.com/shibedrill\nPoise: https://docs.rs/poise/latest/poise/\nRust: https://www.rust-lang.org/", env!("CARGO_PKG_VERSION") )) .await?; @@ -34,6 +34,7 @@ pub async fn add_channel( ctx: Context<'_>, #[description = "Selected channel"] channel: Option, ) -> Result<(), Error> { + ctx.defer_ephemeral().await?; if let Some(channel_ok) = channel { let config = &mut ctx.data().config_manager.lock().await; let channel_id = { u64::from(channel_ok.id()) }; @@ -54,6 +55,7 @@ pub async fn add_channel( #[poise::command(slash_command)] pub async fn list_channels(ctx: Context<'_>) -> Result<(), Error> { + ctx.defer_ephemeral().await?; let config = &mut ctx.data().config_manager.lock().await; let mut channel_ids: Vec = vec![]; config @@ -61,7 +63,7 @@ pub async fn list_channels(ctx: Context<'_>) -> Result<(), Error> { .iter() .for_each(|c| channel_ids.push(u64::from(c.id()))); ctx.say(format!( - "Current channel IDs in registry: {:#?}", + "Current channel IDs in registry: \n{:#?}", channel_ids )) .await?; diff --git a/src/main.rs b/src/main.rs index c213d4f..6d5aaa7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,38 +1,54 @@ +// Tokio async crap use std::sync::Arc; use tokio::sync::Mutex; +// For secure credential handling use dotenv::dotenv; +// Poise and Serenity - Framework and API prelude use poise::serenity_prelude as serenity; use serenity::Channel; +// Logging stuff extern crate pretty_env_logger; #[macro_use] extern crate log; +// For managing config storage use serde::*; +mod settings; +use crate::settings::*; +// Bot commands mod command; -use crate::{ - command::{fun::*, util::*}, - settings::SettingsManager, +use crate::command::{ + // Commands for development and testing + devel::*, + // Useful commands for mods + util::*, }; -mod settings; - +// Data passed to every command (shared state) struct Data { config_manager: Arc>>, -} // User data, which is stored and accessible in all command invocations +} + +// Errors returnable by a command type Error = Box; + +// The full context passed to a command type Context<'a> = poise::Context<'a, Data, Error>; +// The structure making up the configuration #[derive(Debug, Serialize, Deserialize, Default)] struct Settings { channels: Vec, } +// Path at which our settings are stored (currently PWD) const SETTINGS_PATH: &str = "settings.json"; +// Main function for setup #[tokio::main] async fn main() { // Get secure env vars from .env file @@ -55,12 +71,17 @@ async fn main() { // Set up framework let framework = poise::Framework::builder() .options(poise::FrameworkOptions { - commands: vec![age(), info(), add_channel(), list_channels()], + // +---------------------------------------------------------+ + // | ADD COMMANDS HERE | + // +---------------------------------------------------------+ + commands: vec![age(), info(), add_channel(), list_channels(), shutdown()], + initialize_owners: true, ..Default::default() }) .setup(|ctx, _ready, framework| { Box::pin(async move { poise::builtins::register_globally(ctx, &framework.options().commands).await?; + // Shared data has to go here!!! Ok(Data { config_manager }) }) }) @@ -69,6 +90,7 @@ async fn main() { // Log pertinent info info!("Built framework successfully"); { + // List registered commands let mut commands: Vec<&str> = vec![]; framework .options() @@ -78,10 +100,16 @@ async fn main() { info!("Registered commands: {:?}", commands); } - let client = serenity::ClientBuilder::new(token, intents) + // Build client + let mut client = serenity::ClientBuilder::new(token, intents) .framework(framework) - .await; + .await + .unwrap(); info!("Built client successfully"); + + info!("Registered owner: {:?}", client.http.get_current_application_info().await.unwrap().owner.unwrap().name); + + // Finally start everything. Nothing after this should be reachable normally. info!("Starting client"); - client.unwrap().start().await.unwrap(); + client.start().await.unwrap(); } diff --git a/src/settings.rs b/src/settings.rs index d0b8f66..ca6947e 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -23,7 +23,7 @@ impl Deserialize<'a>> SettingsManager { path: String::from(path), }) } - /// Update the data stored in the settings, if it has been modified on the + /// Update the data stored in the settings, if it has been modified on the /// disk but not in memory. Because this is a stupid method, it will most /// likely go unused by most. #[allow(dead_code)]