#[macro_use] extern crate log; #[macro_use] extern crate serde; use std::env; use std::ops::Deref; use std::path::PathBuf; use std::sync::Arc; use clap::ArgMatches; use diesel::r2d2::ConnectionManager; use diesel::sqlite::Sqlite; use diesel::SqliteConnection; use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness}; use poise::framework::FrameworkBuilder; use poise::serenity_prelude::*; use crate::config::ManifoldConfig; use crate::error::{ManifoldError, ManifoldResult}; use crate::events::Handler; use crate::models::user::{ManifoldUserInfo, UserInfo}; use crate::responses::Responses; pub mod config; pub mod error; pub mod events; pub mod responses; pub mod commands; pub mod models; pub mod schema; pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations"); // Retrieve build info from output file pub mod built_info { include!(concat!(env!("OUT_DIR"), "/built.rs")); } pub type ManifoldDatabasePool = r2d2::Pool>; pub struct Db { pub pool: ManifoldDatabasePool, } impl Deref for Db { type Target = ManifoldDatabasePool; fn deref(&self) -> &Self::Target { &self.pool } } pub struct ManifoldDatabase; pub struct ManifoldData(pub Arc); impl Deref for ManifoldData { type Target = ManifoldDataInner; fn deref(&self) -> &Self::Target { &self.0 } } pub struct ManifoldDataInner { bot_config: ManifoldConfig, database: Db, responses: Responses, user_info: Mutex, version_string: String, } pub type ManifoldContext<'a> = poise::Context<'a, ManifoldData, ManifoldError>; pub type ManifoldCommand = poise::Command; pub async fn prepare_client(arguments: ArgMatches, intents: GatewayIntents, injected_commands: Vec, caller_version_string: String) -> ManifoldResult> { let bot_environment = arguments.get_one("environment").unwrap(); let config_file = format!("config/{}", arguments.get_one::("config-file").unwrap()); info!("Reading configuration..."); debug!("Configuration file path: {}", &config_file); let config = ManifoldConfig::load_config(&config_file, bot_environment).expect(&*format!("Could not read configuration file {}", &config_file)); let prefix = config.get_value(&"BotPrefix".to_string()).expect("Could not read bot_prefix from config."); let manager = ConnectionManager::::new("manifold.db"); let pool = r2d2::Pool::builder() .max_size(1) .build(manager) .expect("Database setup error!"); let mut responses = Responses::new(); responses.reload(&PathBuf::from(config.get_value(&"ResponsesFilePath".to_string()).unwrap_or("txt/responses.txt".to_string()))).expect("Could not load responses file!"); let token = env::var("DISCORD_TOKEN").expect( "Could not find an environment variable called DISCORD_TOKEN", ); let framework = poise::Framework::builder() .options(poise::FrameworkOptions { event_handler: |ctx, e, fctx, _| Box::pin(async move { Handler::listen(ctx, fctx, e).await }), pre_command: |ctx: ManifoldContext<'_>| Box::pin(async move { info!("Received command {} from {}", ctx.command().name, ctx.author().name); let config = &ctx.data().bot_config; let log_channel = config.get_channel(&"Log".to_string()).unwrap(); let _ = log_channel.say(ctx, format!("Received command {} from {}", ctx.command().name, ctx.author().name)).await; }), commands: commands::collect_commands(injected_commands), prefix_options: poise::PrefixFrameworkOptions { prefix: Some(prefix), ..Default::default() }, ..Default::default() }) .token(token) .intents(intents) .setup(|ctx, _ready, framework| { Box::pin(async move { poise::builtins::register_globally(ctx, &framework.options().commands).await?; ctx.set_activity(Activity::watching("you")).await; let db = Db { pool }; apply_migrations(&mut db.get()?); let user_info = UserInfo::load(&db).expect("Could not load user info, rejecting"); let git_info: String = built_info::GIT_VERSION.unwrap_or("unknown").to_string(); Ok(ManifoldData(Arc::new(ManifoldDataInner { bot_config: config, database: db, responses, user_info: Mutex::new(user_info), version_string: format!("{caller} (Manifold framework version {mfold_ver} built at {mfold_time} from revision {mfold_rev})", caller=caller_version_string, mfold_ver=built_info::PKG_VERSION, mfold_time=built_info::BUILT_TIME_UTC, mfold_rev=git_info), }))) }) }); Ok(framework) } fn apply_migrations(conn: &mut impl MigrationHarness) { conn.run_pending_migrations(MIGRATIONS) .expect("An error occurred applying migrations."); }