diff options
| author | seth <[email protected]> | 2023-12-05 05:17:49 -0500 |
|---|---|---|
| committer | seth <[email protected]> | 2023-12-15 16:41:13 -0500 |
| commit | 815cb0df3b3e3f9dd2078b00f85754da87b1d55e (patch) | |
| tree | 85099483f8ebb0586bc097b65f6c5a2b5997150e /src/storage/mod.rs | |
| parent | 0ca61ddff6ec7404f0aeabc1c8c785bbc8db7fd5 (diff) | |
refactor: centralize storage handlers
Diffstat (limited to 'src/storage/mod.rs')
| -rw-r--r-- | src/storage/mod.rs | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/src/storage/mod.rs b/src/storage/mod.rs new file mode 100644 index 0000000..e6f186a --- /dev/null +++ b/src/storage/mod.rs @@ -0,0 +1,146 @@ +use std::fmt::{Debug, Display}; + +use color_eyre::eyre::Result; +use log::*; +use poise::serenity_prelude::GuildId; +use redis::{AsyncCommands, Client, FromRedisValue, ToRedisArgs}; + +pub mod reactboard; +pub mod settings; + +pub use reactboard::*; +pub use settings::*; + +#[derive(Clone, Debug)] +pub struct Storage { + client: Client, +} + +impl Storage { + pub fn new(redis_url: &str) -> Result<Self> { + let client = Client::open(redis_url)?; + + Ok(Self { client }) + } + + pub async fn get_key<T>(&self, key: &str) -> Result<T> + where + T: FromRedisValue, + { + debug!("Getting key {key}"); + + let mut con = self.client.get_async_connection().await?; + let res: T = con.get(key).await?; + + Ok(res) + } + + pub async fn set_key<'a>( + &self, + key: &str, + value: impl ToRedisArgs + Debug + Send + Sync + 'a, + ) -> Result<()> { + debug!("Creating key {key}:\n{value:#?}"); + + let mut con = self.client.get_async_connection().await?; + con.set(key, value).await?; + + Ok(()) + } + + pub async fn key_exists(&self, key: &str) -> Result<bool> { + debug!("Checking if key {key} exists"); + + let mut con = self.client.get_async_connection().await?; + let exists: u64 = con.exists(key).await?; + + Ok(exists > 0) + } + + pub async fn delete_key(&self, key: &str) -> Result<()> { + debug!("Deleting key {key}"); + + let mut con = self.client.get_async_connection().await?; + con.del(key).await?; + + Ok(()) + } + + pub async fn add_to_index<'a>( + &self, + key: &str, + member: impl ToRedisArgs + Send + Sync + 'a, + ) -> Result<()> { + let index = format!("{key}:index"); + debug!("Appending index {index}"); + + let mut con = self.client.get_async_connection().await?; + con.sadd(index, member).await?; + + Ok(()) + } + + pub fn format_settings_key(subkey: impl Display) -> String { + format!("{}:{subkey}", SETTINGS_KEY) + } + + pub async fn create_settings_key(&self, settings: Settings) -> Result<()> { + let key = Self::format_settings_key(settings.guild_id); + + self.set_key(&key, &settings).await?; + self.add_to_index(SETTINGS_KEY, settings).await?; + + Ok(()) + } + + /// get guilds that have enabled optional commands + pub async fn get_opted_guilds(&self) -> Result<Vec<GuildId>> { + debug!("Fetching opted-in guilds"); + + let guilds = self.get_all_guild_settings().await?; + let opted: Vec<GuildId> = guilds + .iter() + .filter_map(|g| { + if g.optional_commands_enabled { + Some(g.guild_id) + } else { + None + } + }) + .collect(); + + Ok(opted) + } + + pub async fn get_all_guild_settings(&self) -> Result<Vec<Settings>> { + debug!("Fetching all guild settings"); + + let mut con = self.client.get_async_connection().await?; + let key = Self::format_settings_key("index"); + + let guilds: Vec<Settings> = con.smembers(key).await?; + + Ok(guilds) + } + + pub async fn get_guild_settings(&self, guild_id: &GuildId) -> Result<Settings> { + debug!("Fetching guild settings for {guild_id}"); + + let key = Self::format_settings_key(guild_id); + let settings: Settings = self.get_key(&key).await?; + + Ok(settings) + } + + pub async fn create_reactboard_info_key(&self, reactboard: ReactBoardInfo) -> Result<()> { + self.set_key(REACT_BOARD_KEY, reactboard).await?; + Ok(()) + } + + pub async fn get_reactboard_info(&self) -> Result<ReactBoardInfo> { + debug!("Fetching reactboard info"); + let reactboard: ReactBoardInfo = self.get_key(REACT_BOARD_KEY).await?; + + Ok(reactboard) + } +} |
