diff options
Diffstat (limited to 'src/storage')
| -rw-r--r-- | src/storage/mod.rs | 126 | ||||
| -rw-r--r-- | src/storage/reactboard.rs | 14 |
2 files changed, 100 insertions, 40 deletions
diff --git a/src/storage/mod.rs b/src/storage/mod.rs index 64a3856..2ab54f6 100644 --- a/src/storage/mod.rs +++ b/src/storage/mod.rs @@ -1,15 +1,18 @@ -use std::fmt::{Debug, Display}; +use std::fmt::Debug; use color_eyre::eyre::Result; use log::*; -use poise::serenity_prelude::GuildId; +use poise::serenity_prelude::{GuildId, MessageId}; use redis::{AsyncCommands, Client, FromRedisValue, ToRedisArgs}; -pub mod reactboard; -pub mod settings; +mod reactboard; +mod settings; +// these are purposefully private. see the comment below +use reactboard::REACTBOARD_KEY; +use settings::SETTINGS_KEY; -pub use reactboard::*; -pub use settings::*; +pub use reactboard::ReactBoardEntry; +pub use settings::{Settings, SettingsProperties}; #[derive(Clone, Debug)] pub struct Storage { @@ -23,6 +26,12 @@ impl Storage { Ok(Self { client }) } + /* + these are mainly light abstractions to avoid the `let mut con` + boilerplate, as well as not require the caller to format the + strings for keys + */ + pub async fn get_key<T>(&self, key: &str) -> Result<T> where T: FromRedisValue, @@ -66,6 +75,15 @@ impl Storage { Ok(()) } + pub async fn expire_key(&self, key: &str, expire_seconds: usize) -> Result<()> { + debug!("Expiring key {key} in {expire_seconds}"); + + let mut con = self.client.get_async_connection().await?; + con.expire(key, expire_seconds).await?; + + Ok(()) + } + pub async fn add_to_index<'a>( &self, key: &str, @@ -80,19 +98,60 @@ impl Storage { Ok(()) } - pub fn format_settings_key(subkey: impl Display) -> String { - format!("{}:{subkey}", SETTINGS_KEY) + pub async fn get_from_index<T>(&self, key: &str) -> Result<Vec<T>> + where + T: FromRedisValue, + { + let index = format!("{key}:index"); + debug!("Fetching index {index}"); + + let mut con = self.client.get_async_connection().await?; + let mems = con.smembers(key).await?; + + Ok(mems) } - pub async fn create_settings_key(&self, settings: Settings) -> Result<()> { - let key = Self::format_settings_key(settings.guild_id); + // guild settings + + pub async fn create_guild_settings(&self, settings: Settings) -> Result<()> { + let key = format!("{SETTINGS_KEY}:{}", settings.guild_id); self.set_key(&key, &settings).await?; + // adding to index since we need to look all of these up sometimes self.add_to_index(SETTINGS_KEY, settings).await?; Ok(()) } + pub async fn get_guild_settings(&self, guild_id: &GuildId) -> Result<Settings> { + debug!("Fetching guild settings for {guild_id}"); + + let key = format!("{SETTINGS_KEY}:{guild_id}"); + let settings: Settings = self.get_key(&key).await?; + + Ok(settings) + } + + pub async fn delete_guild_settings(&self, guild_id: &GuildId) -> Result<()> { + let key = format!("{SETTINGS_KEY}:{guild_id}"); + self.delete_key(&key).await?; + + Ok(()) + } + + pub async fn guild_settings_exist(&self, guild_id: &GuildId) -> Result<bool> { + let key = format!("{SETTINGS_KEY}:{guild_id}"); + self.key_exists(&key).await + } + + pub async fn get_all_guild_settings(&self) -> Result<Vec<Settings>> { + debug!("Fetching all guild settings"); + + let guilds: Vec<Settings> = self.get_from_index(SETTINGS_KEY).await?; + + Ok(guilds) + } + /// get guilds that have enabled optional commands pub async fn get_opted_guilds(&self) -> Result<Vec<GuildId>> { debug!("Fetching opted-in guilds"); @@ -112,35 +171,40 @@ impl Storage { Ok(opted) } - pub async fn get_all_guild_settings(&self) -> Result<Vec<Settings>> { - debug!("Fetching all guild settings"); + // reactboard - let mut con = self.client.get_async_connection().await?; - let key = Self::format_settings_key("index"); + pub async fn create_reactboard_entry( + &self, + guild_id: &GuildId, + entry: ReactBoardEntry, + ) -> Result<()> { + let key = format!("{REACTBOARD_KEY}:{guild_id}:{}", entry.original_message_id); - let guilds: Vec<Settings> = con.smembers(key).await?; + self.set_key(&key, &entry).await?; + self.expire_key(&key, 30 * 24 * 60 * 60).await?; // 30 days - Ok(guilds) + Ok(()) } - 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?; + pub async fn get_reactboard_entry( + &self, + guild_id: &GuildId, + message_id: &MessageId, + ) -> Result<ReactBoardEntry> { + debug!("Fetching reactboard entry in {guild_id}"); - Ok(settings) - } + let key = format!("{REACTBOARD_KEY}:{guild_id}:{message_id}"); + let entry: ReactBoardEntry = self.get_key(&key).await?; - pub async fn create_reactboard_info_key(&self, reactboard: ReactBoardInfo) -> Result<()> { - self.set_key(REACT_BOARD_KEY, reactboard).await?; - Ok(()) + Ok(entry) } - 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) + pub async fn reactboard_entry_exists( + &self, + guild_id: &GuildId, + message_id: &MessageId, + ) -> Result<bool> { + let key = format!("{REACTBOARD_KEY}:{guild_id}:{message_id}"); + self.key_exists(&key).await } } diff --git a/src/storage/reactboard.rs b/src/storage/reactboard.rs index e08aa54..19453df 100644 --- a/src/storage/reactboard.rs +++ b/src/storage/reactboard.rs @@ -2,17 +2,13 @@ use poise::serenity_prelude::{ChannelId, MessageId}; use redis_macros::{FromRedisValue, ToRedisArgs}; use serde::{Deserialize, Serialize}; -pub const REACT_BOARD_KEY: &str = "reactboard-v1"; +pub const REACTBOARD_KEY: &str = "reactboard-v2"; #[derive(Clone, Debug, Serialize, Deserialize, FromRedisValue, ToRedisArgs)] pub struct ReactBoardEntry { - pub original_id: MessageId, + pub original_message_id: MessageId, pub reaction_count: u64, - pub channel_id: ChannelId, - pub message_id: MessageId, -} - -#[derive(Clone, Debug, Default, Serialize, Deserialize, FromRedisValue, ToRedisArgs)] -pub struct ReactBoardInfo { - pub reactions: Vec<ReactBoardEntry>, + // we need these to update our message with new interactions + pub posted_channel_id: ChannelId, + pub posted_message_id: MessageId, } |
