aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio/play_queue.rs7
-rw-r--r--src/audio/timeutil.rs1
-rw-r--r--src/commands/meme/history.rs35
-rw-r--r--src/commands/playback.rs6
-rw-r--r--src/commands/sound_levels.rs6
-rw-r--r--src/config.rs80
-rw-r--r--src/game.rs25
-rw-r--r--src/main.rs32
-rw-r--r--src/util.rs19
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)))
-}