glyde/event
Gateway dispatch events, decoded.
decode is total: an unmodelled name, or a payload that did not fit, comes
back as Raw with d untouched, so a host’s case needs no error arm.
dispatch is the same decode with the outcome kept apart, which is how
glyde’s own schema drift is told from an event it never modelled.
The payload records and their decoders live in glyde/event/*, one module
per family. This module is the sum type and the table that routes to them.
Types
pub type Dispatch {
Dispatch(name: String, data: dynamic.Dynamic, outcome: Outcome)
}
Constructors
-
Dispatch(name: String, data: dynamic.Dynamic, outcome: Outcome)Arguments
- data
-
dexactly as it arrived, the hatch for anything glyde does not model.
One decoded dispatch.
pub type Event {
ReadyEvent(ready.Ready)
ResumedEvent
RateLimitedEvent(session.RateLimited)
GuildCreateAvailable(guild: guild.Guild)
GuildCreateUnavailable(id: id.Id(id.Guild))
GuildUpdate(guild: guild.Guild)
GuildUnavailable(id: id.Id(id.Guild))
GuildRemoved(id: id.Id(id.Guild))
GuildMemberAdd(
guild_id: id.Id(id.Guild),
member: member.GuildMember,
)
GuildMemberRemove(guild_id: id.Id(id.Guild), user: user.User)
GuildMemberUpdate(
guild_id: id.Id(id.Guild),
member: member.GuildMember,
)
GuildMembersChunk(guilds.MembersChunk)
GuildRoleCreate(guild_id: id.Id(id.Guild), role: role.Role)
GuildRoleUpdate(guild_id: id.Id(id.Guild), role: role.Role)
GuildRoleDelete(
guild_id: id.Id(id.Guild),
role_id: id.Id(id.Role),
)
GuildBanAdd(guild_id: id.Id(id.Guild), user: user.User)
GuildBanRemove(guild_id: id.Id(id.Guild), user: user.User)
GuildEmojisUpdate(
guild_id: id.Id(id.Guild),
emojis: List(emoji.GuildEmoji),
)
ChannelCreate(channel: channel.Channel)
ChannelUpdate(channel: channel.Channel)
ChannelDelete(channel: channel.Channel)
ChannelPinsUpdate(
guild_id: option.Option(id.Id(id.Guild)),
channel_id: id.Id(id.Channel),
last_pin_timestamp: option.Option(String),
)
ThreadCreate(channel: channel.Channel)
ThreadUpdate(channel: channel.Channel)
ThreadDelete(
id: id.Id(id.Channel),
guild_id: id.Id(id.Guild),
parent_id: option.Option(id.Id(id.Channel)),
type_: channel.ChannelType,
)
MessageCreate(message: message.Message)
MessageUpdate(message: message.MessageUpdate)
MessageDelete(
id: id.Id(id.Message),
channel_id: id.Id(id.Channel),
guild_id: option.Option(id.Id(id.Guild)),
)
MessageDeleteBulk(
ids: List(id.Id(id.Message)),
channel_id: id.Id(id.Channel),
guild_id: option.Option(id.Id(id.Guild)),
)
MessageReactionAdd(messages.ReactionAdd)
MessageReactionRemove(messages.ReactionRemove)
MessageReactionRemoveAll(
channel_id: id.Id(id.Channel),
message_id: id.Id(id.Message),
guild_id: option.Option(id.Id(id.Guild)),
)
MessageReactionRemoveEmoji(
channel_id: id.Id(id.Channel),
message_id: id.Id(id.Message),
guild_id: option.Option(id.Id(id.Guild)),
emoji: emoji.Emoji,
)
InteractionCreate(interaction: interaction.Interaction)
TypingStartEvent(presence.TypingStart)
UserUpdate(user: user.User)
VoiceStateUpdate(voice_state.VoiceState)
VoiceServerUpdate(
token: String,
guild_id: id.Id(id.Guild),
endpoint: option.Option(String),
)
Raw(name: String, data: dynamic.Dynamic)
}
Constructors
-
ReadyEvent(ready.Ready)READY. The handshake reads
session_idandresume_gateway_urlout of this samed, so a decoder bug here cannot cost a session. -
ResumedEventRESUMED. Replay is finished and everything after this is new.
dis{"_trace":[…]}, Discord’s own routing breadcrumb. -
RateLimitedEvent(session.RateLimited)RATE_LIMITED. A dispatch, not an opcode: it arrives with
"op":0and advances the sequence, so a client switching onopnever sees it. -
GuildCreateAvailable(guild: guild.Guild)GUILD_CREATE for a guild that is up. Sent on connect for every guild the bot is in, then again whenever it joins one.
-
GUILD_CREATE for a guild that is still down. Two keys, no more.
-
GuildUpdate(guild: guild.Guild) -
GUILD_DELETE during a Discord outage. Still the bot’s guild, and it comes back as a GUILD_CREATE. Do not evict it from a cache.
-
GUILD_DELETE because the bot was kicked or banned, or the guild was deleted. This one is permanent.
-
GuildMemberAdd( guild_id: id.Id(id.Guild), member: member.GuildMember, )dis the member object with an extraguild_id, which is why the id sits beside the member rather than inside it. -
-
GuildMemberUpdate( guild_id: id.Id(id.Guild), member: member.GuildMember, )A partial member:
deaf,muteandflagscan be missing despite the docs. Privileged behindGuildMembers, bar the bot’s own member. -
GuildMembersChunk(guilds.MembersChunk)The answer to REQUEST_GUILD_MEMBERS, at most 1000 members per chunk.
-
-
-
-
Needs
GuildModerationplus either BAN_MEMBERS or VIEW_AUDIT_LOG. -
-
GuildEmojisUpdate( guild_id: id.Id(id.Guild), emojis: List(emoji.GuildEmoji), )emojisis the guild’s whole list, never a delta. Replace, do not merge: a deleted emoji is only ever signalled by its absence here. -
ChannelCreate(channel: channel.Channel) -
ChannelUpdate(channel: channel.Channel) -
ChannelDelete(channel: channel.Channel) -
ChannelPinsUpdate( guild_id: option.Option(id.Id(id.Guild)), channel_id: id.Id(id.Channel), last_pin_timestamp: option.Option(String), )last_pin_timestampis ISO-8601, andNoneonce the last pin is removed. The event does not say which message was pinned. -
ThreadCreate(channel: channel.Channel)channelcarriesnewly_created, which tells a thread opened on a brand new message from one opened on an old one. -
ThreadUpdate(channel: channel.Channel) -
ThreadDelete( id: id.Id(id.Channel), guild_id: id.Id(id.Guild), parent_id: option.Option(id.Id(id.Channel)), type_: channel.ChannelType, )Four keys and no more. It looks like a channel and is not one, and the channel decoder would accept it: a channel needs only
idandtype. -
MessageCreate(message: message.Message)Without
MessageContent,content,embeds,attachmentsandcomponentsare empty unless the message mentions the bot or is a DM. -
MessageUpdate(message: message.MessageUpdate)Not a
Message. Discord sends only what changed, so everything butidandchannel_idis optional: an embed-only edit has no author. -
MessageDelete( id: id.Id(id.Message), channel_id: id.Id(id.Channel), guild_id: option.Option(id.Id(id.Guild)), ) -
MessageDeleteBulk( ids: List(id.Id(id.Message)), channel_id: id.Id(id.Channel), guild_id: option.Option(id.Id(id.Guild)), )Guild channels only. Discord does not list this one under DIRECT_MESSAGES, so a DM bot relying on it to clean up never gets it.
-
MessageReactionAdd(messages.ReactionAdd) -
MessageReactionRemove(messages.ReactionRemove)Not a mirror of the add. See
messages.ReactionRemove. -
MessageReactionRemoveAll( channel_id: id.Id(id.Channel), message_id: id.Id(id.Message), guild_id: option.Option(id.Id(id.Guild)), )Every reaction on the message is gone.
-
MessageReactionRemoveEmoji( channel_id: id.Id(id.Channel), message_id: id.Id(id.Message), guild_id: option.Option(id.Id(id.Guild)), emoji: emoji.Emoji, )Every reaction of one emoji is gone.
-
InteractionCreate(interaction: interaction.Interaction)Ungated: a bot with no intents still gets every interaction.
-
TypingStartEvent(presence.TypingStart) -
UserUpdate(user: user.User)The bot’s own user changed. Not sent for anyone else.
-
VoiceStateUpdate(voice_state.VoiceState)A null
channel_idon the state means the user left voice, and there is no separate event for that.voice_state.has_leftasks it directly. -
VoiceServerUpdate( token: String, guild_id: id.Id(id.Guild), endpoint: option.Option(String), )endpointisNonewhen the voice server went away. Disconnect and wait for the next one. Reconnecting to nothing loops. -
Raw(name: String, data: dynamic.Dynamic)A dispatch glyde did not model, or one whose
ddid not fit, withdintact.is_modelledtells those apart;dispatchgives the errors.
The three things one dispatch can be. Malformed is a glyde bug or a
Discord schema change: report it. Unmodelled is ordinary.
pub type Outcome {
Decoded(Event)
Unmodelled
Malformed(errors: List(decode.DecodeError))
}
Constructors
-
Decoded(Event) -
Unmodelled -
Malformed(errors: List(decode.DecodeError))
Values
pub fn dispatch(name: String, data: dynamic.Dynamic) -> Dispatch
Decode one dispatch, keeping d and saying which of the three happened.
Total.
pub fn is_modelled(name: String) -> Bool
The question to ask about a Raw: an unmodelled name is ordinary, a
modelled one that came back Raw is a payload that did not fit.