diff options
| author | Nathan Perry <np@nathanperry.dev> | 2020-06-20 16:17:05 -0400 |
|---|---|---|
| committer | Nathan Perry <np@nathanperry.dev> | 2020-06-20 16:17:05 -0400 |
| commit | 16e660f5cd3787e587a5d082f57ab9d900aee0ca (patch) | |
| tree | b6d67d820f2342f42f2dae00318f416d8a6142f9 /src | |
| parent | 7cd17b04f7422dcce1410ec26922cba161cd6e0d (diff) | |
move configuration into envconfig
Diffstat (limited to 'src')
| -rw-r--r-- | src/audio/play_queue.rs | 7 | ||||
| -rw-r--r-- | src/audio/timeutil.rs | 1 | ||||
| -rw-r--r-- | src/commands/meme/history.rs | 35 | ||||
| -rw-r--r-- | src/commands/playback.rs | 6 | ||||
| -rw-r--r-- | src/commands/sound_levels.rs | 6 | ||||
| -rw-r--r-- | src/config.rs | 80 | ||||
| -rw-r--r-- | src/game.rs | 25 | ||||
| -rw-r--r-- | src/main.rs | 32 | ||||
| -rw-r--r-- | src/util.rs | 19 |
9 files changed, 136 insertions, 75 deletions
diff --git a/src/audio/play_queue.rs b/src/audio/play_queue.rs index 6026587..e2d4468 100644 --- a/src/audio/play_queue.rs +++ b/src/audio/play_queue.rs @@ -30,9 +30,8 @@ use crate::{ commands::{ sound_levels::DEFAULT_VOLUME, }, - must_env_lookup, Result, - TARGET_GUILD_ID, + CONFIG, }; const SECONDS_LEAD_TIME: f32 = 0.75; @@ -115,7 +114,7 @@ impl PlayQueue { queue.playing = None; let mut manager = voice_manager.lock(); - manager.leave(*TARGET_GUILD_ID); + manager.leave(CONFIG.discord.guild()); debug!("disconnected because playback finished"); } @@ -228,7 +227,7 @@ impl PlayQueue { }; let mut manager = voice_manager.lock(); - let handler = manager.join(*TARGET_GUILD_ID, must_env_lookup::<u64>("VOICE_CHANNEL")); + let handler = manager.join(CONFIG.discord.guild(), CONFIG.discord.voice_channel()); match handler { Some(handler) => { diff --git a/src/audio/timeutil.rs b/src/audio/timeutil.rs index c9b38dd..238897f 100644 --- a/src/audio/timeutil.rs +++ b/src/audio/timeutil.rs @@ -50,6 +50,7 @@ pub fn parse_times<A: AsRef<str>>(s: A) -> (Option<Duration>, Option<Duration>) #[cfg(test)] mod test { use time::Duration; + use itertools::iproduct; use super::*; diff --git a/src/commands/meme/history.rs b/src/commands/meme/history.rs index 7579524..8186f57 100644 --- a/src/commands/meme/history.rs +++ b/src/commands/meme/history.rs @@ -31,7 +31,7 @@ use crate::{ Meme, Metadata, }, - must_env_lookup, + CONFIG, Result, util::CtxExt, }; @@ -71,7 +71,7 @@ pub fn wat(ctx: &mut Context, msg: &Message, _: Args) -> Result<()> { match meme { Ok(ref meme) => { let metadata = Metadata::find(&conn, meme.metadata_id)?; - let author = crate::TARGET_GUILD_ID.member(&ctx, metadata.created_by as u64)?; + let author = CONFIG.discord.guild().member(&ctx, metadata.created_by as u64)?; ctx.send(msg.channel_id, &format!("that was \"{}\" by {} ({})", @@ -95,21 +95,16 @@ pub fn wat(ctx: &mut Context, msg: &Message, _: Args) -> Result<()> { pub fn history(ctx: &mut Context, msg: &Message, mut args: Args) -> Result<()> { use itertools::Itertools; - lazy_static! { - static ref MAX_HIST: usize = must_env_lookup("MAX_HIST"); - static ref DEFAULT_HIST: usize = must_env_lookup("DEFAULT_HIST"); - } - let conn = connection()?; - let n = args.single_quoted::<usize>().unwrap_or(*DEFAULT_HIST); + let n = args.single_quoted::<usize>().unwrap_or(CONFIG.default_hist); - if n > *MAX_HIST { - debug!("user requested more than MAX_HIST ({}) items from history", *MAX_HIST); + if n > CONFIG.max_hist { + debug!("user requested more than MAX_HIST ({}) items from history", CONFIG.max_hist); ctx.send(msg.channel_id, "YER PUSHIN ME OVER THE FUCKIN LINE", true)?; } - let n = n.min(*MAX_HIST); + let n = n.min(CONFIG.max_hist); let records = InvocationRecord::last_n(&conn, n)?; @@ -133,8 +128,8 @@ pub fn history(ctx: &mut Context, msg: &Message, mut args: Args) -> Result<()> { Metadata::find(&conn, meme.metadata_id).map(|metadata| (metadata, meme)) }) .map(|(metadata, meme)| { - let author_name = crate::TARGET_GUILD_ID.member(&ctx, metadata.created_by as u64).map(|m| m.display_name().into_owned()).unwrap_or("???".to_owned()); - let invoker_name = crate::TARGET_GUILD_ID.member(&ctx, rec.user_id as u64).map(|m| m.display_name().into_owned()).unwrap_or("???".to_owned()); + let author_name = CONFIG.discord.guild().member(&ctx, metadata.created_by as u64).map(|m| m.display_name().into_owned()).unwrap_or("???".to_owned()); + let invoker_name = CONFIG.discord.guild().member(&ctx, rec.user_id as u64).map(|m| m.display_name().into_owned()).unwrap_or("???".to_owned()); format!("{}. [{}{}] \"{}\" by {} ({}). invoked by {}.", i + 1, rand, ago, meme.title, author_name, metadata.created.date().format(CLEAN_DATE_FORMAT), invoker_name) }) .unwrap_or_else(|e| { @@ -144,7 +139,7 @@ pub fn history(ctx: &mut Context, msg: &Message, mut args: Args) -> Result<()> { } } - let invoker_name = crate::TARGET_GUILD_ID.member(&ctx, rec.user_id as u64).map(|m| m.display_name().into_owned()).unwrap_or("???".to_owned()); + let invoker_name = CONFIG.discord.guild().member(&ctx, rec.user_id as u64).map(|m| m.display_name().into_owned()).unwrap_or("???".to_owned()); format!("{}. [{}{}] not found. invoked by {}.", i + 1, rand, ago, invoker_name) }) }) @@ -161,7 +156,6 @@ pub fn stats(ctx: &mut Context, msg: &Message, _: Args) -> Result<()> { id::UserId, user::User, }; - use crate::TARGET_GUILD_ID; let conn = connection()?; let stats = db::stats(&conn)?; @@ -171,8 +165,8 @@ pub fn stats(ctx: &mut Context, msg: &Message, _: Args) -> Result<()> { let rand_user: User = UserId(stats.most_random_meme_user).to_user(&ctx)?; let direct_user: User = UserId(stats.most_directly_named_meme_user).to_user(&ctx)?; - let rand_user = rand_user.nick_in(&ctx, *TARGET_GUILD_ID).unwrap_or(rand_user.name); - let direct_user = direct_user.nick_in(&ctx, *TARGET_GUILD_ID).unwrap_or(direct_user.name); + let rand_user = rand_user.nick_in(&ctx, CONFIG.discord.guild()).unwrap_or(rand_user.name); + let direct_user = direct_user.nick_in(&ctx, CONFIG.discord.guild()).unwrap_or(direct_user.name); let s = format!( r#" @@ -224,13 +218,12 @@ pub fn memers(ctx: &mut Context, msg: &Message, _args: Args) -> Result<()> { use serenity::model::{ id::UserId, }; - use crate::TARGET_GUILD_ID; let s = db::memers()? .into_iter() .map(|info| { let user = UserId(info.user_id).to_user(&ctx)?; - let username = user.nick_in(&ctx, *TARGET_GUILD_ID).unwrap_or(user.name); + let username = user.nick_in(&ctx, CONFIG.discord.guild()).unwrap_or(user.name); let res = format!( "**{}**: {} total, {} random, {} specific. favorite meme: *{}* ({})", @@ -262,7 +255,7 @@ pub fn query(ctx: &mut Context, msg: &Message, mut args: Args) -> Result<()> { use crate::{ game::get_user_id, db, - TARGET_GUILD_ID, + CONFIG, }; lazy_static! { @@ -310,7 +303,7 @@ pub fn query(ctx: &mut Context, msg: &Message, mut args: Args) -> Result<()> { .into_iter() .map(|(meme, metadata)| { let user = UserId(metadata.created_by as u64).to_user(&ctx)?; - let username = user.nick_in(&ctx, *TARGET_GUILD_ID).unwrap_or(user.name); + let username = user.nick_in(&ctx, CONFIG.discord.guild()).unwrap_or(user.name); Ok(format!("*{}* by **{}** ({}). text length: **{}**, image: **{}**, audio: **{}**", meme.title, diff --git a/src/commands/playback.rs b/src/commands/playback.rs index c11eac8..f80ec17 100644 --- a/src/commands/playback.rs +++ b/src/commands/playback.rs @@ -22,7 +22,7 @@ use crate::{ VoiceManager, }, Result, - TARGET_GUILD_ID, + CONFIG, util::CtxExt, commands::sound_levels::*, }; @@ -196,7 +196,7 @@ pub fn skip(ctx: &mut Context, _msg: &Message, _args: Args) -> Result<()> { let queue_lock = data.get::<PlayQueue>().cloned().unwrap(); - if let Some(handler) = manager.get_mut(*TARGET_GUILD_ID) { + if let Some(handler) = manager.get_mut(CONFIG.discord.guild()) { handler.stop(); let mut play_queue = queue_lock.write().unwrap(); play_queue.playing = None; @@ -226,7 +226,7 @@ pub fn die(ctx: &mut Context, msg: &Message, _: Args) -> Result<()> { play_queue.meme_queue.clear(); } - if let Some(handler) = manager.get_mut(*TARGET_GUILD_ID) { + if let Some(handler) = manager.get_mut(CONFIG.discord.guild()) { info!("killing playback"); handler.stop(); handler.leave(); diff --git a/src/commands/sound_levels.rs b/src/commands/sound_levels.rs index 648e54b..ab98806 100644 --- a/src/commands/sound_levels.rs +++ b/src/commands/sound_levels.rs @@ -15,8 +15,8 @@ use serenity::{ use crate::{ Result, + CONFIG, audio::{PlayQueue, VoiceManager}, - TARGET_GUILD_ID, util::CtxExt, }; @@ -27,7 +27,7 @@ pub fn mute(ctx: &mut Context, _: &Message, _: Args) -> Result<()> { let mgr_lock = ctx.data.write().get::<VoiceManager>().cloned().unwrap(); let mut manager = mgr_lock.lock(); - manager.get_mut(*TARGET_GUILD_ID) + manager.get_mut(CONFIG.discord.guild()) .map(|handler| { if handler.self_mute { trace!("Already muted.") @@ -45,7 +45,7 @@ pub fn unmute(ctx: &mut Context, msg: &Message, _: Args) -> Result<()> { let mgr_lock = ctx.data.write().get::<VoiceManager>().cloned().unwrap(); let mut manager = mgr_lock.lock(); - manager.get_mut(*TARGET_GUILD_ID) + manager.get_mut(CONFIG.discord.guild()) .map(|handler| { if !handler.self_mute { trace!("Already unmuted.") diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..13d015e --- /dev/null +++ b/src/config.rs @@ -0,0 +1,80 @@ +use serenity::{ + model::id::{ + GuildId, + UserId, + ChannelId, + }, +}; + +use envconfig::Envconfig; + +#[derive(Envconfig)] +pub struct Config { + #[envconfig(from = "DATABASE_URL")] + pub db_string: String, + + #[envconfig(from = "MAX_HIST")] + pub max_hist: usize, + + #[envconfig(from = "DEFAULT_HIST")] + pub default_hist: usize, + + #[envconfig(from = "STEAM_API_KEY")] + pub steam_api_key: String, + + pub discord: DiscordConfig, + + pub sheets: SheetsConfig, +} + +#[derive(Envconfig)] +pub struct DiscordConfig { + pub auth: DiscordAuth, + + #[envconfig(from = "TARGET_GUILD")] + guild: u64, + + #[envconfig(from = "OWNER_ID")] + owner: u64, + + #[envconfig(from = "VOICE_CHANNEL")] + voice_channel: u64, +} + +impl DiscordConfig { + #[inline] + pub fn guild(&self) -> GuildId { + self.guild.into() + } + + #[inline] + pub fn owner(&self) -> UserId { + self.owner.into() + } + + #[inline] + pub fn voice_channel(&self) -> ChannelId { + self.voice_channel.into() + } +} + +#[derive(Envconfig)] +pub struct DiscordAuth { + #[envconfig(from = "THULANI_CLIENT_ID")] + pub client_id: u64, + + #[envconfig(from = "THULANI_TOKEN")] + pub token: String, +} + +#[derive(Envconfig)] +pub struct SheetsConfig { + #[envconfig(from = "SHEETS_API_KEY")] + pub api_key: String, + + #[envconfig(from = "SPREADSHEET_ID")] + pub spreadsheet: String, + + #[envconfig(from = "MAX_SHEET_COLUMN")] + pub max_column: String, +}
\ No newline at end of file diff --git a/src/game.rs b/src/game.rs index 02f3f45..626c7ff 100644 --- a/src/game.rs +++ b/src/game.rs @@ -43,10 +43,9 @@ use anyhow::{ use lazy_static::lazy_static; use crate::{ - must_env_lookup, Result, util::CtxExt, - VOICE_CHANNEL_ID, + CONFIG, }; pub use self::GAME_GROUP as GROUP; @@ -65,15 +64,10 @@ group!({ }); lazy_static! { - static ref SHEETS_API_KEY: String = must_env_lookup("SHEETS_API_KEY"); - static ref STEAM_API_KEY: String = must_env_lookup("STEAM_API_KEY"); - static ref SPREADSHEET_ID: String = must_env_lookup("SPREADSHEET_ID"); - static ref MAX_SHEET_COLUMN: String = must_env_lookup("MAX_SHEET_COLUMN"); - static ref SPREADSHEET_URL: Url = Url::parse(&format!( "https://sheets.googleapis.com/v4/spreadsheets/{}/values:batchGet", - *SPREADSHEET_ID, - )).expect("prasing spreadsheet url"); + &CONFIG.sheets.spreadsheet, + )).expect("parsing spreadsheet url"); } #[derive(Deserialize, Debug, Clone, PartialEq, Eq, Hash)] @@ -285,12 +279,15 @@ fn _game(ctx: &mut Context, msg: &Message, mut args: Args, min_status: GameStatu }) .collect::<FnvHashMap<_, _>>(); - let channel = pairs.get(&msg.author.id).unwrap_or(&*VOICE_CHANNEL_ID); + let channel = pairs + .get(&msg.author.id) + .cloned() + .unwrap_or(CONFIG.discord.voice_channel()); users = pairs .iter() .filter_map(|(uid, cid)| { - if cid == channel { + if *cid == channel { DISCORD_MAP.get(uid).map(|s| s.to_lowercase()) } else { None } }) @@ -384,10 +381,10 @@ fn load_spreadsheet() -> Result<Vec<Vec<String>>> { let mut u = SPREADSHEET_URL.clone(); u.query_pairs_mut() - .append_pair("ranges", &format!("a1:{}", &*MAX_SHEET_COLUMN)) + .append_pair("ranges", &format!("a1:{}", &CONFIG.sheets.max_column)) .append_pair("valueRenderOption", "FORMATTED_VALUE") .append_pair("majorDimension", "COLUMNS") - .append_pair("key", &*SHEETS_API_KEY); + .append_pair("key", &CONFIG.sheets.api_key); let req = reqwest::Request::new(reqwest::Method::GET, u); let client = reqwest::Client::new(); @@ -482,7 +479,7 @@ pub fn updategaem(ctx: &mut Context, msg: &Message, mut args: Args) -> Result<() let mut u = Url::parse("https://api.steampowered.com/IPlayerService/GetOwnedGames/v1")?; u.query_pairs_mut() - .append_pair("key", &*STEAM_API_KEY) + .append_pair("key", &CONFIG.steam_api_key) .append_pair("include_played_free_games", "1") .append_pair("steamid", &steam_id.to_string()); diff --git a/src/main.rs b/src/main.rs index f3c7bac..55205ba 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,8 +7,8 @@ // trash dependencies that can't be fucked to upgrade to ed. 2018 #[macro_use] extern crate diesel; -#[macro_use] extern crate dotenv_codegen; #[macro_use] extern crate pest_derive; +#[macro_use] extern crate envconfig_derive; use std::{ default::Default, @@ -33,17 +33,19 @@ use serenity::{ framework::StandardFramework, model::{ gateway::Ready, - id::{ChannelId, GuildId, MessageId, UserId}, + id::{ChannelId, MessageId}, }, prelude::*, }; -use anyhow::anyhow; -use dotenv::{dotenv, var as dvar}; +use dotenv::dotenv; use lazy_static::lazy_static; +use envconfig::Envconfig; use self::commands::register_commands; + pub use self::util::*; +pub use self::config::*; #[cfg(feature = "diesel")] mod db; @@ -64,22 +66,25 @@ mod game { mod commands; mod util; mod audio; +mod config; pub type Error = anyhow::Error; pub type Result<T> = anyhow::Result<T>; lazy_static! { - static ref TARGET_GUILD: u64 = dotenv!("TARGET_GUILD").parse().expect("unable to parse TARGET_GUILD as u64"); - static ref TARGET_GUILD_ID: GuildId = GuildId(*TARGET_GUILD); - static ref VOICE_CHANNEL_ID: ChannelId = ChannelId(must_env_lookup::<u64>("VOICE_CHANNEL")); + pub static ref CONFIG: Config = { + dotenv().ok(); + + Config::init().unwrap() + }; } struct Handler; impl EventHandler for Handler { fn ready(&self, ctx: Context, r: Ready) { let guild = r.guilds.iter() - .find(|g| g.id().0 == *TARGET_GUILD); + .find(|g| g.id() == CONFIG.discord.guild()); if guild.is_none() { info!("bot isn't in configured guild. join here: {:?}", OAUTH_URL.as_str()); @@ -114,7 +119,7 @@ lazy_static! { fn run() -> Result<()> { - let token = &dvar("THULANI_TOKEN").map_err(|_| anyhow!("missing token"))?; + let token = &CONFIG.discord.auth.token; let mut client = Client::new(token, Handler)?; audio::VoiceManager::register(&mut client); @@ -140,7 +145,6 @@ fn run() -> Result<()> { .into_iter() .collect::<FnvHashSet<_>>(); - let owner_id = must_env_lookup::<u64>("OWNER_ID"); let mut framework = StandardFramework::new() .configure(|c| c .allow_dm(false) @@ -148,17 +152,17 @@ fn run() -> Result<()> { .prefixes(all_prefixes) .ignore_bots(true) .on_mention(None) - .owners(vec![UserId(owner_id)].into_iter().collect()) + .owners(vec![CONFIG.discord.owner()].into_iter().collect()) .case_insensitivity(true) ) .before(move |ctx, message, cmd| { debug!("got command '{}' from user '{}' ({})", cmd, message.author.name, message.author.id); - if !message.guild_id.map_or(false, |x| x.0 == *TARGET_GUILD) { + if !message.guild_id.map_or(false, |x| x == CONFIG.discord.guild()) { info!("rejecting command '{}' from user '{}': wrong guild", cmd, message.author.name); return false; } - if message.author.id.0 == owner_id { + if message.author.id == CONFIG.discord.owner() { return true; } @@ -239,8 +243,6 @@ fn main() { info!("starting"); - dotenv().ok(); - use fern::colors::{Color, ColoredLevelConfig}; let colors = ColoredLevelConfig::new() .info(Color::Green) diff --git a/src/util.rs b/src/util.rs index eb38d9c..ca50157 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,9 +1,3 @@ -use std::{
- env,
- str::FromStr,
-};
-
-use dotenv;
use serenity::{
client::Context,
model::{
@@ -19,6 +13,7 @@ use url::Url; use lazy_static::lazy_static;
use crate::{
+ CONFIG,
audio::PlayQueue,
Result,
};
@@ -38,13 +33,12 @@ impl CtxExt for Context { }
fn users_listening(&self) -> Result<bool> {
- let channel_id = ChannelId(must_env_lookup::<u64>("VOICE_CHANNEL"));
- let channel = channel_id.to_channel(self)?;
+ let channel = CONFIG.discord.voice_channel().to_channel(self)?;
let res = channel.guild()
.and_then(|ch| ch.read().guild(self))
.map(|g| (&g.read().voice_states)
.into_iter()
- .any(|(_, state)| state.channel_id == Some(channel_id)))
+ .any(|(_, state)| state.channel_id == Some(CONFIG.discord.voice_channel())))
.unwrap_or(false);
Ok(res)
@@ -81,12 +75,7 @@ lazy_static! { pub static ref OAUTH_URL: Url = Url::parse(
&format!(
"https://discordapp.com/api/oauth2/authorize?scope=bot&permissions={}&client_id={}",
- REQUIRED_PERMS.bits(), dotenv!("THULANI_CLIENT_ID"),
+ REQUIRED_PERMS.bits(), CONFIG.discord.auth.client_id,
)
).unwrap();
}
-
-pub fn must_env_lookup<T: FromStr>(s: &str) -> T {
- env::var(s).expect(&format!("missing env var {}", s))
- .parse::<T>().unwrap_or_else(|_| panic!(format!("bad format for {}", s)))
-}
|
