Skip to main content

streamocracy/
main.rs

1//! Streamocracy - A simple Discord bot
2//!
3//! A single-purpose Discord bot built with Serenity using slash commands.
4//!
5//! ## Configuration
6//!
7//! Configuration is loaded from environment variables.
8//! A `.env` file can be used for local development.
9
10use anyhow::Context as AnyhowContext;
11use serenity::all::{Client, Context, EventHandler, GatewayIntents, Interaction, Ready};
12use tracing::{error, info};
13
14use crate::config::Config;
15use crate::utils::Utils;
16
17mod commands;
18mod config;
19mod polls;
20mod utils;
21
22struct Bot {
23    config: Config,
24}
25
26#[serenity::async_trait]
27impl EventHandler for Bot {
28    async fn ready(&self, ctx: Context, ready: Ready) {
29        info!("Bot is connected as {}", ready.user.name);
30
31        let commands: Vec<_> = commands::get_commands()
32            .iter()
33            .map(|cmd| cmd.register())
34            .collect();
35
36        Utils::register_commands(&ctx, self.config.guild_id(), commands).await;
37    }
38
39    async fn interaction_create(&self, ctx: Context, interaction: Interaction) {
40        if let Interaction::Command(command) = interaction {
41            let command_name = command.data.name.clone();
42            let config = self.config.clone();
43
44            for cmd in commands::get_commands() {
45                if cmd.name() == command_name.as_str() {
46                    cmd.run(ctx, command, config).await;
47                    return;
48                }
49            }
50
51            Utils::ephemeral_response(&ctx.http, &command, "Unknown command").await;
52        }
53    }
54}
55
56#[tokio::main]
57async fn main() -> anyhow::Result<()> {
58    dotenvy::dotenv().ok();
59
60    let config = config::init().context("Failed to initialize configuration")?;
61    let intents = GatewayIntents::GUILDS
62        | GatewayIntents::GUILD_VOICE_STATES
63        | GatewayIntents::GUILD_MEMBERS
64        | GatewayIntents::GUILD_MESSAGE_REACTIONS;
65
66    let mut client = Client::builder(&config.discord_token, intents)
67        .event_handler(Bot { config })
68        .await
69        .context("Failed to create Discord client")?;
70
71    info!("Starting Streamocracy Discord Bot...");
72
73    if let Err(e) = client.start().await {
74        error!("Client error: {:?}", e);
75    }
76
77    Ok(())
78}