mod config; use serenity::framework::StandardFramework; use serenity::Client; fn configure(conf: &mut serenity::framework::standard::Configuration) { conf.prefix(config::GLOBAL_COMMAND_PREFIX) .with_whitespace((true, true, true)) .case_insensitivity(true); } struct Handler; #[derive(Debug, Clone)] pub enum BotError { MissingGuild, } impl std::fmt::Display for BotError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { Self::MissingGuild => write!(f, "this command is only usable in a guild"), } } } impl std::error::Error for BotError {} mod commands { use crate::config; use serenity::client::Context; use serenity::framework::standard::{macros::*, CommandError, CommandResult}; use serenity::model::{ channel::{ChannelType, GuildChannel, Message}, guild::Guild, id::ChannelId, }; #[group] #[description = "Commands for the cupido bot"] #[commands(help, create)] struct Group; struct ChannelDescriptor<'n, 'd> { name: &'n str, description: &'d str, kind: ChannelType, parent: Option, } async fn get_guild(ctx: &Context, msg: &Message) -> Result { msg.guild(&ctx.cache) .await .ok_or_else(|| Box::new(super::BotError::MissingGuild).into()) } async fn create_channel_no_cache<'n, 'd>( ctx: &Context, guild: &Guild, desc: ChannelDescriptor<'n, 'd>, ) -> Result { Ok(guild .create_channel(ctx, |c| { let c = c.name(desc.name).topic(desc.description).kind(desc.kind); if let Some(parent) = desc.parent { c.category(parent) } else { c } }) .await?) } async fn create_channel<'n, 'd>( ctx: &Context, guild: &Guild, desc: ChannelDescriptor<'n, 'd>, ) -> Result { let channel = guild.channel_id_from_name(&ctx.cache, desc.name).await; let optional_channel = match channel { Some(channel) => ctx.cache.guild_channel(channel).await, None => None, }; match optional_channel { Some(channel) => Ok(channel), None => create_channel_no_cache(ctx, guild, desc).await, } } #[command] #[aliases("hepl", "?", "h")] async fn help(ctx: &Context, msg: &Message) -> CommandResult { msg.reply(ctx, crate::config::HELP_TEXT).await?; Ok(()) } #[command] #[aliases("craete", "+", "c", "init")] async fn create(ctx: &Context, msg: &Message) -> CommandResult { let guild = get_guild(ctx, msg).await?; let meta_channel = create_channel( ctx, &guild, ChannelDescriptor { name: config::META_CHANNEL_NAME, description: config::META_CHANNEL_DESCRIPTION, kind: ChannelType::Category, parent: None, }, ) .await?; Ok(()) } } impl serenity::client::EventHandler for Handler {} #[tokio::main] async fn main() { println!("crate framework"); let framework = StandardFramework::new() .configure(|c| { configure(c); c }) .group(&commands::GROUP_GROUP); let token = std::env::var(config::TOKEN_ENV).expect("missing token"); println!("crate a new client with token: \"{}\"", token); let mut client = Client::new(token) .framework(framework) .event_handler(Handler) .await .expect("Error creating client"); println!("starting the client"); client.start().await.expect("client error"); }