#[macro_use] extern crate log; extern crate log4rs; extern crate serde; use std::path::Path; use std::process::exit; use std::sync::Arc; use clap::{App, Arg}; use log::LevelFilter; use log4rs::append::console::ConsoleAppender; use log4rs::append::rolling_file::policy::compound::roll::fixed_window::FixedWindowRoller; use log4rs::append::rolling_file::policy::compound::trigger::size::SizeTrigger; use log4rs::append::rolling_file::policy::compound::CompoundPolicy; use log4rs::append::rolling_file::RollingFileAppender; use log4rs::config::{Appender, Config, Root}; use log4rs::encode::pattern::PatternEncoder; use log4rs::filter::threshold::ThresholdFilter; use log4rs::init_config; use serenity::client::Client; use serenity::framework::standard::macros::group; use serenity::framework::standard::StandardFramework; use database::*; use discord::events::{CANCEL_COMMAND, CONFIRM_COMMAND, CREATE_COMMAND}; use discord::handler::Handler; use discord::BOT_HELP; use discord::{log_error, permission_check, DraftEvent}; use hypebot_config::HypeBotConfig; use reminder::Reminders; mod database; mod discord; mod hypebot_config; mod reminder; const INTERESTED_EMOJI: char = '\u{2705}'; const UNINTERESTED_EMOJI: char = '\u{274C}'; type HypeBotResult = std::result::Result>; /// Event command group #[group] #[only_in(guilds)] #[description("Commands for Creating Events")] #[commands(create, confirm, cancel)] struct EventCommands; /// Does the setup for logging fn setup_logging(config: &HypeBotConfig) -> HypeBotResult<()> { // Build log file path let log_file_path = Path::new(&config.log_path); let log_file_path = log_file_path.join("hype_bot.log"); let archive = log_file_path.join("hype_bot.{}.log"); // Number of logs to keep let window_size = 10; // 10MB file size limit let size_limit = 10 * 1024 * 1024; let size_trigger = SizeTrigger::new(size_limit); let fixed_window_roller = FixedWindowRoller::builder() .build(archive.to_str().unwrap(), window_size) .unwrap(); let compound_policy = CompoundPolicy::new(Box::new(size_trigger), Box::new(fixed_window_roller)); let config = Config::builder() .appender( Appender::builder() .filter(Box::new(ThresholdFilter::new(LevelFilter::Warn))) .build( "logfile", Box::new( RollingFileAppender::builder() .encoder(Box::new(PatternEncoder::new("{d} {l}::{m}{n}"))) .build(log_file_path, Box::new(compound_policy))?, ), ), ) .appender( Appender::builder() .filter(Box::new(ThresholdFilter::new(LevelFilter::Info))) .build( "stdout", Box::new( ConsoleAppender::builder() .encoder(Box::new(PatternEncoder::new("{l}::{m}{n}"))) .build(), ), ), ) .build( Root::builder() .appender("logfile") .appender("stdout") .build(LevelFilter::Info), )?; init_config(config)?; Ok(()) } #[tokio::main] async fn main() -> HypeBotResult<()> { // Initialize arg parser let mut app = App::new("Hype Bot") .about("Hype Bot: Hype Up Your Discord Events!") .arg( Arg::with_name("config") .index(1) .short("c") .long("config") .value_name("CONFIG_PATH") .help("Config file path"), ); // Get arg parser let matches = app.clone().get_matches(); // Check if config is set if let Some(config_path) = matches.value_of("config") { // Load config let cfg = match hypebot_config::HypeBotConfig::new(config_path) { Ok(cfg) => cfg, Err(err) => { println!("Error opening config file: {}", err); exit(-1); } }; // Setup logging setup_logging(&cfg)?; // New client let mut client = Client::builder(cfg.discord_key.clone()) .event_handler(Handler) .framework( StandardFramework::new() .configure(|c| { c.prefix(cfg.prefix.as_str()) .allow_dm(false) .ignore_bots(true) .ignore_webhooks(true) }) .before(permission_check) .after(log_error) .group(&EVENTCOMMANDS_GROUP) .help(&BOT_HELP), ) .await?; // Copy config data to client data and setup scheduler { let db = database::Database::new(&cfg.db_location)?; let mut data = client.data.write().await; data.insert::(Arc::new(cfg)); data.insert::(Arc::new(DraftEvent::default())); data.insert::(Reminders::default()); data.insert::(Arc::new(db)); } // Start bot info!("Starting HypeBot!"); if let Err(why) = client.start().await { error!("An error occurred while running the client: {:?}", why); } } else { // Print help app.print_help()?; } Ok(()) }