-- | A thing for storing the last N messages module Calamity.Internal.MessageStore ( MessageStore(..) , addMessage , getMessage , dropMessage ) where import Calamity.Internal.Utils import Calamity.Types.Model.Channel.Message import Calamity.Types.Snowflake import Control.Lens import Control.Lens.Operators ( (.=) ) import Control.Monad.State.Lazy import Data.Default.Class import Data.Generics.Labels () import Data.HashMap.Lazy ( HashMap ) import qualified Data.HashMap.Lazy as H import qualified Deque.Lazy as DQ import Deque.Lazy ( Deque ) import GHC.Generics data MessageStore = MessageStore { messageQueue :: Deque (Snowflake Message) , messages :: HashMap (Snowflake Message) Message , limit :: Int , size :: Int } deriving ( Show, Generic ) instance Default MessageStore where def = MessageStore mempty H.empty 1000 0 type instance (Index MessageStore) = Snowflake Message type instance (IxValue MessageStore) = Message instance Ixed MessageStore instance At MessageStore where at k f m = f mv <&> \case Nothing -> maybe m (const (dropMessage k m)) mv Just v -> addMessage v m where mv = getMessage k m {-# INLINE at #-} addMessage :: Message -> MessageStore -> MessageStore addMessage m = execState $ do unlessM (H.member (m ^. #id) <$> use #messages) do #messageQueue %= DQ.cons (getID m) #size += 1 size <- use #size limit <- use #limit when (size > limit) do q <- use #messageQueue let Just (rid, q') = DQ.unsnoc q #messageQueue .= q' #messages %= sans rid #size -= 1 #messages %= H.insert (getID m) m {-# INLINE addMessage #-} getMessage :: Snowflake Message -> MessageStore -> Maybe Message getMessage id s = H.lookup id (s ^. #messages) {-# INLINE getMessage #-} dropMessage :: Snowflake Message -> MessageStore -> MessageStore dropMessage id = execState $ do whenM (H.member id <$> use #messages) do #size -= 1 #messageQueue %= DQ.filter (/= id) #messages %= H.delete id {-# INLINE dropMessage #-}