use anyhow::{Context as _, Result}; use clap::{value_parser, ArgAction, Parser}; use lambo::{config::Config, handlers::*}; use serenity::{all::GatewayIntents, Client}; use sqlx::sqlite::SqlitePoolOptions; use std::{path::PathBuf, sync::Arc}; use stderrlog::StdErrLog; #[derive(Debug, Parser)] struct Args { /// The path to the lambo configuration file. config_path: PathBuf, /// Decreases the log level. #[clap( short, long, conflicts_with("verbose"), action = ArgAction::Count, value_parser = value_parser!(u8).range(..=2) )] quiet: u8, /// Increases the log level. #[clap( short, long, conflicts_with("quiet"), action = ArgAction::Count, value_parser = value_parser!(u8).range(..=3) )] verbose: u8, } #[tokio::main] async fn main() -> Result<()> { // Parse the arguments. let args = Args::parse(); // Set up logging. { let mut logger = StdErrLog::new(); match args.quiet { 0 => logger.verbosity(1 + args.verbose as usize), 1 => logger.verbosity(0), 2 => logger.quiet(true), // UNREACHABLE: A maximum of two occurrences of quiet are allowed. _ => unreachable!(), }; // UNWRAP: No other logger should be set up. logger.show_module_names(true).init().unwrap() } // Parse the config file. let config = Config::read_from_file(&args.config_path)?; // Connect to the database. let db = SqlitePoolOptions::new() .connect(&config.database_url) .await .with_context(|| format!("failed to connect to database at {:?}", config.database_url))?; // Run any necessary migrations. sqlx::migrate!().run(&db).await.with_context(|| { format!( "failed to run migrations on database at {:?}", config.database_url ) })?; // Create the handlers. let handler = MultiHandler(vec![ Box::new(PresenceSetter), Box::new(X500Mapper { config: Arc::new(config.x500_mapper), db, }), ]); // Start up the client. let intents = GatewayIntents::default() | GatewayIntents::GUILD_MEMBERS; Client::builder(&config.discord_token, intents) .event_handler(handler) .await .context("failed to create Discord client")? .start() .await .context("failed to start Discord client")?; Ok(()) }