From 867de07d6826dc80ff83a643d7cb67f1f6b044e3 Mon Sep 17 00:00:00 2001 From: Maximilian Waidelich Date: Fri, 29 Dec 2023 14:56:56 +0100 Subject: [PATCH] added env module --- src/bot/checks.rs | 25 ++++------------------ src/bot/mod.rs | 32 ++++++++++++----------------- src/env.rs | 39 +++++++++++++++++++++++++++++++++++ src/logging.rs | 28 ++++++------------------- src/main.rs | 2 ++ src/mysql_lib/mod.rs | 49 +++++++------------------------------------- src/redis_lib/mod.rs | 33 ++++++++++------------------- 7 files changed, 82 insertions(+), 126 deletions(-) create mode 100644 src/env.rs diff --git a/src/bot/checks.rs b/src/bot/checks.rs index bb57d11..730f3fd 100644 --- a/src/bot/checks.rs +++ b/src/bot/checks.rs @@ -1,25 +1,8 @@ -use once_cell::sync::Lazy; use poise::serenity_prelude::{ChannelId, Permissions, RoleId}; use sqlx::{MySql, Pool}; -use std::env; -use tracing::error; use crate::bot::Context; -use crate::mysql_lib; - -static MAIN_GUILD_ID: Lazy> = Lazy::new(|| match env::var("MAIN_GUILD_ID") { - Ok(val) => match val.parse() { - Ok(val) => Some(val), - Err(err) => { - error!(error = err.to_string(), "Failed to parse int"); - None - } - }, - Err(_) => { - error!("No Main Guild ID given"); - None - } -}); +use crate::{env, mysql_lib}; /// Checks if the author has any of the specified roles /// @@ -89,13 +72,13 @@ pub async fn is_owner(ctx: Context<'_>) -> bool { /// /// Will return false when: /// - guild is not main guild -/// - guild id env variable is not set -/// - guild id env variable can't be parsed to u64 /// - message was not sent in guild #[allow(dead_code)] pub async fn sent_in_main_guild(ctx: Context<'_>) -> bool { if let Some(guild) = ctx.guild() { - return MAIN_GUILD_ID.map_or(false, |main_guild_id| guild.id.0 == main_guild_id); + return env::MAIN_GUILD_ID + .get() + .map_or(false, |&main_guild_id| guild.id.0 == main_guild_id); } false } diff --git a/src/bot/mod.rs b/src/bot/mod.rs index 0734be3..c353ba5 100644 --- a/src/bot/mod.rs +++ b/src/bot/mod.rs @@ -1,16 +1,14 @@ - -use std::env; use std::time::Duration; use poise::serenity_prelude as serenity; use redis::Client; use sqlx::{MySql, Pool}; -use tracing::{error, info}; +use tracing::info; -use crate::logging; +use crate::{env, logging}; -mod commands; mod checks; +mod commands; /// User data, which is stored and accessible in all command invocations #[derive(Debug)] @@ -30,19 +28,9 @@ pub async fn entrypoint(database_pool: Pool, redis_client: Client) { info!("Starting the bot"); let db_clone = database_pool.clone(); - - let bot_token = match env::var("BOT_TOKEN") { - Ok(val) => val, - Err(_) => { - error!("No Bot Token given"); - return; - } - }; let framework = poise::Framework::builder() .options(poise::FrameworkOptions { - commands: vec![ - commands::ping(), - ], + commands: vec![commands::ping()], allowed_mentions: Some({ let mut f = serenity::CreateAllowedMentions::default(); f.empty_parse() @@ -70,14 +58,17 @@ pub async fn entrypoint(database_pool: Pool, redis_client: Client) { }, ..Default::default() }) - .token(bot_token) + .token(env::BOT_TOKEN.get().unwrap()) .intents( serenity::GatewayIntents::non_privileged() | serenity::GatewayIntents::MESSAGE_CONTENT, ) .setup(|_ctx, ready, _framework| { Box::pin(async move { info!("Logged in as {}", ready.user.name); - Ok(Data { database_pool, redis_client }) + Ok(Data { + database_pool, + redis_client, + }) }) }); @@ -85,5 +76,8 @@ pub async fn entrypoint(database_pool: Pool, redis_client: Client) { logging::setup_discord_logging(built_framework.clone(), db_clone).await; - built_framework.start().await.expect("Err running poise client"); + built_framework + .start() + .await + .expect("Err running poise client"); } diff --git a/src/env.rs b/src/env.rs new file mode 100644 index 0000000..8d7cfd7 --- /dev/null +++ b/src/env.rs @@ -0,0 +1,39 @@ +use std::env; +use std::sync::OnceLock; + +pub static MAIN_GUILD_ID: OnceLock = OnceLock::new(); +pub static REDIS_PORT: OnceLock = OnceLock::new(); +pub static REDIS_HOST: OnceLock = OnceLock::new(); +pub static MYSQL_PORT: OnceLock = OnceLock::new(); +pub static MYSQL_HOST: OnceLock = OnceLock::new(); +pub static MYSQL_DATABASE: OnceLock = OnceLock::new(); +pub static MYSQL_USER: OnceLock = OnceLock::new(); +pub static MYSQL_PASSWORD: OnceLock = OnceLock::new(); +pub static BOT_TOKEN: OnceLock = OnceLock::new(); + +pub fn init() { + MAIN_GUILD_ID.get_or_init(|| { + env::var("MAIN_GUILD_ID") + .expect("No Main Guild ID given") + .parse() + .expect("Failed to parse Main Guild ID to u64") + }); + REDIS_PORT.get_or_init(|| { + env::var("REDIS_PORT") + .unwrap_or("6379".to_owned()) + .parse() + .expect("Failed to parse Redis Port to u16") + }); + REDIS_HOST.get_or_init(|| env::var("REDIS_HOST").unwrap_or("127.0.0.1".to_owned())); + MYSQL_PORT.get_or_init(|| { + env::var("MYSQL_PORT") + .unwrap_or("3306".to_owned()) + .parse() + .expect("Failed to parse MySQL Port to u16") + }); + MYSQL_HOST.get_or_init(|| env::var("MYSQL_HOST").unwrap_or("127.0.0.1".to_owned())); + MYSQL_DATABASE.get_or_init(|| env::var("MYSQL_DATABASE").expect("No database given")); + MYSQL_USER.get_or_init(|| env::var("MYSQL_USER").expect("No database username given")); + MYSQL_PASSWORD.get_or_init(|| env::var("MYSQL_PASSWORD").expect("No password for user given")); + BOT_TOKEN.get_or_init(|| env::var("BOT_TOKEN").expect("No Bot Token given")); +} diff --git a/src/logging.rs b/src/logging.rs index b7b30cb..e5f571e 100644 --- a/src/logging.rs +++ b/src/logging.rs @@ -1,29 +1,19 @@ use std::collections::HashMap; -use std::env; use std::fs; use std::num::NonZeroU64; -use std::sync::Arc; -use std::sync::OnceLock; +use std::sync::{Arc, OnceLock}; use poise::serenity_prelude::futures::executor::block_on; use poise::serenity_prelude::{ChannelId, GuildId}; use rolling_file::RollingConditionBasic; -use sqlx::MySql; -use sqlx::Pool; -use tracing::error; -use tracing::info; -use tracing::Level; -use tracing::Subscriber; +use sqlx::{MySql, Pool}; +use tracing::{error, info, Level, Subscriber}; use tracing_appender::non_blocking::WorkerGuard; -use tracing_subscriber::filter; -use tracing_subscriber::fmt; use tracing_subscriber::prelude::*; -use tracing_subscriber::reload; use tracing_subscriber::reload::Handle; -use tracing_subscriber::Registry; +use tracing_subscriber::{filter, fmt, reload, Registry}; -use crate::bot; -use crate::mysql_lib; +use crate::{bot, env, mysql_lib}; const LOG_FILE_MAX_SIZE_MB: u64 = 10; const MAX_AMOUNT_LOG_FILES: usize = 10; @@ -75,14 +65,8 @@ pub async fn setup_discord_logging(framework: Arc, db: Pool Option> { - let sql_port = env::var("MYSQL_PORT").unwrap_or("3306".to_owned()); - let sql_port = match sql_port.parse() { - Ok(val) => val, - Err(_) => { - error!("Could not parse MYSQL_PORT"); - return None; - } - }; - - let sql_hostname = env::var("MYSQL_HOST").unwrap_or("127.0.0.1".to_owned()); - - let sql_database = match env::var("MYSQL_DATABASE") { - Ok(val) => val, - Err(_) => { - error!("No database given"); - return None; - } - }; - - let sql_username = match env::var("MYSQL_USER") { - Ok(val) => val, - Err(_) => { - error!("No database username given"); - return None; - } - }; - - let sql_password = match env::var("MYSQL_PASSWORD") { - Ok(val) => val, - Err(_) => { - error!("No password for user given"); - return None; - } - }; - match MySqlPoolOptions::new() .max_connections(max_concurrent_connections) .connect_with( MySqlConnectOptions::new() - .host(sql_hostname.as_str()) - .port(sql_port) - .database(sql_database.as_str()) - .username(sql_username.as_str()) - .password(sql_password.as_str()), + .host(env::MYSQL_HOST.get().unwrap().as_str()) + .port(*env::MYSQL_PORT.get().unwrap()) + .database(env::MYSQL_DATABASE.get().unwrap().as_str()) + .username(env::MYSQL_USER.get().unwrap().as_str()) + .password(env::MYSQL_PASSWORD.get().unwrap().as_str()), ) .await { diff --git a/src/redis_lib/mod.rs b/src/redis_lib/mod.rs index fa3356a..7342e81 100644 --- a/src/redis_lib/mod.rs +++ b/src/redis_lib/mod.rs @@ -1,32 +1,21 @@ -use std::env; - use redis::{aio::Connection, AsyncCommands, Client}; use sha1::Digest; use tracing::error; +use crate::env; + /// Tries to establish a connection with the given env variables and return the Redis client if /// successful. -/// -/// # Env Variables -/// -/// * REDIS_PORT: the port of redis, defaults to 6379 -/// * REDIS_HOST: the host of redis, ip or hostname or domain, defaults to 127.0.0.1 pub async fn get_connection() -> Option { - let redis_port: u16 = match env::var("REDIS_PORT").unwrap_or("6379".to_owned()).parse() { - Ok(val) => val, - Err(err) => { - error!(error = err.to_string(), "Failed to parse int"); - return None; - } - }; - - let redis_hostname = env::var("REDIS_HOST").unwrap_or("127.0.0.1".to_owned()); - - let client = Client::open(format!("redis://{redis_hostname}:{redis_port}")) - .map_err(|e| { - error!(error = e.to_string(), "Problem creating redis client"); - }) - .ok()?; + let client = Client::open(format!( + "redis://{}:{}", + env::REDIS_HOST.get().unwrap(), + env::REDIS_PORT.get().unwrap() + )) + .map_err(|e| { + error!(error = e.to_string(), "Problem creating redis client"); + }) + .ok()?; match client.get_async_connection().await { Err(err) => {