{-# LANGUAGE TemplateHaskell #-} -- | module containing all dispatch events module Calamity.Gateway.DispatchEvents where import Calamity.Internal.ConstructorName import Calamity.Internal.UnixTimestamp 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.Interaction import Calamity.Types.Model.Presence.Presence import Calamity.Types.Model.User import Calamity.Types.Model.Voice import Calamity.Types.Snowflake import Data.Aeson ((.:), (.:?)) import Data.Aeson qualified as Aeson import Data.Kind (Type) import Data.Text (Text) import Data.Time import Data.Typeable (Typeable) import GHC.Generics import Optics.TH data CalamityEvent = Dispatch -- | The shard that pushed this event Int -- | The attached data DispatchData | -- | The data sent to the custom event forall (a :: Type). (Typeable a) => Custom a | ShutDown data DispatchData = Ready !ReadyData | Resumed | ChannelCreate !Channel | ChannelUpdate !Channel | ChannelDelete !Channel | ChannelPinsUpdate !ChannelPinsUpdateData | GuildCreate !Guild | GuildUpdate !UpdatedGuild | GuildDelete !UnavailableGuild | GuildBanAdd !BanData | GuildBanRemove !BanData | GuildEmojisUpdate !GuildEmojisUpdateData | GuildIntegrationsUpdate !GuildIntegrationsUpdateData | GuildMemberAdd !(Snowflake Guild) !Member | GuildMemberRemove !GuildMemberRemoveData | GuildMemberUpdate !GuildMemberUpdateData | GuildMembersChunk !GuildMembersChunkData | GuildRoleCreate !GuildRoleData | GuildRoleUpdate !GuildRoleData | GuildRoleDelete !GuildRoleDeleteData | InviteCreate !InviteCreateData | InviteDelete !InviteDeleteData | MessageCreate !Message !(Maybe User) !(Maybe Member) | MessageUpdate !UpdatedMessage !(Maybe User) !(Maybe Member) | MessageDelete !MessageDeleteData | MessageDeleteBulk !MessageDeleteBulkData | MessageReactionAdd !ReactionEvtData | MessageReactionRemove !ReactionEvtData | MessageReactionRemoveAll !MessageReactionRemoveAllData | PresenceUpdate !PresenceUpdateData | TypingStart !TypingStartData | UserUpdate !User | VoiceStateUpdate !VoiceState | VoiceServerUpdate !VoiceServerUpdateData | WebhooksUpdate !WebhooksUpdateData | InteractionCreate !Interaction | UNHANDLED Text deriving (Show, Generic, CtorName) data ReadyData = ReadyData { v :: Integer , user :: User , guilds :: [UnavailableGuild] , sessionID :: Text } deriving (Show) instance Aeson.FromJSON ReadyData where parseJSON = Aeson.withObject "ReadyData" $ \v -> ReadyData <$> v .: "v" <*> v .: "user" <*> v .: "guilds" <*> v .: "session_id" data ChannelPinsUpdateData = ChannelPinsUpdateData { channelID :: Snowflake Channel , lastPinTimestamp :: Maybe UTCTime } deriving (Show) instance Aeson.FromJSON ChannelPinsUpdateData where parseJSON = Aeson.withObject "ChannelPinsUpdateData" $ \v -> ChannelPinsUpdateData <$> v .: "channel_id" <*> v .: "last_pin_timestamp" data GuildEmojisUpdateData = GuildEmojisUpdateData { guildID :: Snowflake Guild , emojis :: [Emoji] } deriving (Show) instance Aeson.FromJSON GuildEmojisUpdateData where parseJSON = Aeson.withObject "GuildEmojisUpdateData" $ \v -> GuildEmojisUpdateData <$> v .: "guild_id" <*> v .: "emojis" newtype GuildIntegrationsUpdateData = GuildIntegrationsUpdateData { guildID :: Snowflake Guild } deriving stock (Show) instance Aeson.FromJSON GuildIntegrationsUpdateData where parseJSON = Aeson.withObject "GuildIntegrationsUpdateData" $ \v -> GuildIntegrationsUpdateData <$> v .: "guild_id" data GuildMemberRemoveData = GuildMemberRemoveData { guildID :: Snowflake Guild , user :: User } deriving (Show) instance Aeson.FromJSON GuildMemberRemoveData where parseJSON = Aeson.withObject "GuildMemberRemoveData" $ \v -> GuildMemberRemoveData <$> v .: "guild_id" <*> v .: "user" data GuildMemberUpdateData = GuildMemberUpdateData { guildID :: Snowflake Guild , roles :: AesonVector (Snowflake Role) , user :: User , nick :: Maybe Text } deriving (Show) instance Aeson.FromJSON GuildMemberUpdateData where parseJSON = Aeson.withObject "GuildMemberUpdateData" $ \v -> GuildMemberUpdateData <$> v .: "guild_id" <*> v .: "roles" <*> v .: "user" <*> v .:? "nick" data GuildMembersChunkData = GuildMembersChunkData { guildID :: Snowflake Guild , members :: [Member] } deriving (Show) instance Aeson.FromJSON GuildMembersChunkData where parseJSON = Aeson.withObject "GuildMembersChunkData" $ \v -> do guildID <- v Aeson..: "guild_id" members' <- do members' <- v Aeson..: "members" traverse (Aeson.parseJSON . Aeson.Object) members' pure $ GuildMembersChunkData guildID members' data GuildRoleData = GuildRoleData { guildID :: Snowflake Guild , role :: Role } deriving (Show) instance Aeson.FromJSON GuildRoleData where parseJSON = Aeson.withObject "GuildRoleData" $ \v -> GuildRoleData <$> v .: "guild_id" <*> v .: "role" data GuildRoleDeleteData = GuildRoleDeleteData { guildID :: Snowflake Guild , roleID :: Snowflake Role } deriving (Show) instance Aeson.FromJSON GuildRoleDeleteData where parseJSON = Aeson.withObject "GuildRoleDeleteData" $ \v -> GuildRoleDeleteData <$> v .: "guild_id" <*> v .: "role_id" 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) , targetUserType :: Maybe Integer , temporary :: Bool , uses :: Integer } deriving (Show) instance Aeson.FromJSON InviteCreateData where parseJSON = Aeson.withObject "InviteCreateData" $ \v -> do let inviter = (v .:? "inviter") >>= traverse (.: "id") targetUser = (v .:? "target_user") >>= traverse (.: "id") InviteCreateData <$> v .: "channel_id" <*> v .: "code" <*> v .: "created_at" <*> v .:? "guild_id" <*> inviter <*> v .: "max_age" <*> v .: "max_uses" <*> targetUser <*> v .:? "target_user_type" <*> v .: "temporary" <*> v .: "uses" data InviteDeleteData = InviteDeleteData { channelID :: Snowflake Channel , guildID :: Maybe (Snowflake Guild) , code :: Text } deriving (Show) instance Aeson.FromJSON InviteDeleteData where parseJSON = Aeson.withObject "InviteDeleteData" $ \v -> InviteDeleteData <$> v .: "channel_id" <*> v .:? "guild_id" <*> v .: "code" data MessageDeleteData = MessageDeleteData { id :: Snowflake Message , channelID :: Snowflake Channel , guildID :: Snowflake Guild } deriving (Show) instance Aeson.FromJSON MessageDeleteData where parseJSON = Aeson.withObject "MessageDeleteData" $ \v -> MessageDeleteData <$> v .: "id" <*> v .: "channel_id" <*> v .: "guild_id" data MessageDeleteBulkData = MessageDeleteBulkData { guildID :: Snowflake Guild , channelID :: Snowflake Channel , ids :: [Snowflake Message] } deriving (Show) instance Aeson.FromJSON MessageDeleteBulkData where parseJSON = Aeson.withObject "MessageDeleteBulkData" $ \v -> MessageDeleteBulkData <$> v .: "guild_id" <*> v .: "channel_id" <*> v .: "ids" data MessageReactionRemoveAllData = MessageReactionRemoveAllData { channelID :: Snowflake Channel , messageID :: Snowflake Message , guildID :: Maybe (Snowflake Guild) } deriving (Show) instance Aeson.FromJSON MessageReactionRemoveAllData where parseJSON = Aeson.withObject "MessageReactionRemoveAllData" $ \v -> MessageReactionRemoveAllData <$> v .: "channel_id" <*> v .: "message_id" <*> v .: "guild_id" data PresenceUpdateData = PresenceUpdateData { userID :: Snowflake User , presence :: Presence } deriving (Show) instance Aeson.FromJSON PresenceUpdateData where parseJSON = Aeson.withObject "PresenceUpdate" $ \v -> do user <- (v Aeson..: "user") >>= (Aeson..: "id") presence <- Aeson.parseJSON $ Aeson.Object v pure $ PresenceUpdateData user presence data TypingStartData = TypingStartData { channelID :: Snowflake Channel , guildID :: Maybe (Snowflake Guild) , userID :: Snowflake User , timestamp :: UnixTimestamp } deriving (Show) instance Aeson.FromJSON TypingStartData where parseJSON = Aeson.withObject "TypingStartData" $ \v -> TypingStartData <$> v .: "channel_id" <*> v .: "guild_id" <*> v .: "user_id" <*> v .: "timestamp" newtype VoiceServerUpdateData = VoiceServerUpdateData Aeson.Value deriving stock (Show) deriving newtype (Aeson.ToJSON, Aeson.FromJSON) newtype WebhooksUpdateData = WebhooksUpdateData Aeson.Value deriving stock (Show) deriving newtype (Aeson.ToJSON, Aeson.FromJSON) data ReactionEvtData = ReactionEvtData { userID :: Snowflake User , channelID :: Snowflake Channel , messageID :: Snowflake Message , guildID :: Maybe (Snowflake Guild) , emoji :: RawEmoji } deriving (Eq, Show) deriving (HasID User) via HasIDField "userID" ReactionEvtData deriving (HasID Channel) via HasIDField "channelID" ReactionEvtData deriving (HasID Message) via HasIDField "messageID" ReactionEvtData instance Aeson.FromJSON ReactionEvtData where parseJSON = Aeson.withObject "ReactionEvtData" $ \v -> ReactionEvtData <$> v .: "user_id" <*> v .: "channel_id" <*> v .: "message_id" <*> v .: "guild_id" <*> v .: "emoji" $(makeFieldLabelsNoPrefix ''ReadyData) $(makeFieldLabelsNoPrefix ''ReactionEvtData)