mod commands; mod db; use affluences_api::AffluencesClient; use diesel::r2d2::{ConnectionManager, Pool}; use diesel::sqlite::SqliteConnection; use poise::serenity_prelude as serenity; use std::{env::var, time::Duration}; // Types used by all command functions type Error = Box; type Context<'a> = poise::Context<'a, Data, Error>; // Custom user data passed to all command functions pub struct Data { client: AffluencesClient, pool: Pool>, } async fn on_error(error: poise::FrameworkError<'_, Data, Error>) { // This is our custom error handler // They are many errors that can occur, so we only handle the ones we want to customize // and forward the rest to the default handler match error { poise::FrameworkError::Setup { error, .. } => panic!("Failed to start bot: {:?}", error), poise::FrameworkError::Command { error, ctx } => { println!("Error in command `{}`: {:?}", ctx.command().name, error,); } error => { if let Err(e) = poise::builtins::on_error(error).await { println!("Error while handling error: {}", e) } } } } #[tokio::main] async fn main() { // FrameworkOptions contains all of poise's configuration option in one struct // Every option can be omitted to use its default value let options = poise::FrameworkOptions { commands: commands::commands(), prefix_options: poise::PrefixFrameworkOptions { prefix: Some("~".into()), edit_tracker: Some(poise::EditTracker::for_timespan(Duration::from_secs(3600))), additional_prefixes: vec![ poise::Prefix::Literal("hey bot"), poise::Prefix::Literal("hey bot,"), ], ..Default::default() }, /// The global error handler for all error cases that may occur on_error: |error| Box::pin(on_error(error)), /// This code is run before every command pre_command: |ctx| { Box::pin(async move { println!("Executing command {}...", ctx.command().qualified_name); }) }, /// This code is run after a command if it was successful (returned Ok) post_command: |ctx| { Box::pin(async move { println!("Executed command {}!", ctx.command().qualified_name); }) }, /// Every command invocation must pass this check to continue execution command_check: Some(|ctx| { Box::pin(async move { if ctx.author().id == 123456789 { return Ok(false); } Ok(true) }) }), /// Enforce command checks even for owners (enforced by default) /// Set to true to bypass checks, which is useful for testing skip_checks_for_owners: false, event_handler: |_ctx, event, _framework, _data| { Box::pin(async move { println!("Got an event in event handler: {:?}", event.name()); Ok(()) }) }, ..Default::default() }; let pool = db::initialize_pool("affy.db").unwrap(); poise::Framework::builder() .token( var("DISCORD_TOKEN") .expect("Missing `DISCORD_TOKEN` env var, see README for more information."), ) .setup(move |ctx, _ready, framework| { Box::pin(async move { println!("Logged in as {}", _ready.user.name); poise::builtins::register_globally(ctx, &framework.options().commands).await?; Ok(Data { client: AffluencesClient::new(), pool, }) }) }) .options(options) .intents( serenity::GatewayIntents::non_privileged() | serenity::GatewayIntents::MESSAGE_CONTENT, ) .run() .await .unwrap(); }