packages feed

calamity 0.1.26.1 → 0.1.27.0

raw patch · 13 files changed

+470/−382 lines, 13 filesdep +http-api-dataPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: http-api-data

API changes (from Hackage documentation)

- Calamity.Types.Model.Channel.Reaction: [$sel:channelID:Reaction] :: Reaction -> Snowflake Channel
- Calamity.Types.Model.Channel.Reaction: [$sel:guildID:Reaction] :: Reaction -> Maybe (Snowflake Guild)
- Calamity.Types.Model.Channel.Reaction: [$sel:messageID:Reaction] :: Reaction -> Snowflake Message
- Calamity.Types.Model.Channel.Reaction: [$sel:userID:Reaction] :: Reaction -> Snowflake User
- Calamity.Types.Model.Channel.Reaction: instance Calamity.Types.Snowflake.HasID Calamity.Types.Model.Channel.Channel Calamity.Types.Model.Channel.Reaction.Reaction
- Calamity.Types.Model.Channel.Reaction: instance Calamity.Types.Snowflake.HasID Calamity.Types.Model.Channel.Message.Message Calamity.Types.Model.Channel.Reaction.Reaction
- Calamity.Types.Model.Channel.Reaction: instance Calamity.Types.Snowflake.HasID Calamity.Types.Model.User.User Calamity.Types.Model.Channel.Reaction.Reaction
+ Calamity.Gateway.DispatchEvents: ReactionEvtData :: Snowflake User -> Snowflake Channel -> Snowflake Message -> Maybe (Snowflake Guild) -> RawEmoji -> ReactionEvtData
+ Calamity.Gateway.DispatchEvents: [$sel:channelID:ReactionEvtData] :: ReactionEvtData -> Snowflake Channel
+ Calamity.Gateway.DispatchEvents: [$sel:emoji:ReactionEvtData] :: ReactionEvtData -> RawEmoji
+ Calamity.Gateway.DispatchEvents: [$sel:guildID:ReactionEvtData] :: ReactionEvtData -> Maybe (Snowflake Guild)
+ Calamity.Gateway.DispatchEvents: [$sel:messageID:ReactionEvtData] :: ReactionEvtData -> Snowflake Message
+ Calamity.Gateway.DispatchEvents: [$sel:userID:ReactionEvtData] :: ReactionEvtData -> Snowflake User
+ Calamity.Gateway.DispatchEvents: data ReactionEvtData
+ Calamity.Gateway.DispatchEvents: instance Calamity.Types.Snowflake.HasID Calamity.Types.Model.Channel.Channel Calamity.Gateway.DispatchEvents.ReactionEvtData
+ Calamity.Gateway.DispatchEvents: instance Calamity.Types.Snowflake.HasID Calamity.Types.Model.Channel.Message.Message Calamity.Gateway.DispatchEvents.ReactionEvtData
+ Calamity.Gateway.DispatchEvents: instance Calamity.Types.Snowflake.HasID Calamity.Types.Model.User.User Calamity.Gateway.DispatchEvents.ReactionEvtData
+ Calamity.Gateway.DispatchEvents: instance Data.Aeson.Types.FromJSON.FromJSON Calamity.Gateway.DispatchEvents.ReactionEvtData
+ Calamity.Gateway.DispatchEvents: instance Data.Aeson.Types.ToJSON.ToJSON Calamity.Gateway.DispatchEvents.ReactionEvtData
+ Calamity.Gateway.DispatchEvents: instance GHC.Classes.Eq Calamity.Gateway.DispatchEvents.ReactionEvtData
+ Calamity.Gateway.DispatchEvents: instance GHC.Generics.Generic Calamity.Gateway.DispatchEvents.ReactionEvtData
+ Calamity.Gateway.DispatchEvents: instance GHC.Show.Show Calamity.Gateway.DispatchEvents.ReactionEvtData
+ Calamity.Types.Model.Channel.Reaction: [$sel:count:Reaction] :: Reaction -> Integer
+ Calamity.Types.Model.Channel.Reaction: [$sel:me:Reaction] :: Reaction -> Bool
- Calamity.Cache.Eff: delDM :: forall r_a9gC1. MemberWithError CacheEff r_a9gC1 => Snowflake DMChannel -> Sem r_a9gC1 ()
+ Calamity.Cache.Eff: delDM :: forall r_a9cSc. MemberWithError CacheEff r_a9cSc => Snowflake DMChannel -> Sem r_a9cSc ()
- Calamity.Cache.Eff: delGuild :: forall r_a9gBU. MemberWithError CacheEff r_a9gBU => Snowflake Guild -> Sem r_a9gBU ()
+ Calamity.Cache.Eff: delGuild :: forall r_a9cS5. MemberWithError CacheEff r_a9cS5 => Snowflake Guild -> Sem r_a9cS5 ()
- Calamity.Cache.Eff: delMessage :: forall r_a9gCm. MemberWithError CacheEff r_a9gCm => Snowflake Message -> Sem r_a9gCm ()
+ Calamity.Cache.Eff: delMessage :: forall r_a9cSx. MemberWithError CacheEff r_a9cSx => Snowflake Message -> Sem r_a9cSx ()
- Calamity.Cache.Eff: delUnavailableGuild :: forall r_a9gCf. MemberWithError CacheEff r_a9gCf => Snowflake Guild -> Sem r_a9gCf ()
+ Calamity.Cache.Eff: delUnavailableGuild :: forall r_a9cSq. MemberWithError CacheEff r_a9cSq => Snowflake Guild -> Sem r_a9cSq ()
- Calamity.Cache.Eff: delUser :: forall r_a9gC8. MemberWithError CacheEff r_a9gC8 => Snowflake User -> Sem r_a9gC8 ()
+ Calamity.Cache.Eff: delUser :: forall r_a9cSj. MemberWithError CacheEff r_a9cSj => Snowflake User -> Sem r_a9cSj ()
- Calamity.Cache.Eff: getBotUser :: forall r_a9gBM. MemberWithError CacheEff r_a9gBM => Sem r_a9gBM (Maybe User)
+ Calamity.Cache.Eff: getBotUser :: forall r_a9cRX. MemberWithError CacheEff r_a9cRX => Sem r_a9cRX (Maybe User)
- Calamity.Cache.Eff: getDM :: forall r_a9gBY. MemberWithError CacheEff r_a9gBY => Snowflake DMChannel -> Sem r_a9gBY (Maybe DMChannel)
+ Calamity.Cache.Eff: getDM :: forall r_a9cS9. MemberWithError CacheEff r_a9cS9 => Snowflake DMChannel -> Sem r_a9cS9 (Maybe DMChannel)
- Calamity.Cache.Eff: getDMs :: forall r_a9gC0. MemberWithError CacheEff r_a9gC0 => Sem r_a9gC0 [DMChannel]
+ Calamity.Cache.Eff: getDMs :: forall r_a9cSb. MemberWithError CacheEff r_a9cSb => Sem r_a9cSb [DMChannel]
- Calamity.Cache.Eff: getGuild :: forall r_a9gBP. MemberWithError CacheEff r_a9gBP => Snowflake Guild -> Sem r_a9gBP (Maybe Guild)
+ Calamity.Cache.Eff: getGuild :: forall r_a9cS0. MemberWithError CacheEff r_a9cS0 => Snowflake Guild -> Sem r_a9cS0 (Maybe Guild)
- Calamity.Cache.Eff: getGuildChannel :: forall r_a9gBR. MemberWithError CacheEff r_a9gBR => Snowflake GuildChannel -> Sem r_a9gBR (Maybe GuildChannel)
+ Calamity.Cache.Eff: getGuildChannel :: forall r_a9cS2. MemberWithError CacheEff r_a9cS2 => Snowflake GuildChannel -> Sem r_a9cS2 (Maybe GuildChannel)
- Calamity.Cache.Eff: getGuilds :: forall r_a9gBT. MemberWithError CacheEff r_a9gBT => Sem r_a9gBT [Guild]
+ Calamity.Cache.Eff: getGuilds :: forall r_a9cS4. MemberWithError CacheEff r_a9cS4 => Sem r_a9cS4 [Guild]
- Calamity.Cache.Eff: getMessage :: forall r_a9gCj. MemberWithError CacheEff r_a9gCj => Snowflake Message -> Sem r_a9gCj (Maybe Message)
+ Calamity.Cache.Eff: getMessage :: forall r_a9cSu. MemberWithError CacheEff r_a9cSu => Snowflake Message -> Sem r_a9cSu (Maybe Message)
- Calamity.Cache.Eff: getMessages :: forall r_a9gCl. MemberWithError CacheEff r_a9gCl => Sem r_a9gCl [Message]
+ Calamity.Cache.Eff: getMessages :: forall r_a9cSw. MemberWithError CacheEff r_a9cSw => Sem r_a9cSw [Message]
- Calamity.Cache.Eff: getUnavailableGuilds :: forall r_a9gCe. MemberWithError CacheEff r_a9gCe => Sem r_a9gCe [Snowflake Guild]
+ Calamity.Cache.Eff: getUnavailableGuilds :: forall r_a9cSp. MemberWithError CacheEff r_a9cSp => Sem r_a9cSp [Snowflake Guild]
- Calamity.Cache.Eff: getUser :: forall r_a9gC5. MemberWithError CacheEff r_a9gC5 => Snowflake User -> Sem r_a9gC5 (Maybe User)
+ Calamity.Cache.Eff: getUser :: forall r_a9cSg. MemberWithError CacheEff r_a9cSg => Snowflake User -> Sem r_a9cSg (Maybe User)
- Calamity.Cache.Eff: getUsers :: forall r_a9gC7. MemberWithError CacheEff r_a9gC7 => Sem r_a9gC7 [User]
+ Calamity.Cache.Eff: getUsers :: forall r_a9cSi. MemberWithError CacheEff r_a9cSi => Sem r_a9cSi [User]
- Calamity.Cache.Eff: isUnavailableGuild :: forall r_a9gCc. MemberWithError CacheEff r_a9gCc => Snowflake Guild -> Sem r_a9gCc Bool
+ Calamity.Cache.Eff: isUnavailableGuild :: forall r_a9cSn. MemberWithError CacheEff r_a9cSn => Snowflake Guild -> Sem r_a9cSn Bool
- Calamity.Cache.Eff: setBotUser :: forall r_a9gBK. MemberWithError CacheEff r_a9gBK => User -> Sem r_a9gBK ()
+ Calamity.Cache.Eff: setBotUser :: forall r_a9cRV. MemberWithError CacheEff r_a9cRV => User -> Sem r_a9cRV ()
- Calamity.Cache.Eff: setDM :: forall r_a9gBW. MemberWithError CacheEff r_a9gBW => DMChannel -> Sem r_a9gBW ()
+ Calamity.Cache.Eff: setDM :: forall r_a9cS7. MemberWithError CacheEff r_a9cS7 => DMChannel -> Sem r_a9cS7 ()
- Calamity.Cache.Eff: setGuild :: forall r_a9gBN. MemberWithError CacheEff r_a9gBN => Guild -> Sem r_a9gBN ()
+ Calamity.Cache.Eff: setGuild :: forall r_a9cRY. MemberWithError CacheEff r_a9cRY => Guild -> Sem r_a9cRY ()
- Calamity.Cache.Eff: setMessage :: forall r_a9gCh. MemberWithError CacheEff r_a9gCh => Message -> Sem r_a9gCh ()
+ Calamity.Cache.Eff: setMessage :: forall r_a9cSs. MemberWithError CacheEff r_a9cSs => Message -> Sem r_a9cSs ()
- Calamity.Cache.Eff: setUnavailableGuild :: forall r_a9gCa. MemberWithError CacheEff r_a9gCa => Snowflake Guild -> Sem r_a9gCa ()
+ Calamity.Cache.Eff: setUnavailableGuild :: forall r_a9cSl. MemberWithError CacheEff r_a9cSl => Snowflake Guild -> Sem r_a9cSl ()
- Calamity.Cache.Eff: setUser :: forall r_a9gC3. MemberWithError CacheEff r_a9gC3 => User -> Sem r_a9gC3 ()
+ Calamity.Cache.Eff: setUser :: forall r_a9cSe. MemberWithError CacheEff r_a9cSe => User -> Sem r_a9cSe ()
- Calamity.Commands.ParsePrefix: parsePrefix :: forall r_a6Xxv. MemberWithError ParsePrefix r_a6Xxv => Message -> Sem r_a6Xxv (Maybe (Text, Text))
+ Calamity.Commands.ParsePrefix: parsePrefix :: forall r_a6THv. MemberWithError ParsePrefix r_a6THv => Message -> Sem r_a6THv (Maybe (Text, Text))
- Calamity.Gateway.DispatchEvents: MessageReactionAdd :: !Reaction -> DispatchData
+ Calamity.Gateway.DispatchEvents: MessageReactionAdd :: !ReactionEvtData -> DispatchData
- Calamity.Gateway.DispatchEvents: MessageReactionRemove :: !Reaction -> DispatchData
+ Calamity.Gateway.DispatchEvents: MessageReactionRemove :: !ReactionEvtData -> DispatchData
- Calamity.HTTP.Internal.Request: (=:?) :: Text -> Maybe Text -> Option 'Https
+ Calamity.HTTP.Internal.Request: (=:?) :: ToHttpApiData a => Text -> Maybe a -> Option 'Https
- Calamity.Types.Model.Channel.Reaction: Reaction :: Snowflake User -> Snowflake Channel -> Snowflake Message -> Maybe (Snowflake Guild) -> RawEmoji -> Reaction
+ Calamity.Types.Model.Channel.Reaction: Reaction :: Integer -> Bool -> RawEmoji -> Reaction

Files

Calamity/Client/Client.hs view
@@ -550,20 +550,36 @@ handleEvent' eh evt@(MessageReactionAdd reaction) = do   updateCache evt   msg <- getMessage (getID reaction)+  user <- getUser (getID reaction)+  chan <- case reaction ^. #guildID of+    Just _ -> do+      chan <- getGuildChannel (coerceSnowflake $ getID @Channel reaction)+      pure (GuildChannel' <$> chan)+    Nothing -> do+      chan <- getDM (coerceSnowflake $ getID @Channel reaction)+      pure (DMChannel' <$> chan)   let rawActions = map ($ reaction) (getEventHandlers @'RawMessageReactionAddEvt eh)-  let actions = case msg of-        Just msg' ->-          map ($ (msg', reaction)) (getEventHandlers @'MessageReactionAddEvt eh)+  let actions = case (msg, user, chan) of+        (Just msg', Just user', Just chan') ->+          map ($ (msg', user', chan', reaction ^. #emoji)) (getEventHandlers @'MessageReactionAddEvt eh)         _ -> []   pure $ rawActions <> actions  handleEvent' eh evt@(MessageReactionRemove reaction) = do   msg <- getMessage (getID reaction)   updateCache evt+  user <- getUser (getID reaction)+  chan <- case reaction ^. #guildID of+    Just _ -> do+      chan <- getGuildChannel (coerceSnowflake $ getID @Channel reaction)+      pure (GuildChannel' <$> chan)+    Nothing -> do+      chan <- getDM (coerceSnowflake $ getID @Channel reaction)+      pure (DMChannel' <$> chan)   let rawActions = map ($ reaction) (getEventHandlers @'RawMessageReactionRemoveEvt eh)-  let actions = case msg of-        Just msg' ->-          map ($ (msg', reaction)) (getEventHandlers @'MessageReactionRemoveEvt eh)+  let actions = case (msg, user, chan) of+        (Just msg', Just user', Just chan') ->+          map ($ (msg', user', chan', reaction ^. #emoji)) (getEventHandlers @'MessageReactionRemoveEvt eh)         _ -> []   pure $ rawActions <> actions @@ -607,7 +623,7 @@   pure $ map ($ (oldUser, newUser)) (getEventHandlers @'UserUpdateEvt eh)  handleEvent' eh evt@(VoiceStateUpdate newVoiceState@V.VoiceState{guildID=Just guildID}) = do-  oldVoiceState <- join . fmap (find ((==V.sessionID newVoiceState) . V.sessionID) . voiceStates) <$> getGuild guildID+  oldVoiceState <- ((find ((== V.sessionID newVoiceState) . V.sessionID) . voiceStates) =<<) <$> getGuild guildID   updateCache evt   pure $ map ($ (oldVoiceState, newVoiceState)) (getEventHandlers @'VoiceStateUpdateEvt eh) @@ -690,11 +706,27 @@ updateCache (MessageDeleteBulk MessageDeleteBulkData { ids }) =   for_ ids delMessage -updateCache (MessageReactionAdd reaction) =-  updateMessage (getID reaction) (#reactions %~ cons reaction)--updateCache (MessageReactionRemove reaction) =-  updateMessage (getID reaction) (#reactions %~ filter (\r -> r ^. #emoji /= reaction ^. #emoji))+updateCache (MessageReactionAdd reaction) = do+  isMe <- (\u -> Just (getID @User reaction) == (getID @User <$> u)) <$> getBotUser+  updateMessage+    (getID reaction)+    ( \m ->+        case m ^. #reactions & filter ((== (reaction ^. #emoji)) . (^. #emoji)) of+          [] -> m & #reactions <>~ [Reaction 1 isMe (reaction ^. #emoji)]+          _ ->+            m & #reactions . traverse . filtered ((== (reaction ^. #emoji)) . (^. #emoji))+              %~ (#count +~ 1) . (#me ||~ isMe)+    )+updateCache (MessageReactionRemove reaction) = do+  isMe <- (\u -> Just (getID @User reaction) == (getID @User <$> u)) <$> getBotUser+  updateMessage+    (getID reaction)+    ( \m ->+        m+          & #reactions . traverse . filtered ((== (reaction ^. #emoji)) . (^. #emoji))+            %~ (#count -~ 1) . (#me &&~ not isMe)+          & #reactions %~ filter (\r -> r ^. #count /= 0)+    )  updateCache (MessageReactionRemoveAll MessageReactionRemoveAllData { messageID }) =   updateMessage messageID (#reactions .~ mempty)
Calamity/Client/Types.hs view
@@ -1,93 +1,105 @@ -- | Types for the client-module Calamity.Client.Types-    ( Client(..)-    , StartupError(..)-    , EventType(..)-    , GuildCreateStatus(..)-    , GuildDeleteStatus(..)-    , EHType-    , BotC-    , SetupEff-    , ReactConstraints-    , EventHandlers(..)-    , InsertEventHandler(..)-    , RemoveEventHandler(..)-    , getEventHandlers-    , getCustomEventHandlers ) where+module Calamity.Client.Types (+  Client (..),+  StartupError (..),+  EventType (..),+  GuildCreateStatus (..),+  GuildDeleteStatus (..),+  EHType,+  BotC,+  SetupEff,+  ReactConstraints,+  EventHandlers (..),+  InsertEventHandler (..),+  RemoveEventHandler (..),+  getEventHandlers,+  getCustomEventHandlers,+) where -import           Calamity.Cache.Eff-import           Calamity.Gateway.DispatchEvents ( CalamityEvent(..), InviteCreateData, InviteDeleteData, ReadyData )-import           Calamity.Gateway.Types          ( ControlMessage )-import           Calamity.HTTP.Internal.Types-import           Calamity.Metrics.Eff-import           Calamity.Types.LogEff-import           Calamity.Types.Model.Channel-import           Calamity.Types.Model.Channel.UpdatedMessage-import           Calamity.Types.Model.Guild-import           Calamity.Types.Model.User-import           Calamity.Types.Model.Voice-import           Calamity.Types.Token-import           Calamity.Types.UnixTimestamp-import           Calamity.Types.Snowflake+import Calamity.Cache.Eff+import Calamity.Gateway.DispatchEvents (CalamityEvent (..), InviteCreateData, InviteDeleteData, ReactionEvtData, ReadyData)+import Calamity.Gateway.Types (ControlMessage)+import Calamity.HTTP.Internal.Types+import Calamity.Metrics.Eff+import Calamity.Types.LogEff+import Calamity.Types.Model.Channel+import Calamity.Types.Model.Channel.UpdatedMessage+import Calamity.Types.Model.Guild+import Calamity.Types.Model.User+import Calamity.Types.Model.Voice+import Calamity.Types.Snowflake+import Calamity.Types.Token+import Calamity.Types.UnixTimestamp -import           Control.Concurrent.Async-import           Control.Concurrent.Chan.Unagi-import           Control.Concurrent.MVar-import           Control.Concurrent.STM.TVar+import Control.Concurrent.Async+import Control.Concurrent.Chan.Unagi+import Control.Concurrent.MVar+import Control.Concurrent.STM.TVar -import           Data.Default.Class-import           Data.Dynamic-import qualified Data.HashMap.Lazy               as LH-import           Data.IORef-import           Data.Maybe-import           Data.Time-import qualified Data.TypeRepMap                 as TM-import           Data.TypeRepMap                 ( TypeRepMap, WrapTypeable(..) )-import           Data.Typeable-import           Data.Void+import Data.Default.Class+import Data.Dynamic+import qualified Data.HashMap.Lazy as LH+import Data.IORef+import Data.Maybe+import Data.Time+import Data.TypeRepMap (TypeRepMap, WrapTypeable (..))+import qualified Data.TypeRepMap as TM+import Data.Typeable+import Data.Void -import           GHC.Exts                        ( fromList )-import           GHC.Generics+import GHC.Exts (fromList)+import GHC.Generics -import qualified Polysemy                        as P-import qualified Polysemy.Async                  as P-import qualified Polysemy.AtomicState            as P-import qualified Polysemy.Reader                 as P+import qualified Polysemy as P+import qualified Polysemy.Async as P+import qualified Polysemy.AtomicState as P+import qualified Polysemy.Reader as P -import qualified TextShow.Generic                as TSG-import TextShow import qualified Df1 as Df1 import qualified Di.Core as DC+import TextShow+import qualified TextShow.Generic as TSG  data Client = Client-  { shards              :: TVar [(InChan ControlMessage, Async (Maybe ()))]-  , numShards           :: MVar Int-  , token               :: Token-  , rlState             :: RateLimitState-  , eventsIn            :: InChan CalamityEvent-  , eventsOut           :: OutChan CalamityEvent-  , ehidCounter         :: IORef Integer-  , initialDi           :: Maybe (DC.Di Df1.Level Df1.Path Df1.Message)+  { shards :: TVar [(InChan ControlMessage, Async (Maybe ()))]+  , numShards :: MVar Int+  , token :: Token+  , rlState :: RateLimitState+  , eventsIn :: InChan CalamityEvent+  , eventsOut :: OutChan CalamityEvent+  , ehidCounter :: IORef Integer+  , initialDi :: Maybe (DC.Di Df1.Level Df1.Path Df1.Message)   }-  deriving ( Generic )+  deriving (Generic)  type BotC r =-  ( P.Members '[LogEff, MetricEff, CacheEff, P.Reader Client,-  P.AtomicState EventHandlers, P.Embed IO, P.Final IO, P.Async] r-  , Typeable r)+  ( P.Members+      '[ LogEff+       , MetricEff+       , CacheEff+       , P.Reader Client+       , P.AtomicState EventHandlers+       , P.Embed IO+       , P.Final IO+       , P.Async+       ]+      r+  , Typeable r+  )  -- | A concrete effect stack used inside the bot type SetupEff r = (P.Reader Client ': P.AtomicState EventHandlers ': P.Async ': r) --- | Some constraints that 'Calamity.Client.Client.react' needs to work. Don't--- worry about these since they are satisfied for any type @s@ can be+{- | Some constraints that 'Calamity.Client.Client.react' needs to work. Don't+ worry about these since they are satisfied for any type @s@ can be+-} type ReactConstraints s =   ( InsertEventHandler s   , RemoveEventHandler s   )  newtype StartupError = StartupError String-  deriving ( Show )+  deriving (Show)  -- | A Data Kind used to fire custom events data EventType@@ -113,104 +125,109 @@   | InviteCreateEvt   | InviteDeleteEvt   | MessageCreateEvt-  | MessageUpdateEvt-  -- ^ Fired when a cached message is updated, use 'RawMessageUpdateEvt' to see-  -- updates of uncached messages-  | RawMessageUpdateEvt-  -- ^ Fired when a message is updated-  | MessageDeleteEvt-  -- ^ Fired when a cached message is deleted, use 'RawMessageDeleteEvt' to see-  -- deletes of uncached messages.-  ---  -- Does not include messages deleted through bulk deletes, use-  -- 'MessageDeleteBulkEvt' for those-  | RawMessageDeleteEvt-  -- ^ Fired when a message is deleted.-  ---  -- Does not include messages deleted through bulk deletes, use-  -- 'RawMessageDeleteBulkEvt' for those-  | MessageDeleteBulkEvt-  -- ^ Fired when messages are bulk deleted. Only includes cached messages, use-  -- 'RawMessageDeleteBulkEvt' to see deletes of uncached messages.-  | RawMessageDeleteBulkEvt-  -- ^ Fired when messages are bulk deleted.-  | MessageReactionAddEvt-  -- ^ Fired when a reaction is added to a cached message, use-  -- 'RawMessageReactionAddEvt' to see reactions on uncached messages.-  | RawMessageReactionAddEvt-  -- ^ Fired when a reaction is added to a message.-  | MessageReactionRemoveEvt-  -- ^ Fired when a reaction is removed from a cached message, use-  -- 'RawMessageReactionRemoveEvt' to see reactions on uncached messages.-  | RawMessageReactionRemoveEvt-  -- ^ Fired when a reaction is removed from a message.-  | MessageReactionRemoveAllEvt-  -- ^ Fired when all reactions are removed from a cached message, use-  -- 'RawMessageReactionRemoveEvt' to see reactions on uncached messages.-  ---  -- The message passed will contain the removed events.-  | RawMessageReactionRemoveAllEvt-  -- ^ Fired when all reactions are removed from a message.+  | -- | Fired when a cached message is updated, use 'RawMessageUpdateEvt' to see+    -- updates of uncached messages+    MessageUpdateEvt+  | -- | Fired when a message is updated+    RawMessageUpdateEvt+  | -- | Fired when a cached message is deleted, use 'RawMessageDeleteEvt' to see+    -- deletes of uncached messages.+    --+    -- Does not include messages deleted through bulk deletes, use+    -- 'MessageDeleteBulkEvt' for those+    MessageDeleteEvt+  | -- | Fired when a message is deleted.+    --+    -- Does not include messages deleted through bulk deletes, use+    -- 'RawMessageDeleteBulkEvt' for those+    RawMessageDeleteEvt+  | -- | Fired when messages are bulk deleted. Only includes cached messages, use+    -- 'RawMessageDeleteBulkEvt' to see deletes of uncached messages.+    MessageDeleteBulkEvt+  | -- | Fired when messages are bulk deleted.+    RawMessageDeleteBulkEvt+  | -- | Fired when a reaction is added to a cached message, use+    -- 'RawMessageReactionAddEvt' to see reactions on uncached messages.+    MessageReactionAddEvt+  | -- | Fired when a reaction is added to a message.+    RawMessageReactionAddEvt+  | -- | Fired when a reaction is removed from a cached message, use+    -- 'RawMessageReactionRemoveEvt' to see reactions on uncached messages.+    MessageReactionRemoveEvt+  | -- | Fired when a reaction is removed from a message.+    RawMessageReactionRemoveEvt+  | -- | Fired when all reactions are removed from a cached message, use+    -- 'RawMessageReactionRemoveEvt' to see reactions on uncached messages.+    --+    -- The message passed will contain the removed events.+    MessageReactionRemoveAllEvt+  | -- | Fired when all reactions are removed from a message.+    RawMessageReactionRemoveAllEvt   | TypingStartEvt   | UserUpdateEvt-  | VoiceStateUpdateEvt-  -- ^ Sent when someone joins/leaves/moves voice channels-  | forall s a. CustomEvt s a-  -- ^ A custom event, @s@ is the name and @a@ is the data sent to the handler+  | -- | Sent when someone joins/leaves/moves voice channels+    VoiceStateUpdateEvt+  | -- | A custom event, @s@ is the name and @a@ is the data sent to the handler+    forall s a. CustomEvt s a  data GuildCreateStatus-  = GuildCreateNew -- ^ The guild was just joined-  | GuildCreateAvailable -- ^ The guild is becoming available-  deriving ( Generic, Show )-  deriving ( TextShow ) via TSG.FromGeneric GuildCreateStatus+  = -- | The guild was just joined+    GuildCreateNew+  | -- | The guild is becoming available+    GuildCreateAvailable+  deriving (Generic, Show)+  deriving (TextShow) via TSG.FromGeneric GuildCreateStatus  data GuildDeleteStatus-  = GuildDeleteUnavailable -- ^ The guild became unavailable-  | GuildDeleteRemoved -- ^ The bot was removed from the guild-  deriving ( Generic, Show )-  deriving ( TextShow ) via TSG.FromGeneric GuildDeleteStatus+  = -- | The guild became unavailable+    GuildDeleteUnavailable+  | -- | The bot was removed from the guild+    GuildDeleteRemoved+  deriving (Generic, Show)+  deriving (TextShow) via TSG.FromGeneric GuildDeleteStatus --- | A type family to decide what the parameters for an event handler should be--- determined by the type of event it is handling.+{- | A type family to decide what the parameters for an event handler should be+ determined by the type of event it is handling.+-} type family EHType (d :: EventType) where-  EHType 'ReadyEvt                    = ReadyData-  EHType 'ChannelCreateEvt            = Channel-  EHType 'ChannelUpdateEvt            = (Channel, Channel)-  EHType 'ChannelDeleteEvt            = Channel-  EHType 'ChannelpinsUpdateEvt        = (Channel, Maybe UTCTime)-  EHType 'GuildCreateEvt              = (Guild, GuildCreateStatus)-  EHType 'GuildUpdateEvt              = (Guild, Guild)-  EHType 'GuildDeleteEvt              = (Guild, GuildDeleteStatus)-  EHType 'GuildBanAddEvt              = (Guild, User)-  EHType 'GuildBanRemoveEvt           = (Guild, User)-  EHType 'GuildEmojisUpdateEvt        = (Guild, [Emoji])-  EHType 'GuildIntegrationsUpdateEvt  = Guild-  EHType 'GuildMemberAddEvt           = Member-  EHType 'GuildMemberRemoveEvt        = Member-  EHType 'GuildMemberUpdateEvt        = (Member, Member)-  EHType 'GuildMembersChunkEvt        = (Guild, [Member])-  EHType 'GuildRoleCreateEvt          = (Guild, Role)-  EHType 'GuildRoleUpdateEvt          = (Guild, Role, Role)-  EHType 'GuildRoleDeleteEvt          = (Guild, Role)-  EHType 'InviteCreateEvt             = InviteCreateData-  EHType 'InviteDeleteEvt             = InviteDeleteData-  EHType 'MessageCreateEvt            = Message-  EHType 'MessageUpdateEvt            = (Message, Message)-  EHType 'MessageDeleteEvt            = Message-  EHType 'MessageDeleteBulkEvt        = [Message]-  EHType 'MessageReactionAddEvt       = (Message, Reaction)-  EHType 'MessageReactionRemoveEvt    = (Message, Reaction)+  EHType 'ReadyEvt = ReadyData+  EHType 'ChannelCreateEvt = Channel+  EHType 'ChannelUpdateEvt = (Channel, Channel)+  EHType 'ChannelDeleteEvt = Channel+  EHType 'ChannelpinsUpdateEvt = (Channel, Maybe UTCTime)+  EHType 'GuildCreateEvt = (Guild, GuildCreateStatus)+  EHType 'GuildUpdateEvt = (Guild, Guild)+  EHType 'GuildDeleteEvt = (Guild, GuildDeleteStatus)+  EHType 'GuildBanAddEvt = (Guild, User)+  EHType 'GuildBanRemoveEvt = (Guild, User)+  EHType 'GuildEmojisUpdateEvt = (Guild, [Emoji])+  EHType 'GuildIntegrationsUpdateEvt = Guild+  EHType 'GuildMemberAddEvt = Member+  EHType 'GuildMemberRemoveEvt = Member+  EHType 'GuildMemberUpdateEvt = (Member, Member)+  EHType 'GuildMembersChunkEvt = (Guild, [Member])+  EHType 'GuildRoleCreateEvt = (Guild, Role)+  EHType 'GuildRoleUpdateEvt = (Guild, Role, Role)+  EHType 'GuildRoleDeleteEvt = (Guild, Role)+  EHType 'InviteCreateEvt = InviteCreateData+  EHType 'InviteDeleteEvt = InviteDeleteData+  EHType 'MessageCreateEvt = Message+  EHType 'MessageUpdateEvt = (Message, Message)+  EHType 'MessageDeleteEvt = Message+  EHType 'MessageDeleteBulkEvt = [Message]+  EHType 'MessageReactionAddEvt = (Message, User, Channel, RawEmoji)+  EHType 'MessageReactionRemoveEvt = (Message, User, Channel, RawEmoji)   EHType 'MessageReactionRemoveAllEvt = Message-  EHType 'RawMessageUpdateEvt            = UpdatedMessage-  EHType 'RawMessageDeleteEvt            = Snowflake Message-  EHType 'RawMessageDeleteBulkEvt        = [Snowflake Message]-  EHType 'RawMessageReactionAddEvt       = Reaction-  EHType 'RawMessageReactionRemoveEvt    = Reaction+  EHType 'RawMessageUpdateEvt = UpdatedMessage+  EHType 'RawMessageDeleteEvt = Snowflake Message+  EHType 'RawMessageDeleteBulkEvt = [Snowflake Message]+  EHType 'RawMessageReactionAddEvt = ReactionEvtData+  EHType 'RawMessageReactionRemoveEvt = ReactionEvtData   EHType 'RawMessageReactionRemoveAllEvt = Snowflake Message-  EHType 'TypingStartEvt              = (Channel, Snowflake User, UnixTimestamp)-  EHType 'UserUpdateEvt               = (User, User)-  EHType 'VoiceStateUpdateEvt         = (Maybe VoiceState, VoiceState)-  EHType ('CustomEvt s a)             = a+  EHType 'TypingStartEvt = (Channel, Snowflake User, UnixTimestamp)+  EHType 'UserUpdateEvt = (User, User)+  EHType 'VoiceStateUpdateEvt = (Maybe VoiceState, VoiceState)+  EHType ( 'CustomEvt s a) = a  type StoredEHType t = EHType t -> IO () @@ -218,12 +235,12 @@  data EventHandlerWithID a = EventHandlerWithID   { ehID :: Integer-  , eh   :: a+  , eh :: a   }  type family EHStorageType (t :: EventType) where-  EHStorageType ('CustomEvt s a) = LH.HashMap TypeRep (LH.HashMap TypeRep [EventHandlerWithID (StoredEHType ('CustomEvt s a))])-  EHStorageType t                = [EventHandlerWithID (StoredEHType t)]+  EHStorageType ( 'CustomEvt s a) = LH.HashMap TypeRep (LH.HashMap TypeRep [EventHandlerWithID (StoredEHType ( 'CustomEvt s a))])+  EHStorageType t = [EventHandlerWithID (StoredEHType t)]  newtype EventHandler (t :: EventType) = EH   { unwrapEventHandler :: (Semigroup (EHStorageType t), Monoid (EHStorageType t)) => EHStorageType t@@ -236,36 +253,39 @@   mempty = EH mempty  instance Default EventHandlers where-  def = EventHandlers $ fromList [ WrapTypeable $ EH @'ReadyEvt []-                                 , WrapTypeable $ EH @'ChannelCreateEvt []-                                 , WrapTypeable $ EH @'ChannelUpdateEvt []-                                 , WrapTypeable $ EH @'ChannelDeleteEvt []-                                 , WrapTypeable $ EH @'ChannelpinsUpdateEvt []-                                 , WrapTypeable $ EH @'GuildCreateEvt []-                                 , WrapTypeable $ EH @'GuildUpdateEvt []-                                 , WrapTypeable $ EH @'GuildDeleteEvt []-                                 , WrapTypeable $ EH @'GuildBanAddEvt []-                                 , WrapTypeable $ EH @'GuildBanRemoveEvt []-                                 , WrapTypeable $ EH @'GuildEmojisUpdateEvt []-                                 , WrapTypeable $ EH @'GuildIntegrationsUpdateEvt []-                                 , WrapTypeable $ EH @'GuildMemberAddEvt []-                                 , WrapTypeable $ EH @'GuildMemberRemoveEvt []-                                 , WrapTypeable $ EH @'GuildMemberUpdateEvt []-                                 , WrapTypeable $ EH @'GuildMembersChunkEvt []-                                 , WrapTypeable $ EH @'GuildRoleCreateEvt []-                                 , WrapTypeable $ EH @'GuildRoleUpdateEvt []-                                 , WrapTypeable $ EH @'GuildRoleDeleteEvt []-                                 , WrapTypeable $ EH @'MessageCreateEvt []-                                 , WrapTypeable $ EH @'MessageUpdateEvt []-                                 , WrapTypeable $ EH @'MessageDeleteEvt []-                                 , WrapTypeable $ EH @'MessageDeleteBulkEvt []-                                 , WrapTypeable $ EH @'MessageReactionAddEvt []-                                 , WrapTypeable $ EH @'MessageReactionRemoveEvt []-                                 , WrapTypeable $ EH @'MessageReactionRemoveAllEvt []-                                 , WrapTypeable $ EH @'TypingStartEvt []-                                 , WrapTypeable $ EH @'UserUpdateEvt []-                                 , WrapTypeable $ EH @('CustomEvt Void Dynamic) LH.empty-                                 ]+  def =+    EventHandlers $+      fromList+        [ WrapTypeable $ EH @ 'ReadyEvt []+        , WrapTypeable $ EH @ 'ChannelCreateEvt []+        , WrapTypeable $ EH @ 'ChannelUpdateEvt []+        , WrapTypeable $ EH @ 'ChannelDeleteEvt []+        , WrapTypeable $ EH @ 'ChannelpinsUpdateEvt []+        , WrapTypeable $ EH @ 'GuildCreateEvt []+        , WrapTypeable $ EH @ 'GuildUpdateEvt []+        , WrapTypeable $ EH @ 'GuildDeleteEvt []+        , WrapTypeable $ EH @ 'GuildBanAddEvt []+        , WrapTypeable $ EH @ 'GuildBanRemoveEvt []+        , WrapTypeable $ EH @ 'GuildEmojisUpdateEvt []+        , WrapTypeable $ EH @ 'GuildIntegrationsUpdateEvt []+        , WrapTypeable $ EH @ 'GuildMemberAddEvt []+        , WrapTypeable $ EH @ 'GuildMemberRemoveEvt []+        , WrapTypeable $ EH @ 'GuildMemberUpdateEvt []+        , WrapTypeable $ EH @ 'GuildMembersChunkEvt []+        , WrapTypeable $ EH @ 'GuildRoleCreateEvt []+        , WrapTypeable $ EH @ 'GuildRoleUpdateEvt []+        , WrapTypeable $ EH @ 'GuildRoleDeleteEvt []+        , WrapTypeable $ EH @ 'MessageCreateEvt []+        , WrapTypeable $ EH @ 'MessageUpdateEvt []+        , WrapTypeable $ EH @ 'MessageDeleteEvt []+        , WrapTypeable $ EH @ 'MessageDeleteBulkEvt []+        , WrapTypeable $ EH @ 'MessageReactionAddEvt []+        , WrapTypeable $ EH @ 'MessageReactionRemoveEvt []+        , WrapTypeable $ EH @ 'MessageReactionRemoveAllEvt []+        , WrapTypeable $ EH @ 'TypingStartEvt []+        , WrapTypeable $ EH @ 'UserUpdateEvt []+        , WrapTypeable $ EH @( 'CustomEvt Void Dynamic) LH.empty+        ]  instance Semigroup EventHandlers where   (EventHandlers a) <> (EventHandlers b) = EventHandlers $ TM.unionWith (<>) a b@@ -276,18 +296,17 @@ -- not sure what to think of this  type family EHInstanceSelector (d :: EventType) :: Bool where-  EHInstanceSelector ('CustomEvt _ _) = 'True-  EHInstanceSelector _                = 'False-+  EHInstanceSelector ( 'CustomEvt _ _) = 'True+  EHInstanceSelector _ = 'False  fromDynamicJust :: forall a. Typeable a => Dynamic -> a fromDynamicJust d = case fromDynamic d of   Just x -> x   Nothing -> error $ "Extracting dynamic failed, wanted: " <> (show . typeRep $ Proxy @a) <> ", got: " <> (show $ dynTypeRep d) ---- | A helper typeclass that is used to decide how to register regular--- events, and custom events which require storing in a map at runtime.+{- | A helper typeclass that is used to decide how to register regular+ events, and custom events which require storing in a map at runtime.+-} class InsertEventHandler a where   makeEventHandlers :: Proxy a -> Integer -> StoredEHType a -> EventHandlers @@ -300,15 +319,18 @@ intoDynFn :: forall a. Typeable a => (a -> IO ()) -> (Dynamic -> IO ()) intoDynFn fn = \d -> fn $ fromDynamicJust d -instance (Typeable a, Typeable s, Typeable (StoredEHType ('CustomEvt s a)), (EHType ('CustomEvt s a) -> IO ()) ~ (a -> IO ()))-  => InsertEventHandler' 'True ('CustomEvt s a) where-  makeEventHandlers' _ _ id' handler = EventHandlers . TM.one $ EH @('CustomEvt Void Dynamic)-    (LH.singleton (typeRep $ Proxy @s) (LH.singleton (typeRep $ Proxy @a) [EventHandlerWithID id' (intoDynFn handler)]))+instance+  (Typeable a, Typeable s, Typeable (StoredEHType ( 'CustomEvt s a)), (EHType ( 'CustomEvt s a) -> IO ()) ~ (a -> IO ())) =>+  InsertEventHandler' 'True ( 'CustomEvt s a)+  where+  makeEventHandlers' _ _ id' handler =+    EventHandlers . TM.one $+      EH @( 'CustomEvt Void Dynamic)+        (LH.singleton (typeRep $ Proxy @s) (LH.singleton (typeRep $ Proxy @a) [EventHandlerWithID id' (intoDynFn handler)]))  instance (Typeable s, EHStorageType s ~ [EventHandlerWithID (StoredEHType s)], Typeable (StoredEHType s)) => InsertEventHandler' 'False s where   makeEventHandlers' _ _ id' handler = EventHandlers . TM.one $ EH @s [EventHandlerWithID id' handler] - class GetEventHandlers a where   getEventHandlers :: EventHandlers -> [StoredEHType a] @@ -318,14 +340,13 @@ class GetEventHandlers' (flag :: Bool) a where   getEventHandlers' :: Proxy a -> Proxy flag -> EventHandlers -> [StoredEHType a] -instance GetEventHandlers' 'True ('CustomEvt s a) where+instance GetEventHandlers' 'True ( 'CustomEvt s a) where   getEventHandlers' _ _ _ = error "use getCustomEventHandlers instead"  instance (Typeable s, Typeable (StoredEHType s), EHStorageType s ~ [EventHandlerWithID (StoredEHType s)]) => GetEventHandlers' 'False s where   getEventHandlers' _ _ (EventHandlers handlers) =     let theseHandlers = unwrapEventHandler @s $ fromMaybe mempty (TM.lookup handlers :: Maybe (EventHandler s))-    in map eh theseHandlers-+     in map eh theseHandlers  class RemoveEventHandler a where   removeEventHandler :: Proxy a -> Integer -> EventHandlers -> EventHandlers@@ -336,19 +357,35 @@ class RemoveEventHandler' (flag :: Bool) a where   removeEventHandler' :: Proxy flag -> Proxy a -> Integer -> EventHandlers -> EventHandlers -instance (Typeable s, Typeable a) => RemoveEventHandler' 'True ('CustomEvt s a) where-  removeEventHandler' _ _ id' (EventHandlers handlers) = EventHandlers $ TM.adjust @('CustomEvt Void Dynamic)-    (\(EH ehs) -> EH (LH.update (Just . LH.update (Just . filter ((/= id') . ehID)) (typeRep $ Proxy @a))-                      (typeRep $ Proxy @s) ehs)) handlers--instance (Typeable s, Typeable (StoredEHType s), EHStorageType s ~ [EventHandlerWithID (StoredEHType s)])-  => RemoveEventHandler' 'False s where-  removeEventHandler' _ _ id' (EventHandlers handlers) = EventHandlers $ TM.adjust @s-    (\(EH ehs) -> EH $ filter ((/= id') . ehID) ehs) handlers+instance (Typeable s, Typeable a) => RemoveEventHandler' 'True ( 'CustomEvt s a) where+  removeEventHandler' _ _ id' (EventHandlers handlers) =+    EventHandlers $+      TM.adjust @( 'CustomEvt Void Dynamic)+        ( \(EH ehs) ->+            EH+              ( LH.update+                  (Just . LH.update (Just . filter ((/= id') . ehID)) (typeRep $ Proxy @a))+                  (typeRep $ Proxy @s)+                  ehs+              )+        )+        handlers +instance+  (Typeable s, Typeable (StoredEHType s), EHStorageType s ~ [EventHandlerWithID (StoredEHType s)]) =>+  RemoveEventHandler' 'False s+  where+  removeEventHandler' _ _ id' (EventHandlers handlers) =+    EventHandlers $+      TM.adjust @s+        (\(EH ehs) -> EH $ filter ((/= id') . ehID) ehs)+        handlers  getCustomEventHandlers :: TypeRep -> TypeRep -> EventHandlers -> [Dynamic -> IO ()] getCustomEventHandlers s a (EventHandlers handlers) =-    let handlerMap = unwrapEventHandler @('CustomEvt Void Dynamic) $ fromMaybe mempty-          (TM.lookup handlers :: Maybe (EventHandler ('CustomEvt Void Dynamic)))-    in map eh . concat $ LH.lookup s handlerMap >>= LH.lookup a+  let handlerMap =+        unwrapEventHandler @( 'CustomEvt Void Dynamic) $+          fromMaybe+            mempty+            (TM.lookup handlers :: Maybe (EventHandler ( 'CustomEvt Void Dynamic)))+   in map eh . concat $ LH.lookup s handlerMap >>= LH.lookup a
Calamity/Gateway/DispatchEvents.hs view
@@ -1,41 +1,45 @@ -- | module containing all dispatch events module Calamity.Gateway.DispatchEvents where -import           Calamity.Internal.AesonThings-import           Calamity.Internal.ConstructorName-import           Calamity.Internal.Utils                     ()-import           Calamity.Types.Model.Channel-import           Calamity.Types.Model.Channel.UpdatedMessage-import           Calamity.Types.Model.Guild.Ban-import           Calamity.Types.Model.Guild.Emoji-import           Calamity.Types.Model.Guild.Guild-import           Calamity.Types.Model.Guild.Member-import           Calamity.Types.Model.Guild.Role-import           Calamity.Types.Model.Guild.UnavailableGuild-import           Calamity.Types.Model.Presence.Presence-import           Calamity.Types.Model.User-import           Calamity.Types.Model.Voice-import           Calamity.Types.Snowflake-import           Calamity.Types.UnixTimestamp+import Calamity.Internal.AesonThings+import Calamity.Internal.ConstructorName+import Calamity.Internal.Utils ()+import Calamity.Types.Model.Channel+import Calamity.Types.Model.Channel.UpdatedMessage+import Calamity.Types.Model.Guild.Ban+import Calamity.Types.Model.Guild.Emoji+import Calamity.Types.Model.Guild.Guild+import Calamity.Types.Model.Guild.Member+import Calamity.Types.Model.Guild.Role+import Calamity.Types.Model.Guild.UnavailableGuild+import Calamity.Types.Model.Presence.Presence+import Calamity.Types.Model.User+import Calamity.Types.Model.Voice+import Calamity.Types.Snowflake+import Calamity.Types.UnixTimestamp -import           Data.Aeson-import           Data.Dynamic-import           Data.Text.Lazy                              ( Text )-import           Data.Time-import           Data.Typeable-import           Data.Vector.Unboxing                        ( Vector )+import Data.Aeson+import Data.Dynamic+import Data.Text.Lazy (Text)+import Data.Time+import Data.Typeable+import Data.Vector.Unboxing (Vector) -import           GHC.Generics+import GHC.Generics  data CalamityEvent   = Dispatch-    Int -- ^ The shard that pushed this event-    DispatchData -- ^ The attached data+      Int+      -- ^ The shard that pushed this event+      DispatchData+      -- ^ The attached data   | Custom-    TypeRep -- ^ The name of the custom event-    Dynamic -- ^ The data sent to the custom event+      TypeRep+      -- ^ The name of the custom event+      Dynamic+      -- ^ The data sent to the custom event   | ShutDown-  deriving ( Show, Generic )+  deriving (Show, Generic)  data DispatchData   = Ready !ReadyData@@ -64,8 +68,8 @@   | MessageUpdate !UpdatedMessage   | MessageDelete !MessageDeleteData   | MessageDeleteBulk !MessageDeleteBulkData-  | MessageReactionAdd !Reaction-  | MessageReactionRemove !Reaction+  | MessageReactionAdd !ReactionEvtData+  | MessageReactionRemove !ReactionEvtData   | MessageReactionRemoveAll !MessageReactionRemoveAllData   | PresenceUpdate !PresenceUpdateData   | TypingStart !TypingStartData@@ -73,58 +77,58 @@   | VoiceStateUpdate !VoiceState   | VoiceServerUpdate !VoiceServerUpdateData   | WebhooksUpdate !WebhooksUpdateData-  deriving ( Show, Generic, CtorName )+  deriving (Show, Generic, CtorName)  data ReadyData = ReadyData-  { v         :: Integer-  , user      :: User-  , guilds    :: [UnavailableGuild]+  { v :: Integer+  , user :: User+  , guilds :: [UnavailableGuild]   , sessionID :: Text   }-  deriving ( Show, Generic )-  deriving FromJSON via CalamityJSON ReadyData+  deriving (Show, Generic)+  deriving (FromJSON) via CalamityJSON ReadyData  data ChannelPinsUpdateData = ChannelPinsUpdateData-  { channelID        :: Snowflake Channel+  { channelID :: Snowflake Channel   , lastPinTimestamp :: Maybe UTCTime   }-  deriving ( Show, Generic )-  deriving FromJSON via CalamityJSON ChannelPinsUpdateData+  deriving (Show, Generic)+  deriving (FromJSON) via CalamityJSON ChannelPinsUpdateData  data GuildEmojisUpdateData = GuildEmojisUpdateData   { guildID :: Snowflake Guild-  , emojis  :: [Emoji]+  , emojis :: [Emoji]   }-  deriving ( Show, Generic )-  deriving FromJSON via CalamityJSON GuildEmojisUpdateData+  deriving (Show, Generic)+  deriving (FromJSON) via CalamityJSON GuildEmojisUpdateData  newtype GuildIntegrationsUpdateData = GuildIntegrationsUpdateData   { guildID :: Snowflake Guild   }-  deriving newtype ( Show, Generic )-  deriving FromJSON via CalamityJSON GuildIntegrationsUpdateData+  deriving newtype (Show, Generic)+  deriving (FromJSON) via CalamityJSON GuildIntegrationsUpdateData  data GuildMemberRemoveData = GuildMemberRemoveData   { guildID :: Snowflake Guild-  , user    :: User+  , user :: User   }-  deriving ( Show, Generic )-  deriving FromJSON via CalamityJSON GuildMemberRemoveData+  deriving (Show, Generic)+  deriving (FromJSON) via CalamityJSON GuildMemberRemoveData  data GuildMemberUpdateData = GuildMemberUpdateData-  { guildID  :: Snowflake Guild-  , roles    :: Vector (Snowflake Role)-  , user     :: User-  , nick     :: Maybe Text+  { guildID :: Snowflake Guild+  , roles :: Vector (Snowflake Role)+  , user :: User+  , nick :: Maybe Text   }-  deriving ( Show, Generic )-  deriving FromJSON via CalamityJSON GuildMemberUpdateData+  deriving (Show, Generic)+  deriving (FromJSON) via CalamityJSON GuildMemberUpdateData  data GuildMembersChunkData = GuildMembersChunkData   { guildID :: Snowflake Guild   , members :: [Member]   }-  deriving ( Show, Generic )+  deriving (Show, Generic)  instance FromJSON GuildMembersChunkData where   parseJSON = withObject "GuildMembersChunkData" $ \v -> do@@ -138,73 +142,75 @@  data GuildRoleData = GuildRoleData   { guildID :: Snowflake Guild-  , role    :: Role+  , role :: Role   }-  deriving ( Show, Generic )-  deriving FromJSON via CalamityJSON GuildRoleData+  deriving (Show, Generic)+  deriving (FromJSON) via CalamityJSON GuildRoleData  data GuildRoleDeleteData = GuildRoleDeleteData   { guildID :: Snowflake Guild-  , roleID  :: Snowflake Role+  , roleID :: Snowflake Role   }-  deriving ( Show, Generic )-  deriving FromJSON via CalamityJSON GuildRoleDeleteData+  deriving (Show, Generic)+  deriving (FromJSON) via CalamityJSON GuildRoleDeleteData  data InviteCreateData = InviteCreateData-  { channelID      :: Snowflake Channel-  , code           :: Text-  , createdAt      :: UTCTime-  , guildID        :: Maybe (Snowflake Guild)-  , inviter        :: Maybe (Snowflake User)-  , maxAge         :: Int-  , maxUses        :: Int-  , targetUser     :: Maybe (Snowflake User)+  { channelID :: Snowflake Channel+  , code :: Text+  , createdAt :: UTCTime+  , guildID :: Maybe (Snowflake Guild)+  , inviter :: Maybe (Snowflake User)+  , maxAge :: Int+  , maxUses :: Int+  , targetUser :: Maybe (Snowflake User)   , targetUserType :: Maybe Integer-  , temporary      :: Bool-  , uses           :: Integer+  , temporary :: Bool+  , uses :: Integer   }-  deriving ( Show, Generic )-  deriving ( FromJSON ) via WithSpecialCases-      '["inviter" `ExtractFieldFrom` "id", "targetUser" `ExtractFieldFrom` "id"]-      InviteCreateData+  deriving (Show, Generic)+  deriving+    (FromJSON)+    via WithSpecialCases+          '["inviter" `ExtractFieldFrom` "id", "targetUser" `ExtractFieldFrom` "id"]+          InviteCreateData  data InviteDeleteData = InviteDeleteData   { channelID :: Snowflake Channel-  , guildID   :: Maybe (Snowflake Guild)-  , code      :: Text+  , guildID :: Maybe (Snowflake Guild)+  , code :: Text   }-  deriving ( Show, Generic )-  deriving ( FromJSON ) via CalamityJSON InviteDeleteData+  deriving (Show, Generic)+  deriving (FromJSON) via CalamityJSON InviteDeleteData  data MessageDeleteData = MessageDeleteData-  { id        :: Snowflake Message+  { id :: Snowflake Message   , channelID :: Snowflake Channel-  , guildID   :: Snowflake Guild+  , guildID :: Snowflake Guild   }-  deriving ( Show, Generic )-  deriving FromJSON via CalamityJSON MessageDeleteData+  deriving (Show, Generic)+  deriving (FromJSON) via CalamityJSON MessageDeleteData  data MessageDeleteBulkData = MessageDeleteBulkData-  { guildID   :: Snowflake Guild+  { guildID :: Snowflake Guild   , channelID :: Snowflake Channel-  , ids       :: [Snowflake Message]+  , ids :: [Snowflake Message]   }-  deriving ( Show, Generic )-  deriving FromJSON via CalamityJSON MessageDeleteBulkData+  deriving (Show, Generic)+  deriving (FromJSON) via CalamityJSON MessageDeleteBulkData  data MessageReactionRemoveAllData = MessageReactionRemoveAllData   { channelID :: Snowflake Channel   , messageID :: Snowflake Message-  , guildID   :: Maybe (Snowflake Guild)+  , guildID :: Maybe (Snowflake Guild)   }-  deriving ( Show, Generic )-  deriving FromJSON via CalamityJSON MessageReactionRemoveAllData+  deriving (Show, Generic)+  deriving (FromJSON) via CalamityJSON MessageReactionRemoveAllData  data PresenceUpdateData = PresenceUpdateData-  { userID   :: Snowflake User+  { userID :: Snowflake User   , presence :: Presence   }-  deriving ( Show, Generic )+  deriving (Show, Generic)  instance FromJSON PresenceUpdateData where   parseJSON = withObject "PresenceUpdate" $ \v -> do@@ -214,17 +220,30 @@  data TypingStartData = TypingStartData   { channelID :: Snowflake Channel-  , guildID   :: Maybe (Snowflake Guild)-  , userID    :: Snowflake User+  , guildID :: Maybe (Snowflake Guild)+  , userID :: Snowflake User   , timestamp :: UnixTimestamp   }-  deriving ( Show, Generic )-  deriving FromJSON via CalamityJSON TypingStartData+  deriving (Show, Generic)+  deriving (FromJSON) via CalamityJSON TypingStartData  newtype VoiceServerUpdateData = VoiceServerUpdateData Value-  deriving newtype ( Show, Generic )-  deriving newtype ( ToJSON, FromJSON )+  deriving newtype (Show, Generic)+  deriving newtype (ToJSON, FromJSON)  newtype WebhooksUpdateData = WebhooksUpdateData Value-  deriving newtype ( Show, Generic )-  deriving newtype ( ToJSON, FromJSON )+  deriving newtype (Show, Generic)+  deriving newtype (ToJSON, FromJSON)++data ReactionEvtData = ReactionEvtData+  { userID :: Snowflake User+  , channelID :: Snowflake Channel+  , messageID :: Snowflake Message+  , guildID :: Maybe (Snowflake Guild)+  , emoji :: RawEmoji+  }+  deriving (Eq, Show, Generic)+  deriving (ToJSON, FromJSON) via CalamityJSON ReactionEvtData+  deriving (HasID User) via HasIDField "userID" ReactionEvtData+  deriving (HasID Channel) via HasIDField "channelID" ReactionEvtData+  deriving (HasID Message) via HasIDField "messageID" ReactionEvtData
Calamity/HTTP/AuditLog.hs view
@@ -17,8 +17,6 @@  import GHC.Generics -import TextShow (showt)- data GetAuditLogOptions = GetAuditLogOptions   { userID :: Maybe (Snowflake User)   , actionType :: Maybe AuditLogAction@@ -40,8 +38,8 @@    action (GetAuditLog _ GetAuditLogOptions{userID, actionType, before, limit}) =     getWithP-      ( "user_id" =:? (showt <$> userID)-          <> "action_type" =:? (showt . fromEnum <$> actionType)-          <> "before" =:? (showt <$> before)-          <> "limit" =:? (showt <$> limit)+      ( "user_id" =:? (fromSnowflake <$> userID)+          <> "action_type" =:? (fromEnum <$> actionType)+          <> "before" =:? (fromSnowflake <$> before)+          <> "limit" =:? limit       )
Calamity/HTTP/Channel.hs view
@@ -301,22 +301,22 @@   action (GetChannel _) = getWith   action (ModifyChannel _ p) = putWith' (ReqBodyJson p)   action (DeleteChannel _) = deleteWith-  action (GetChannelMessages _ (Just (ChannelMessagesAround (showt . fromSnowflake -> a))) l) =-    getWithP ("around" =: a <> "limit" =:? (showt . (^. #limit) <$> l))-  action (GetChannelMessages _ (Just (ChannelMessagesBefore (showt . fromSnowflake -> a))) l) =-    getWithP ("before" =: a <> "limit" =:? (showt . (^. #limit) <$> l))-  action (GetChannelMessages _ (Just (ChannelMessagesAfter (showt . fromSnowflake -> a))) l) =-    getWithP ("after" =: a <> "limit" =:? (showt . (^. #limit) <$> l))-  action (GetChannelMessages _ Nothing l) = getWithP ("limit" =:? (showt . (^. #limit) <$> l))+  action (GetChannelMessages _ (Just (ChannelMessagesAround (fromSnowflake -> a))) l) =+    getWithP ("around" =: a <> "limit" =:? (l ^? _Just . #limit))+  action (GetChannelMessages _ (Just (ChannelMessagesBefore (fromSnowflake -> a))) l) =+    getWithP ("before" =: a <> "limit" =:? (l ^? _Just . #limit))+  action (GetChannelMessages _ (Just (ChannelMessagesAfter (fromSnowflake -> a))) l) =+    getWithP ("after" =: a <> "limit" =:? (l ^? _Just . #limit))+  action (GetChannelMessages _ Nothing l) = getWithP ("limit" =:? (l ^? _Just . #limit))   action (GetMessage _ _) = getWith   action CreateReaction{} = putEmpty   action DeleteOwnReaction{} = deleteWith   action DeleteUserReaction{} = deleteWith   action (GetReactions _ _ _ GetReactionsOptions{before, after, limit}) =     getWithP-      ( "before" =:? (showt <$> before)-          <> "after" =:? (showt <$> after)-          <> "limit" =:? (showt <$> limit)+      ( "before" =:? (fromSnowflake <$> before)+          <> "after" =:? (fromSnowflake <$> after)+          <> "limit" =:? limit       )   action (DeleteAllReactions _ _) = deleteWith   action (EditMessage _ _ o) = patchWith' (ReqBodyJson o)
Calamity/HTTP/Guild.hs view
@@ -328,7 +328,7 @@   action (GetGuildMember _ _) = getWith   action (ListGuildMembers _ ListMembersOptions{limit, after}) =     getWithP-      ("limit" =:? (showt <$> limit) <> "after" =:? (showt <$> after))+      ("limit" =:? limit <> "after" =:? (fromSnowflake <$> after))   action (AddGuildMember _ _ o) = putWith' (ReqBodyJson o)   action (ModifyGuildMember _ _ o) = patchWith' (ReqBodyJson o)   action (ModifyCurrentUserNick _ nick) = patchWith' (ReqBodyJson $ object ["nick" .= nick])@@ -339,7 +339,7 @@   action (GetGuildBan _ _) = getWith   action (CreateGuildBan _ _ CreateGuildBanData{deleteMessageDays, reason}) =     putEmptyP-      ("delete-message-days" =:? (showt <$> deleteMessageDays) <> "reason" =:? (showt <$> reason))+      ("delete-message-days" =:? deleteMessageDays <> "reason" =:? reason)   action (RemoveGuildBan _ _) = deleteWith   action (GetGuildRoles _) = getWith   action (CreateGuildRole _ o) = postWith' (ReqBodyJson o)
Calamity/HTTP/Internal/Request.hs view
@@ -35,6 +35,7 @@ import DiPolysemy hiding (debug, error, info)  import Network.HTTP.Req+import Web.HttpApiData  import Polysemy (Sem) import qualified Polysemy as P@@ -140,6 +141,6 @@ deleteWith :: Url 'Https -> Option 'Https -> Req LbsResponse deleteWith u = req DELETE u NoReqBody lbsResponse -(=:?) :: T.Text -> Maybe T.Text -> Option 'Https+(=:?) :: ToHttpApiData a => T.Text -> Maybe a -> Option 'Https n =:? (Just x) = n =: x n =:? Nothing = mempty
Calamity/HTTP/User.hs view
@@ -23,8 +23,6 @@  import Network.HTTP.Req -import TextShow- data ModifyUserData = ModifyUserData   { username :: Maybe Text   , -- | The avatar field should be in discord's image data format: https://discord.com/developers/docs/reference#image-data@@ -80,8 +78,8 @@   action (ModifyCurrentUser o) = patchWith' $ ReqBodyJson o   action (GetCurrentUserGuilds GetCurrentUserGuildsOptions{before, after, limit}) =     getWithP-      ( "before" =:? (showt <$> before) <> "after" =:? (showt <$> after)-          <> "limit" =:? (showt <$> limit)+      ( "before" =:? (fromSnowflake <$> before) <> "after" =:? (fromSnowflake <$> after)+          <> "limit" =:? limit       )   action (LeaveGuild _) = deleteWith   action (CreateDM (getID @User -> uid)) = postWith' $ ReqBodyJson (object ["recipient_id" .= uid])
Calamity/HTTP/Webhook.hs view
@@ -26,7 +26,6 @@ import Network.HTTP.Req  import Network.HTTP.Client.MultipartFormData-import TextShow  data CreateWebhookData = CreateWebhookData   { username :: Maybe Text@@ -130,7 +129,7 @@   action (ExecuteWebhook _ _ o@ExecuteWebhookOptions{file = Nothing}) =     postWithP'       (ReqBodyJson . upcast @ExecuteWebhookJson $ o)-      ("wait" =:? (showt <$> o ^. #wait))+      ("wait" =:? (o ^. #wait))   action (ExecuteWebhook _ _ wh@ExecuteWebhookOptions{file = Just f}) = \u o -> do     body <- reqBodyMultipart [partLBS @IO "file" f, partLBS "payload_json" (encode . upcast @ExecuteWebhookJson $ wh)]-    postWithP' body ("wait" =:? (showt <$> wh ^. #wait)) u o+    postWithP' body ("wait" =:? (wh ^. #wait)) u o
Calamity/Types/Model/Channel/Reaction.hs view
@@ -1,32 +1,21 @@ -- | Message reactions-module Calamity.Types.Model.Channel.Reaction-    ( Reaction(..) ) where+module Calamity.Types.Model.Channel.Reaction (Reaction (..)) where -import           Calamity.Internal.AesonThings-import {-# SOURCE #-} Calamity.Types.Model.Channel-import {-# SOURCE #-} Calamity.Types.Model.Channel.Message-import           Calamity.Types.Model.Guild.Emoji-import {-# SOURCE #-} Calamity.Types.Model.Guild.Guild-import           Calamity.Types.Model.User-import           Calamity.Types.Snowflake+import Calamity.Internal.AesonThings+import Calamity.Types.Model.Guild.Emoji -import           Data.Aeson+import Data.Aeson -import           GHC.Generics+import GHC.Generics -import           TextShow-import qualified TextShow.Generic                     as TSG+import TextShow+import qualified TextShow.Generic as TSG  data Reaction = Reaction-  { userID    :: Snowflake User-  , channelID :: Snowflake Channel-  , messageID :: Snowflake Message-  , guildID   :: Maybe (Snowflake Guild)-  , emoji     :: RawEmoji+  { count :: Integer+  , me :: Bool+  , emoji :: RawEmoji   }-  deriving ( Eq, Show, Generic )-  deriving ( TextShow ) via TSG.FromGeneric Reaction-  deriving ( ToJSON, FromJSON ) via CalamityJSON Reaction-  deriving ( HasID User ) via HasIDField "userID" Reaction-  deriving ( HasID Channel ) via HasIDField "channelID" Reaction-  deriving ( HasID Message ) via HasIDField "messageID" Reaction+  deriving (Eq, Show, Generic)+  deriving (TextShow) via TSG.FromGeneric Reaction+  deriving (ToJSON, FromJSON) via CalamityJSON Reaction
Calamity/Types/Model/Guild/Guild.hs view
@@ -20,6 +20,8 @@ import Control.DeepSeq import Control.Lens ((^.)) import Data.Aeson+import Data.Aeson.Types+import Data.Maybe import Data.Generics.Product.Fields import Data.HashMap.Strict (HashMap) import qualified Data.HashMap.Strict as LH@@ -72,23 +74,22 @@   parseJSON = withObject "Guild" $ \v -> do     id <- v .: "id" +    -- sadly we have now way of logging members/channels/presences' that failed to parser here     members' <- do       members' <- v .: "members"-      SM.fromList <$> traverse (\m -> parseJSON $ Object (m <> "guild_id" .= id)) members'+      pure . SM.fromList . mapMaybe (parseMaybe @Object @Member (\m -> parseJSON $ Object (m <> "guild_id" .= id))) $ members'      channels' <- do       channels' <- v .: "channels"-      SM.fromList <$> traverse (\m -> parseJSON $ Object (m <> "guild_id" .= id)) channels'+      pure . SM.fromList . mapMaybe (parseMaybe @Object @GuildChannel (\m -> parseJSON $ Object (m <> "guild_id" .= id))) $ channels'      presences' <- do       presences' <- v .: "presences"-      LH.fromList-        <$> traverse+      pure . LH.fromList . mapMaybe (parseMaybe @Object @(Snowflake User, Presence)           ( \m -> do               p <- parseJSON $ Object (m <> "guild_id" .= id)               pure (getID $ p ^. field @"user", p)-          )-          presences'+          )) $ presences'      Guild id       <$> v .: "name"
ChangeLog.md view
@@ -1,5 +1,18 @@ # Changelog for Calamity +## 0.1.27.0+++ Change the structure of `Reaction` to be `(count, me, emoji)`++ The previous structure of `Reaction` is now known as `ReactionEvtData`++ The type of `MessageReactionAddEvt` and `MessageReactionRemoveEvt` events has+  been changed from `(Message, Reaction)` to `(Message, User, Channel,+  RawEmoji)`++ The type of `RawMessageReactionAddEvt` and `RawMessageReactionRemoveEvt`+  events has been changed from `Reaction` to `ReactionEvtData`++ More fixes to HTTP++ When parsing guilds, channels/members/ and presences that cannot be parsed are+  (silently) ignored instead of causing parsing of the guild to fail.+ ## 0.1.26.1  + Quick fix of GetChannelMessages
calamity.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: fd4324b88c3e1af82980462b807e21231e704910a8187311dbb902ed02735a29+-- hash: 40f996e3e284d2ed02f53b7bd8da0fa83fe1e3c156c0d0f71a46cc4afab91437  name:           calamity-version:        0.1.26.1+version:        0.1.27.0 synopsis:       A library for writing discord bots in haskell description:    Please see the README on GitHub at <https://github.com/simmsb/calamity#readme> category:       Network, Web@@ -156,6 +156,7 @@     , focus >=1.0 && <2     , generic-lens >=2.0 && <3     , hashable >=1.2 && <2+    , http-api-data >=0.4.3 && <0.5     , http-client >=0.5 && <0.8     , http-date >=0.0.8 && <0.1     , http-types >=0.12 && <0.13