manifold/src/lib.rs

207 lines
6.5 KiB
Rust
Raw Normal View History

2021-11-12 12:05:26 +00:00
#[macro_use] extern crate log;
2021-11-12 13:56:05 +00:00
#[macro_use] extern crate serde;
2021-11-12 12:05:26 +00:00
use std::collections::HashSet;
use std::env;
use std::fs::File;
use std::ops::Deref;
use std::path::PathBuf;
use std::sync::Arc;
use clap::ArgMatches;
use diesel::r2d2::{ConnectionManager};
use diesel::SqliteConnection;
use crate::config::{Config, ManifoldConfig};
use serenity::prelude::*;
use serenity::framework::standard::{*, macros::*};
use serenity::http::Http;
2021-11-12 12:22:16 +00:00
use serenity::model::prelude::{GuildId, Message, UserId};
2021-11-12 12:05:26 +00:00
use crate::error::ManifoldResult;
use crate::responses::Responses;
pub mod config;
pub mod error;
pub mod responses;
pub mod events;
2021-11-12 13:23:14 +00:00
pub mod core_commands;
// Retrieve build info from output file
pub mod built_info {
include!(concat!(env!("OUT_DIR"), "/built.rs"));
}
use crate::core_commands::*;
2021-11-12 12:05:26 +00:00
2021-11-12 22:22:20 +00:00
pub type ManifoldDatabasePool = diesel::r2d2::Pool<ConnectionManager<SqliteConnection>>;
2021-11-12 12:05:26 +00:00
pub struct Db {
2021-11-12 22:28:51 +00:00
pub pool: ManifoldDatabasePool,
2021-11-12 12:05:26 +00:00
}
impl Deref for Db {
2021-11-12 22:22:20 +00:00
type Target = ManifoldDatabasePool;
2021-11-12 12:05:26 +00:00
fn deref(&self) -> &Self::Target { &self.pool }
}
2021-11-12 22:22:20 +00:00
pub struct ManifoldDatabase;
2021-11-12 12:05:26 +00:00
impl TypeMapKey for ManifoldDatabase {
type Value = Arc<Mutex<Db>>;
}
impl TypeMapKey for Responses {
type Value = Arc<Mutex<Responses>>;
}
impl TypeMapKey for ManifoldConfig {
type Value = Arc<Mutex<ManifoldConfig>>;
}
2021-11-12 12:15:59 +00:00
#[group]
2021-11-12 13:23:14 +00:00
#[commands(ping, set_config, get_config, version, set_activity, get_environment)]
2021-11-12 12:15:59 +00:00
struct Core;
2022-02-16 15:39:24 +00:00
pub async fn prepare_client<T: 'static + EventHandler>(arguments: ArgMatches, mut framework: StandardFramework, event_handler: T) -> ManifoldResult<Client> {
2021-11-12 12:05:26 +00:00
let bot_environment = arguments.value_of("environment").unwrap_or("Production").to_string();
let config_file = format!("config/{}", arguments.value_of("config-file").unwrap_or("manifold.json"));
if arguments.occurrences_of("make-config") > 0 {
if File::open(&config_file).is_ok() {
warn!("Not making a new configuration file - configuration exists at {}. Please remove this if you want to generate a fresh config, or provide an alternative path.", &config_file);
Err("ConfigExists")?
} else {
let config = ManifoldConfig::new();
match config.create_default_config(&config_file, &bot_environment) {
Ok(_) => warn!("Writing new configuration to {}", &config_file),
Err(e) => {error!("Could not write new config! {}", e.details); Err(e)?}
}
}
2021-11-17 15:12:21 +00:00
Err("MadeConfig")?
2021-11-12 12:05:26 +00:00
}
info!("Reading configuration...");
debug!("Configuration file path: {}", &config_file);
let config = load_config(&config_file, &bot_environment);
debug!("Current configuration: {:?}", &config);
let prefix = config.get_value(&"BotPrefix".to_string()).unwrap();
let manager = ConnectionManager::<SqliteConnection>::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",
);
2022-02-16 00:55:59 +00:00
let application_id: u64 = env::var("APPLICATION_ID").expect(
"Could not find an application ID in the APPLICATION_ID environment variable, please provide one",
).parse().expect("That wasn't a number");
2021-11-12 12:05:26 +00:00
let http = Http::new_with_token(&token);
let (owners, bot_id) = match http.get_current_application_info().await {
Ok(info) => {
let mut owners = HashSet::new();
owners.insert(info.owner.id);
(owners, info.id)
}
Err(why) => panic!("Could not get HTTP application information - exiting: {:?}", why),
};
2021-11-12 12:43:20 +00:00
framework = framework.configure(|c| c
2021-11-12 12:05:26 +00:00
.with_whitespace(true)
.on_mention(Some(bot_id))
.prefix(&prefix)
.owners(owners)
.case_insensitivity(true)
2021-11-12 12:43:20 +00:00
).before(before)
.help(&MANIFOLD_HELP);
framework.group_add(&CORE_GROUP);
2021-11-12 12:05:26 +00:00
2021-11-12 12:15:59 +00:00
let client = Client::builder(&token)
2021-11-12 22:56:41 +00:00
.event_handler(event_handler)
2022-02-16 00:55:59 +00:00
.application_id(application_id)
2021-11-12 12:05:26 +00:00
.framework(framework)
.await
.expect("Error creating client!");
{
let mut data = client.data.write().await;
let db = Db { pool };
data.insert::<ManifoldConfig>(Arc::new(Mutex::new(config)));
data.insert::<ManifoldDatabase>(Arc::new(Mutex::new(db)));
data.insert::<Responses>(Arc::new(Mutex::new(responses)));
}
Ok(client)
}
fn load_config(config_file: &String, bot_environment: &String) -> ManifoldConfig {
let mut config = ManifoldConfig::new();
*config.get_path_mut() = PathBuf::from(config_file);
*config.get_environment_mut() = bot_environment.to_owned();
config.load_config().expect("Could not load config - halting");
config
}
2021-11-12 12:22:16 +00:00
#[help]
async fn manifold_help(
ctx: &Context,
msg: &Message,
args: Args,
help_options: &'static HelpOptions,
groups: &[&'static CommandGroup],
owners: HashSet<UserId>
) -> CommandResult {
let _ = help_commands::with_embeds(ctx, msg, args, help_options, groups, owners).await;
Ok(())
}
2021-11-12 12:05:26 +00:00
#[check]
#[name = "ModOrHigher"]
async fn mod_or_higher_check(ctx: &Context, msg: &Message, _: &mut Args, _: &CommandOptions) -> Result<(), Reason> {
let data = ctx.data.read().await;
let config = match data.get::<ManifoldConfig>() {
Some(c) => c.lock().await,
None => return Err(Reason::Log("Couldn't lock config".to_string()))
};
let role_guild_config = match config.get_value(&"RoleGuild".to_string()) {
Some(rgc) => rgc,
None => {
error!("Guild not configured");
return Err(Reason::Unknown);
}
};
let role_guild_number = match role_guild_config.parse::<u64>() {
Ok(rgn) => rgn,
Err(e) => {
error!("Parse GuildId fail");
return Err(Reason::Log(e.to_string()));
}
};
let guild_id = GuildId(role_guild_number);
let administrator_role = config.get_role(&"Admin".to_string());
if !msg.author.has_role(&ctx, guild_id, administrator_role).await.unwrap_or(false) {
return Err(Reason::User("User not administrative".to_string()));
}
Ok(())
}
#[hook]
async fn before(_: &Context, msg: &Message, command_name: &str) -> bool {
info!("Received command '{}' from user '{}'", command_name, msg.author.name);
true
}