aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/config.rs80
-rw-r--r--src/hooks/mod.rs2
-rw-r--r--src/hooks/wolfram_alpha.rs38
-rw-r--r--src/lib.rs35
-rw-r--r--src/main.rs4
5 files changed, 112 insertions, 47 deletions
diff --git a/src/config.rs b/src/config.rs
index 776d60c..1a88b95 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -1,6 +1,12 @@
-use serde::Deserialize;
+use serde::{Deserialize, Serialize};
-#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default, Deserialize)]
+use figment::{
+ providers::{Format, Toml},
+ value::{Dict, Map},
+ Error, Figment, Metadata, Profile, Provider,
+};
+
+#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize, Serialize)]
pub struct Config {
pub user: User,
pub server: Server,
@@ -13,7 +19,7 @@ impl From<Config> for irc::client::prelude::Config {
nickname: Some(input.user.nickname),
username: Some(input.user.username),
realname: Some(input.user.realname),
- nick_password: Some(input.user.password),
+ nick_password: input.user.password,
server: Some(input.server.hostname),
port: Some(input.server.port),
use_tls: Some(input.server.tls),
@@ -23,25 +29,83 @@ impl From<Config> for irc::client::prelude::Config {
}
}
-#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default, Deserialize)]
+#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize, Serialize)]
pub struct User {
pub nickname: String,
pub username: String,
- pub password: String,
+ #[serde(default)]
+ pub password: Option<String>,
pub realname: String,
}
-#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default, Deserialize)]
+#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize, Serialize)]
pub struct Server {
pub hostname: String,
+ #[serde(default = "default_port")]
pub port: u16,
+ #[serde(default = "default_tls")]
pub tls: bool,
+ #[serde(default)]
pub sasl: bool,
+ #[serde(default)]
pub channels: Vec<String>,
}
-#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default, Deserialize)]
+const fn default_port() -> u16 {
+ 6697
+}
+
+const fn default_tls() -> bool {
+ true
+}
+
+#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize, Serialize)]
pub struct Settings {
+ #[serde(default = "default_prefix")]
pub prefix: char,
- pub wa_api_key: String,
+ // pub wa_api_key: String,
+}
+
+const fn default_prefix() -> char {
+ ':'
+}
+
+impl Config {
+ // Allow the configuration to be extracted from any `Provider`.
+ pub fn from<T: Provider>(provider: T) -> Result<Config, Error> {
+ Figment::from(provider).extract()
+ }
+
+ // Provide a default provider, a `Figment`.
+ pub fn figment() -> Figment {
+ use figment::providers::Env;
+
+ let figment = Figment::new();
+
+ #[cfg(debug_assertions)]
+ const PROFILE: &str = "debug";
+ #[cfg(not(debug_assertions))]
+ const PROFILE: &str = "release";
+
+ figment
+ .merge(Toml::file("config.toml").nested())
+ .merge(Toml::file("config.debug.toml").nested())
+ .merge(Env::prefixed("CATINATOR_").split('_'))
+ .select(PROFILE)
+ }
+}
+
+// Make `Config` a provider itself for composability.
+impl Provider for Config {
+ fn metadata(&self) -> Metadata {
+ Metadata::named("Library Config")
+ }
+
+ fn data(&self) -> Result<Map<Profile, Dict>, Error> {
+ figment::providers::Serialized::defaults(self).data()
+ }
+
+ fn profile(&self) -> Option<Profile> {
+ Some(Profile::Default)
+ }
}
diff --git a/src/hooks/mod.rs b/src/hooks/mod.rs
index cdf3787..86d5697 100644
--- a/src/hooks/mod.rs
+++ b/src/hooks/mod.rs
@@ -36,7 +36,7 @@ pub fn sasl(bot: &crate::Bot, msg: Message) -> Result<()> {
if text == "+" {
let creds = Credentials::default()
.with_username(bot.config.clone().user.username)
- .with_password(bot.config.clone().user.password);
+ .with_password(bot.config.clone().user.password.unwrap());
let mut mechanism = Plain::from_credentials(creds)?;
diff --git a/src/hooks/wolfram_alpha.rs b/src/hooks/wolfram_alpha.rs
index 3faddbf..0fceb0b 100644
--- a/src/hooks/wolfram_alpha.rs
+++ b/src/hooks/wolfram_alpha.rs
@@ -3,12 +3,39 @@ use crate::util::{
web::{quote_plus, IsgdUrlShortener, UrlShortener},
};
use anyhow::{bail, Context, Error, Result};
+use figment::providers::Env;
use futures::join;
use irc::client::prelude::*;
use macros::privmsg;
use reqwest::{get, Url};
use serde::{Deserialize, Serialize};
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct WolframAlpha {
+ wa_api_key: String,
+}
+
+impl WolframAlpha {
+ pub fn new(bot: &crate::Bot) -> Result<WolframAlpha> {
+ bot.figment
+ .clone()
+ .merge(Env::prefixed("CATINATOR_"))
+ .extract()
+ .context("failed to extract wolfram alpha config")
+ }
+
+ pub async fn wa(&self, bot: &crate::Bot, msg: Message) -> Result<()> {
+ privmsg!(msg, {
+ let content = get_input_query(text)?;
+ bot.send_privmsg(
+ msg.response_target()
+ .context("failed to get response target")?,
+ &wa_query(&content, Some(&self.wa_api_key), None).await?,
+ )?;
+ })
+ }
+}
+
#[derive(Serialize, Deserialize, Debug)]
struct WaResponse {
queryresult: QueryResult,
@@ -147,17 +174,6 @@ fn get_input_query(text: &str) -> Result<String, Error> {
Ok(content.to_string())
}
-pub async fn wa(bot: &crate::Bot, msg: Message) -> Result<()> {
- privmsg!(msg, {
- let content = get_input_query(text)?;
- bot.send_privmsg(
- msg.response_target()
- .context("failed to get response target")?,
- &wa_query(&content, Some(&bot.config.settings.wa_api_key), None).await?,
- )?;
- })
-}
-
#[cfg(test)]
mod tests {
diff --git a/src/lib.rs b/src/lib.rs
index 82bdad5..37e9d89 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,12 +2,10 @@
#[cfg(all(test, feature = "bench"))]
extern crate test;
-use anyhow::Result;
+use anyhow::{Context, Result};
use irc::client::prelude::*;
-use tracing::info;
-
pub mod config;
pub mod hooks;
pub mod util;
@@ -23,44 +21,29 @@ macro_rules! reply {
pub struct Bot {
pub config: config::Config,
+ pub figment: figment::Figment,
pub irc_client: irc::client::Client,
}
-fn get_env_var(var_name: &str) -> Option<String> {
- match std::env::var(var_name) {
- Ok(var) => {
- info!("using {} from env", var_name);
- Some(var)
- }
- Err(_) => None,
- }
-}
-
impl Bot {
- pub async fn new(config_path: &str) -> Result<Bot> {
- use std::fs;
+ pub async fn new() -> Result<Bot> {
+ let figment = config::Config::figment();
+ let config: config::Config = figment.extract().context("failed to extract config")?;
+
+ let irc_client = Client::from_config(config.clone().into()).await?;
- let config_str = fs::read_to_string(config_path)?;
- let mut config: config::Config = toml::from_str(&config_str)?;
let bot = Bot { irc_client, config, figment };
- if let Some(v) = get_env_var("CATINATOR_PASSWORD") {
- config.user.password = v
- };
if bot.config.server.sasl && bot.config.user.password.is_some() {
tracing::info!("initializing sasl");
bot.sasl_init().await.unwrap()
}
- if let Some(v) = get_env_var("CATINATOR_WA_API_KEY") {
- config.settings.wa_api_key = v
- };
-
- let irc_client = Client::from_config(config.clone().into()).await?;
Ok(bot)
}
- Ok(Bot { irc_client, config })
+ pub fn figment(&self) -> &figment::Figment {
+ &self.figment
}
pub async fn sasl_init(&self) -> Result<()> {
diff --git a/src/main.rs b/src/main.rs
index 100af91..2428dff 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -12,6 +12,8 @@ async fn main() {
let mut bot = Bot::new().await.unwrap();
let mut sed = catinator::hooks::sed::Sed::new();
+ let wolfram_alpha = catinator::hooks::wolfram_alpha::WolframAlpha::new(&bot)
+ .expect("failed to initialize WolframAlpha command");
catinator![
hook(
@@ -57,7 +59,7 @@ async fn main() {
async command(
"wa",
"Returns Wolfram Alpha results for a query",
- catinator::hooks::wolfram_alpha::wa
+ wolfram_alpha.wa
),
];
}