From d34a1a52ff17fe3235b9dcfc65c3cc86522e8574 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Mon, 29 Mar 2021 00:11:41 +0200 Subject: [PATCH 01/65] changed testbot back to gateway interactions & fixed typo in endpoints --- api/endpoints/endpoints.go | 2 +- testbot/testbot.go | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/api/endpoints/endpoints.go b/api/endpoints/endpoints.go index ac61ca2c..264458cd 100644 --- a/api/endpoints/endpoints.go +++ b/api/endpoints/endpoints.go @@ -46,7 +46,7 @@ var ( GetUser = NewAPIRoute(GET, "/users/{user.id}") GetSelfUser = NewAPIRoute(GET, "/users/@me") UpdateSelfUser = NewAPIRoute(PATCH, "/users/@me") - GetGuilds = NewAPIRoute(GET, "/users/@me/guilds/{guild.id}") + GetGuilds = NewAPIRoute(GET, "/users/@me/guilds") LeaveGuild = NewAPIRoute(DELETE, "/users/@me/guilds/{guild.id}") GetDMChannels = NewAPIRoute(GET, "/users/@me/channels") CreateDMChannel = NewAPIRoute(POST, "/users/@me/channels") diff --git a/testbot/testbot.go b/testbot/testbot.go index 5a6724ea..6beaaac5 100644 --- a/testbot/testbot.go +++ b/testbot/testbot.go @@ -15,13 +15,11 @@ import ( func main() { log.Infof("starting testbot...") token := os.Getenv("token") - publicKey := os.Getenv("public-key") dgo, err := disgo.NewBuilder(token). SetLogLevel(log.InfoLevel). SetIntents(api.IntentsGuilds|api.IntentsGuildMessages|api.IntentsGuildMembers). SetMemberCachePolicy(api.MemberCachePolicyAll). - SetWebhookServerProperties("/webhooks/interactions/callback", 80, publicKey). AddEventListeners(&events.ListenerAdapter{ OnGuildAvailable: guildAvailListener, OnGuildMessageReceived: messageListener, @@ -91,11 +89,6 @@ func main() { log.Errorf("error while registering guild commands: %s", err) } - err = dgo.Start() - if err != nil { - log.Fatalf("error while starting webhookserver: %s", err) - } - err = dgo.Connect() if err != nil { log.Fatalf("error while connecting to discord: %s", err) From 6bce01d47085aefa083affda6b2507c6326cf847 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Mon, 29 Mar 2021 00:54:21 +0200 Subject: [PATCH 02/65] added message edit, delete, crosspost, bulk-delete --- api/channels.go | 34 ++++++++++++-- api/message.go | 44 ++++++++++++++++--- api/{message_create.go => message_builder.go} | 9 ---- api/restclient.go | 5 +++ internal/restclient.go | 30 ++++++++++++- 5 files changed, 103 insertions(+), 19 deletions(-) rename api/{message_create.go => message_builder.go} (81%) diff --git a/api/channels.go b/api/channels.go index 529c2383..83a05d30 100644 --- a/api/channels.go +++ b/api/channels.go @@ -1,5 +1,7 @@ package api +import "errors" + // ChannelType for interacting with discord's channels type ChannelType int @@ -37,18 +39,42 @@ type Channel struct { //LastPinTimestamp *time.Time `json:"last_pin_timestamp,omitempty"` } -// MessageChannel is used for sending messages to user +// MessageChannel is used for sending Message(s) to User(s) type MessageChannel struct { Channel } -// SendMessage a Message to a TextChannel +// SendMessage sends a Message to a TextChannel func (c MessageChannel) SendMessage(message MessageCreate) (*Message, error) { - // Todo: embeds, attachments etc. + // Todo: attachments return c.Disgo.RestClient().SendMessage(c.ID, message) } -// DMChannel is used for interacting in private messages with users + +// EditMessage edits a Message in this TextChannel +func (c MessageChannel) EditMessage(messageID Snowflake, message MessageUpdate) (*Message, error) { + return c.Disgo.RestClient().EditMessage(c.ID, messageID, message) +} + +// DeleteMessage allows you to edit an existing Message sent by you +func (c MessageChannel) DeleteMessage(messageID Snowflake) error { + return c.Disgo.RestClient().DeleteMessage(c.ID, messageID) +} + +// DeleteMessage allows you bulk delete Message(s) +func (c MessageChannel) BulkDeleteMessages(messageIDs ...Snowflake) error { + return c.Disgo.RestClient().BulkDeleteMessages(c.ID, messageIDs...) +} + +// CrosspostMessage crossposts an existing Message +func (c MessageChannel) CrosspostMessage(messageID Snowflake) (*Message, error) { + if c.Type != ChannelTypeNews { + return nil, errors.New("channel type is not NEWS") + } + return c.Disgo.RestClient().CrosspostMessage(c.ID, messageID) +} + +// DMChannel is used for interacting in private Message(s) with users type DMChannel struct { MessageChannel Users []User `json:"recipients"` diff --git a/api/message.go b/api/message.go index 36cd9fcb..fb107339 100644 --- a/api/message.go +++ b/api/message.go @@ -1,6 +1,7 @@ package api import ( + "errors" "time" ) @@ -163,12 +164,31 @@ func (m Message) AddReaction(emoji string) error { return m.Disgo.RestClient().AddReaction(m.ChannelID, m.ID, emoji) } +// Edit allows you to edit an existing Message sent by you +func (m Message) Edit(message MessageUpdate) (*Message, error) { + return m.Disgo.RestClient().EditMessage(m.ChannelID, m.ID, message) +} + +// Delete allows you to edit an existing Message sent by you +func (m Message) Delete() error { + return m.Disgo.RestClient().DeleteMessage(m.ChannelID, m.ID) +} + +// Crosspost crossposts an existing message +func (m Message) Crosspost() (*Message, error) { + channel := m.Channel() + if channel != nil && channel.Type != ChannelTypeNews { + return nil, errors.New("channel type is not NEWS") + } + return m.Disgo.RestClient().CrosspostMessage(m.ChannelID, m.ID) +} + // Reply allows you to reply to an existing Message func (m Message) Reply(message MessageCreate) (*Message, error) { message.MessageReference = &MessageReference{ MessageID: &m.ID, } - return m.Channel().SendMessage(message) + return m.Disgo.RestClient().SendMessage(m.ChannelID, message) } // Reactions contains information about the reactions of a message_events @@ -178,10 +198,24 @@ type Reactions struct { Emoji Emote `json:"emoji"` } -// UpdateMessage is used to edit a message -type UpdateMessage struct { - Content *string `json:"content,omitempty"` +// MessageUpdate is used to edit a Message +type MessageUpdate struct { + Content string `json:"content,omitempty"` Embed *Embed `json:"embed,omitempty"` - Flags *MessageFlags `json:"flags,omitempty"` + Flags MessageFlags `json:"flags,omitempty"` AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` } + +// MessageCreate is the struct to create a new Message with +type MessageCreate struct { + Content string `json:"content,omitempty"` + TTS bool `json:"tts,omitempty"` + Embed *Embed `json:"embed,omitempty"` + AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` + MessageReference *MessageReference `json:"message_reference,omitempty"` +} + +// MessageBulkDelete is used to bulk delete Message(s) +type MessageBulkDelete struct { + Messages []Snowflake `json:"messages"` +} diff --git a/api/message_create.go b/api/message_builder.go similarity index 81% rename from api/message_create.go rename to api/message_builder.go index 217b1754..4a5616d7 100644 --- a/api/message_create.go +++ b/api/message_builder.go @@ -1,14 +1,5 @@ package api -// MessageCreate is the struct to create a new Message with -type MessageCreate struct { - Content string `json:"content,omitempty"` - TTS bool `json:"tts,omitempty"` - Embed *Embed `json:"embed,omitempty"` - AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` - MessageReference *MessageReference `json:"message_reference,omitempty"` -} - // MessageBuilder helper to build Message(s) easier type MessageBuilder struct { MessageCreate diff --git a/api/restclient.go b/api/restclient.go index 13acef68..70880083 100644 --- a/api/restclient.go +++ b/api/restclient.go @@ -24,6 +24,11 @@ type RestClient interface { Request(route endpoints.CompiledAPIRoute, rqBody interface{}, rsBody interface{}) error SendMessage(channelID Snowflake, message MessageCreate) (*Message, error) + EditMessage(channelID Snowflake, messageID Snowflake, message MessageUpdate) (*Message, error) + DeleteMessage(channelID Snowflake, messageID Snowflake) error + BulkDeleteMessages(channelID Snowflake, messageIDs ...Snowflake) error + CrosspostMessage(channelID Snowflake, messageID Snowflake) (*Message, error) + OpenDMChannel(userID Snowflake) (*DMChannel, error) UpdateSelfNick(guildID Snowflake, nick *string) (*string, error) diff --git a/internal/restclient.go b/internal/restclient.go index d6e763d6..a6d310ab 100644 --- a/internal/restclient.go +++ b/internal/restclient.go @@ -128,7 +128,7 @@ func (r RestClientImpl) Request(route endpoints.CompiledAPIRoute, rqBody interfa } } -// SendMessage lets you send a message_events to a channel +// SendMessage lets you send a api.Message to a api.MessageChannel func (r RestClientImpl) SendMessage(channelID api.Snowflake, message api.MessageCreate) (rMessage *api.Message, err error) { err = r.Request(endpoints.CreateMessage.Compile(channelID), message, &rMessage) if rMessage != nil { @@ -137,6 +137,34 @@ func (r RestClientImpl) SendMessage(channelID api.Snowflake, message api.Message return } +// EditMessage lets you edit a api.Message +func (r RestClientImpl) EditMessage(channelID api.Snowflake, messageID api.Snowflake, message api.MessageUpdate) (rMessage *api.Message, err error) { + err = r.Request(endpoints.UpdateMessage.Compile(channelID, messageID), message, &rMessage) + if rMessage != nil { + //r.Disgo().Cache().CacheMessage(rMessage) + } + return +} + +// DeleteMessage lets you delete a api.Message +func (r RestClientImpl) DeleteMessage(channelID api.Snowflake, messageID api.Snowflake) error { + return r.Request(endpoints.DeleteMessage.Compile(channelID, messageID), nil, nil) +} + +// BulkDeleteMessages lets you bulk delete api.Message(s) +func (r RestClientImpl) BulkDeleteMessages(channelID api.Snowflake, messageIDs... api.Snowflake) error { + return r.Request(endpoints.BulkDeleteMessage.Compile(channelID), api.MessageBulkDelete{Messages: messageIDs}, nil) +} + +// CrosspostMessage lets you crosspost a api.Message in a channel with type api.ChannelTypeNews +func (r RestClientImpl) CrosspostMessage(channelID api.Snowflake, messageID api.Snowflake) (rMessage *api.Message, err error) { + err = r.Request(endpoints.CrosspostMessage.Compile(channelID, messageID), nil, &rMessage) + if rMessage != nil { + //r.Disgo().Cache().CacheMessage(rMessage) + } + return +} + // OpenDMChannel opens a new dm channel a user func (r RestClientImpl) OpenDMChannel(userID api.Snowflake) (channel *api.DMChannel, err error) { body := struct { From 21cdaaba7ec3f5bc4690e55827616422cb05a0aa Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Mon, 29 Mar 2021 21:38:10 +0200 Subject: [PATCH 03/65] added voice satte cache --- api/cache.go | 6 ++ api/disgo.go | 4 +- api/disgo_builder.go | 1 + api/events/guild_member_voice_events.go | 24 ++++++++ api/guild.go | 31 ++++++++-- api/voice_dispatch_interceptor.go | 39 ++++++++++++ api/voice_state.go | 55 +++++++++++++---- internal/cache.go | 47 ++++++++++++++ internal/disgo.go | 29 ++++++--- internal/disgo_builder.go | 61 +++++++++++-------- internal/handlers/all_handlers.go | 3 + internal/handlers/guild_create_handler.go | 20 +++--- .../handlers/voice_server_update_handler.go | 34 +++++++++++ .../handlers/voice_state_update_handler.go | 47 ++++++++++++++ testbot/testbot.go | 2 +- 15 files changed, 341 insertions(+), 62 deletions(-) create mode 100644 api/events/guild_member_voice_events.go create mode 100644 api/voice_dispatch_interceptor.go create mode 100644 internal/handlers/voice_server_update_handler.go create mode 100644 internal/handlers/voice_state_update_handler.go diff --git a/api/cache.go b/api/cache.go index 06aa3aff..d8e9a22e 100644 --- a/api/cache.go +++ b/api/cache.go @@ -42,6 +42,12 @@ type Cache interface { FindMember(Snowflake, func(*Member) bool) *Member FindMembers(Snowflake, func(*Member) bool) []*Member + VoiceState(guildID Snowflake, userID Snowflake) *VoiceState + VoiceStates(guildID Snowflake) []*VoiceState + VoiceStateCache(guildID Snowflake) map[Snowflake]*VoiceState + CacheVoiceState(voiceState *VoiceState) + UncacheVoiceState(guildID Snowflake, userID Snowflake) + Role(Snowflake, Snowflake) *Role RolesByName(Snowflake, string, bool) []*Role Roles(Snowflake) []*Role diff --git a/api/disgo.go b/api/disgo.go index ad149a78..e6e875ee 100644 --- a/api/disgo.go +++ b/api/disgo.go @@ -20,8 +20,10 @@ type Disgo interface { Intents() Intents ApplicationID() Snowflake SelfUser() *User - SetSelfUser(*User) + SetSelfUser(user *User) EventManager() EventManager + VoiceDispatchInterceptor() VoiceDispatchInterceptor + SetVoiceDispatchInterceptor(voiceInterceptor VoiceDispatchInterceptor) HeartbeatLatency() time.Duration GetCommand(commandID Snowflake) (*SlashCommand, error) diff --git a/api/disgo_builder.go b/api/disgo_builder.go index d2b86cfb..a389655c 100644 --- a/api/disgo_builder.go +++ b/api/disgo_builder.go @@ -8,6 +8,7 @@ type DisgoBuilder interface { SetToken(token string) DisgoBuilder SetIntents(intents Intents) DisgoBuilder SetEventManager(eventManager EventManager) DisgoBuilder + SetVoiceDispatchInterceptor(VoiceDispatchInterceptor) DisgoBuilder AddEventListeners(eventsListeners ...EventListener) DisgoBuilder SetWebhookServer(webhookServer WebhookServer) DisgoBuilder SetWebhookServerProperties(listenURL string, listenPort int, publicKey string) DisgoBuilder diff --git a/api/events/guild_member_voice_events.go b/api/events/guild_member_voice_events.go new file mode 100644 index 00000000..fa1bf6b6 --- /dev/null +++ b/api/events/guild_member_voice_events.go @@ -0,0 +1,24 @@ +package events + +import "github.com/DisgoOrg/disgo/api" + +type GenericGuildVoiceEvent struct { + GenericGuildMemberEvent + Member *api.Member + VoiceState *api.VoiceState +} + +// GuildMemberVoiceStateUpdateEvent indicates that the api.VoiceState of a api.Member updated +type GuildMemberVoiceStateUpdateEvent struct { + GenericGuildVoiceEvent + Left *api.VoiceChannel + Joined *api.VoiceChannel +} + +type GuildMemberVoiceDeafenEvent struct { + GenericGuildVoiceEvent +} + +func (e GuildMemberVoiceDeafenEvent) Deafened() bool { + return e.VoiceState.Deafened() +} diff --git a/api/guild.go b/api/guild.go index 9b35600e..6447ad2d 100644 --- a/api/guild.go +++ b/api/guild.go @@ -89,6 +89,16 @@ const ( GuildFeaturePreviewEnabled GuildFeature = "PREVIEW_ENABLED" ) +type FullGuild struct { + *Guild + Roles []*Role `json:"roles"` + Emojis []*Emote `json:"emojis"` + Members []*Member `json:"members"` + Channels []*GuildChannel `json:"channels"` + VoiceStates []*VoiceState `json:"voice_states"` + //Presences []*Presence `json:"presences"` +} + // Guild represents a discord guild_events type Guild struct { Disgo Disgo @@ -106,13 +116,8 @@ type Guild struct { VerificationLevel VerificationLevel `json:"verification_level"` Large *bool `json:"large"` DefaultMessageNotifications MessageNotifications `json:"default_message_notifications"` - Roles []*Role `json:"roles"` - Emojis []*Emote `json:"emojis"` - Members []*Member `json:"members"` MaxPresences *int `json:"max_presences"` MaxMembers *int `json:"max_members"` - Channels []*GuildChannel `json:"channels"` - VoiceStates []*VoiceState `json:"voice_states"` Unavailable bool `json:"unavailable"` ExplicitContentFilter ExplicitContentFilterLevel `json:"explicit_content_filter"` Features []GuildFeature `json:"features"` @@ -133,7 +138,21 @@ type Guild struct { MaxVideoChannelUsers *int `json:"max_video_channel_users"` ApproximateMemberCount *int `json:"approximate_member_count"` ApproximatePresenceCount *int `json:"approximate_presence_count"` - //Presences []*Presence `json:"presences"` +} + +// SelfMember returns the self Member for this Guild. SelfMember is always cached +func (g Guild) SelfMember() *Member { + return g.Member(g.Disgo.ApplicationID()) +} + +// Member returns the specific Member for this Guild from the Cache +func (g Guild) Member(userID Snowflake) *Member { + return g.Disgo.Cache().Member(g.ID, userID) +} + +// Role returns the specific Role for this Guild from the Cache +func (g Guild) Role(roleID Snowflake) *Role { + return g.Disgo.Cache().Role(g.ID, roleID) } // CreateRole allows you to create a new Role diff --git a/api/voice_dispatch_interceptor.go b/api/voice_dispatch_interceptor.go new file mode 100644 index 00000000..06a6f3c6 --- /dev/null +++ b/api/voice_dispatch_interceptor.go @@ -0,0 +1,39 @@ +package api + +// VoiceServerUpdate sent when a guilds voice server is updated +type VoiceServerUpdate struct { + Disgo Disgo + Token string `json:"token"` + GuildID Snowflake `json:"guild_id"` + Endpoint *string `json:"endpoint"` +} + +// Guild returns the Guild for this VoiceServerUpdate from the Cache +func (u VoiceServerUpdate) Guild() *Guild { + return u.Disgo.Cache().Guild(u.GuildID) +} + +// VoiceStateUpdate sent when someone joins/leaves/moves voice channels +type VoiceStateUpdate struct { + VoiceState + Member *Member `json:"member"` +} + +// Guild returns the Guild for this VoiceStateUpdate from the Cache +func (u VoiceStateUpdate) Guild() *Guild { + return u.Disgo.Cache().Guild(u.GuildID) +} + +// VoiceChannel returns the VoiceChannel for this VoiceStateUpdate from the Cache +func (u VoiceStateUpdate) VoiceChannel() *VoiceChannel { + if u.ChannelID == nil { + return nil + } + return u.Disgo.Cache().VoiceChannel(*u.ChannelID) +} + +// VoiceDispatchInterceptor lets you listen to VoiceServerUpdate & VoiceStateUpdate +type VoiceDispatchInterceptor interface { + OnVoiceServerUpdate(voiceServerUpdateEvent VoiceServerUpdate) + OnVoiceStateUpdate(voiceStateUpdateEvent VoiceStateUpdate) +} diff --git a/api/voice_state.go b/api/voice_state.go index 8fb900a5..9f3e9bf6 100644 --- a/api/voice_state.go +++ b/api/voice_state.go @@ -2,16 +2,47 @@ package api // A VoiceState from Discord type VoiceState struct { - GuildID *Snowflake `json:"guild_id,omitempty"` - ChannelID *Snowflake `json:"channel_id"` - UserID Snowflake `json:"user_id"` - Member *Member `json:"member,omitempty"` - SessionID string `json:"session_id"` - Deaf bool `json:"deaf"` - Mute bool `json:"mute"` - SelfDeaf bool `json:"self_deaf"` - SelfMute bool `json:"self_mute"` - SelfStream *bool `json:"self_stream,omitempty"` - SelfVideo bool `json:"self_video"` - Suppress bool `json:"suppress"` + Disgo Disgo + GuildID Snowflake `json:"guild_id"` + ChannelID *Snowflake `json:"channel_id"` + UserID Snowflake `json:"user_id"` + SessionID string `json:"session_id"` + GuildDeafened bool `json:"deaf"` + GuildMuted bool `json:"mute"` + SelfDeafened bool `json:"self_deaf"` + SelfMuted bool `json:"self_mute"` + Stream bool `json:"self_stream"` + Video bool `json:"self_video"` + Suppressed bool `json:"suppress"` +} + +func (s VoiceState) Muted() bool { + return s.GuildMuted || s.SelfMuted +} + +func (s VoiceState) Deafened() bool { + return s.GuildDeafened || s.SelfDeafened +} + +// Member returns the Member of this VoiceState from the Cache +func (s VoiceState) Member() *Member { + return s.Disgo.Cache().Member(s.GuildID, s.UserID) +} + +// User returns the User of this VoiceState from the Cache +func (s VoiceState) User() *User { + return s.Disgo.Cache().User(s.UserID) +} + +// Guild returns the Guild of this VoiceState from the Cache +func (s VoiceState) Guild() *Guild { + return s.Disgo.Cache().Guild(s.GuildID) +} + +// VoiceChannel returns the VoiceChannel of this VoiceState from the Cache +func (s VoiceState) VoiceChannel() *VoiceChannel { + if s.ChannelID == nil { + return nil + } + return s.Disgo.Cache().VoiceChannel(*s.ChannelID) } diff --git a/internal/cache.go b/internal/cache.go index e2fd4206..273ad118 100644 --- a/internal/cache.go +++ b/internal/cache.go @@ -16,6 +16,7 @@ func newCacheImpl(memberCachePolicy api.MemberCachePolicy) api.Cache { users: map[api.Snowflake]*api.User{}, guilds: map[api.Snowflake]*api.Guild{}, members: map[api.Snowflake]map[api.Snowflake]*api.Member{}, + voiceStates: map[api.Snowflake]map[api.Snowflake]*api.VoiceState{}, roles: map[api.Snowflake]map[api.Snowflake]*api.Role{}, dmChannels: map[api.Snowflake]*api.DMChannel{}, categories: map[api.Snowflake]map[api.Snowflake]*api.Category{}, @@ -34,6 +35,7 @@ type CacheImpl struct { users map[api.Snowflake]*api.User guilds map[api.Snowflake]*api.Guild members map[api.Snowflake]map[api.Snowflake]*api.Member + voiceStates map[api.Snowflake]map[api.Snowflake]*api.VoiceState roles map[api.Snowflake]map[api.Snowflake]*api.Role dmChannels map[api.Snowflake]*api.DMChannel categories map[api.Snowflake]map[api.Snowflake]*api.Category @@ -202,6 +204,7 @@ func (c *CacheImpl) CacheGuild(guild *api.Guild) { // guild_events was not yet cached so cache it directly c.guilds[guild.ID] = guild c.members[guild.ID] = map[api.Snowflake]*api.Member{} + c.voiceStates[guild.ID] = map[api.Snowflake]*api.VoiceState{} c.roles[guild.ID] = map[api.Snowflake]*api.Role{} c.categories[guild.ID] = map[api.Snowflake]*api.Category{} c.textChannels[guild.ID] = map[api.Snowflake]*api.TextChannel{} @@ -213,6 +216,7 @@ func (c *CacheImpl) CacheGuild(guild *api.Guild) { func (c *CacheImpl) UncacheGuild(guildID api.Snowflake) { delete(c.guilds, guildID) delete(c.members, guildID) + delete(c.voiceStates, guildID) delete(c.roles, guildID) delete(c.categories, guildID) delete(c.textChannels, guildID) @@ -350,6 +354,49 @@ func (c *CacheImpl) FindMembers(guildID api.Snowflake, check func(u *api.Member) return members } +// VoiceState returns a Member's api.VoiceState for a api.Guild +func (c *CacheImpl) VoiceState(guildID api.Snowflake, userID api.Snowflake) *api.VoiceState { + if voiceStates, ok := c.voiceStates[guildID]; ok { + return voiceStates[userID] + } + return nil +} + +// VoiceStates returns the member cache of a guild by snowflake +func (c *CacheImpl) VoiceStates(guildID api.Snowflake) []*api.VoiceState { + if guildVoiceStates, ok := c.voiceStates[guildID]; ok { + voiceStates := make([]*api.VoiceState, len(guildVoiceStates)) + i := 0 + for _, voiceState := range guildVoiceStates { + voiceStates[i] = voiceState + i++ + } + return voiceStates + } + return nil +} + +// VoiceStateCache returns the api.VoiceState api.Cache of a api.Guild as a map +func (c *CacheImpl) VoiceStateCache(guildID api.Snowflake) map[api.Snowflake]*api.VoiceState { + return c.voiceStates[guildID] +} + +// CacheVoiceState adds a api.VoiceState from the api.Cache +func (c *CacheImpl) CacheVoiceState(voiceState *api.VoiceState) { + if voiceStates, ok := c.voiceStates[voiceState.GuildID]; ok { + if _, ok := voiceStates[voiceState.UserID]; ok { + *voiceStates[voiceState.UserID] = *voiceState + return + } + voiceStates[voiceState.UserID] = voiceState + } +} + +// UncacheVoiceState removes a api.VoiceState from the api.Cache +func (c *CacheImpl) UncacheVoiceState(guildID api.Snowflake, userID api.Snowflake) { + delete(c.voiceStates[guildID], userID) +} + // Role returns a role from cache by guild ID and role ID func (c *CacheImpl) Role(guildID api.Snowflake, roleID api.Snowflake) *api.Role { if guildRoles, ok := c.roles[guildID]; ok { diff --git a/internal/disgo.go b/internal/disgo.go index 480a6bfd..64a9b020 100644 --- a/internal/disgo.go +++ b/internal/disgo.go @@ -38,15 +38,16 @@ func New(token string, options api.Options) (api.Disgo, error) { // DisgoImpl is the main discord client type DisgoImpl struct { - token string - gateway api.Gateway - restClient api.RestClient - intents api.Intents - selfUser *api.User - eventManager api.EventManager - webhookServer api.WebhookServer - cache api.Cache - applicationID api.Snowflake + token string + gateway api.Gateway + restClient api.RestClient + intents api.Intents + selfUser *api.User + eventManager api.EventManager + voiceDispatchInterceptor api.VoiceDispatchInterceptor + webhookServer api.WebhookServer + cache api.Cache + applicationID api.Snowflake } // Connect opens the gateway connection to discord @@ -95,6 +96,16 @@ func (d *DisgoImpl) EventManager() api.EventManager { return d.eventManager } +// VoiceDispatchInterceptor returns the api.VoiceDispatchInterceptor +func (d *DisgoImpl) VoiceDispatchInterceptor() api.VoiceDispatchInterceptor { + return d.voiceDispatchInterceptor +} + +// SetVoiceDispatchInterceptor sets the api.VoiceDispatchInterceptor +func (d *DisgoImpl) SetVoiceDispatchInterceptor(voiceDispatchInterceptor api.VoiceDispatchInterceptor) { + d.voiceDispatchInterceptor = voiceDispatchInterceptor +} + // WebhookServer returns the api.EventManager func (d *DisgoImpl) WebhookServer() api.WebhookServer { return d.webhookServer diff --git a/internal/disgo_builder.go b/internal/disgo_builder.go index c567a7b9..b18b8dfc 100644 --- a/internal/disgo_builder.go +++ b/internal/disgo_builder.go @@ -10,7 +10,7 @@ import ( // NewBuilder returns a new api.DisgoBuilder instance func NewBuilder(token string) api.DisgoBuilder { - return DisgoBuilderImpl{ + return &DisgoBuilderImpl{ logLevel: log.InfoLevel, token: &token, } @@ -18,61 +18,68 @@ func NewBuilder(token string) api.DisgoBuilder { // DisgoBuilderImpl implementation of the api.DisgoBuilder interface type DisgoBuilderImpl struct { - logLevel log.Level - token *string - gateway api.Gateway - restClient api.RestClient - cache api.Cache - memberCachePolicy api.MemberCachePolicy - intents api.Intents - eventManager api.EventManager - webhookServer api.WebhookServer - listenURL *string - listenPort *int - publicKey *string - eventListeners []api.EventListener + logLevel log.Level + token *string + gateway api.Gateway + restClient api.RestClient + cache api.Cache + memberCachePolicy api.MemberCachePolicy + intents api.Intents + eventManager api.EventManager + voiceDispatchInterceptor api.VoiceDispatchInterceptor + webhookServer api.WebhookServer + listenURL *string + listenPort *int + publicKey *string + eventListeners []api.EventListener } // SetLogLevel sets logrus.Level of logrus -func (b DisgoBuilderImpl) SetLogLevel(logLevel log.Level) api.DisgoBuilder { +func (b *DisgoBuilderImpl) SetLogLevel(logLevel log.Level) api.DisgoBuilder { b.logLevel = logLevel return b } // SetToken sets the token to connect to discord -func (b DisgoBuilderImpl) SetToken(token string) api.DisgoBuilder { +func (b *DisgoBuilderImpl) SetToken(token string) api.DisgoBuilder { b.token = &token return b } // SetIntents sets the api.Intents to connect to discord -func (b DisgoBuilderImpl) SetIntents(intents api.Intents) api.DisgoBuilder { +func (b *DisgoBuilderImpl) SetIntents(intents api.Intents) api.DisgoBuilder { b.intents = intents return b } // SetEventManager lets you inject your own api.EventManager -func (b DisgoBuilderImpl) SetEventManager(eventManager api.EventManager) api.DisgoBuilder { +func (b *DisgoBuilderImpl) SetEventManager(eventManager api.EventManager) api.DisgoBuilder { b.eventManager = eventManager return b } // AddEventListeners lets you add an api.EventListener to your api.EventManager -func (b DisgoBuilderImpl) AddEventListeners(eventListeners ...api.EventListener) api.DisgoBuilder { +func (b *DisgoBuilderImpl) AddEventListeners(eventListeners ...api.EventListener) api.DisgoBuilder { for _, eventListener := range eventListeners { b.eventListeners = append(b.eventListeners, eventListener) } return b } +// SetVoiceDispatchInterceptor sets the api.VoiceDispatchInterceptor +func (b *DisgoBuilderImpl) SetVoiceDispatchInterceptor(voiceDispatchInterceptor api.VoiceDispatchInterceptor) api.DisgoBuilder { + b.voiceDispatchInterceptor = voiceDispatchInterceptor + return b +} + // SetWebhookServer lets you inject your own api.EventManager -func (b DisgoBuilderImpl) SetWebhookServer(webhookServer api.WebhookServer) api.DisgoBuilder { +func (b *DisgoBuilderImpl) SetWebhookServer(webhookServer api.WebhookServer) api.DisgoBuilder { b.webhookServer = webhookServer return b } // SetWebhookServerProperties sets the default api.WebhookServer properties -func (b DisgoBuilderImpl) SetWebhookServerProperties(listenURL string, listenPort int, publicKey string) api.DisgoBuilder { +func (b *DisgoBuilderImpl) SetWebhookServerProperties(listenURL string, listenPort int, publicKey string) api.DisgoBuilder { b.listenURL = &listenURL b.listenPort = &listenPort b.publicKey = &publicKey @@ -80,31 +87,31 @@ func (b DisgoBuilderImpl) SetWebhookServerProperties(listenURL string, listenPor } // SetRestClient lets you inject your own api.RestClient -func (b DisgoBuilderImpl) SetRestClient(restClient api.RestClient) api.DisgoBuilder { +func (b *DisgoBuilderImpl) SetRestClient(restClient api.RestClient) api.DisgoBuilder { b.restClient = restClient return b } // SetCache lets you inject your own api.Cache -func (b DisgoBuilderImpl) SetCache(cache api.Cache) api.DisgoBuilder { +func (b *DisgoBuilderImpl) SetCache(cache api.Cache) api.DisgoBuilder { b.cache = cache return b } // SetMemberCachePolicy lets oyu set your own api.MemberCachePolicy -func (b DisgoBuilderImpl) SetMemberCachePolicy(memberCachePolicy api.MemberCachePolicy) api.DisgoBuilder { +func (b *DisgoBuilderImpl) SetMemberCachePolicy(memberCachePolicy api.MemberCachePolicy) api.DisgoBuilder { b.memberCachePolicy = memberCachePolicy return b } // SetGateway lets you inject your own api.Gateway -func (b DisgoBuilderImpl) SetGateway(gateway api.Gateway) api.DisgoBuilder { +func (b *DisgoBuilderImpl) SetGateway(gateway api.Gateway) api.DisgoBuilder { b.gateway = gateway return b } // Build builds your api.Disgo instance -func (b DisgoBuilderImpl) Build() (api.Disgo, error) { +func (b *DisgoBuilderImpl) Build() (api.Disgo, error) { log.SetLevel(b.logLevel) disgo := &DisgoImpl{} @@ -138,6 +145,8 @@ func (b DisgoBuilderImpl) Build() (api.Disgo, error) { } disgo.eventManager = b.eventManager + disgo.voiceDispatchInterceptor = b.voiceDispatchInterceptor + if b.webhookServer == nil && b.listenURL != nil && b.listenPort != nil && b.publicKey != nil { b.webhookServer = newWebhookServerImpl(disgo, *b.listenURL, *b.listenPort, *b.publicKey) } diff --git a/internal/handlers/all_handlers.go b/internal/handlers/all_handlers.go index e6a71d6d..cd62ee26 100644 --- a/internal/handlers/all_handlers.go +++ b/internal/handlers/all_handlers.go @@ -9,6 +9,9 @@ func GetAllHandlers() []api.EventHandler { return []api.EventHandler{ ReadyHandler{}, + VoiceServerUpdateHandler{}, + VoiceStateUpdateHandler{}, + GuildCreateHandler{}, GuildUpdateHandler{}, GuildDeleteHandler{}, diff --git a/internal/handlers/guild_create_handler.go b/internal/handlers/guild_create_handler.go index defa9fdc..fe03982f 100644 --- a/internal/handlers/guild_create_handler.go +++ b/internal/handlers/guild_create_handler.go @@ -15,15 +15,17 @@ func (h GuildCreateHandler) Name() string { // New constructs a new payload receiver for the raw gateway event func (h GuildCreateHandler) New() interface{} { - return &api.Guild{} + return &api.FullGuild{} } // Handle handles the specific raw gateway event func (h GuildCreateHandler) Handle(disgo api.Disgo, eventManager api.EventManager, i interface{}) { - guild, ok := i.(*api.Guild) + fullGuild, ok := i.(*api.FullGuild) if !ok { return } + + guild := fullGuild.Guild guild.Disgo = disgo oldGuild := disgo.Cache().Guild(guild.ID) var wasUnavailable bool @@ -34,8 +36,8 @@ func (h GuildCreateHandler) Handle(disgo api.Disgo, eventManager api.EventManage } disgo.Cache().CacheGuild(guild) - for i := range guild.Channels { - channel := guild.Channels[i] + + for _, channel := range fullGuild.Channels { channel.Disgo = disgo channel.GuildID = guild.ID switch channel.Type { @@ -61,13 +63,18 @@ func (h GuildCreateHandler) Handle(disgo api.Disgo, eventManager api.EventManage } } - for i := range guild.Roles { - role := guild.Roles[i] + for _, role := range fullGuild.Roles { role.Disgo = disgo role.GuildID = guild.ID disgo.Cache().CacheRole(role) } + for _, voiceState := range fullGuild.VoiceStates { + voiceState.Disgo = disgo + voiceState.GuildID = guild.ID + disgo.Cache().CacheVoiceState(voiceState) + } + genericGuildEvent := events.GenericGuildEvent{ Event: api.Event{ Disgo: disgo, @@ -83,7 +90,6 @@ func (h GuildCreateHandler) Handle(disgo api.Disgo, eventManager api.EventManage Guild: guild, }) } else { - // guild join eventManager.Dispatch(events.GuildJoinEvent{ GenericGuildEvent: genericGuildEvent, Guild: guild, diff --git a/internal/handlers/voice_server_update_handler.go b/internal/handlers/voice_server_update_handler.go new file mode 100644 index 00000000..d12cfcad --- /dev/null +++ b/internal/handlers/voice_server_update_handler.go @@ -0,0 +1,34 @@ +package handlers + +import "github.com/DisgoOrg/disgo/api" + +// InteractionCreateHandler handles api.VoiceServerUpdateGatewayEvent +type VoiceServerUpdateHandler struct{} + +// Name returns the raw gateway event name +func (h VoiceServerUpdateHandler) Name() string { + return api.VoiceServerUpdateGatewayEvent +} + +// New constructs a new payload receiver for the raw gateway event +func (h VoiceServerUpdateHandler) New() interface{} { + return &api.VoiceServerUpdate{} +} + +// Handle handles the specific raw gateway event +func (h VoiceServerUpdateHandler) Handle(disgo api.Disgo, eventManager api.EventManager, i interface{}) { + voiceServerUpdate, ok := i.(*api.VoiceServerUpdate) + if !ok { + return + } + + if voiceServerUpdate.Endpoint == nil { + return + } + + voiceServerUpdate.Disgo = disgo + + if interceptor := disgo.VoiceDispatchInterceptor(); interceptor != nil { + interceptor.OnVoiceServerUpdate(*voiceServerUpdate) + } +} diff --git a/internal/handlers/voice_state_update_handler.go b/internal/handlers/voice_state_update_handler.go new file mode 100644 index 00000000..798e6f7a --- /dev/null +++ b/internal/handlers/voice_state_update_handler.go @@ -0,0 +1,47 @@ +package handlers + +import ( + log "github.com/sirupsen/logrus" + + "github.com/DisgoOrg/disgo/api" +) + +// VoiceStateUpdateHandler handles api.VoiceStateUpdateGatewayEvent +type VoiceStateUpdateHandler struct{} + +// Name returns the raw gateway event name +func (h VoiceStateUpdateHandler) Name() string { + return api.VoiceStateUpdateGatewayEvent +} + +// New constructs a new payload receiver for the raw gateway event +func (h VoiceStateUpdateHandler) New() interface{} { + return &api.VoiceStateUpdate{} +} + +// Handle handles the specific raw gateway event +func (h VoiceStateUpdateHandler) Handle(disgo api.Disgo, eventManager api.EventManager, i interface{}) { + voiceStateUpdate, ok := i.(*api.VoiceStateUpdate) + if !ok { + return + } + + log.Printf("%+v", *voiceStateUpdate) + + voiceStateUpdate.Disgo = disgo + + //guild := disgo.Cache().Guild(voiceStateUpdate.GuildID) + + //oldMember := disgo.Cache().Member(voiceStateUpdate.GuildID, voiceStateUpdate.UserID) + //newMember := voiceStateUpdate.Member + + // TODO update voice state cache + // TODO fire several events + + if disgo.ApplicationID() == voiceStateUpdate.UserID { + if interceptor := disgo.VoiceDispatchInterceptor(); interceptor != nil { + interceptor.OnVoiceStateUpdate(*voiceStateUpdate) + } + } + +} diff --git a/testbot/testbot.go b/testbot/testbot.go index 6beaaac5..72e83935 100644 --- a/testbot/testbot.go +++ b/testbot/testbot.go @@ -18,7 +18,7 @@ func main() { dgo, err := disgo.NewBuilder(token). SetLogLevel(log.InfoLevel). - SetIntents(api.IntentsGuilds|api.IntentsGuildMessages|api.IntentsGuildMembers). + SetIntents(api.IntentsGuilds | api.IntentsGuildMessages | api.IntentsGuildMembers | api.IntentsGuildVoiceStates). SetMemberCachePolicy(api.MemberCachePolicyAll). AddEventListeners(&events.ListenerAdapter{ OnGuildAvailable: guildAvailListener, From 8f79a02416eb6993dbaddf91316e08a3c7ae380c Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Tue, 30 Mar 2021 01:22:26 +0200 Subject: [PATCH 04/65] implemented better cache control --- api/disgo_builder.go | 5 ++ api/options.go | 6 ++ internal/cache.go | 122 +++++++++++++++++++++++++------------- internal/disgo.go | 7 +++ internal/disgo_builder.go | 48 ++++++++++++++- 5 files changed, 144 insertions(+), 44 deletions(-) diff --git a/api/disgo_builder.go b/api/disgo_builder.go index a389655c..f05d47f2 100644 --- a/api/disgo_builder.go +++ b/api/disgo_builder.go @@ -14,7 +14,12 @@ type DisgoBuilder interface { SetWebhookServerProperties(listenURL string, listenPort int, publicKey string) DisgoBuilder SetRestClient(restClient RestClient) DisgoBuilder SetCache(cache Cache) DisgoBuilder + SetMessageCachePolicy(messageCachePolicy MessageCachePolicy) DisgoBuilder SetMemberCachePolicy(memberCachePolicy MemberCachePolicy) DisgoBuilder + SetCacheVoiceStates(cacheVoiceStates bool) DisgoBuilder + SetCacheRoles(cacheRoles bool) DisgoBuilder + SetCacheChannels(cacheChannels bool) DisgoBuilder + SetCacheEmotes(cacheEmotes bool) DisgoBuilder SetGateway(gateway Gateway) DisgoBuilder Build() (Disgo, error) } diff --git a/api/options.go b/api/options.go index 75b3b660..cd0f2b4e 100644 --- a/api/options.go +++ b/api/options.go @@ -8,4 +8,10 @@ type Options struct { ListenPort int ListenURL string PublicKey string + MessageCachePolicy MessageCachePolicy + MemberCachePolicy MemberCachePolicy + CacheVoiceStates bool + CacheRoles bool + CacheChannels bool + CacheEmotes bool } diff --git a/internal/cache.go b/internal/cache.go index 273ad118..fc33cc4f 100644 --- a/internal/cache.go +++ b/internal/cache.go @@ -10,19 +10,29 @@ import ( "github.com/DisgoOrg/disgo/api" ) -func newCacheImpl(memberCachePolicy api.MemberCachePolicy) api.Cache { +// TODO: maybe cacheX currently replaces pointers which invalidates old ones which may be bad? +// should we instead keep the old one & return the set pointer on cacheX so we work further with that one in our handlers? +// else we may end up with 2 pointers for the same struct + +func newCacheImpl(messageCachePolicy api.MessageCachePolicy, memberCachePolicy api.MemberCachePolicy, cacheVoiceStates bool, cacheRoles bool, cacheChannels bool, cacheEmotes bool) api.Cache { cache := &CacheImpl{ - memberCachePolicy: memberCachePolicy, - users: map[api.Snowflake]*api.User{}, - guilds: map[api.Snowflake]*api.Guild{}, - members: map[api.Snowflake]map[api.Snowflake]*api.Member{}, - voiceStates: map[api.Snowflake]map[api.Snowflake]*api.VoiceState{}, - roles: map[api.Snowflake]map[api.Snowflake]*api.Role{}, - dmChannels: map[api.Snowflake]*api.DMChannel{}, - categories: map[api.Snowflake]map[api.Snowflake]*api.Category{}, - textChannels: map[api.Snowflake]map[api.Snowflake]*api.TextChannel{}, - voiceChannels: map[api.Snowflake]map[api.Snowflake]*api.VoiceChannel{}, - storeChannels: map[api.Snowflake]map[api.Snowflake]*api.StoreChannel{}, + quit: make(chan interface{}), + messageCachePolicy: messageCachePolicy, + memberCachePolicy: memberCachePolicy, + cacheVoiceStates: cacheVoiceStates, + cacheRoles: cacheRoles, + cacheChannels: cacheChannels, + cacheEmotes: cacheEmotes, + users: map[api.Snowflake]*api.User{}, + guilds: map[api.Snowflake]*api.Guild{}, + members: map[api.Snowflake]map[api.Snowflake]*api.Member{}, + voiceStates: map[api.Snowflake]map[api.Snowflake]*api.VoiceState{}, + roles: map[api.Snowflake]map[api.Snowflake]*api.Role{}, + dmChannels: map[api.Snowflake]*api.DMChannel{}, + categories: map[api.Snowflake]map[api.Snowflake]*api.Category{}, + textChannels: map[api.Snowflake]map[api.Snowflake]*api.TextChannel{}, + voiceChannels: map[api.Snowflake]map[api.Snowflake]*api.VoiceChannel{}, + storeChannels: map[api.Snowflake]map[api.Snowflake]*api.StoreChannel{}, } go cache.cleanup(10 * time.Second) return cache @@ -30,18 +40,23 @@ func newCacheImpl(memberCachePolicy api.MemberCachePolicy) api.Cache { // CacheImpl is used for Disgo's Cache type CacheImpl struct { - quit chan bool - memberCachePolicy api.MemberCachePolicy - users map[api.Snowflake]*api.User - guilds map[api.Snowflake]*api.Guild - members map[api.Snowflake]map[api.Snowflake]*api.Member - voiceStates map[api.Snowflake]map[api.Snowflake]*api.VoiceState - roles map[api.Snowflake]map[api.Snowflake]*api.Role - dmChannels map[api.Snowflake]*api.DMChannel - categories map[api.Snowflake]map[api.Snowflake]*api.Category - textChannels map[api.Snowflake]map[api.Snowflake]*api.TextChannel - voiceChannels map[api.Snowflake]map[api.Snowflake]*api.VoiceChannel - storeChannels map[api.Snowflake]map[api.Snowflake]*api.StoreChannel + quit chan interface{} + messageCachePolicy api.MessageCachePolicy + memberCachePolicy api.MemberCachePolicy + cacheVoiceStates bool + cacheRoles bool + cacheChannels bool + cacheEmotes bool + users map[api.Snowflake]*api.User + guilds map[api.Snowflake]*api.Guild + members map[api.Snowflake]map[api.Snowflake]*api.Member + voiceStates map[api.Snowflake]map[api.Snowflake]*api.VoiceState + roles map[api.Snowflake]map[api.Snowflake]*api.Role + dmChannels map[api.Snowflake]*api.DMChannel + categories map[api.Snowflake]map[api.Snowflake]*api.Category + textChannels map[api.Snowflake]map[api.Snowflake]*api.TextChannel + voiceChannels map[api.Snowflake]map[api.Snowflake]*api.VoiceChannel + storeChannels map[api.Snowflake]map[api.Snowflake]*api.StoreChannel } // Close cleans up the cache and it's internal tasks @@ -126,8 +141,9 @@ func (c *CacheImpl) UserCache() map[api.Snowflake]*api.User { // CacheUser adds a user to the cache func (c *CacheImpl) CacheUser(user *api.User) { + // TODO: only cache if we have a guild in common if _, ok := c.guilds[user.ID]; ok { - // update old user + *c.users[user.ID] = *user return } c.users[user.ID] = user @@ -197,7 +213,6 @@ func (c *CacheImpl) GuildCache() map[api.Snowflake]*api.Guild { // CacheGuild adds a guild to the cache func (c *CacheImpl) CacheGuild(guild *api.Guild) { if _, ok := c.guilds[guild.ID]; ok { - // update old guild_events *c.guilds[guild.ID] = *guild return } @@ -319,9 +334,10 @@ func (c *CacheImpl) AllMemberCache() map[api.Snowflake]map[api.Snowflake]*api.Me // CacheMember adds a member to the cache func (c *CacheImpl) CacheMember(member *api.Member) { + c.memberCachePolicy(member) if guildMembers, ok := c.members[member.GuildID]; ok { - if _, ok := guildMembers[member.User.ID]; ok { - // update old guild_events + if _, ok = guildMembers[member.User.ID]; ok { + *guildMembers[member.User.ID] = *member return } guildMembers[member.User.ID] = member @@ -383,8 +399,11 @@ func (c *CacheImpl) VoiceStateCache(guildID api.Snowflake) map[api.Snowflake]*ap // CacheVoiceState adds a api.VoiceState from the api.Cache func (c *CacheImpl) CacheVoiceState(voiceState *api.VoiceState) { + if !c.cacheVoiceStates || c.Member(voiceState.GuildID, voiceState.UserID) == nil { + return + } if voiceStates, ok := c.voiceStates[voiceState.GuildID]; ok { - if _, ok := voiceStates[voiceState.UserID]; ok { + if _, ok = voiceStates[voiceState.UserID]; ok { *voiceStates[voiceState.UserID] = *voiceState return } @@ -459,9 +478,12 @@ func (c *CacheImpl) AllRoleCache() map[api.Snowflake]map[api.Snowflake]*api.Role // CacheRole adds a role to the cache func (c *CacheImpl) CacheRole(role *api.Role) { + if !c.cacheRoles { + return + } if guildRoles, ok := c.roles[role.GuildID]; ok { - if _, ok := guildRoles[role.ID]; ok { - // update old role + if _, ok = guildRoles[role.ID]; ok { + *guildRoles[role.ID] = *role return } guildRoles[role.ID] = role @@ -576,8 +598,11 @@ func (c *CacheImpl) DMChannelCache() map[api.Snowflake]*api.DMChannel { // CacheDMChannel adds a DM channel to the cache func (c *CacheImpl) CacheDMChannel(dmChannel *api.DMChannel) { - if oldChannel, ok := c.dmChannels[dmChannel.ID]; ok { - *oldChannel = *dmChannel + if !c.cacheChannels { + return + } + if _, ok := c.dmChannels[dmChannel.ID]; ok { + *c.dmChannels[dmChannel.ID] = *dmChannel return } c.dmChannels[dmChannel.ID] = dmChannel @@ -673,9 +698,12 @@ func (c *CacheImpl) AllTextChannelCache() map[api.Snowflake]map[api.Snowflake]*a // CacheTextChannel adds a channel to the cache func (c *CacheImpl) CacheTextChannel(textChannel *api.TextChannel) { + if !c.cacheChannels { + return + } if guildTextChannels, ok := c.textChannels[textChannel.GuildID]; ok { - if guildTextChannel, ok := guildTextChannels[textChannel.MessageChannel.ID]; ok { - *guildTextChannel = *textChannel + if _, ok = guildTextChannels[textChannel.MessageChannel.ID]; ok { + *guildTextChannels[textChannel.MessageChannel.ID] = *textChannel return } guildTextChannels[textChannel.MessageChannel.ID] = textChannel @@ -772,9 +800,12 @@ func (c *CacheImpl) AllStoreChannelCache() map[api.Snowflake]map[api.Snowflake]* // CacheStoreChannel adds a store channel to the cache func (c *CacheImpl) CacheStoreChannel(storeChannel *api.StoreChannel) { + if !c.cacheChannels { + return + } if guildStoreChannels, ok := c.storeChannels[storeChannel.GuildID]; ok { - if guildStoreChannel, ok := guildStoreChannels[storeChannel.ID]; ok { - *guildStoreChannel = *storeChannel + if _, ok = guildStoreChannels[storeChannel.ID]; ok { + *guildStoreChannels[storeChannel.ID] = *storeChannel return } guildStoreChannels[storeChannel.ID] = storeChannel @@ -871,9 +902,12 @@ func (c *CacheImpl) AllVoiceChannelCache() map[api.Snowflake]map[api.Snowflake]* // CacheVoiceChannel adds a voice channel to cache func (c *CacheImpl) CacheVoiceChannel(voiceChannel *api.VoiceChannel) { + if !c.cacheChannels { + return + } if guildVoiceChannels, ok := c.voiceChannels[voiceChannel.GuildID]; ok { - if guildVoiceChannel, ok := guildVoiceChannels[voiceChannel.ID]; ok { - *guildVoiceChannel = *voiceChannel + if _, ok = guildVoiceChannels[voiceChannel.ID]; ok { + *guildVoiceChannels[voiceChannel.ID] = *voiceChannel return } guildVoiceChannels[voiceChannel.ID] = voiceChannel @@ -970,9 +1004,12 @@ func (c *CacheImpl) AllCategoryCache() map[api.Snowflake]map[api.Snowflake]*api. //CacheCategory adds a category to the cache func (c *CacheImpl) CacheCategory(category *api.Category) { + if !c.cacheChannels { + return + } if guildCategories, ok := c.categories[category.GuildID]; ok { - if guildCategory, ok := guildCategories[category.ID]; ok { - *guildCategory = *category + if _, ok = guildCategories[category.ID]; ok { + *guildCategories[category.ID] = *category return } guildCategories[category.ID] = category @@ -1004,3 +1041,6 @@ func (c *CacheImpl) FindCategories(guildID api.Snowflake, check func(u *api.Cate } return categories } + +// TODO: add emote cache +// TODO: add message cache \ No newline at end of file diff --git a/internal/disgo.go b/internal/disgo.go index 64a9b020..e5a63cf9 100644 --- a/internal/disgo.go +++ b/internal/disgo.go @@ -10,9 +10,16 @@ import ( // New creates a new api.Disgo instance func New(token string, options api.Options) (api.Disgo, error) { + if options.MessageCachePolicy == nil { + options.MessageCachePolicy = api.MessageCachePolicyDefault + } + if options.MemberCachePolicy == nil { + options.MemberCachePolicy = api.MemberCachePolicyDefault + } disgo := &DisgoImpl{ token: token, intents: options.Intents, + cache: newCacheImpl(options.MessageCachePolicy, options.MemberCachePolicy, options.CacheVoiceStates, options.CacheRoles, options.CacheChannels, options.CacheEmotes), } id, err := IDFromToken(token) diff --git a/internal/disgo_builder.go b/internal/disgo_builder.go index b18b8dfc..5cb5f879 100644 --- a/internal/disgo_builder.go +++ b/internal/disgo_builder.go @@ -11,8 +11,12 @@ import ( // NewBuilder returns a new api.DisgoBuilder instance func NewBuilder(token string) api.DisgoBuilder { return &DisgoBuilderImpl{ - logLevel: log.InfoLevel, - token: &token, + logLevel: log.InfoLevel, + token: &token, + cacheVoiceStates: true, + cacheRoles: true, + cacheChannels: true, + cacheEmotes: true, } } @@ -23,7 +27,12 @@ type DisgoBuilderImpl struct { gateway api.Gateway restClient api.RestClient cache api.Cache + messageCachePolicy api.MessageCachePolicy memberCachePolicy api.MemberCachePolicy + cacheVoiceStates bool + cacheRoles bool + cacheChannels bool + cacheEmotes bool intents api.Intents eventManager api.EventManager voiceDispatchInterceptor api.VoiceDispatchInterceptor @@ -98,12 +107,42 @@ func (b *DisgoBuilderImpl) SetCache(cache api.Cache) api.DisgoBuilder { return b } +// SetMessageCachePolicy lets you set your own api.MessageCachePolicy +func (b *DisgoBuilderImpl) SetMessageCachePolicy(messageCachePolicy api.MessageCachePolicy) api.DisgoBuilder { + b.messageCachePolicy = messageCachePolicy + return b +} + // SetMemberCachePolicy lets oyu set your own api.MemberCachePolicy func (b *DisgoBuilderImpl) SetMemberCachePolicy(memberCachePolicy api.MemberCachePolicy) api.DisgoBuilder { b.memberCachePolicy = memberCachePolicy return b } +// SetCacheVoiceStates lets you disable the api.VoiceState api.Cache +func (b *DisgoBuilderImpl) SetCacheVoiceStates(cacheVoiceStates bool) api.DisgoBuilder { + b.cacheVoiceStates = cacheVoiceStates + return b +} + +// SetCacheRoles lets you disable the api.Role api.Cache +func (b *DisgoBuilderImpl) SetCacheRoles(cacheRoles bool) api.DisgoBuilder { + b.cacheRoles = cacheRoles + return b +} + +// SetCacheChannels lets you disable the api.Channel api.Cache +func (b *DisgoBuilderImpl) SetCacheChannels(cacheChannels bool) api.DisgoBuilder { + b.cacheChannels = cacheChannels + return b +} + +// SetCacheEmotes lets you disable the api.Emote api.Cache +func (b *DisgoBuilderImpl) SetCacheEmotes(cacheEmotes bool) api.DisgoBuilder { + b.cacheEmotes = cacheEmotes + return b +} + // SetGateway lets you inject your own api.Gateway func (b *DisgoBuilderImpl) SetGateway(gateway api.Gateway) api.DisgoBuilder { b.gateway = gateway @@ -153,10 +192,13 @@ func (b *DisgoBuilderImpl) Build() (api.Disgo, error) { disgo.webhookServer = b.webhookServer if b.cache == nil { + if b.messageCachePolicy == nil { + b.messageCachePolicy = api.MessageCachePolicyDefault + } if b.memberCachePolicy == nil { b.memberCachePolicy = api.MemberCachePolicyDefault } - b.cache = newCacheImpl(b.memberCachePolicy) + b.cache = newCacheImpl(b.messageCachePolicy, b.memberCachePolicy, b.cacheVoiceStates, b.cacheRoles, b.cacheChannels, b.cacheEmotes) } disgo.cache = b.cache From e1766eed3955102dd0614f5735cd649562435482 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Tue, 30 Mar 2021 17:59:15 +0200 Subject: [PATCH 05/65] added correct time parsing --- api/activity.go | 8 +++---- api/channels.go | 3 +-- api/embed.go | 3 +-- api/endpoints/route_test.go | 2 +- api/guild.go | 3 +-- api/member.go | 6 ++--- api/message.go | 5 ++--- api/time.go | 44 +++++++++++++++++++++++++++++++++++++ internal/restclient.go | 2 +- 9 files changed, 56 insertions(+), 20 deletions(-) create mode 100644 api/time.go diff --git a/api/activity.go b/api/activity.go index c13c6e67..0820a41a 100644 --- a/api/activity.go +++ b/api/activity.go @@ -1,7 +1,5 @@ package api -import "time" - // ActivityType represents the status of a user, one of Game, Streaming, Listening, Custom or Competing type ActivityType int @@ -20,7 +18,7 @@ type Activity struct { Name string `json:"name"` Type ActivityType `json:"type"` URL *string `json:"url"` - CreatedAt time.Time `json:"created_at"` + CreatedAt Time `json:"created_at"` Timestamps *ActivityTimestamps `json:"timestamps,omitempty"` ApplicationID Snowflake `json:"application_id,omitempty"` Details *string `json:"details,omitempty"` @@ -35,8 +33,8 @@ type Activity struct { // ActivityTimestamps represents when a user started and ended their activity type ActivityTimestamps struct { - Start *time.Time `json:"start,omitempty"` - End *time.Time `json:"end,omitempty"` + Start *Time `json:"start,omitempty"` + End *Time `json:"end,omitempty"` } // ActivityEmoji is an Emoji object for an Activity diff --git a/api/channels.go b/api/channels.go index 83a05d30..b6ff373e 100644 --- a/api/channels.go +++ b/api/channels.go @@ -36,7 +36,7 @@ type Channel struct { ApplicationID *Snowflake `json:"application_id,omitempty"` ParentID *Snowflake `json:"parent_id,omitempty"` Permissions *Permissions `json:"permissions,omitempty"` - //LastPinTimestamp *time.Time `json:"last_pin_timestamp,omitempty"` + //LastPinTimestamp *Time `json:"last_pin_timestamp,omitempty"` } // MessageChannel is used for sending Message(s) to User(s) @@ -50,7 +50,6 @@ func (c MessageChannel) SendMessage(message MessageCreate) (*Message, error) { return c.Disgo.RestClient().SendMessage(c.ID, message) } - // EditMessage edits a Message in this TextChannel func (c MessageChannel) EditMessage(messageID Snowflake, message MessageUpdate) (*Message, error) { return c.Disgo.RestClient().EditMessage(c.ID, messageID, message) diff --git a/api/embed.go b/api/embed.go index c6d7aa17..15ed1292 100644 --- a/api/embed.go +++ b/api/embed.go @@ -2,7 +2,6 @@ package api import ( "fmt" - "time" ) // EmbedType is the type of an Embed @@ -24,7 +23,7 @@ type Embed struct { Type *EmbedType `json:"type,omitempty"` Description *string `json:"description,omitempty"` URL *string `json:"url,omitempty"` - Timestamp *time.Time `json:"timestamp,omitempty"` + Timestamp *Time `json:"timestamp,omitempty"` Color *int `json:"color,omitempty"` Footer *EmbedFooter `json:"footer,omitempty"` Image *EmbedResource `json:"image,omitempty"` diff --git a/api/endpoints/route_test.go b/api/endpoints/route_test.go index 62c91b59..22a0b965 100644 --- a/api/endpoints/route_test.go +++ b/api/endpoints/route_test.go @@ -19,4 +19,4 @@ func TestCustomRoute_Compile(t *testing.T) { testAPI := NewCustomRoute(GET, "https://test.de/{test}") assert.Equal(t, "https://test.de/test", testAPI.Compile("test").Route()) -} \ No newline at end of file +} diff --git a/api/guild.go b/api/guild.go index 6447ad2d..0cc650f1 100644 --- a/api/guild.go +++ b/api/guild.go @@ -2,7 +2,6 @@ package api import ( "strings" - "time" "github.com/DisgoOrg/disgo/api/endpoints" ) @@ -107,7 +106,7 @@ type Guild struct { Icon *string `json:"icon"` Region string `json:"region"` OwnerID Snowflake `json:"owner_id"` - JoinedAt *time.Time `json:"joined_at"` + JoinedAt *Time `json:"joined_at"` DiscoverySplash *string `json:"discovery_splash"` Splash *string `json:"splash"` AfkChannelID *Snowflake `json:"afk_channel_id"` diff --git a/api/member.go b/api/member.go index f74f566d..44d2bcfd 100644 --- a/api/member.go +++ b/api/member.go @@ -1,7 +1,5 @@ package api -import "time" - // Member is a discord GuildMember type Member struct { Disgo Disgo @@ -9,8 +7,8 @@ type Member struct { User *User `json:"user"` Nick *string `json:"nick"` Roles []Snowflake `json:"roles,omitempty"` - JoinedAt time.Time `json:"joined_at"` - PremiumSince *time.Time `json:"premium_since,omitempty"` + JoinedAt Time `json:"joined_at"` + PremiumSince *Time `json:"premium_since,omitempty"` Deaf *bool `json:"deaf,omitempty"` Mute *bool `json:"mute,omitempty"` Pending bool `json:"pending"` diff --git a/api/message.go b/api/message.go index fb107339..6e0f705c 100644 --- a/api/message.go +++ b/api/message.go @@ -2,7 +2,6 @@ package api import ( "errors" - "time" ) // The MessageType indicates the Message type @@ -107,7 +106,7 @@ type Message struct { Attachments []interface{} `json:"attachments"` Tts bool `json:"tts"` Embeds []*Embed `json:"embeds,omitempty"` - CreatedAt time.Time `json:"timestamp"` + CreatedAt Time `json:"timestamp"` MentionEveryone bool `json:"mention_everyone"` Pinned bool `json:"pinned"` EditedTimestamp interface{} `json:"edited_timestamp"` @@ -118,7 +117,7 @@ type Message struct { Mentions []interface{} `json:"mentions"` MessageType MessageType `json:"type"` MessageReference *MessageReference `json:"message_reference,omitempty"` - LastUpdated *time.Time + LastUpdated *Time } // MessageReference is a reference to another message diff --git a/api/time.go b/api/time.go new file mode 100644 index 00000000..decabb25 --- /dev/null +++ b/api/time.go @@ -0,0 +1,44 @@ +package api + +import ( + "bytes" + "encoding/json" + "time" +) + +const timestampFormat = "2006-01-02T15:04:05.000000+00:00" + +var emptyTime = []byte("\"\"") +var nullTime = []byte("null") + +type Time struct { + time.Time +} + +func (t Time) MarshalJSON() ([]byte, error) { + var ts string + if !t.IsZero() { + ts = t.String() + } + + return []byte(`"` + ts + `"`), nil +} + +func (t *Time) UnmarshalJSON(data []byte) error { + var ts time.Time + + if bytes.Equal(emptyTime, data) || bytes.Equal(nullTime, data) { + return nil + } + + if err := json.Unmarshal(data, &ts); err != nil { + return err + } + + t.Time = ts + return nil +} + +func (t Time) String() string { + return t.Format(timestampFormat) +} diff --git a/internal/restclient.go b/internal/restclient.go index a6d310ab..67f7cbfa 100644 --- a/internal/restclient.go +++ b/internal/restclient.go @@ -152,7 +152,7 @@ func (r RestClientImpl) DeleteMessage(channelID api.Snowflake, messageID api.Sno } // BulkDeleteMessages lets you bulk delete api.Message(s) -func (r RestClientImpl) BulkDeleteMessages(channelID api.Snowflake, messageIDs... api.Snowflake) error { +func (r RestClientImpl) BulkDeleteMessages(channelID api.Snowflake, messageIDs ...api.Snowflake) error { return r.Request(endpoints.BulkDeleteMessage.Compile(channelID), api.MessageBulkDelete{Messages: messageIDs}, nil) } From e75d90215a00f6c4b72ee6bc776629f4b5b08db8 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Wed, 31 Mar 2021 01:58:20 +0200 Subject: [PATCH 06/65] smol cache stuff --- api/cache.go | 27 ++++++++++++++------------- internal/cache.go | 26 +++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/api/cache.go b/api/cache.go index d8e9a22e..7086c940 100644 --- a/api/cache.go +++ b/api/cache.go @@ -5,6 +5,16 @@ type Cache interface { Close() DoCleanup() + User(Snowflake) *User + UserByTag(string) *User + UsersByName(string, bool) []*User + Users() []*User + UserCache() map[Snowflake]*User + CacheUser(*User) + UncacheUser(Snowflake) + FindUser(func(*User) bool) *User + FindUsers(func(*User) bool) []*User + Guild(Snowflake) *Guild GuildsByName(string, bool) []*Guild Guilds() []*Guild @@ -12,23 +22,14 @@ type Cache interface { CacheGuild(*Guild) UncacheGuild(Snowflake) - /*Message(Snowflake) *Message + Message(Snowflake) *Message Messages(Snowflake) []*Message AllMessages() []*Message MessageCache(Snowflake) map[Snowflake]*Message AllMessageCache() map[Snowflake]map[Snowflake]*Message CacheMessage(*Message) - UncacheMessage(Snowflake)*/ + UncacheMessage(Snowflake) - User(Snowflake) *User - UserByTag(string) *User - UsersByName(string, bool) []*User - Users() []*User - UserCache() map[Snowflake]*User - CacheUser(*User) - UncacheUser(Snowflake) - FindUser(func(*User) bool) *User - FindUsers(func(*User) bool) []*User Member(Snowflake, Snowflake) *Member MemberByTag(Snowflake, string) *Member @@ -109,10 +110,10 @@ type Cache interface { FindCategory(Snowflake, func(*Category) bool) *Category FindCategories(Snowflake, func(*Category) bool) []*Category - /*Emote(Snowflake) *Emote + Emote(Snowflake) *Emote EmotesByName(string, bool) []*Emote Emotes() []*Emote EmoteCache() map[Snowflake]*Emote CacheEmote(*Emote) - UncacheEmote(Snowflake)*/ + UncacheEmote(Snowflake) } diff --git a/internal/cache.go b/internal/cache.go index fc33cc4f..eec1019e 100644 --- a/internal/cache.go +++ b/internal/cache.go @@ -25,6 +25,7 @@ func newCacheImpl(messageCachePolicy api.MessageCachePolicy, memberCachePolicy a cacheEmotes: cacheEmotes, users: map[api.Snowflake]*api.User{}, guilds: map[api.Snowflake]*api.Guild{}, + messages: map[api.Snowflake]*api.Message{}, members: map[api.Snowflake]map[api.Snowflake]*api.Member{}, voiceStates: map[api.Snowflake]map[api.Snowflake]*api.VoiceState{}, roles: map[api.Snowflake]map[api.Snowflake]*api.Role{}, @@ -49,6 +50,7 @@ type CacheImpl struct { cacheEmotes bool users map[api.Snowflake]*api.User guilds map[api.Snowflake]*api.Guild + messages map[api.Snowflake]*api.Message members map[api.Snowflake]map[api.Snowflake]*api.Member voiceStates map[api.Snowflake]map[api.Snowflake]*api.VoiceState roles map[api.Snowflake]map[api.Snowflake]*api.Role @@ -260,6 +262,28 @@ func (c *CacheImpl) FindGuilds(check func(g *api.Guild) bool) []*api.Guild { return guilds } +func (c *CacheImpl) Message(messageID api.Snowflake) *api.Message { + +} +func (c *CacheImpl) Messages(messageID api.Snowflake) []*api.Message { + +} +func (c *CacheImpl) AllMessages() []*api.Message { + +} +func (c *CacheImpl) MessageCache(messageID api.Snowflake) map[api.Snowflake]*api.Message { + +} +func (c *CacheImpl) AllMessageCache() map[api.Snowflake]map[api.Snowflake]*api.Message { + +} +func (c *CacheImpl) CacheMessage(message *api.Message) { + +} +func (c *CacheImpl) UncacheMessage(messageID api.Snowflake) { + +} + // Member returns a member from cache by guild ID and user ID func (c *CacheImpl) Member(guildID api.Snowflake, userID api.Snowflake) *api.Member { if guildMembers, ok := c.members[guildID]; ok { @@ -1043,4 +1067,4 @@ func (c *CacheImpl) FindCategories(guildID api.Snowflake, check func(u *api.Cate } // TODO: add emote cache -// TODO: add message cache \ No newline at end of file +// TODO: add message cache From 1948952820d939e16a3332a84bf2226de74a0e2c Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Wed, 31 Mar 2021 18:05:13 +0200 Subject: [PATCH 07/65] wip interfaces --- api/user.go | 64 ++++++++++++++++---------------- internal/user_impl.go | 86 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+), 31 deletions(-) create mode 100644 internal/user_impl.go diff --git a/api/user.go b/api/user.go index 70b04138..fb2679ec 100644 --- a/api/user.go +++ b/api/user.go @@ -1,38 +1,40 @@ package api -// User is a struct for interacting with discord's users -type User struct { - Disgo Disgo - ID Snowflake `json:"id"` - Username string `json:"username"` - Discriminator string `json:"discriminator"` - Avatar *string `json:"avatar"` - IsBot bool `json:"bot"` - System *bool `json:"system"` - MfaEnabled *bool `json:"mfa_enabled"` - Locale *string `json:"locale"` - Verified *bool `json:"verified"` - Email *string `json:"email"` - Flags *int `json:"flags"` - PremiumType *int `json:"premium_type"` - PublicFlags *int `json:"public_flags"` -} +var _ Mentionable = (User)(nil) -// Mention returns the user as a mention -func (u User) Mention() string { - return "<@" + u.ID.String() + ">" -} -// Tag returns the user's Username and Discriminator -func (u User) Tag() string { - return u.Username + "#" + u.Discriminator +// User is a struct for interacting with discord's users +type User interface { + Disgo() Disgo + ID() Snowflake + Username() string + Discriminator() int + Tag() string + AvatarURL() *string + EffectiveAvatarURL() string + Bot() bool + Flags() UserFlags + String() string + Mention() string + OpenDMChannel() (*DMChannel, error) } -func (u User) String() string { - return u.Mention() -} -// OpenDMChannel creates a DMChannel between the user and the Disgo client -func (u User) OpenDMChannel() (*DMChannel, error) { - return u.Disgo.RestClient().OpenDMChannel(u.ID) -} +type UserFlags int64 + +const ( + UserFlagsNone UserFlags = 0 + UserFlagDiscordEmployee UserFlags = 1 << iota + UserFlagPartneredServerOwner + UserFlagHypeSquadEvents + UserFlagBugHunterLevel1 + UserFlagHouseBravery + UserFlagHouseBrilliance + UserFlagHouseBalance + UserFlagEarlySupporter + UserFlagTeamUser + UserFlagSystem + UserFlagBugHunterLevel2 + UserFlagVerifiedBot + UserFlagEarlyVerifiedBotDeveloper +) diff --git a/internal/user_impl.go b/internal/user_impl.go new file mode 100644 index 00000000..2c2bc7f2 --- /dev/null +++ b/internal/user_impl.go @@ -0,0 +1,86 @@ +package internal + +import ( + "fmt" + "strings" + + "github.com/DisgoOrg/disgo/api" + "github.com/DisgoOrg/disgo/api/endpoints" +) + +var _ api.User = (UserImpl)(nil) +var _ api.Mentionable = (UserImpl)(nil) + +type UserImpl struct { + disgo api.Disgo + id api.Snowflake `json:"id"` + username string `json:"username"` + discriminator int `json:"discriminator"` + avatar *string `json:"avatar"` + bot bool `json:"bot"` + flags api.UserFlags `json:"public_flags"` +} + +func (u UserImpl) Disgo() api.Disgo { + return u.disgo +} + +func (u UserImpl) ID() api.Snowflake { + return u.id +} + +func (u UserImpl) Username() string { + return u.username +} + +func (u UserImpl) Discriminator() int { + return u.discriminator +} + +// Tag returns the user's Username#Discriminator +func (u UserImpl) Tag() string { + return fmt.Sprintf("%s#%d", u.username, u.discriminator) +} + +func (u UserImpl) AvatarURL() *string { + if u.avatar == nil { + return nil + } + animated := strings.HasPrefix(*u.avatar, "a_") + format := endpoints.PNG + if animated { + format = endpoints.GIF + } + a := endpoints.UserAvatar.Compile(format, u.id, *u.avatar).Route() + return &a +} + +func (u UserImpl) EffectiveAvatarURL() string { + a := u.AvatarURL() + if a != nil { + return *a + } + return endpoints.DefaultUserAvatar.Compile(endpoints.PNG, u.discriminator%5).Route() +} + +func (u UserImpl) Bot() bool { + return u.bot +} + +func (u UserImpl) Flags() api.UserFlags { + return u.flags +} + +// Mention returns the user as a mention +func (u UserImpl) Mention() string { + return "<@" + u.id.String() + ">" +} + +func (u UserImpl) String() string { + return u.Mention() +} + +// OpenDMChannel creates a DMChannel between the user and the Disgo client +func (u UserImpl) OpenDMChannel() (*api.DMChannel, error) { + return u.Disgo().RestClient().OpenDMChannel(u.ID()) +} From 063e49fed17735ae423bcc77d9784744b0517034 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Thu, 1 Apr 2021 01:00:10 +0200 Subject: [PATCH 08/65] =?UTF-8?q?I'm=20not=20doing=20much=20progress=20her?= =?UTF-8?q?e=20stop=20lurking=20=F0=9F=91=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/{cache.go => cache_impl.go} | 0 internal/{disgo_builder.go => disgo_builder_impl.go} | 0 internal/{disgo.go => disgo_impl.go} | 0 internal/{event_manager.go => event_manager_impl.go} | 0 internal/{gateway.go => gateway_impl.go} | 0 internal/member_impl.go | 1 + internal/{restclient.go => restclient_impl.go} | 0 7 files changed, 1 insertion(+) rename internal/{cache.go => cache_impl.go} (100%) rename internal/{disgo_builder.go => disgo_builder_impl.go} (100%) rename internal/{disgo.go => disgo_impl.go} (100%) rename internal/{event_manager.go => event_manager_impl.go} (100%) rename internal/{gateway.go => gateway_impl.go} (100%) create mode 100644 internal/member_impl.go rename internal/{restclient.go => restclient_impl.go} (100%) diff --git a/internal/cache.go b/internal/cache_impl.go similarity index 100% rename from internal/cache.go rename to internal/cache_impl.go diff --git a/internal/disgo_builder.go b/internal/disgo_builder_impl.go similarity index 100% rename from internal/disgo_builder.go rename to internal/disgo_builder_impl.go diff --git a/internal/disgo.go b/internal/disgo_impl.go similarity index 100% rename from internal/disgo.go rename to internal/disgo_impl.go diff --git a/internal/event_manager.go b/internal/event_manager_impl.go similarity index 100% rename from internal/event_manager.go rename to internal/event_manager_impl.go diff --git a/internal/gateway.go b/internal/gateway_impl.go similarity index 100% rename from internal/gateway.go rename to internal/gateway_impl.go diff --git a/internal/member_impl.go b/internal/member_impl.go new file mode 100644 index 00000000..5bf0569c --- /dev/null +++ b/internal/member_impl.go @@ -0,0 +1 @@ +package internal diff --git a/internal/restclient.go b/internal/restclient_impl.go similarity index 100% rename from internal/restclient.go rename to internal/restclient_impl.go From 0e2026757d05ef54d4885725270c9ddc933ce307 Mon Sep 17 00:00:00 2001 From: Alex <46286597+Alex-R-31@users.noreply.github.com> Date: Sat, 3 Apr 2021 09:15:13 +0100 Subject: [PATCH 09/65] Add message flags 16/17 --- api/message.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/message.go b/api/message.go index fb107339..cf724513 100644 --- a/api/message.go +++ b/api/message.go @@ -26,8 +26,8 @@ const ( _ MessageTypeGuildDiscoveryDisqualified MessageTypeGuildDiscoveryRequalified - _ - _ + MessageTypeGuildDiscoveryInitialWarning + MessageTypeGuildDiscoveryFinalWarning _ MessageTypeReply MessageTypeApplicationCommand From 8cd4f10720d0c6ea324665cd5ccf28de738dca3c Mon Sep 17 00:00:00 2001 From: Alex <46286597+Alex-R-31@users.noreply.github.com> Date: Sat, 3 Apr 2021 09:21:18 +0100 Subject: [PATCH 10/65] Add MessageFlagLoading --- api/message.go | 1 + 1 file changed, 1 insertion(+) diff --git a/api/message.go b/api/message.go index cf724513..9a0ace89 100644 --- a/api/message.go +++ b/api/message.go @@ -96,6 +96,7 @@ const ( MessageFlagUrgent _ MessageFlagEphemeral + MessageFlagLoading // Message is an interaction of type 5, awaiting further response ) // Message is a struct for messages sent in discord text-based channels From be38a2ae7261fdc867fea51f4e7eca449fe1d2a3 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Sat, 3 Apr 2021 19:59:14 +0200 Subject: [PATCH 11/65] added interaction follow up messages --- api/events/interaction_events.go | 31 ++++++++++++ api/interaction_followup.go | 81 ++++++++++++++++++++++++++++++++ api/interaction_response.go | 5 -- api/restclient.go | 2 +- internal/restclient.go | 8 ++-- testbot/testbot.go | 20 ++++---- 6 files changed, 128 insertions(+), 19 deletions(-) create mode 100644 api/interaction_followup.go diff --git a/api/events/interaction_events.go b/api/events/interaction_events.go index 87fdf2cd..d8e737ba 100644 --- a/api/events/interaction_events.go +++ b/api/events/interaction_events.go @@ -205,6 +205,11 @@ func (e SlashCommandEvent) OptionsByType(optionType api.SlashCommandOptionType) return options } +// Acknowledge replies to the api.Interaction with api.InteractionResponseTypeDeferredChannelMessageWithSource +func (e *SlashCommandEvent) Acknowledge() error { + return e.Reply(api.NewInteractionResponseBuilder().SetType(api.InteractionResponseTypeDeferredChannelMessageWithSource).Build()) +} + // Reply replies to the api.Interaction with the provided api.InteractionResponse func (e *SlashCommandEvent) Reply(response api.InteractionResponse) error { if e.Replied { @@ -219,3 +224,29 @@ func (e *SlashCommandEvent) Reply(response api.InteractionResponse) error { return e.Disgo.RestClient().SendInteractionResponse(e.Interaction.ID, e.Interaction.Token, response) } + +// EditOriginal edits the original api.InteractionResponse +func (e *SlashCommandEvent) EditOriginal(followupMessage api.FollowupMessage) (*api.Message, error) { + return e.Disgo.RestClient().EditInteractionResponse(e.Interaction.ID, e.Interaction.Token, followupMessage) +} + +// DeleteOriginal deletes the original api.InteractionResponse +func (e *SlashCommandEvent) DeleteOriginal() error { + return e.Disgo.RestClient().DeleteInteractionResponse(e.Interaction.ID, e.Interaction.Token) +} + +// SendFollowup used to send a api.FollowupMessage to an api.Interaction +func (e *SlashCommandEvent) SendFollowup(followupMessage api.FollowupMessage) (*api.Message, error) { + return e.Disgo.RestClient().SendFollowupMessage(e.Interaction.ID, e.Interaction.Token, followupMessage) +} + +// EditFollowup used to edit a api.FollowupMessage from an api.Interaction +func (e *SlashCommandEvent) EditFollowup(messageID api.Snowflake, followupMessage api.FollowupMessage) (*api.Message, error) { + return e.Disgo.RestClient().EditFollowupMessage(e.Interaction.ID, e.Interaction.Token, messageID, followupMessage) +} + +// DeleteFollowup used to delete a api.FollowupMessage from an api.Interaction +func (e *SlashCommandEvent) DeleteFollowup(messageID api.Snowflake) error { + return e.Disgo.RestClient().DeleteFollowupMessage(e.Interaction.ID, e.Interaction.Token, messageID) +} + diff --git a/api/interaction_followup.go b/api/interaction_followup.go new file mode 100644 index 00000000..6aaf33fa --- /dev/null +++ b/api/interaction_followup.go @@ -0,0 +1,81 @@ +package api + +// FollowupMessage is used to add additional messages to an Interaction after you've responded initially +type FollowupMessage struct { + Content string `json:"content,omitempty"` + Username string `json:"username,omitempty"` + AvatarURL string `json:"avatar_url,omitempty"` + TTS bool `json:"tts,omitempty"` + Embeds []Embed `json:"embeds,omitempty"` + AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` + //PayloadJSON string `json:"payload_json"` + //File FileContents `json:"file"` +} + +// FollowupMessageBuilder allows you to create an FollowupMessage with ease +type FollowupMessageBuilder struct { + FollowupMessage +} + +// NewInteractionResponseBuilder returns a new FollowupMessageBuilder +func NewFollowupMessageBuilder() *FollowupMessageBuilder { + return &FollowupMessageBuilder{ + FollowupMessage{}, + } +} + +// SetTTS sets if the FollowupMessage is a tts message +func (b *FollowupMessageBuilder) SetTTS(tts bool) *FollowupMessageBuilder { + b.TTS = tts + return b +} + +// SetContent sets the content of the FollowupMessage +func (b *FollowupMessageBuilder) SetContent(content string) *FollowupMessageBuilder { + b.Content = content + return b +} + +// SetEmbeds sets the embeds of the FollowupMessage +func (b *FollowupMessageBuilder) SetEmbeds(embeds ...Embed) *FollowupMessageBuilder { + b.Embeds = embeds + return b +} + +// AddEmbeds adds multiple embeds to the FollowupMessage +func (b *FollowupMessageBuilder) AddEmbeds(embeds ...Embed) *FollowupMessageBuilder { + b.Embeds = append(b.Embeds, embeds...) + return b +} + +// ClearEmbeds removes all of the embeds from the FollowupMessage +func (b *FollowupMessageBuilder) ClearEmbeds() *FollowupMessageBuilder { + if b.Embeds != nil { + b.Embeds = []Embed{} + } + return b +} + +// RemoveEmbed removes an embed from the FollowupMessage +func (b *FollowupMessageBuilder) RemoveEmbed(index int) *FollowupMessageBuilder { + if b != nil && len(b.Embeds) > index { + b.Embeds = append(b.Embeds[:index], b.Embeds[index+1:]...) + } + return b +} + +// SetAllowedMentions sets the allowed mentions of the FollowupMessage +func (b *FollowupMessageBuilder) SetAllowedMentions(allowedMentions *AllowedMentions) *FollowupMessageBuilder { + b.AllowedMentions = allowedMentions + return b +} + +// SetAllowedMentionsEmpty sets the allowed mentions of the FollowupMessage to nothing +func (b *FollowupMessageBuilder) SetAllowedMentionsEmpty() *FollowupMessageBuilder { + return b.SetAllowedMentions(&AllowedMentions{}) +} + +// Build returns your built FollowupMessage +func (b *FollowupMessageBuilder) Build() FollowupMessage { + return b.FollowupMessage +} diff --git a/api/interaction_response.go b/api/interaction_response.go index 3c9ab372..c0918e3e 100644 --- a/api/interaction_response.go +++ b/api/interaction_response.go @@ -148,8 +148,3 @@ func (b *InteractionResponseBuilder) SetEphemeral(ephemeral bool) *InteractionRe func (b *InteractionResponseBuilder) Build() InteractionResponse { return b.InteractionResponse } - -// FollowupMessage is used to add additional messages to an Interaction after you've responded initially -type FollowupMessage struct { - // Todo: fill this -} diff --git a/api/restclient.go b/api/restclient.go index 70880083..2db18690 100644 --- a/api/restclient.go +++ b/api/restclient.go @@ -68,7 +68,7 @@ type RestClient interface { DeleteGuildCommand(applicationID Snowflake, guildID Snowflake, commandID Snowflake) error SendInteractionResponse(interactionID Snowflake, interactionToken string, interactionResponse InteractionResponse) error - EditInteractionResponse(applicationID Snowflake, interactionToken string, interactionResponse InteractionResponse) (*Message, error) + EditInteractionResponse(applicationID Snowflake, interactionToken string, followupMessage FollowupMessage) (*Message, error) DeleteInteractionResponse(applicationID Snowflake, interactionToken string) error SendFollowupMessage(applicationID Snowflake, interactionToken string, followupMessage FollowupMessage) (*Message, error) diff --git a/internal/restclient.go b/internal/restclient.go index a6d310ab..92718cfe 100644 --- a/internal/restclient.go +++ b/internal/restclient.go @@ -438,8 +438,8 @@ func (r RestClientImpl) SendInteractionResponse(interactionID api.Snowflake, int } // EditInteractionResponse used to edit the initial response on an interaction -func (r RestClientImpl) EditInteractionResponse(applicationID api.Snowflake, interactionToken string, interactionResponse api.InteractionResponse) (message *api.Message, err error) { - return message, r.Request(endpoints.EditInteractionResponse.Compile(applicationID, interactionToken), interactionResponse, &message) +func (r RestClientImpl) EditInteractionResponse(applicationID api.Snowflake, interactionToken string, followupMessage api.FollowupMessage) (message *api.Message, err error) { + return message, r.Request(endpoints.EditInteractionResponse.Compile(applicationID, interactionToken), followupMessage, &message) } // DeleteInteractionResponse used to delete the initial response on an interaction @@ -452,12 +452,12 @@ func (r RestClientImpl) SendFollowupMessage(applicationID api.Snowflake, interac return message, r.Request(endpoints.CreateInteractionResponse.Compile(applicationID, interactionToken), followupMessage, &message) } -// EditFollowupMessage used to send the initial response on an interaction +// EditFollowupMessage used to edit a api.FollowupMessage from an api.Interaction func (r RestClientImpl) EditFollowupMessage(applicationID api.Snowflake, interactionToken string, messageID api.Snowflake, followupMessage api.FollowupMessage) (message *api.Message, err error) { return message, r.Request(endpoints.CreateInteractionResponse.Compile(applicationID, interactionToken, messageID), followupMessage, &message) } -// DeleteFollowupMessage used to send a followup message_events to an interaction +// DeleteFollowupMessage used to delete a api.FollowupMessage from an api.Interaction func (r RestClientImpl) DeleteFollowupMessage(applicationID api.Snowflake, interactionToken string, messageID api.Snowflake) error { return r.Request(endpoints.CreateInteractionResponse.Compile(applicationID, interactionToken, messageID), nil, nil) } diff --git a/testbot/testbot.go b/testbot/testbot.go index 6beaaac5..93e23c99 100644 --- a/testbot/testbot.go +++ b/testbot/testbot.go @@ -4,6 +4,7 @@ import ( "os" "os/signal" "syscall" + "time" log "github.com/sirupsen/logrus" @@ -115,15 +116,16 @@ func slashCommandListener(event *events.SlashCommandEvent) { Build(), ) case "test": - _ = event.Reply(api.NewInteractionResponseBuilder(). - SetContent("test"). - SetEphemeral(true). - AddEmbeds( - api.NewEmbedBuilder().SetDescription("test1").Build(), - api.NewEmbedBuilder().SetDescription("test2").Build(), - ). - Build(), - ) + go func() { + _ = event.Acknowledge() + time.Sleep(2 * time.Second) + _, _ = event.EditOriginal(api.NewFollowupMessageBuilder(). + SetEmbeds(api.NewEmbedBuilder(). + SetDescription("Edited Original"). + Build(), + ).Build(), + ) + }() case "addrole": user := event.OptionByName("member").User() role := event.OptionByName("role").Role() From a7700957333bc7b9712850da64832a1a0e41f4ca Mon Sep 17 00:00:00 2001 From: Alex <46286597+Alex-R-31@users.noreply.github.com> Date: Sat, 3 Apr 2021 19:07:23 +0100 Subject: [PATCH 12/65] Let tests run on PRs to development branch --- .github/workflows/go.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 89635783..c7a74648 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -2,9 +2,9 @@ name: Go on: push: - branches: [ master ] + branches: [ master, development ] pull_request: - branches: [ master ] + branches: [ master, development ] jobs: From 185cdd94cbdb572656e141b98dd8d10e59f5c13d Mon Sep 17 00:00:00 2001 From: Alex <46286597+Alex-R-31@users.noreply.github.com> Date: Sat, 3 Apr 2021 19:09:20 +0100 Subject: [PATCH 13/65] fix channels lint --- api/channels.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/channels.go b/api/channels.go index 83a05d30..274aab6a 100644 --- a/api/channels.go +++ b/api/channels.go @@ -61,7 +61,7 @@ func (c MessageChannel) DeleteMessage(messageID Snowflake) error { return c.Disgo.RestClient().DeleteMessage(c.ID, messageID) } -// DeleteMessage allows you bulk delete Message(s) +// BulkDeleteMessages allows you bulk delete Message(s) func (c MessageChannel) BulkDeleteMessages(messageIDs ...Snowflake) error { return c.Disgo.RestClient().BulkDeleteMessages(c.ID, messageIDs...) } From 6b7a761da2c6ceb1d5e750617f036a6bf71ec222 Mon Sep 17 00:00:00 2001 From: Alex <46286597+Alex-R-31@users.noreply.github.com> Date: Sat, 3 Apr 2021 19:09:44 +0100 Subject: [PATCH 14/65] fix interaction followup lint --- api/interaction_followup.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/interaction_followup.go b/api/interaction_followup.go index 6aaf33fa..da3ce590 100644 --- a/api/interaction_followup.go +++ b/api/interaction_followup.go @@ -17,7 +17,7 @@ type FollowupMessageBuilder struct { FollowupMessage } -// NewInteractionResponseBuilder returns a new FollowupMessageBuilder +// NewFollowupMessageBuilder returns a new FollowupMessageBuilder func NewFollowupMessageBuilder() *FollowupMessageBuilder { return &FollowupMessageBuilder{ FollowupMessage{}, From 6d12fe980db768a675ec47ba1fe690202828d092 Mon Sep 17 00:00:00 2001 From: Alex <46286597+Alex-R-31@users.noreply.github.com> Date: Sat, 3 Apr 2021 19:15:11 +0100 Subject: [PATCH 15/65] Revert "voice state cache" --- api/activity.go | 8 +- api/cache.go | 33 ++- api/channels.go | 3 +- api/disgo.go | 4 +- api/disgo_builder.go | 6 - api/embed.go | 3 +- api/endpoints/route_test.go | 2 +- api/events/guild_member_voice_events.go | 24 -- api/guild.go | 34 +-- api/member.go | 6 +- api/message.go | 5 +- api/options.go | 6 - api/time.go | 44 ---- api/user.go | 64 +++--- api/voice_dispatch_interceptor.go | 39 ---- api/voice_state.go | 55 +---- internal/{cache_impl.go => cache.go} | 187 ++++------------ internal/{disgo_impl.go => disgo.go} | 36 +-- internal/disgo_builder.go | 155 +++++++++++++ internal/disgo_builder_impl.go | 206 ------------------ ...event_manager_impl.go => event_manager.go} | 0 internal/{gateway_impl.go => gateway.go} | 0 internal/handlers/all_handlers.go | 3 - internal/handlers/guild_create_handler.go | 20 +- .../handlers/voice_server_update_handler.go | 34 --- .../handlers/voice_state_update_handler.go | 47 ---- internal/member_impl.go | 1 - .../{restclient_impl.go => restclient.go} | 2 +- internal/user_impl.go | 86 -------- testbot/testbot.go | 2 +- 30 files changed, 293 insertions(+), 822 deletions(-) delete mode 100644 api/events/guild_member_voice_events.go delete mode 100644 api/time.go delete mode 100644 api/voice_dispatch_interceptor.go rename internal/{cache_impl.go => cache.go} (82%) rename internal/{disgo_impl.go => disgo.go} (77%) create mode 100644 internal/disgo_builder.go delete mode 100644 internal/disgo_builder_impl.go rename internal/{event_manager_impl.go => event_manager.go} (100%) rename internal/{gateway_impl.go => gateway.go} (100%) delete mode 100644 internal/handlers/voice_server_update_handler.go delete mode 100644 internal/handlers/voice_state_update_handler.go delete mode 100644 internal/member_impl.go rename internal/{restclient_impl.go => restclient.go} (99%) delete mode 100644 internal/user_impl.go diff --git a/api/activity.go b/api/activity.go index 0820a41a..c13c6e67 100644 --- a/api/activity.go +++ b/api/activity.go @@ -1,5 +1,7 @@ package api +import "time" + // ActivityType represents the status of a user, one of Game, Streaming, Listening, Custom or Competing type ActivityType int @@ -18,7 +20,7 @@ type Activity struct { Name string `json:"name"` Type ActivityType `json:"type"` URL *string `json:"url"` - CreatedAt Time `json:"created_at"` + CreatedAt time.Time `json:"created_at"` Timestamps *ActivityTimestamps `json:"timestamps,omitempty"` ApplicationID Snowflake `json:"application_id,omitempty"` Details *string `json:"details,omitempty"` @@ -33,8 +35,8 @@ type Activity struct { // ActivityTimestamps represents when a user started and ended their activity type ActivityTimestamps struct { - Start *Time `json:"start,omitempty"` - End *Time `json:"end,omitempty"` + Start *time.Time `json:"start,omitempty"` + End *time.Time `json:"end,omitempty"` } // ActivityEmoji is an Emoji object for an Activity diff --git a/api/cache.go b/api/cache.go index 7086c940..06aa3aff 100644 --- a/api/cache.go +++ b/api/cache.go @@ -5,16 +5,6 @@ type Cache interface { Close() DoCleanup() - User(Snowflake) *User - UserByTag(string) *User - UsersByName(string, bool) []*User - Users() []*User - UserCache() map[Snowflake]*User - CacheUser(*User) - UncacheUser(Snowflake) - FindUser(func(*User) bool) *User - FindUsers(func(*User) bool) []*User - Guild(Snowflake) *Guild GuildsByName(string, bool) []*Guild Guilds() []*Guild @@ -22,14 +12,23 @@ type Cache interface { CacheGuild(*Guild) UncacheGuild(Snowflake) - Message(Snowflake) *Message + /*Message(Snowflake) *Message Messages(Snowflake) []*Message AllMessages() []*Message MessageCache(Snowflake) map[Snowflake]*Message AllMessageCache() map[Snowflake]map[Snowflake]*Message CacheMessage(*Message) - UncacheMessage(Snowflake) + UncacheMessage(Snowflake)*/ + User(Snowflake) *User + UserByTag(string) *User + UsersByName(string, bool) []*User + Users() []*User + UserCache() map[Snowflake]*User + CacheUser(*User) + UncacheUser(Snowflake) + FindUser(func(*User) bool) *User + FindUsers(func(*User) bool) []*User Member(Snowflake, Snowflake) *Member MemberByTag(Snowflake, string) *Member @@ -43,12 +42,6 @@ type Cache interface { FindMember(Snowflake, func(*Member) bool) *Member FindMembers(Snowflake, func(*Member) bool) []*Member - VoiceState(guildID Snowflake, userID Snowflake) *VoiceState - VoiceStates(guildID Snowflake) []*VoiceState - VoiceStateCache(guildID Snowflake) map[Snowflake]*VoiceState - CacheVoiceState(voiceState *VoiceState) - UncacheVoiceState(guildID Snowflake, userID Snowflake) - Role(Snowflake, Snowflake) *Role RolesByName(Snowflake, string, bool) []*Role Roles(Snowflake) []*Role @@ -110,10 +103,10 @@ type Cache interface { FindCategory(Snowflake, func(*Category) bool) *Category FindCategories(Snowflake, func(*Category) bool) []*Category - Emote(Snowflake) *Emote + /*Emote(Snowflake) *Emote EmotesByName(string, bool) []*Emote Emotes() []*Emote EmoteCache() map[Snowflake]*Emote CacheEmote(*Emote) - UncacheEmote(Snowflake) + UncacheEmote(Snowflake)*/ } diff --git a/api/channels.go b/api/channels.go index 5c9e2b93..274aab6a 100644 --- a/api/channels.go +++ b/api/channels.go @@ -36,7 +36,7 @@ type Channel struct { ApplicationID *Snowflake `json:"application_id,omitempty"` ParentID *Snowflake `json:"parent_id,omitempty"` Permissions *Permissions `json:"permissions,omitempty"` - //LastPinTimestamp *Time `json:"last_pin_timestamp,omitempty"` + //LastPinTimestamp *time.Time `json:"last_pin_timestamp,omitempty"` } // MessageChannel is used for sending Message(s) to User(s) @@ -50,6 +50,7 @@ func (c MessageChannel) SendMessage(message MessageCreate) (*Message, error) { return c.Disgo.RestClient().SendMessage(c.ID, message) } + // EditMessage edits a Message in this TextChannel func (c MessageChannel) EditMessage(messageID Snowflake, message MessageUpdate) (*Message, error) { return c.Disgo.RestClient().EditMessage(c.ID, messageID, message) diff --git a/api/disgo.go b/api/disgo.go index e6e875ee..ad149a78 100644 --- a/api/disgo.go +++ b/api/disgo.go @@ -20,10 +20,8 @@ type Disgo interface { Intents() Intents ApplicationID() Snowflake SelfUser() *User - SetSelfUser(user *User) + SetSelfUser(*User) EventManager() EventManager - VoiceDispatchInterceptor() VoiceDispatchInterceptor - SetVoiceDispatchInterceptor(voiceInterceptor VoiceDispatchInterceptor) HeartbeatLatency() time.Duration GetCommand(commandID Snowflake) (*SlashCommand, error) diff --git a/api/disgo_builder.go b/api/disgo_builder.go index f05d47f2..d2b86cfb 100644 --- a/api/disgo_builder.go +++ b/api/disgo_builder.go @@ -8,18 +8,12 @@ type DisgoBuilder interface { SetToken(token string) DisgoBuilder SetIntents(intents Intents) DisgoBuilder SetEventManager(eventManager EventManager) DisgoBuilder - SetVoiceDispatchInterceptor(VoiceDispatchInterceptor) DisgoBuilder AddEventListeners(eventsListeners ...EventListener) DisgoBuilder SetWebhookServer(webhookServer WebhookServer) DisgoBuilder SetWebhookServerProperties(listenURL string, listenPort int, publicKey string) DisgoBuilder SetRestClient(restClient RestClient) DisgoBuilder SetCache(cache Cache) DisgoBuilder - SetMessageCachePolicy(messageCachePolicy MessageCachePolicy) DisgoBuilder SetMemberCachePolicy(memberCachePolicy MemberCachePolicy) DisgoBuilder - SetCacheVoiceStates(cacheVoiceStates bool) DisgoBuilder - SetCacheRoles(cacheRoles bool) DisgoBuilder - SetCacheChannels(cacheChannels bool) DisgoBuilder - SetCacheEmotes(cacheEmotes bool) DisgoBuilder SetGateway(gateway Gateway) DisgoBuilder Build() (Disgo, error) } diff --git a/api/embed.go b/api/embed.go index 15ed1292..c6d7aa17 100644 --- a/api/embed.go +++ b/api/embed.go @@ -2,6 +2,7 @@ package api import ( "fmt" + "time" ) // EmbedType is the type of an Embed @@ -23,7 +24,7 @@ type Embed struct { Type *EmbedType `json:"type,omitempty"` Description *string `json:"description,omitempty"` URL *string `json:"url,omitempty"` - Timestamp *Time `json:"timestamp,omitempty"` + Timestamp *time.Time `json:"timestamp,omitempty"` Color *int `json:"color,omitempty"` Footer *EmbedFooter `json:"footer,omitempty"` Image *EmbedResource `json:"image,omitempty"` diff --git a/api/endpoints/route_test.go b/api/endpoints/route_test.go index 22a0b965..62c91b59 100644 --- a/api/endpoints/route_test.go +++ b/api/endpoints/route_test.go @@ -19,4 +19,4 @@ func TestCustomRoute_Compile(t *testing.T) { testAPI := NewCustomRoute(GET, "https://test.de/{test}") assert.Equal(t, "https://test.de/test", testAPI.Compile("test").Route()) -} +} \ No newline at end of file diff --git a/api/events/guild_member_voice_events.go b/api/events/guild_member_voice_events.go deleted file mode 100644 index fa1bf6b6..00000000 --- a/api/events/guild_member_voice_events.go +++ /dev/null @@ -1,24 +0,0 @@ -package events - -import "github.com/DisgoOrg/disgo/api" - -type GenericGuildVoiceEvent struct { - GenericGuildMemberEvent - Member *api.Member - VoiceState *api.VoiceState -} - -// GuildMemberVoiceStateUpdateEvent indicates that the api.VoiceState of a api.Member updated -type GuildMemberVoiceStateUpdateEvent struct { - GenericGuildVoiceEvent - Left *api.VoiceChannel - Joined *api.VoiceChannel -} - -type GuildMemberVoiceDeafenEvent struct { - GenericGuildVoiceEvent -} - -func (e GuildMemberVoiceDeafenEvent) Deafened() bool { - return e.VoiceState.Deafened() -} diff --git a/api/guild.go b/api/guild.go index 0cc650f1..9b35600e 100644 --- a/api/guild.go +++ b/api/guild.go @@ -2,6 +2,7 @@ package api import ( "strings" + "time" "github.com/DisgoOrg/disgo/api/endpoints" ) @@ -88,16 +89,6 @@ const ( GuildFeaturePreviewEnabled GuildFeature = "PREVIEW_ENABLED" ) -type FullGuild struct { - *Guild - Roles []*Role `json:"roles"` - Emojis []*Emote `json:"emojis"` - Members []*Member `json:"members"` - Channels []*GuildChannel `json:"channels"` - VoiceStates []*VoiceState `json:"voice_states"` - //Presences []*Presence `json:"presences"` -} - // Guild represents a discord guild_events type Guild struct { Disgo Disgo @@ -106,7 +97,7 @@ type Guild struct { Icon *string `json:"icon"` Region string `json:"region"` OwnerID Snowflake `json:"owner_id"` - JoinedAt *Time `json:"joined_at"` + JoinedAt *time.Time `json:"joined_at"` DiscoverySplash *string `json:"discovery_splash"` Splash *string `json:"splash"` AfkChannelID *Snowflake `json:"afk_channel_id"` @@ -115,8 +106,13 @@ type Guild struct { VerificationLevel VerificationLevel `json:"verification_level"` Large *bool `json:"large"` DefaultMessageNotifications MessageNotifications `json:"default_message_notifications"` + Roles []*Role `json:"roles"` + Emojis []*Emote `json:"emojis"` + Members []*Member `json:"members"` MaxPresences *int `json:"max_presences"` MaxMembers *int `json:"max_members"` + Channels []*GuildChannel `json:"channels"` + VoiceStates []*VoiceState `json:"voice_states"` Unavailable bool `json:"unavailable"` ExplicitContentFilter ExplicitContentFilterLevel `json:"explicit_content_filter"` Features []GuildFeature `json:"features"` @@ -137,21 +133,7 @@ type Guild struct { MaxVideoChannelUsers *int `json:"max_video_channel_users"` ApproximateMemberCount *int `json:"approximate_member_count"` ApproximatePresenceCount *int `json:"approximate_presence_count"` -} - -// SelfMember returns the self Member for this Guild. SelfMember is always cached -func (g Guild) SelfMember() *Member { - return g.Member(g.Disgo.ApplicationID()) -} - -// Member returns the specific Member for this Guild from the Cache -func (g Guild) Member(userID Snowflake) *Member { - return g.Disgo.Cache().Member(g.ID, userID) -} - -// Role returns the specific Role for this Guild from the Cache -func (g Guild) Role(roleID Snowflake) *Role { - return g.Disgo.Cache().Role(g.ID, roleID) + //Presences []*Presence `json:"presences"` } // CreateRole allows you to create a new Role diff --git a/api/member.go b/api/member.go index 44d2bcfd..f74f566d 100644 --- a/api/member.go +++ b/api/member.go @@ -1,5 +1,7 @@ package api +import "time" + // Member is a discord GuildMember type Member struct { Disgo Disgo @@ -7,8 +9,8 @@ type Member struct { User *User `json:"user"` Nick *string `json:"nick"` Roles []Snowflake `json:"roles,omitempty"` - JoinedAt Time `json:"joined_at"` - PremiumSince *Time `json:"premium_since,omitempty"` + JoinedAt time.Time `json:"joined_at"` + PremiumSince *time.Time `json:"premium_since,omitempty"` Deaf *bool `json:"deaf,omitempty"` Mute *bool `json:"mute,omitempty"` Pending bool `json:"pending"` diff --git a/api/message.go b/api/message.go index acd25dfd..9a0ace89 100644 --- a/api/message.go +++ b/api/message.go @@ -2,6 +2,7 @@ package api import ( "errors" + "time" ) // The MessageType indicates the Message type @@ -107,7 +108,7 @@ type Message struct { Attachments []interface{} `json:"attachments"` Tts bool `json:"tts"` Embeds []*Embed `json:"embeds,omitempty"` - CreatedAt Time `json:"timestamp"` + CreatedAt time.Time `json:"timestamp"` MentionEveryone bool `json:"mention_everyone"` Pinned bool `json:"pinned"` EditedTimestamp interface{} `json:"edited_timestamp"` @@ -118,7 +119,7 @@ type Message struct { Mentions []interface{} `json:"mentions"` MessageType MessageType `json:"type"` MessageReference *MessageReference `json:"message_reference,omitempty"` - LastUpdated *Time + LastUpdated *time.Time } // MessageReference is a reference to another message diff --git a/api/options.go b/api/options.go index cd0f2b4e..75b3b660 100644 --- a/api/options.go +++ b/api/options.go @@ -8,10 +8,4 @@ type Options struct { ListenPort int ListenURL string PublicKey string - MessageCachePolicy MessageCachePolicy - MemberCachePolicy MemberCachePolicy - CacheVoiceStates bool - CacheRoles bool - CacheChannels bool - CacheEmotes bool } diff --git a/api/time.go b/api/time.go deleted file mode 100644 index decabb25..00000000 --- a/api/time.go +++ /dev/null @@ -1,44 +0,0 @@ -package api - -import ( - "bytes" - "encoding/json" - "time" -) - -const timestampFormat = "2006-01-02T15:04:05.000000+00:00" - -var emptyTime = []byte("\"\"") -var nullTime = []byte("null") - -type Time struct { - time.Time -} - -func (t Time) MarshalJSON() ([]byte, error) { - var ts string - if !t.IsZero() { - ts = t.String() - } - - return []byte(`"` + ts + `"`), nil -} - -func (t *Time) UnmarshalJSON(data []byte) error { - var ts time.Time - - if bytes.Equal(emptyTime, data) || bytes.Equal(nullTime, data) { - return nil - } - - if err := json.Unmarshal(data, &ts); err != nil { - return err - } - - t.Time = ts - return nil -} - -func (t Time) String() string { - return t.Format(timestampFormat) -} diff --git a/api/user.go b/api/user.go index fb2679ec..70b04138 100644 --- a/api/user.go +++ b/api/user.go @@ -1,40 +1,38 @@ package api -var _ Mentionable = (User)(nil) - - // User is a struct for interacting with discord's users -type User interface { - Disgo() Disgo - ID() Snowflake - Username() string - Discriminator() int - Tag() string - AvatarURL() *string - EffectiveAvatarURL() string - Bot() bool - Flags() UserFlags - String() string - Mention() string - OpenDMChannel() (*DMChannel, error) +type User struct { + Disgo Disgo + ID Snowflake `json:"id"` + Username string `json:"username"` + Discriminator string `json:"discriminator"` + Avatar *string `json:"avatar"` + IsBot bool `json:"bot"` + System *bool `json:"system"` + MfaEnabled *bool `json:"mfa_enabled"` + Locale *string `json:"locale"` + Verified *bool `json:"verified"` + Email *string `json:"email"` + Flags *int `json:"flags"` + PremiumType *int `json:"premium_type"` + PublicFlags *int `json:"public_flags"` } +// Mention returns the user as a mention +func (u User) Mention() string { + return "<@" + u.ID.String() + ">" +} -type UserFlags int64 +// Tag returns the user's Username and Discriminator +func (u User) Tag() string { + return u.Username + "#" + u.Discriminator +} -const ( - UserFlagsNone UserFlags = 0 - UserFlagDiscordEmployee UserFlags = 1 << iota - UserFlagPartneredServerOwner - UserFlagHypeSquadEvents - UserFlagBugHunterLevel1 - UserFlagHouseBravery - UserFlagHouseBrilliance - UserFlagHouseBalance - UserFlagEarlySupporter - UserFlagTeamUser - UserFlagSystem - UserFlagBugHunterLevel2 - UserFlagVerifiedBot - UserFlagEarlyVerifiedBotDeveloper -) +func (u User) String() string { + return u.Mention() +} + +// OpenDMChannel creates a DMChannel between the user and the Disgo client +func (u User) OpenDMChannel() (*DMChannel, error) { + return u.Disgo.RestClient().OpenDMChannel(u.ID) +} diff --git a/api/voice_dispatch_interceptor.go b/api/voice_dispatch_interceptor.go deleted file mode 100644 index 06a6f3c6..00000000 --- a/api/voice_dispatch_interceptor.go +++ /dev/null @@ -1,39 +0,0 @@ -package api - -// VoiceServerUpdate sent when a guilds voice server is updated -type VoiceServerUpdate struct { - Disgo Disgo - Token string `json:"token"` - GuildID Snowflake `json:"guild_id"` - Endpoint *string `json:"endpoint"` -} - -// Guild returns the Guild for this VoiceServerUpdate from the Cache -func (u VoiceServerUpdate) Guild() *Guild { - return u.Disgo.Cache().Guild(u.GuildID) -} - -// VoiceStateUpdate sent when someone joins/leaves/moves voice channels -type VoiceStateUpdate struct { - VoiceState - Member *Member `json:"member"` -} - -// Guild returns the Guild for this VoiceStateUpdate from the Cache -func (u VoiceStateUpdate) Guild() *Guild { - return u.Disgo.Cache().Guild(u.GuildID) -} - -// VoiceChannel returns the VoiceChannel for this VoiceStateUpdate from the Cache -func (u VoiceStateUpdate) VoiceChannel() *VoiceChannel { - if u.ChannelID == nil { - return nil - } - return u.Disgo.Cache().VoiceChannel(*u.ChannelID) -} - -// VoiceDispatchInterceptor lets you listen to VoiceServerUpdate & VoiceStateUpdate -type VoiceDispatchInterceptor interface { - OnVoiceServerUpdate(voiceServerUpdateEvent VoiceServerUpdate) - OnVoiceStateUpdate(voiceStateUpdateEvent VoiceStateUpdate) -} diff --git a/api/voice_state.go b/api/voice_state.go index 9f3e9bf6..8fb900a5 100644 --- a/api/voice_state.go +++ b/api/voice_state.go @@ -2,47 +2,16 @@ package api // A VoiceState from Discord type VoiceState struct { - Disgo Disgo - GuildID Snowflake `json:"guild_id"` - ChannelID *Snowflake `json:"channel_id"` - UserID Snowflake `json:"user_id"` - SessionID string `json:"session_id"` - GuildDeafened bool `json:"deaf"` - GuildMuted bool `json:"mute"` - SelfDeafened bool `json:"self_deaf"` - SelfMuted bool `json:"self_mute"` - Stream bool `json:"self_stream"` - Video bool `json:"self_video"` - Suppressed bool `json:"suppress"` -} - -func (s VoiceState) Muted() bool { - return s.GuildMuted || s.SelfMuted -} - -func (s VoiceState) Deafened() bool { - return s.GuildDeafened || s.SelfDeafened -} - -// Member returns the Member of this VoiceState from the Cache -func (s VoiceState) Member() *Member { - return s.Disgo.Cache().Member(s.GuildID, s.UserID) -} - -// User returns the User of this VoiceState from the Cache -func (s VoiceState) User() *User { - return s.Disgo.Cache().User(s.UserID) -} - -// Guild returns the Guild of this VoiceState from the Cache -func (s VoiceState) Guild() *Guild { - return s.Disgo.Cache().Guild(s.GuildID) -} - -// VoiceChannel returns the VoiceChannel of this VoiceState from the Cache -func (s VoiceState) VoiceChannel() *VoiceChannel { - if s.ChannelID == nil { - return nil - } - return s.Disgo.Cache().VoiceChannel(*s.ChannelID) + GuildID *Snowflake `json:"guild_id,omitempty"` + ChannelID *Snowflake `json:"channel_id"` + UserID Snowflake `json:"user_id"` + Member *Member `json:"member,omitempty"` + SessionID string `json:"session_id"` + Deaf bool `json:"deaf"` + Mute bool `json:"mute"` + SelfDeaf bool `json:"self_deaf"` + SelfMute bool `json:"self_mute"` + SelfStream *bool `json:"self_stream,omitempty"` + SelfVideo bool `json:"self_video"` + Suppress bool `json:"suppress"` } diff --git a/internal/cache_impl.go b/internal/cache.go similarity index 82% rename from internal/cache_impl.go rename to internal/cache.go index eec1019e..e2fd4206 100644 --- a/internal/cache_impl.go +++ b/internal/cache.go @@ -10,30 +10,18 @@ import ( "github.com/DisgoOrg/disgo/api" ) -// TODO: maybe cacheX currently replaces pointers which invalidates old ones which may be bad? -// should we instead keep the old one & return the set pointer on cacheX so we work further with that one in our handlers? -// else we may end up with 2 pointers for the same struct - -func newCacheImpl(messageCachePolicy api.MessageCachePolicy, memberCachePolicy api.MemberCachePolicy, cacheVoiceStates bool, cacheRoles bool, cacheChannels bool, cacheEmotes bool) api.Cache { +func newCacheImpl(memberCachePolicy api.MemberCachePolicy) api.Cache { cache := &CacheImpl{ - quit: make(chan interface{}), - messageCachePolicy: messageCachePolicy, - memberCachePolicy: memberCachePolicy, - cacheVoiceStates: cacheVoiceStates, - cacheRoles: cacheRoles, - cacheChannels: cacheChannels, - cacheEmotes: cacheEmotes, - users: map[api.Snowflake]*api.User{}, - guilds: map[api.Snowflake]*api.Guild{}, - messages: map[api.Snowflake]*api.Message{}, - members: map[api.Snowflake]map[api.Snowflake]*api.Member{}, - voiceStates: map[api.Snowflake]map[api.Snowflake]*api.VoiceState{}, - roles: map[api.Snowflake]map[api.Snowflake]*api.Role{}, - dmChannels: map[api.Snowflake]*api.DMChannel{}, - categories: map[api.Snowflake]map[api.Snowflake]*api.Category{}, - textChannels: map[api.Snowflake]map[api.Snowflake]*api.TextChannel{}, - voiceChannels: map[api.Snowflake]map[api.Snowflake]*api.VoiceChannel{}, - storeChannels: map[api.Snowflake]map[api.Snowflake]*api.StoreChannel{}, + memberCachePolicy: memberCachePolicy, + users: map[api.Snowflake]*api.User{}, + guilds: map[api.Snowflake]*api.Guild{}, + members: map[api.Snowflake]map[api.Snowflake]*api.Member{}, + roles: map[api.Snowflake]map[api.Snowflake]*api.Role{}, + dmChannels: map[api.Snowflake]*api.DMChannel{}, + categories: map[api.Snowflake]map[api.Snowflake]*api.Category{}, + textChannels: map[api.Snowflake]map[api.Snowflake]*api.TextChannel{}, + voiceChannels: map[api.Snowflake]map[api.Snowflake]*api.VoiceChannel{}, + storeChannels: map[api.Snowflake]map[api.Snowflake]*api.StoreChannel{}, } go cache.cleanup(10 * time.Second) return cache @@ -41,24 +29,17 @@ func newCacheImpl(messageCachePolicy api.MessageCachePolicy, memberCachePolicy a // CacheImpl is used for Disgo's Cache type CacheImpl struct { - quit chan interface{} - messageCachePolicy api.MessageCachePolicy - memberCachePolicy api.MemberCachePolicy - cacheVoiceStates bool - cacheRoles bool - cacheChannels bool - cacheEmotes bool - users map[api.Snowflake]*api.User - guilds map[api.Snowflake]*api.Guild - messages map[api.Snowflake]*api.Message - members map[api.Snowflake]map[api.Snowflake]*api.Member - voiceStates map[api.Snowflake]map[api.Snowflake]*api.VoiceState - roles map[api.Snowflake]map[api.Snowflake]*api.Role - dmChannels map[api.Snowflake]*api.DMChannel - categories map[api.Snowflake]map[api.Snowflake]*api.Category - textChannels map[api.Snowflake]map[api.Snowflake]*api.TextChannel - voiceChannels map[api.Snowflake]map[api.Snowflake]*api.VoiceChannel - storeChannels map[api.Snowflake]map[api.Snowflake]*api.StoreChannel + quit chan bool + memberCachePolicy api.MemberCachePolicy + users map[api.Snowflake]*api.User + guilds map[api.Snowflake]*api.Guild + members map[api.Snowflake]map[api.Snowflake]*api.Member + roles map[api.Snowflake]map[api.Snowflake]*api.Role + dmChannels map[api.Snowflake]*api.DMChannel + categories map[api.Snowflake]map[api.Snowflake]*api.Category + textChannels map[api.Snowflake]map[api.Snowflake]*api.TextChannel + voiceChannels map[api.Snowflake]map[api.Snowflake]*api.VoiceChannel + storeChannels map[api.Snowflake]map[api.Snowflake]*api.StoreChannel } // Close cleans up the cache and it's internal tasks @@ -143,9 +124,8 @@ func (c *CacheImpl) UserCache() map[api.Snowflake]*api.User { // CacheUser adds a user to the cache func (c *CacheImpl) CacheUser(user *api.User) { - // TODO: only cache if we have a guild in common if _, ok := c.guilds[user.ID]; ok { - *c.users[user.ID] = *user + // update old user return } c.users[user.ID] = user @@ -215,13 +195,13 @@ func (c *CacheImpl) GuildCache() map[api.Snowflake]*api.Guild { // CacheGuild adds a guild to the cache func (c *CacheImpl) CacheGuild(guild *api.Guild) { if _, ok := c.guilds[guild.ID]; ok { + // update old guild_events *c.guilds[guild.ID] = *guild return } // guild_events was not yet cached so cache it directly c.guilds[guild.ID] = guild c.members[guild.ID] = map[api.Snowflake]*api.Member{} - c.voiceStates[guild.ID] = map[api.Snowflake]*api.VoiceState{} c.roles[guild.ID] = map[api.Snowflake]*api.Role{} c.categories[guild.ID] = map[api.Snowflake]*api.Category{} c.textChannels[guild.ID] = map[api.Snowflake]*api.TextChannel{} @@ -233,7 +213,6 @@ func (c *CacheImpl) CacheGuild(guild *api.Guild) { func (c *CacheImpl) UncacheGuild(guildID api.Snowflake) { delete(c.guilds, guildID) delete(c.members, guildID) - delete(c.voiceStates, guildID) delete(c.roles, guildID) delete(c.categories, guildID) delete(c.textChannels, guildID) @@ -262,28 +241,6 @@ func (c *CacheImpl) FindGuilds(check func(g *api.Guild) bool) []*api.Guild { return guilds } -func (c *CacheImpl) Message(messageID api.Snowflake) *api.Message { - -} -func (c *CacheImpl) Messages(messageID api.Snowflake) []*api.Message { - -} -func (c *CacheImpl) AllMessages() []*api.Message { - -} -func (c *CacheImpl) MessageCache(messageID api.Snowflake) map[api.Snowflake]*api.Message { - -} -func (c *CacheImpl) AllMessageCache() map[api.Snowflake]map[api.Snowflake]*api.Message { - -} -func (c *CacheImpl) CacheMessage(message *api.Message) { - -} -func (c *CacheImpl) UncacheMessage(messageID api.Snowflake) { - -} - // Member returns a member from cache by guild ID and user ID func (c *CacheImpl) Member(guildID api.Snowflake, userID api.Snowflake) *api.Member { if guildMembers, ok := c.members[guildID]; ok { @@ -358,10 +315,9 @@ func (c *CacheImpl) AllMemberCache() map[api.Snowflake]map[api.Snowflake]*api.Me // CacheMember adds a member to the cache func (c *CacheImpl) CacheMember(member *api.Member) { - c.memberCachePolicy(member) if guildMembers, ok := c.members[member.GuildID]; ok { - if _, ok = guildMembers[member.User.ID]; ok { - *guildMembers[member.User.ID] = *member + if _, ok := guildMembers[member.User.ID]; ok { + // update old guild_events return } guildMembers[member.User.ID] = member @@ -394,52 +350,6 @@ func (c *CacheImpl) FindMembers(guildID api.Snowflake, check func(u *api.Member) return members } -// VoiceState returns a Member's api.VoiceState for a api.Guild -func (c *CacheImpl) VoiceState(guildID api.Snowflake, userID api.Snowflake) *api.VoiceState { - if voiceStates, ok := c.voiceStates[guildID]; ok { - return voiceStates[userID] - } - return nil -} - -// VoiceStates returns the member cache of a guild by snowflake -func (c *CacheImpl) VoiceStates(guildID api.Snowflake) []*api.VoiceState { - if guildVoiceStates, ok := c.voiceStates[guildID]; ok { - voiceStates := make([]*api.VoiceState, len(guildVoiceStates)) - i := 0 - for _, voiceState := range guildVoiceStates { - voiceStates[i] = voiceState - i++ - } - return voiceStates - } - return nil -} - -// VoiceStateCache returns the api.VoiceState api.Cache of a api.Guild as a map -func (c *CacheImpl) VoiceStateCache(guildID api.Snowflake) map[api.Snowflake]*api.VoiceState { - return c.voiceStates[guildID] -} - -// CacheVoiceState adds a api.VoiceState from the api.Cache -func (c *CacheImpl) CacheVoiceState(voiceState *api.VoiceState) { - if !c.cacheVoiceStates || c.Member(voiceState.GuildID, voiceState.UserID) == nil { - return - } - if voiceStates, ok := c.voiceStates[voiceState.GuildID]; ok { - if _, ok = voiceStates[voiceState.UserID]; ok { - *voiceStates[voiceState.UserID] = *voiceState - return - } - voiceStates[voiceState.UserID] = voiceState - } -} - -// UncacheVoiceState removes a api.VoiceState from the api.Cache -func (c *CacheImpl) UncacheVoiceState(guildID api.Snowflake, userID api.Snowflake) { - delete(c.voiceStates[guildID], userID) -} - // Role returns a role from cache by guild ID and role ID func (c *CacheImpl) Role(guildID api.Snowflake, roleID api.Snowflake) *api.Role { if guildRoles, ok := c.roles[guildID]; ok { @@ -502,12 +412,9 @@ func (c *CacheImpl) AllRoleCache() map[api.Snowflake]map[api.Snowflake]*api.Role // CacheRole adds a role to the cache func (c *CacheImpl) CacheRole(role *api.Role) { - if !c.cacheRoles { - return - } if guildRoles, ok := c.roles[role.GuildID]; ok { - if _, ok = guildRoles[role.ID]; ok { - *guildRoles[role.ID] = *role + if _, ok := guildRoles[role.ID]; ok { + // update old role return } guildRoles[role.ID] = role @@ -622,11 +529,8 @@ func (c *CacheImpl) DMChannelCache() map[api.Snowflake]*api.DMChannel { // CacheDMChannel adds a DM channel to the cache func (c *CacheImpl) CacheDMChannel(dmChannel *api.DMChannel) { - if !c.cacheChannels { - return - } - if _, ok := c.dmChannels[dmChannel.ID]; ok { - *c.dmChannels[dmChannel.ID] = *dmChannel + if oldChannel, ok := c.dmChannels[dmChannel.ID]; ok { + *oldChannel = *dmChannel return } c.dmChannels[dmChannel.ID] = dmChannel @@ -722,12 +626,9 @@ func (c *CacheImpl) AllTextChannelCache() map[api.Snowflake]map[api.Snowflake]*a // CacheTextChannel adds a channel to the cache func (c *CacheImpl) CacheTextChannel(textChannel *api.TextChannel) { - if !c.cacheChannels { - return - } if guildTextChannels, ok := c.textChannels[textChannel.GuildID]; ok { - if _, ok = guildTextChannels[textChannel.MessageChannel.ID]; ok { - *guildTextChannels[textChannel.MessageChannel.ID] = *textChannel + if guildTextChannel, ok := guildTextChannels[textChannel.MessageChannel.ID]; ok { + *guildTextChannel = *textChannel return } guildTextChannels[textChannel.MessageChannel.ID] = textChannel @@ -824,12 +725,9 @@ func (c *CacheImpl) AllStoreChannelCache() map[api.Snowflake]map[api.Snowflake]* // CacheStoreChannel adds a store channel to the cache func (c *CacheImpl) CacheStoreChannel(storeChannel *api.StoreChannel) { - if !c.cacheChannels { - return - } if guildStoreChannels, ok := c.storeChannels[storeChannel.GuildID]; ok { - if _, ok = guildStoreChannels[storeChannel.ID]; ok { - *guildStoreChannels[storeChannel.ID] = *storeChannel + if guildStoreChannel, ok := guildStoreChannels[storeChannel.ID]; ok { + *guildStoreChannel = *storeChannel return } guildStoreChannels[storeChannel.ID] = storeChannel @@ -926,12 +824,9 @@ func (c *CacheImpl) AllVoiceChannelCache() map[api.Snowflake]map[api.Snowflake]* // CacheVoiceChannel adds a voice channel to cache func (c *CacheImpl) CacheVoiceChannel(voiceChannel *api.VoiceChannel) { - if !c.cacheChannels { - return - } if guildVoiceChannels, ok := c.voiceChannels[voiceChannel.GuildID]; ok { - if _, ok = guildVoiceChannels[voiceChannel.ID]; ok { - *guildVoiceChannels[voiceChannel.ID] = *voiceChannel + if guildVoiceChannel, ok := guildVoiceChannels[voiceChannel.ID]; ok { + *guildVoiceChannel = *voiceChannel return } guildVoiceChannels[voiceChannel.ID] = voiceChannel @@ -1028,12 +923,9 @@ func (c *CacheImpl) AllCategoryCache() map[api.Snowflake]map[api.Snowflake]*api. //CacheCategory adds a category to the cache func (c *CacheImpl) CacheCategory(category *api.Category) { - if !c.cacheChannels { - return - } if guildCategories, ok := c.categories[category.GuildID]; ok { - if _, ok = guildCategories[category.ID]; ok { - *guildCategories[category.ID] = *category + if guildCategory, ok := guildCategories[category.ID]; ok { + *guildCategory = *category return } guildCategories[category.ID] = category @@ -1065,6 +957,3 @@ func (c *CacheImpl) FindCategories(guildID api.Snowflake, check func(u *api.Cate } return categories } - -// TODO: add emote cache -// TODO: add message cache diff --git a/internal/disgo_impl.go b/internal/disgo.go similarity index 77% rename from internal/disgo_impl.go rename to internal/disgo.go index e5a63cf9..480a6bfd 100644 --- a/internal/disgo_impl.go +++ b/internal/disgo.go @@ -10,16 +10,9 @@ import ( // New creates a new api.Disgo instance func New(token string, options api.Options) (api.Disgo, error) { - if options.MessageCachePolicy == nil { - options.MessageCachePolicy = api.MessageCachePolicyDefault - } - if options.MemberCachePolicy == nil { - options.MemberCachePolicy = api.MemberCachePolicyDefault - } disgo := &DisgoImpl{ token: token, intents: options.Intents, - cache: newCacheImpl(options.MessageCachePolicy, options.MemberCachePolicy, options.CacheVoiceStates, options.CacheRoles, options.CacheChannels, options.CacheEmotes), } id, err := IDFromToken(token) @@ -45,16 +38,15 @@ func New(token string, options api.Options) (api.Disgo, error) { // DisgoImpl is the main discord client type DisgoImpl struct { - token string - gateway api.Gateway - restClient api.RestClient - intents api.Intents - selfUser *api.User - eventManager api.EventManager - voiceDispatchInterceptor api.VoiceDispatchInterceptor - webhookServer api.WebhookServer - cache api.Cache - applicationID api.Snowflake + token string + gateway api.Gateway + restClient api.RestClient + intents api.Intents + selfUser *api.User + eventManager api.EventManager + webhookServer api.WebhookServer + cache api.Cache + applicationID api.Snowflake } // Connect opens the gateway connection to discord @@ -103,16 +95,6 @@ func (d *DisgoImpl) EventManager() api.EventManager { return d.eventManager } -// VoiceDispatchInterceptor returns the api.VoiceDispatchInterceptor -func (d *DisgoImpl) VoiceDispatchInterceptor() api.VoiceDispatchInterceptor { - return d.voiceDispatchInterceptor -} - -// SetVoiceDispatchInterceptor sets the api.VoiceDispatchInterceptor -func (d *DisgoImpl) SetVoiceDispatchInterceptor(voiceDispatchInterceptor api.VoiceDispatchInterceptor) { - d.voiceDispatchInterceptor = voiceDispatchInterceptor -} - // WebhookServer returns the api.EventManager func (d *DisgoImpl) WebhookServer() api.WebhookServer { return d.webhookServer diff --git a/internal/disgo_builder.go b/internal/disgo_builder.go new file mode 100644 index 00000000..c567a7b9 --- /dev/null +++ b/internal/disgo_builder.go @@ -0,0 +1,155 @@ +package internal + +import ( + "errors" + + log "github.com/sirupsen/logrus" + + "github.com/DisgoOrg/disgo/api" +) + +// NewBuilder returns a new api.DisgoBuilder instance +func NewBuilder(token string) api.DisgoBuilder { + return DisgoBuilderImpl{ + logLevel: log.InfoLevel, + token: &token, + } +} + +// DisgoBuilderImpl implementation of the api.DisgoBuilder interface +type DisgoBuilderImpl struct { + logLevel log.Level + token *string + gateway api.Gateway + restClient api.RestClient + cache api.Cache + memberCachePolicy api.MemberCachePolicy + intents api.Intents + eventManager api.EventManager + webhookServer api.WebhookServer + listenURL *string + listenPort *int + publicKey *string + eventListeners []api.EventListener +} + +// SetLogLevel sets logrus.Level of logrus +func (b DisgoBuilderImpl) SetLogLevel(logLevel log.Level) api.DisgoBuilder { + b.logLevel = logLevel + return b +} + +// SetToken sets the token to connect to discord +func (b DisgoBuilderImpl) SetToken(token string) api.DisgoBuilder { + b.token = &token + return b +} + +// SetIntents sets the api.Intents to connect to discord +func (b DisgoBuilderImpl) SetIntents(intents api.Intents) api.DisgoBuilder { + b.intents = intents + return b +} + +// SetEventManager lets you inject your own api.EventManager +func (b DisgoBuilderImpl) SetEventManager(eventManager api.EventManager) api.DisgoBuilder { + b.eventManager = eventManager + return b +} + +// AddEventListeners lets you add an api.EventListener to your api.EventManager +func (b DisgoBuilderImpl) AddEventListeners(eventListeners ...api.EventListener) api.DisgoBuilder { + for _, eventListener := range eventListeners { + b.eventListeners = append(b.eventListeners, eventListener) + } + return b +} + +// SetWebhookServer lets you inject your own api.EventManager +func (b DisgoBuilderImpl) SetWebhookServer(webhookServer api.WebhookServer) api.DisgoBuilder { + b.webhookServer = webhookServer + return b +} + +// SetWebhookServerProperties sets the default api.WebhookServer properties +func (b DisgoBuilderImpl) SetWebhookServerProperties(listenURL string, listenPort int, publicKey string) api.DisgoBuilder { + b.listenURL = &listenURL + b.listenPort = &listenPort + b.publicKey = &publicKey + return b +} + +// SetRestClient lets you inject your own api.RestClient +func (b DisgoBuilderImpl) SetRestClient(restClient api.RestClient) api.DisgoBuilder { + b.restClient = restClient + return b +} + +// SetCache lets you inject your own api.Cache +func (b DisgoBuilderImpl) SetCache(cache api.Cache) api.DisgoBuilder { + b.cache = cache + return b +} + +// SetMemberCachePolicy lets oyu set your own api.MemberCachePolicy +func (b DisgoBuilderImpl) SetMemberCachePolicy(memberCachePolicy api.MemberCachePolicy) api.DisgoBuilder { + b.memberCachePolicy = memberCachePolicy + return b +} + +// SetGateway lets you inject your own api.Gateway +func (b DisgoBuilderImpl) SetGateway(gateway api.Gateway) api.DisgoBuilder { + b.gateway = gateway + return b +} + +// Build builds your api.Disgo instance +func (b DisgoBuilderImpl) Build() (api.Disgo, error) { + log.SetLevel(b.logLevel) + + disgo := &DisgoImpl{} + if b.token == nil { + return nil, errors.New("please specify the token") + } + disgo.token = *b.token + + id, err := IDFromToken(disgo.token) + if err != nil { + log.Errorf("error while getting application id from token: %s", err) + return nil, err + } + + disgo.applicationID = *id + + if b.gateway == nil { + b.gateway = newGatewayImpl(disgo) + } + disgo.gateway = b.gateway + + if b.restClient == nil { + b.restClient = newRestClientImpl(disgo, *b.token) + } + disgo.restClient = b.restClient + + disgo.intents = b.intents + + if b.eventManager == nil { + b.eventManager = newEventManagerImpl(disgo, b.eventListeners) + } + disgo.eventManager = b.eventManager + + if b.webhookServer == nil && b.listenURL != nil && b.listenPort != nil && b.publicKey != nil { + b.webhookServer = newWebhookServerImpl(disgo, *b.listenURL, *b.listenPort, *b.publicKey) + } + disgo.webhookServer = b.webhookServer + + if b.cache == nil { + if b.memberCachePolicy == nil { + b.memberCachePolicy = api.MemberCachePolicyDefault + } + b.cache = newCacheImpl(b.memberCachePolicy) + } + disgo.cache = b.cache + + return disgo, nil +} diff --git a/internal/disgo_builder_impl.go b/internal/disgo_builder_impl.go deleted file mode 100644 index 5cb5f879..00000000 --- a/internal/disgo_builder_impl.go +++ /dev/null @@ -1,206 +0,0 @@ -package internal - -import ( - "errors" - - log "github.com/sirupsen/logrus" - - "github.com/DisgoOrg/disgo/api" -) - -// NewBuilder returns a new api.DisgoBuilder instance -func NewBuilder(token string) api.DisgoBuilder { - return &DisgoBuilderImpl{ - logLevel: log.InfoLevel, - token: &token, - cacheVoiceStates: true, - cacheRoles: true, - cacheChannels: true, - cacheEmotes: true, - } -} - -// DisgoBuilderImpl implementation of the api.DisgoBuilder interface -type DisgoBuilderImpl struct { - logLevel log.Level - token *string - gateway api.Gateway - restClient api.RestClient - cache api.Cache - messageCachePolicy api.MessageCachePolicy - memberCachePolicy api.MemberCachePolicy - cacheVoiceStates bool - cacheRoles bool - cacheChannels bool - cacheEmotes bool - intents api.Intents - eventManager api.EventManager - voiceDispatchInterceptor api.VoiceDispatchInterceptor - webhookServer api.WebhookServer - listenURL *string - listenPort *int - publicKey *string - eventListeners []api.EventListener -} - -// SetLogLevel sets logrus.Level of logrus -func (b *DisgoBuilderImpl) SetLogLevel(logLevel log.Level) api.DisgoBuilder { - b.logLevel = logLevel - return b -} - -// SetToken sets the token to connect to discord -func (b *DisgoBuilderImpl) SetToken(token string) api.DisgoBuilder { - b.token = &token - return b -} - -// SetIntents sets the api.Intents to connect to discord -func (b *DisgoBuilderImpl) SetIntents(intents api.Intents) api.DisgoBuilder { - b.intents = intents - return b -} - -// SetEventManager lets you inject your own api.EventManager -func (b *DisgoBuilderImpl) SetEventManager(eventManager api.EventManager) api.DisgoBuilder { - b.eventManager = eventManager - return b -} - -// AddEventListeners lets you add an api.EventListener to your api.EventManager -func (b *DisgoBuilderImpl) AddEventListeners(eventListeners ...api.EventListener) api.DisgoBuilder { - for _, eventListener := range eventListeners { - b.eventListeners = append(b.eventListeners, eventListener) - } - return b -} - -// SetVoiceDispatchInterceptor sets the api.VoiceDispatchInterceptor -func (b *DisgoBuilderImpl) SetVoiceDispatchInterceptor(voiceDispatchInterceptor api.VoiceDispatchInterceptor) api.DisgoBuilder { - b.voiceDispatchInterceptor = voiceDispatchInterceptor - return b -} - -// SetWebhookServer lets you inject your own api.EventManager -func (b *DisgoBuilderImpl) SetWebhookServer(webhookServer api.WebhookServer) api.DisgoBuilder { - b.webhookServer = webhookServer - return b -} - -// SetWebhookServerProperties sets the default api.WebhookServer properties -func (b *DisgoBuilderImpl) SetWebhookServerProperties(listenURL string, listenPort int, publicKey string) api.DisgoBuilder { - b.listenURL = &listenURL - b.listenPort = &listenPort - b.publicKey = &publicKey - return b -} - -// SetRestClient lets you inject your own api.RestClient -func (b *DisgoBuilderImpl) SetRestClient(restClient api.RestClient) api.DisgoBuilder { - b.restClient = restClient - return b -} - -// SetCache lets you inject your own api.Cache -func (b *DisgoBuilderImpl) SetCache(cache api.Cache) api.DisgoBuilder { - b.cache = cache - return b -} - -// SetMessageCachePolicy lets you set your own api.MessageCachePolicy -func (b *DisgoBuilderImpl) SetMessageCachePolicy(messageCachePolicy api.MessageCachePolicy) api.DisgoBuilder { - b.messageCachePolicy = messageCachePolicy - return b -} - -// SetMemberCachePolicy lets oyu set your own api.MemberCachePolicy -func (b *DisgoBuilderImpl) SetMemberCachePolicy(memberCachePolicy api.MemberCachePolicy) api.DisgoBuilder { - b.memberCachePolicy = memberCachePolicy - return b -} - -// SetCacheVoiceStates lets you disable the api.VoiceState api.Cache -func (b *DisgoBuilderImpl) SetCacheVoiceStates(cacheVoiceStates bool) api.DisgoBuilder { - b.cacheVoiceStates = cacheVoiceStates - return b -} - -// SetCacheRoles lets you disable the api.Role api.Cache -func (b *DisgoBuilderImpl) SetCacheRoles(cacheRoles bool) api.DisgoBuilder { - b.cacheRoles = cacheRoles - return b -} - -// SetCacheChannels lets you disable the api.Channel api.Cache -func (b *DisgoBuilderImpl) SetCacheChannels(cacheChannels bool) api.DisgoBuilder { - b.cacheChannels = cacheChannels - return b -} - -// SetCacheEmotes lets you disable the api.Emote api.Cache -func (b *DisgoBuilderImpl) SetCacheEmotes(cacheEmotes bool) api.DisgoBuilder { - b.cacheEmotes = cacheEmotes - return b -} - -// SetGateway lets you inject your own api.Gateway -func (b *DisgoBuilderImpl) SetGateway(gateway api.Gateway) api.DisgoBuilder { - b.gateway = gateway - return b -} - -// Build builds your api.Disgo instance -func (b *DisgoBuilderImpl) Build() (api.Disgo, error) { - log.SetLevel(b.logLevel) - - disgo := &DisgoImpl{} - if b.token == nil { - return nil, errors.New("please specify the token") - } - disgo.token = *b.token - - id, err := IDFromToken(disgo.token) - if err != nil { - log.Errorf("error while getting application id from token: %s", err) - return nil, err - } - - disgo.applicationID = *id - - if b.gateway == nil { - b.gateway = newGatewayImpl(disgo) - } - disgo.gateway = b.gateway - - if b.restClient == nil { - b.restClient = newRestClientImpl(disgo, *b.token) - } - disgo.restClient = b.restClient - - disgo.intents = b.intents - - if b.eventManager == nil { - b.eventManager = newEventManagerImpl(disgo, b.eventListeners) - } - disgo.eventManager = b.eventManager - - disgo.voiceDispatchInterceptor = b.voiceDispatchInterceptor - - if b.webhookServer == nil && b.listenURL != nil && b.listenPort != nil && b.publicKey != nil { - b.webhookServer = newWebhookServerImpl(disgo, *b.listenURL, *b.listenPort, *b.publicKey) - } - disgo.webhookServer = b.webhookServer - - if b.cache == nil { - if b.messageCachePolicy == nil { - b.messageCachePolicy = api.MessageCachePolicyDefault - } - if b.memberCachePolicy == nil { - b.memberCachePolicy = api.MemberCachePolicyDefault - } - b.cache = newCacheImpl(b.messageCachePolicy, b.memberCachePolicy, b.cacheVoiceStates, b.cacheRoles, b.cacheChannels, b.cacheEmotes) - } - disgo.cache = b.cache - - return disgo, nil -} diff --git a/internal/event_manager_impl.go b/internal/event_manager.go similarity index 100% rename from internal/event_manager_impl.go rename to internal/event_manager.go diff --git a/internal/gateway_impl.go b/internal/gateway.go similarity index 100% rename from internal/gateway_impl.go rename to internal/gateway.go diff --git a/internal/handlers/all_handlers.go b/internal/handlers/all_handlers.go index cd62ee26..e6a71d6d 100644 --- a/internal/handlers/all_handlers.go +++ b/internal/handlers/all_handlers.go @@ -9,9 +9,6 @@ func GetAllHandlers() []api.EventHandler { return []api.EventHandler{ ReadyHandler{}, - VoiceServerUpdateHandler{}, - VoiceStateUpdateHandler{}, - GuildCreateHandler{}, GuildUpdateHandler{}, GuildDeleteHandler{}, diff --git a/internal/handlers/guild_create_handler.go b/internal/handlers/guild_create_handler.go index fe03982f..defa9fdc 100644 --- a/internal/handlers/guild_create_handler.go +++ b/internal/handlers/guild_create_handler.go @@ -15,17 +15,15 @@ func (h GuildCreateHandler) Name() string { // New constructs a new payload receiver for the raw gateway event func (h GuildCreateHandler) New() interface{} { - return &api.FullGuild{} + return &api.Guild{} } // Handle handles the specific raw gateway event func (h GuildCreateHandler) Handle(disgo api.Disgo, eventManager api.EventManager, i interface{}) { - fullGuild, ok := i.(*api.FullGuild) + guild, ok := i.(*api.Guild) if !ok { return } - - guild := fullGuild.Guild guild.Disgo = disgo oldGuild := disgo.Cache().Guild(guild.ID) var wasUnavailable bool @@ -36,8 +34,8 @@ func (h GuildCreateHandler) Handle(disgo api.Disgo, eventManager api.EventManage } disgo.Cache().CacheGuild(guild) - - for _, channel := range fullGuild.Channels { + for i := range guild.Channels { + channel := guild.Channels[i] channel.Disgo = disgo channel.GuildID = guild.ID switch channel.Type { @@ -63,18 +61,13 @@ func (h GuildCreateHandler) Handle(disgo api.Disgo, eventManager api.EventManage } } - for _, role := range fullGuild.Roles { + for i := range guild.Roles { + role := guild.Roles[i] role.Disgo = disgo role.GuildID = guild.ID disgo.Cache().CacheRole(role) } - for _, voiceState := range fullGuild.VoiceStates { - voiceState.Disgo = disgo - voiceState.GuildID = guild.ID - disgo.Cache().CacheVoiceState(voiceState) - } - genericGuildEvent := events.GenericGuildEvent{ Event: api.Event{ Disgo: disgo, @@ -90,6 +83,7 @@ func (h GuildCreateHandler) Handle(disgo api.Disgo, eventManager api.EventManage Guild: guild, }) } else { + // guild join eventManager.Dispatch(events.GuildJoinEvent{ GenericGuildEvent: genericGuildEvent, Guild: guild, diff --git a/internal/handlers/voice_server_update_handler.go b/internal/handlers/voice_server_update_handler.go deleted file mode 100644 index d12cfcad..00000000 --- a/internal/handlers/voice_server_update_handler.go +++ /dev/null @@ -1,34 +0,0 @@ -package handlers - -import "github.com/DisgoOrg/disgo/api" - -// InteractionCreateHandler handles api.VoiceServerUpdateGatewayEvent -type VoiceServerUpdateHandler struct{} - -// Name returns the raw gateway event name -func (h VoiceServerUpdateHandler) Name() string { - return api.VoiceServerUpdateGatewayEvent -} - -// New constructs a new payload receiver for the raw gateway event -func (h VoiceServerUpdateHandler) New() interface{} { - return &api.VoiceServerUpdate{} -} - -// Handle handles the specific raw gateway event -func (h VoiceServerUpdateHandler) Handle(disgo api.Disgo, eventManager api.EventManager, i interface{}) { - voiceServerUpdate, ok := i.(*api.VoiceServerUpdate) - if !ok { - return - } - - if voiceServerUpdate.Endpoint == nil { - return - } - - voiceServerUpdate.Disgo = disgo - - if interceptor := disgo.VoiceDispatchInterceptor(); interceptor != nil { - interceptor.OnVoiceServerUpdate(*voiceServerUpdate) - } -} diff --git a/internal/handlers/voice_state_update_handler.go b/internal/handlers/voice_state_update_handler.go deleted file mode 100644 index 798e6f7a..00000000 --- a/internal/handlers/voice_state_update_handler.go +++ /dev/null @@ -1,47 +0,0 @@ -package handlers - -import ( - log "github.com/sirupsen/logrus" - - "github.com/DisgoOrg/disgo/api" -) - -// VoiceStateUpdateHandler handles api.VoiceStateUpdateGatewayEvent -type VoiceStateUpdateHandler struct{} - -// Name returns the raw gateway event name -func (h VoiceStateUpdateHandler) Name() string { - return api.VoiceStateUpdateGatewayEvent -} - -// New constructs a new payload receiver for the raw gateway event -func (h VoiceStateUpdateHandler) New() interface{} { - return &api.VoiceStateUpdate{} -} - -// Handle handles the specific raw gateway event -func (h VoiceStateUpdateHandler) Handle(disgo api.Disgo, eventManager api.EventManager, i interface{}) { - voiceStateUpdate, ok := i.(*api.VoiceStateUpdate) - if !ok { - return - } - - log.Printf("%+v", *voiceStateUpdate) - - voiceStateUpdate.Disgo = disgo - - //guild := disgo.Cache().Guild(voiceStateUpdate.GuildID) - - //oldMember := disgo.Cache().Member(voiceStateUpdate.GuildID, voiceStateUpdate.UserID) - //newMember := voiceStateUpdate.Member - - // TODO update voice state cache - // TODO fire several events - - if disgo.ApplicationID() == voiceStateUpdate.UserID { - if interceptor := disgo.VoiceDispatchInterceptor(); interceptor != nil { - interceptor.OnVoiceStateUpdate(*voiceStateUpdate) - } - } - -} diff --git a/internal/member_impl.go b/internal/member_impl.go deleted file mode 100644 index 5bf0569c..00000000 --- a/internal/member_impl.go +++ /dev/null @@ -1 +0,0 @@ -package internal diff --git a/internal/restclient_impl.go b/internal/restclient.go similarity index 99% rename from internal/restclient_impl.go rename to internal/restclient.go index 9c3792a3..92718cfe 100644 --- a/internal/restclient_impl.go +++ b/internal/restclient.go @@ -152,7 +152,7 @@ func (r RestClientImpl) DeleteMessage(channelID api.Snowflake, messageID api.Sno } // BulkDeleteMessages lets you bulk delete api.Message(s) -func (r RestClientImpl) BulkDeleteMessages(channelID api.Snowflake, messageIDs ...api.Snowflake) error { +func (r RestClientImpl) BulkDeleteMessages(channelID api.Snowflake, messageIDs... api.Snowflake) error { return r.Request(endpoints.BulkDeleteMessage.Compile(channelID), api.MessageBulkDelete{Messages: messageIDs}, nil) } diff --git a/internal/user_impl.go b/internal/user_impl.go deleted file mode 100644 index 2c2bc7f2..00000000 --- a/internal/user_impl.go +++ /dev/null @@ -1,86 +0,0 @@ -package internal - -import ( - "fmt" - "strings" - - "github.com/DisgoOrg/disgo/api" - "github.com/DisgoOrg/disgo/api/endpoints" -) - -var _ api.User = (UserImpl)(nil) -var _ api.Mentionable = (UserImpl)(nil) - -type UserImpl struct { - disgo api.Disgo - id api.Snowflake `json:"id"` - username string `json:"username"` - discriminator int `json:"discriminator"` - avatar *string `json:"avatar"` - bot bool `json:"bot"` - flags api.UserFlags `json:"public_flags"` -} - -func (u UserImpl) Disgo() api.Disgo { - return u.disgo -} - -func (u UserImpl) ID() api.Snowflake { - return u.id -} - -func (u UserImpl) Username() string { - return u.username -} - -func (u UserImpl) Discriminator() int { - return u.discriminator -} - -// Tag returns the user's Username#Discriminator -func (u UserImpl) Tag() string { - return fmt.Sprintf("%s#%d", u.username, u.discriminator) -} - -func (u UserImpl) AvatarURL() *string { - if u.avatar == nil { - return nil - } - animated := strings.HasPrefix(*u.avatar, "a_") - format := endpoints.PNG - if animated { - format = endpoints.GIF - } - a := endpoints.UserAvatar.Compile(format, u.id, *u.avatar).Route() - return &a -} - -func (u UserImpl) EffectiveAvatarURL() string { - a := u.AvatarURL() - if a != nil { - return *a - } - return endpoints.DefaultUserAvatar.Compile(endpoints.PNG, u.discriminator%5).Route() -} - -func (u UserImpl) Bot() bool { - return u.bot -} - -func (u UserImpl) Flags() api.UserFlags { - return u.flags -} - -// Mention returns the user as a mention -func (u UserImpl) Mention() string { - return "<@" + u.id.String() + ">" -} - -func (u UserImpl) String() string { - return u.Mention() -} - -// OpenDMChannel creates a DMChannel between the user and the Disgo client -func (u UserImpl) OpenDMChannel() (*api.DMChannel, error) { - return u.Disgo().RestClient().OpenDMChannel(u.ID()) -} diff --git a/testbot/testbot.go b/testbot/testbot.go index d1f81bf0..93e23c99 100644 --- a/testbot/testbot.go +++ b/testbot/testbot.go @@ -19,7 +19,7 @@ func main() { dgo, err := disgo.NewBuilder(token). SetLogLevel(log.InfoLevel). - SetIntents(api.IntentsGuilds | api.IntentsGuildMessages | api.IntentsGuildMembers | api.IntentsGuildVoiceStates). + SetIntents(api.IntentsGuilds|api.IntentsGuildMessages|api.IntentsGuildMembers). SetMemberCachePolicy(api.MemberCachePolicyAll). AddEventListeners(&events.ListenerAdapter{ OnGuildAvailable: guildAvailListener, From 339bce3f2f11644f61df8c77d279c7c871d40db1 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Mon, 5 Apr 2021 13:13:50 +0200 Subject: [PATCH 16/65] added cacheflags --- api/cache.go | 1 + api/cache_flags.go | 72 ++++++++++++++++++++++++++++++++++++ api/disgo_builder.go | 2 + internal/cache.go | 78 +++++++++++++++++++++++++++------------ internal/disgo_builder.go | 64 +++++++++++++++++++++++--------- 5 files changed, 177 insertions(+), 40 deletions(-) create mode 100644 api/cache_flags.go diff --git a/api/cache.go b/api/cache.go index 06aa3aff..00f4f971 100644 --- a/api/cache.go +++ b/api/cache.go @@ -4,6 +4,7 @@ package api type Cache interface { Close() DoCleanup() + CacheFlags() CacheFlags Guild(Snowflake) *Guild GuildsByName(string, bool) []*Guild diff --git a/api/cache_flags.go b/api/cache_flags.go new file mode 100644 index 00000000..8c9402e2 --- /dev/null +++ b/api/cache_flags.go @@ -0,0 +1,72 @@ +package api + +type CacheFlags int + +const ( + CacheFlagDMChannels CacheFlags = 0 << iota + CacheFlagCategories + CacheFlagTextChannels + CacheFlagVoiceChannels + CacheFlagStoreChannels + CacheFlagRoles + CacheFlagEmotes + CacheFlagVoiceState + + CacheFlagsDefault = CacheFlagDMChannels | + CacheFlagCategories | + CacheFlagTextChannels | + CacheFlagVoiceChannels | + CacheFlagStoreChannels | + CacheFlagRoles | + CacheFlagEmotes +) + +// Add allows you to add multiple bits together, producing a new bit +func (c CacheFlags) Add(bits ...Bit) Bit { + total := CacheFlags(0) + for _, bit := range bits { + total |= bit.(CacheFlags) + } + c |= total + return c +} + +// Remove allows you to subtract multiple bits from the first, producing a new bit +func (c CacheFlags) Remove(bits ...Bit) Bit { + total := CacheFlags(0) + for _, bit := range bits { + total |= bit.(CacheFlags) + } + c &^= total + return c +} + +// HasAll will ensure that the bit includes all of the bits entered +func (c CacheFlags) HasAll(bits ...Bit) bool { + for _, bit := range bits { + if !c.Has(bit) { + return false + } + } + return true +} + +// Has will check whether the Bit contains another bit +func (c CacheFlags) Has(bit Bit) bool { + return (c & bit.(CacheFlags)) == bit +} + +// MissingAny will check whether the bit is missing any one of the bits +func (c CacheFlags) MissingAny(bits ...Bit) bool { + for _, bit := range bits { + if !c.Has(bit) { + return true + } + } + return false +} + +// Missing will do the inverse of Bit.Has +func (c CacheFlags) Missing(bit Bit) bool { + return !c.Has(bit) +} diff --git a/api/disgo_builder.go b/api/disgo_builder.go index d2b86cfb..27bc14c5 100644 --- a/api/disgo_builder.go +++ b/api/disgo_builder.go @@ -14,6 +14,8 @@ type DisgoBuilder interface { SetRestClient(restClient RestClient) DisgoBuilder SetCache(cache Cache) DisgoBuilder SetMemberCachePolicy(memberCachePolicy MemberCachePolicy) DisgoBuilder + SetMessageCachePolicy(messageCachePolicy MessageCachePolicy) DisgoBuilder + SetCacheFlags(cacheFlags CacheFlags) DisgoBuilder SetGateway(gateway Gateway) DisgoBuilder Build() (Disgo, error) } diff --git a/internal/cache.go b/internal/cache.go index e2fd4206..e210d60e 100644 --- a/internal/cache.go +++ b/internal/cache.go @@ -10,36 +10,40 @@ import ( "github.com/DisgoOrg/disgo/api" ) -func newCacheImpl(memberCachePolicy api.MemberCachePolicy) api.Cache { +func newCacheImpl(memberCachePolicy api.MemberCachePolicy, messageCachePolicy api.MessageCachePolicy, cacheFlags api.CacheFlags) api.Cache { cache := &CacheImpl{ - memberCachePolicy: memberCachePolicy, - users: map[api.Snowflake]*api.User{}, - guilds: map[api.Snowflake]*api.Guild{}, - members: map[api.Snowflake]map[api.Snowflake]*api.Member{}, - roles: map[api.Snowflake]map[api.Snowflake]*api.Role{}, - dmChannels: map[api.Snowflake]*api.DMChannel{}, - categories: map[api.Snowflake]map[api.Snowflake]*api.Category{}, - textChannels: map[api.Snowflake]map[api.Snowflake]*api.TextChannel{}, - voiceChannels: map[api.Snowflake]map[api.Snowflake]*api.VoiceChannel{}, - storeChannels: map[api.Snowflake]map[api.Snowflake]*api.StoreChannel{}, + memberCachePolicy: memberCachePolicy, + messageCachePolicy: messageCachePolicy, + cacheFlags: cacheFlags, + users: map[api.Snowflake]*api.User{}, + guilds: map[api.Snowflake]*api.Guild{}, + members: map[api.Snowflake]map[api.Snowflake]*api.Member{}, + roles: map[api.Snowflake]map[api.Snowflake]*api.Role{}, + dmChannels: map[api.Snowflake]*api.DMChannel{}, + categories: map[api.Snowflake]map[api.Snowflake]*api.Category{}, + textChannels: map[api.Snowflake]map[api.Snowflake]*api.TextChannel{}, + voiceChannels: map[api.Snowflake]map[api.Snowflake]*api.VoiceChannel{}, + storeChannels: map[api.Snowflake]map[api.Snowflake]*api.StoreChannel{}, } go cache.cleanup(10 * time.Second) return cache } -// CacheImpl is used for Disgo's Cache +// CacheImpl is used for api.Disgo's api.Cache type CacheImpl struct { - quit chan bool - memberCachePolicy api.MemberCachePolicy - users map[api.Snowflake]*api.User - guilds map[api.Snowflake]*api.Guild - members map[api.Snowflake]map[api.Snowflake]*api.Member - roles map[api.Snowflake]map[api.Snowflake]*api.Role - dmChannels map[api.Snowflake]*api.DMChannel - categories map[api.Snowflake]map[api.Snowflake]*api.Category - textChannels map[api.Snowflake]map[api.Snowflake]*api.TextChannel - voiceChannels map[api.Snowflake]map[api.Snowflake]*api.VoiceChannel - storeChannels map[api.Snowflake]map[api.Snowflake]*api.StoreChannel + quit chan bool + memberCachePolicy api.MemberCachePolicy + messageCachePolicy api.MessageCachePolicy + cacheFlags api.CacheFlags + users map[api.Snowflake]*api.User + guilds map[api.Snowflake]*api.Guild + members map[api.Snowflake]map[api.Snowflake]*api.Member + roles map[api.Snowflake]map[api.Snowflake]*api.Role + dmChannels map[api.Snowflake]*api.DMChannel + categories map[api.Snowflake]map[api.Snowflake]*api.Category + textChannels map[api.Snowflake]map[api.Snowflake]*api.TextChannel + voiceChannels map[api.Snowflake]map[api.Snowflake]*api.VoiceChannel + storeChannels map[api.Snowflake]map[api.Snowflake]*api.StoreChannel } // Close cleans up the cache and it's internal tasks @@ -77,6 +81,10 @@ func (c *CacheImpl) DoCleanup() { // TODO cleanup cache } +func (c CacheImpl) CacheFlags() api.CacheFlags { + return c.cacheFlags +} + // User allows you to get a user from the cache by ID func (c *CacheImpl) User(id api.Snowflake) *api.User { return c.users[id] @@ -124,6 +132,7 @@ func (c *CacheImpl) UserCache() map[api.Snowflake]*api.User { // CacheUser adds a user to the cache func (c *CacheImpl) CacheUser(user *api.User) { + // TODO: only cache user if we have a mutal guild if _, ok := c.guilds[user.ID]; ok { // update old user return @@ -194,6 +203,7 @@ func (c *CacheImpl) GuildCache() map[api.Snowflake]*api.Guild { // CacheGuild adds a guild to the cache func (c *CacheImpl) CacheGuild(guild *api.Guild) { + // TODO: guilds are always cached? if _, ok := c.guilds[guild.ID]; ok { // update old guild_events *c.guilds[guild.ID] = *guild @@ -315,6 +325,10 @@ func (c *CacheImpl) AllMemberCache() map[api.Snowflake]map[api.Snowflake]*api.Me // CacheMember adds a member to the cache func (c *CacheImpl) CacheMember(member *api.Member) { + // only cache member if we want to! + if !c.memberCachePolicy(member) { + return + } if guildMembers, ok := c.members[member.GuildID]; ok { if _, ok := guildMembers[member.User.ID]; ok { // update old guild_events @@ -412,6 +426,9 @@ func (c *CacheImpl) AllRoleCache() map[api.Snowflake]map[api.Snowflake]*api.Role // CacheRole adds a role to the cache func (c *CacheImpl) CacheRole(role *api.Role) { + if !c.cacheFlags.Has(api.CacheFlagRoles) { + return + } if guildRoles, ok := c.roles[role.GuildID]; ok { if _, ok := guildRoles[role.ID]; ok { // update old role @@ -529,6 +546,9 @@ func (c *CacheImpl) DMChannelCache() map[api.Snowflake]*api.DMChannel { // CacheDMChannel adds a DM channel to the cache func (c *CacheImpl) CacheDMChannel(dmChannel *api.DMChannel) { + if !c.cacheFlags.Has(api.CacheFlagDMChannels) { + return + } if oldChannel, ok := c.dmChannels[dmChannel.ID]; ok { *oldChannel = *dmChannel return @@ -626,6 +646,9 @@ func (c *CacheImpl) AllTextChannelCache() map[api.Snowflake]map[api.Snowflake]*a // CacheTextChannel adds a channel to the cache func (c *CacheImpl) CacheTextChannel(textChannel *api.TextChannel) { + if !c.cacheFlags.Has(api.CacheFlagTextChannels) { + return + } if guildTextChannels, ok := c.textChannels[textChannel.GuildID]; ok { if guildTextChannel, ok := guildTextChannels[textChannel.MessageChannel.ID]; ok { *guildTextChannel = *textChannel @@ -725,6 +748,9 @@ func (c *CacheImpl) AllStoreChannelCache() map[api.Snowflake]map[api.Snowflake]* // CacheStoreChannel adds a store channel to the cache func (c *CacheImpl) CacheStoreChannel(storeChannel *api.StoreChannel) { + if !c.cacheFlags.Has(api.CacheFlagStoreChannels) { + return + } if guildStoreChannels, ok := c.storeChannels[storeChannel.GuildID]; ok { if guildStoreChannel, ok := guildStoreChannels[storeChannel.ID]; ok { *guildStoreChannel = *storeChannel @@ -824,6 +850,9 @@ func (c *CacheImpl) AllVoiceChannelCache() map[api.Snowflake]map[api.Snowflake]* // CacheVoiceChannel adds a voice channel to cache func (c *CacheImpl) CacheVoiceChannel(voiceChannel *api.VoiceChannel) { + if !c.cacheFlags.Has(api.CacheFlagVoiceChannels) { + return + } if guildVoiceChannels, ok := c.voiceChannels[voiceChannel.GuildID]; ok { if guildVoiceChannel, ok := guildVoiceChannels[voiceChannel.ID]; ok { *guildVoiceChannel = *voiceChannel @@ -923,6 +952,9 @@ func (c *CacheImpl) AllCategoryCache() map[api.Snowflake]map[api.Snowflake]*api. //CacheCategory adds a category to the cache func (c *CacheImpl) CacheCategory(category *api.Category) { + if !c.cacheFlags.Has(api.CacheFlagCategories) { + return + } if guildCategories, ok := c.categories[category.GuildID]; ok { if guildCategory, ok := guildCategories[category.ID]; ok { *guildCategory = *category diff --git a/internal/disgo_builder.go b/internal/disgo_builder.go index c567a7b9..94275835 100644 --- a/internal/disgo_builder.go +++ b/internal/disgo_builder.go @@ -11,26 +11,29 @@ import ( // NewBuilder returns a new api.DisgoBuilder instance func NewBuilder(token string) api.DisgoBuilder { return DisgoBuilderImpl{ - logLevel: log.InfoLevel, - token: &token, + logLevel: log.InfoLevel, + token: &token, + cacheFlags: api.CacheFlagsDefault, } } // DisgoBuilderImpl implementation of the api.DisgoBuilder interface type DisgoBuilderImpl struct { - logLevel log.Level - token *string - gateway api.Gateway - restClient api.RestClient - cache api.Cache - memberCachePolicy api.MemberCachePolicy - intents api.Intents - eventManager api.EventManager - webhookServer api.WebhookServer - listenURL *string - listenPort *int - publicKey *string - eventListeners []api.EventListener + logLevel log.Level + token *string + gateway api.Gateway + restClient api.RestClient + cache api.Cache + memberCachePolicy api.MemberCachePolicy + messageCachePolicy api.MessageCachePolicy + cacheFlags api.CacheFlags + intents api.Intents + eventManager api.EventManager + webhookServer api.WebhookServer + listenURL *string + listenPort *int + publicKey *string + eventListeners []api.EventListener } // SetLogLevel sets logrus.Level of logrus @@ -91,12 +94,36 @@ func (b DisgoBuilderImpl) SetCache(cache api.Cache) api.DisgoBuilder { return b } -// SetMemberCachePolicy lets oyu set your own api.MemberCachePolicy +// SetMemberCachePolicy lets you set your own api.MemberCachePolicy func (b DisgoBuilderImpl) SetMemberCachePolicy(memberCachePolicy api.MemberCachePolicy) api.DisgoBuilder { b.memberCachePolicy = memberCachePolicy return b } +// SetMessageCachePolicy lets you set your own api.MessageCachePolicy +func (b DisgoBuilderImpl) SetMessageCachePolicy(messageCachePolicy api.MessageCachePolicy) api.DisgoBuilder { + b.messageCachePolicy = messageCachePolicy + return b +} + +// SetCacheFlags lets you set the api.CacheFlags +func (b DisgoBuilderImpl) SetCacheFlags(cacheFlags api.CacheFlags) api.DisgoBuilder { + b.cacheFlags = cacheFlags + return b +} + +// EnableCacheFlags lets you enable certain api.CacheFlags +func (b DisgoBuilderImpl) EnableCacheFlags(cacheFlags api.CacheFlags) api.DisgoBuilder { + b.cacheFlags.Add(cacheFlags) + return b +} + +// DisableCacheFlags lets you disable certain api.CacheFlags +func (b DisgoBuilderImpl) DisableCacheFlags(cacheFlags api.CacheFlags) api.DisgoBuilder { + b.cacheFlags.Remove(cacheFlags) + return b +} + // SetGateway lets you inject your own api.Gateway func (b DisgoBuilderImpl) SetGateway(gateway api.Gateway) api.DisgoBuilder { b.gateway = gateway @@ -147,7 +174,10 @@ func (b DisgoBuilderImpl) Build() (api.Disgo, error) { if b.memberCachePolicy == nil { b.memberCachePolicy = api.MemberCachePolicyDefault } - b.cache = newCacheImpl(b.memberCachePolicy) + if b.messageCachePolicy == nil { + b.messageCachePolicy = api.MessageCachePolicyDefault + } + b.cache = newCacheImpl(b.memberCachePolicy, b.messageCachePolicy, b.cacheFlags) } disgo.cache = b.cache From 99e9fe0bc68cd7e1d99e3617fccebfb37075c184 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Tue, 6 Apr 2021 02:42:09 +0200 Subject: [PATCH 17/65] some smol tweaks --- api/disgo.go | 3 +-- api/guild.go | 12 ++++++------ internal/cache.go | 21 +++++++++++--------- internal/disgo.go | 31 +++++++++++++----------------- internal/disgo_builder.go | 2 +- internal/gateway.go | 2 +- internal/handlers/ready_handler.go | 4 +++- internal/restclient.go | 2 +- testbot/testbot.go | 2 +- 9 files changed, 39 insertions(+), 40 deletions(-) diff --git a/api/disgo.go b/api/disgo.go index ad149a78..d6e53b0a 100644 --- a/api/disgo.go +++ b/api/disgo.go @@ -18,9 +18,8 @@ type Disgo interface { WebhookServer() WebhookServer Cache() Cache Intents() Intents - ApplicationID() Snowflake + SelfUserID() Snowflake SelfUser() *User - SetSelfUser(*User) EventManager() EventManager HeartbeatLatency() time.Duration diff --git a/api/guild.go b/api/guild.go index 9b35600e..ab304baa 100644 --- a/api/guild.go +++ b/api/guild.go @@ -162,30 +162,30 @@ func (g Guild) IconURL() *string { // GetCommand fetches a specific guild command func (g Guild) GetCommand(commandID Snowflake) (*SlashCommand, error) { - return g.Disgo.RestClient().GetGuildCommand(g.Disgo.ApplicationID(), g.ID, commandID) + return g.Disgo.RestClient().GetGuildCommand(g.Disgo.SelfUserID(), g.ID, commandID) } // GetCommands fetches all guild commands func (g Guild) GetCommands() ([]*SlashCommand, error) { - return g.Disgo.RestClient().GetGuildCommands(g.Disgo.ApplicationID(), g.ID) + return g.Disgo.RestClient().GetGuildCommands(g.Disgo.SelfUserID(), g.ID) } // CreateCommand creates a new command for this guild func (g Guild) CreateCommand(command SlashCommand) (*SlashCommand, error) { - return g.Disgo.RestClient().CreateGuildGuildCommand(g.Disgo.ApplicationID(), g.ID, command) + return g.Disgo.RestClient().CreateGuildGuildCommand(g.Disgo.SelfUserID(), g.ID, command) } // EditCommand edits a specific guild command func (g Guild) EditCommand(commandID Snowflake, command SlashCommand) (*SlashCommand, error) { - return g.Disgo.RestClient().EditGuildCommand(g.Disgo.ApplicationID(), g.ID, commandID, command) + return g.Disgo.RestClient().EditGuildCommand(g.Disgo.SelfUserID(), g.ID, commandID, command) } // DeleteCommand creates a new command for this guild func (g Guild) DeleteCommand(command SlashCommand) (*SlashCommand, error) { - return g.Disgo.RestClient().CreateGuildGuildCommand(g.Disgo.ApplicationID(), g.ID, command) + return g.Disgo.RestClient().CreateGuildGuildCommand(g.Disgo.SelfUserID(), g.ID, command) } // SetCommands overrides all commands for this guild func (g Guild) SetCommands(commands ...SlashCommand) ([]*SlashCommand, error) { - return g.Disgo.RestClient().SetGuildCommands(g.Disgo.ApplicationID(), g.ID, commands...) + return g.Disgo.RestClient().SetGuildCommands(g.Disgo.SelfUserID(), g.ID, commands...) } diff --git a/internal/cache.go b/internal/cache.go index e210d60e..5f6aa8e6 100644 --- a/internal/cache.go +++ b/internal/cache.go @@ -10,8 +10,10 @@ import ( "github.com/DisgoOrg/disgo/api" ) -func newCacheImpl(memberCachePolicy api.MemberCachePolicy, messageCachePolicy api.MessageCachePolicy, cacheFlags api.CacheFlags) api.Cache { +func newCacheImpl(disgo api.Disgo, memberCachePolicy api.MemberCachePolicy, messageCachePolicy api.MessageCachePolicy, cacheFlags api.CacheFlags) api.Cache { cache := &CacheImpl{ + disgo: disgo, + quit: make(chan interface{}), memberCachePolicy: memberCachePolicy, messageCachePolicy: messageCachePolicy, cacheFlags: cacheFlags, @@ -25,13 +27,14 @@ func newCacheImpl(memberCachePolicy api.MemberCachePolicy, messageCachePolicy ap voiceChannels: map[api.Snowflake]map[api.Snowflake]*api.VoiceChannel{}, storeChannels: map[api.Snowflake]map[api.Snowflake]*api.StoreChannel{}, } - go cache.cleanup(10 * time.Second) + go cache.startCleanup(10 * time.Second) return cache } // CacheImpl is used for api.Disgo's api.Cache type CacheImpl struct { - quit chan bool + disgo api.Disgo + quit chan interface{} memberCachePolicy api.MemberCachePolicy messageCachePolicy api.MessageCachePolicy cacheFlags api.CacheFlags @@ -49,16 +52,16 @@ type CacheImpl struct { // Close cleans up the cache and it's internal tasks func (c *CacheImpl) Close() { log.Info("closing cache goroutines...") - close(c.quit) + c.quit <- true log.Info("closed cache goroutines") } -func (c CacheImpl) cleanup(cleanupInterval time.Duration) { +func (c CacheImpl) startCleanup(cleanupInterval time.Duration) { defer func() { if r := recover(); r != nil { log.Errorf("recovered cache cleanup goroutine error: %s", r) debug.PrintStack() - c.cleanup(cleanupInterval) + c.startCleanup(cleanupInterval) return } log.Info("shut down cache cleanup goroutine") @@ -132,7 +135,7 @@ func (c *CacheImpl) UserCache() map[api.Snowflake]*api.User { // CacheUser adds a user to the cache func (c *CacheImpl) CacheUser(user *api.User) { - // TODO: only cache user if we have a mutal guild + // TODO: only cache user if we have a mutal guild & always cache self user if _, ok := c.guilds[user.ID]; ok { // update old user return @@ -325,8 +328,8 @@ func (c *CacheImpl) AllMemberCache() map[api.Snowflake]map[api.Snowflake]*api.Me // CacheMember adds a member to the cache func (c *CacheImpl) CacheMember(member *api.Member) { - // only cache member if we want to! - if !c.memberCachePolicy(member) { + // only cache member if we want to & always cache self member! + if member.User.ID != member.Disgo.SelfUserID() && !c.memberCachePolicy(member) { return } if guildMembers, ok := c.members[member.GuildID]; ok { diff --git a/internal/disgo.go b/internal/disgo.go index 480a6bfd..961a526a 100644 --- a/internal/disgo.go +++ b/internal/disgo.go @@ -21,7 +21,7 @@ func New(token string, options api.Options) (api.Disgo, error) { return nil, err } - disgo.applicationID = *id + disgo.selfUserID = *id disgo.restClient = newRestClientImpl(disgo, token) @@ -42,11 +42,10 @@ type DisgoImpl struct { gateway api.Gateway restClient api.RestClient intents api.Intents - selfUser *api.User eventManager api.EventManager webhookServer api.WebhookServer cache api.Cache - applicationID api.Snowflake + selfUserID api.Snowflake } // Connect opens the gateway connection to discord @@ -73,6 +72,7 @@ func (d *DisgoImpl) Start() error { func (d *DisgoImpl) Close() { d.RestClient().Close() d.Gateway().Close() + d.Cache().Close() } // Token returns the token of the client @@ -112,19 +112,14 @@ func (d *DisgoImpl) Intents() api.Intents { return c } -// ApplicationID returns the current application id -func (d *DisgoImpl) ApplicationID() api.Snowflake { - return d.applicationID +// SelfUserID returns the current application id +func (d *DisgoImpl) SelfUserID() api.Snowflake { + return d.selfUserID } // SelfUser returns a user object for the client, if available func (d *DisgoImpl) SelfUser() *api.User { - return d.selfUser -} - -// SetSelfUser sets the self user -func (d *DisgoImpl) SetSelfUser(user *api.User) { - d.selfUser = user + return d.cache.User(d.selfUserID) } // HeartbeatLatency returns the heartbeat latency @@ -134,30 +129,30 @@ func (d *DisgoImpl) HeartbeatLatency() time.Duration { // GetCommand fetches a specific guild command func (d DisgoImpl) GetCommand(commandID api.Snowflake) (*api.SlashCommand, error) { - return d.RestClient().GetGlobalCommand(d.ApplicationID(), commandID) + return d.RestClient().GetGlobalCommand(d.SelfUserID(), commandID) } // GetCommands fetches all guild commands func (d DisgoImpl) GetCommands() ([]*api.SlashCommand, error) { - return d.RestClient().GetGlobalCommands(d.ApplicationID()) + return d.RestClient().GetGlobalCommands(d.SelfUserID()) } // CreateCommand creates a new command for this guild func (d DisgoImpl) CreateCommand(command api.SlashCommand) (*api.SlashCommand, error) { - return d.RestClient().CreateGlobalCommand(d.ApplicationID(), command) + return d.RestClient().CreateGlobalCommand(d.SelfUserID(), command) } // EditCommand edits a specific guild command func (d DisgoImpl) EditCommand(commandID api.Snowflake, command api.SlashCommand) (*api.SlashCommand, error) { - return d.RestClient().EditGlobalCommand(d.ApplicationID(), commandID, command) + return d.RestClient().EditGlobalCommand(d.SelfUserID(), commandID, command) } // DeleteCommand creates a new command for this guild func (d DisgoImpl) DeleteCommand(command api.SlashCommand) (*api.SlashCommand, error) { - return d.RestClient().CreateGlobalCommand(d.ApplicationID(), command) + return d.RestClient().CreateGlobalCommand(d.SelfUserID(), command) } // SetCommands overrides all commands for this guild func (d DisgoImpl) SetCommands(commands ...api.SlashCommand) ([]*api.SlashCommand, error) { - return d.RestClient().SetGlobalCommands(d.ApplicationID(), commands...) + return d.RestClient().SetGlobalCommands(d.SelfUserID(), commands...) } diff --git a/internal/disgo_builder.go b/internal/disgo_builder.go index 94275835..a49f2480 100644 --- a/internal/disgo_builder.go +++ b/internal/disgo_builder.go @@ -177,7 +177,7 @@ func (b DisgoBuilderImpl) Build() (api.Disgo, error) { if b.messageCachePolicy == nil { b.messageCachePolicy = api.MessageCachePolicyDefault } - b.cache = newCacheImpl(b.memberCachePolicy, b.messageCachePolicy, b.cacheFlags) + b.cache = newCacheImpl(disgo, b.memberCachePolicy, b.messageCachePolicy, b.cacheFlags) } disgo.cache = b.cache diff --git a/internal/gateway.go b/internal/gateway.go index 4b202655..82505f94 100644 --- a/internal/gateway.go +++ b/internal/gateway.go @@ -153,7 +153,7 @@ func (g *GatewayImpl) Close() { return } log.Info("closing gateway goroutines...") - close(g.quit) + g.quit <- true log.Info("closed gateway goroutines") } diff --git a/internal/handlers/ready_handler.go b/internal/handlers/ready_handler.go index 58b3e94d..73531cce 100644 --- a/internal/handlers/ready_handler.go +++ b/internal/handlers/ready_handler.go @@ -32,7 +32,9 @@ func (h ReadyHandler) Handle(disgo api.Disgo, eventManager api.EventManager, i i if !ok { return } - disgo.SetSelfUser(&readyEvent.SelfUser) + + disgo.Cache().CacheUser(&readyEvent.SelfUser) + for i := range readyEvent.Guilds { disgo.Cache().CacheGuild(readyEvent.Guilds[i]) } diff --git a/internal/restclient.go b/internal/restclient.go index 92718cfe..676d5f54 100644 --- a/internal/restclient.go +++ b/internal/restclient.go @@ -185,7 +185,7 @@ func (r RestClientImpl) UpdateSelfNick(guildID api.Snowflake, nick *string) (new var updateNick *api.UpdateSelfNick err = r.Request(endpoints.UpdateSelfNick.Compile(guildID), api.UpdateSelfNick{Nick: nick}, &updateNick) if updateNick != nil { - r.Disgo().Cache().Member(guildID, r.Disgo().ApplicationID()).Nick = updateNick.Nick + r.Disgo().Cache().Member(guildID, r.Disgo().SelfUserID()).Nick = updateNick.Nick newNick = updateNick.Nick } return diff --git a/testbot/testbot.go b/testbot/testbot.go index 93e23c99..7e1823d3 100644 --- a/testbot/testbot.go +++ b/testbot/testbot.go @@ -32,7 +32,7 @@ func main() { return } - _, err = dgo.RestClient().SetGuildCommands(dgo.ApplicationID(), "817327181659111454", + _, err = dgo.RestClient().SetGuildCommands(dgo.SelfUserID(), "817327181659111454", api.SlashCommand{ Name: "test", Description: "test test test test test test", From 802279db0ce939735831670cceecc6522ca3a147 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Tue, 6 Apr 2021 12:38:18 +0200 Subject: [PATCH 18/65] added voice state cache & refactored some stuff --- .github/workflows/codeql-analysis.yml | 86 +++++++++---------- api/cache.go | 7 ++ api/channels.go | 1 - api/command_thread.go | 2 +- api/disgo.go | 8 +- api/disgo_builder.go | 1 + api/endpoints/route_test.go | 2 +- api/events/channel_events.go | 16 ++-- api/events/dm_event.go | 6 +- api/events/dm_message_event.go | 2 +- api/events/guild_events.go | 6 +- api/events/guild_member_events.go | 2 +- api/events/guild_message_events.go | 9 +- api/events/interaction_events.go | 47 +++++----- api/events/listener_adapter.go | 4 +- api/events/message_event.go | 7 +- api/events/ready_events.go | 2 +- api/gateway.go | 82 +++++++++--------- api/gateway_commands.go | 6 +- api/generic_event.go | 22 +++-- api/interaction_followup.go | 6 +- api/message.go | 2 +- api/voice_dispatch_interceptor.go | 39 +++++++++ api/voice_state.go | 57 +++++++++--- api/webhook_server.go | 8 +- internal/{cache.go => cache_impl.go} | 54 ++++++++++++ ...disgo_builder.go => disgo_builder_impl.go} | 75 +++++++++------- internal/{disgo.go => disgo_impl.go} | 27 ++++-- ...event_manager.go => event_manager_impl.go} | 14 +-- internal/{gateway.go => gateway_impl.go} | 2 +- internal/handlers/all_handlers.go | 3 + internal/handlers/guild_create_handler.go | 12 ++- internal/handlers/guild_delete_handler.go | 14 ++- internal/handlers/guild_member_add_handler.go | 12 ++- .../handlers/guild_member_remove_handler.go | 12 ++- .../handlers/guild_member_update_handler.go | 13 ++- .../handlers/guild_role_create_handler.go | 12 ++- .../handlers/guild_role_delete_handler.go | 12 ++- .../handlers/guild_role_update_handler.go | 12 ++- internal/handlers/guild_update_handler.go | 12 ++- .../handlers/interaction_create_handler.go | 37 ++++---- .../interaction_create_webhook_handler.go | 8 +- internal/handlers/message_create_handler.go | 17 ++-- internal/handlers/ready_handler.go | 6 +- .../handlers/voice_server_update_handler.go | 34 ++++++++ .../handlers/voice_state_update_handler.go | 43 ++++++++++ .../{restclient.go => restclient_impl.go} | 2 +- ...bhook_server.go => webhook_server_impl.go} | 2 +- testbot/testbot.go | 6 +- 49 files changed, 554 insertions(+), 317 deletions(-) create mode 100644 api/voice_dispatch_interceptor.go rename internal/{cache.go => cache_impl.go} (93%) rename internal/{disgo_builder.go => disgo_builder_impl.go} (58%) rename internal/{disgo.go => disgo_impl.go} (83%) rename internal/{event_manager.go => event_manager_impl.go} (82%) rename internal/{gateway.go => gateway_impl.go} (99%) create mode 100644 internal/handlers/voice_server_update_handler.go create mode 100644 internal/handlers/voice_state_update_handler.go rename internal/{restclient.go => restclient_impl.go} (99%) rename internal/{webhook_server.go => webhook_server_impl.go} (96%) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 01229092..426058c5 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -12,56 +12,56 @@ name: "CodeQL" on: - push: - branches: [ master ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ master ] - schedule: - - cron: '00 12 * * *' + push: + branches: [ master ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ master ] + schedule: + - cron: '00 12 * * *' jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest + analyze: + name: Analyze + runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - language: [ 'go' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] - # Learn more: - # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed + strategy: + fail-fast: false + matrix: + language: [ 'go' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] + # Learn more: + # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed - steps: - - name: Checkout repository - uses: actions/checkout@v2 + steps: + - name: Checkout repository + uses: actions/checkout@v2 - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v1 + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language - #- run: | - # make bootstrap - # make release + #- run: | + # make bootstrap + # make release - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff --git a/api/cache.go b/api/cache.go index 00f4f971..db246dc0 100644 --- a/api/cache.go +++ b/api/cache.go @@ -2,6 +2,7 @@ package api // Cache allows you to access the objects that are stored in-memory by Discord type Cache interface { + Disgo() Disgo Close() DoCleanup() CacheFlags() CacheFlags @@ -43,6 +44,12 @@ type Cache interface { FindMember(Snowflake, func(*Member) bool) *Member FindMembers(Snowflake, func(*Member) bool) []*Member + VoiceState(guildID Snowflake, userID Snowflake) *VoiceState + VoiceStates(guildID Snowflake) []*VoiceState + VoiceStateCache(guildID Snowflake) map[Snowflake]*VoiceState + CacheVoiceState(voiceState *VoiceState) + UncacheVoiceState(guildID Snowflake, userID Snowflake) + Role(Snowflake, Snowflake) *Role RolesByName(Snowflake, string, bool) []*Role Roles(Snowflake) []*Role diff --git a/api/channels.go b/api/channels.go index 274aab6a..9d80cdb5 100644 --- a/api/channels.go +++ b/api/channels.go @@ -50,7 +50,6 @@ func (c MessageChannel) SendMessage(message MessageCreate) (*Message, error) { return c.Disgo.RestClient().SendMessage(c.ID, message) } - // EditMessage edits a Message in this TextChannel func (c MessageChannel) EditMessage(messageID Snowflake, message MessageUpdate) (*Message, error) { return c.Disgo.RestClient().EditMessage(c.ID, messageID, message) diff --git a/api/command_thread.go b/api/command_thread.go index 6df7c14e..a73c69b2 100644 --- a/api/command_thread.go +++ b/api/command_thread.go @@ -9,7 +9,7 @@ package api // CommandThread allows you to follow up Interactions (https://discord.com/developers/docs/interactions/slash-commands) type CommandThread interface { Disgo() Disgo - Event() events.SlashCommandEvent + GenericEvent() events.SlashCommandEvent Ephemeral(ephemeral bool) CommandThread SendMessage() *promise.Promise EditOriginal(message_events string) *promise.Promise diff --git a/api/disgo.go b/api/disgo.go index d6e53b0a..8dc3216c 100644 --- a/api/disgo.go +++ b/api/disgo.go @@ -21,6 +21,8 @@ type Disgo interface { SelfUserID() Snowflake SelfUser() *User EventManager() EventManager + VoiceDispatchInterceptor() VoiceDispatchInterceptor + SetVoiceDispatchInterceptor(voiceInterceptor VoiceDispatchInterceptor) HeartbeatLatency() time.Duration GetCommand(commandID Snowflake) (*SlashCommand, error) @@ -33,7 +35,7 @@ type Disgo interface { // EventHandler provides info about the EventHandler type EventHandler interface { - Name() string + Event() GatewayEvent New() interface{} } @@ -57,8 +59,8 @@ type EventListener interface { // EventManager lets you listen for specific events triggered by raw gateway events type EventManager interface { AddEventListeners(...EventListener) - Handle(string, json.RawMessage, chan interface{}) - Dispatch(GenericEvent) + Handle(GatewayEvent, json.RawMessage, chan interface{}) + Dispatch(Event) } // GetOS returns the simplified version of the operating system for sending to Discord in the IdentifyCommandDataProperties.OS payload diff --git a/api/disgo_builder.go b/api/disgo_builder.go index 27bc14c5..f4b47310 100644 --- a/api/disgo_builder.go +++ b/api/disgo_builder.go @@ -7,6 +7,7 @@ type DisgoBuilder interface { SetLogLevel(level log.Level) DisgoBuilder SetToken(token string) DisgoBuilder SetIntents(intents Intents) DisgoBuilder + SetVoiceDispatchInterceptor(VoiceDispatchInterceptor) DisgoBuilder SetEventManager(eventManager EventManager) DisgoBuilder AddEventListeners(eventsListeners ...EventListener) DisgoBuilder SetWebhookServer(webhookServer WebhookServer) DisgoBuilder diff --git a/api/endpoints/route_test.go b/api/endpoints/route_test.go index 62c91b59..22a0b965 100644 --- a/api/endpoints/route_test.go +++ b/api/endpoints/route_test.go @@ -19,4 +19,4 @@ func TestCustomRoute_Compile(t *testing.T) { testAPI := NewCustomRoute(GET, "https://test.de/{test}") assert.Equal(t, "https://test.de/test", testAPI.Compile("test").Route()) -} \ No newline at end of file +} diff --git a/api/events/channel_events.go b/api/events/channel_events.go index 1c0279c7..067c9a16 100644 --- a/api/events/channel_events.go +++ b/api/events/channel_events.go @@ -4,13 +4,13 @@ import "github.com/DisgoOrg/disgo/api" // GenericChannelEvent is called upon receiving an event in a api.Channel type GenericChannelEvent struct { - api.Event + api.GenericEvent ChannelID api.Snowflake } // Channel returns the api.Channel from the api.Cache func (e GenericChannelEvent) Channel() *api.Channel { - return e.Disgo.Cache().Channel(e.ChannelID) + return e.Disgo().Cache().Channel(e.ChannelID) } // GenericDMChannelEvent is called upon receiving an event in a api.DMChannel @@ -20,7 +20,7 @@ type GenericDMChannelEvent struct { // DMChannel returns the api.DMChannel from the api.Cache func (e GenericDMChannelEvent) DMChannel() *api.DMChannel { - return e.Disgo.Cache().DMChannel(e.ChannelID) + return e.Disgo().Cache().DMChannel(e.ChannelID) } // GenericMessageChannelEvent is called upon receiving an event in a api.MessageChannel @@ -30,7 +30,7 @@ type GenericMessageChannelEvent struct { // MessageChannel returns the api.MessageChannel from the api.Cache func (e GenericMessageChannelEvent) MessageChannel() *api.MessageChannel { - return e.Disgo.Cache().MessageChannel(e.ChannelID) + return e.Disgo().Cache().MessageChannel(e.ChannelID) } // GenericTextChannelEvent is called upon receiving an event in a api.TextChannel @@ -40,7 +40,7 @@ type GenericTextChannelEvent struct { // TextChannel returns the api.TextChannel from the api.Cache func (e GenericTextChannelEvent) TextChannel() *api.TextChannel { - return e.Disgo.Cache().TextChannel(e.ChannelID) + return e.Disgo().Cache().TextChannel(e.ChannelID) } // GenericVoiceChannelEvent is called upon receiving an event in a api.VoiceChannel @@ -50,7 +50,7 @@ type GenericVoiceChannelEvent struct { // VoiceChannel returns the api.VoiceChannel from the api.Cache func (e GenericVoiceChannelEvent) VoiceChannel() *api.VoiceChannel { - return e.Disgo.Cache().VoiceChannel(e.ChannelID) + return e.Disgo().Cache().VoiceChannel(e.ChannelID) } // GenericCategoryEvent is called upon receiving an event in a api.Category @@ -60,7 +60,7 @@ type GenericCategoryEvent struct { // Category returns the api.Category from the api.Cache func (e GenericCategoryEvent) Category() *api.Category { - return e.Disgo.Cache().Category(e.ChannelID) + return e.Disgo().Cache().Category(e.ChannelID) } // GenericStoreChannelEvent is called upon receiving an event in a api.StoreChannel @@ -70,5 +70,5 @@ type GenericStoreChannelEvent struct { // StoreChannel returns the api.StoreChannel from the api.Cache func (e GenericStoreChannelEvent) StoreChannel() *api.StoreChannel { - return e.Disgo.Cache().StoreChannel(e.ChannelID) + return e.Disgo().Cache().StoreChannel(e.ChannelID) } diff --git a/api/events/dm_event.go b/api/events/dm_event.go index 6e84ef32..0f9d048b 100644 --- a/api/events/dm_event.go +++ b/api/events/dm_event.go @@ -4,17 +4,17 @@ import "github.com/DisgoOrg/disgo/api" // GenericDMEvent is a generic dm channel event type GenericDMEvent struct { - api.Event + api.GenericEvent UserID api.Snowflake DMChannelID api.Snowflake } // User gets the user from the api.Cache func (e GenericDMEvent) User() *api.DMChannel { - return e.Disgo.Cache().DMChannel(e.DMChannelID) + return e.Disgo().Cache().DMChannel(e.DMChannelID) } // DMChannel returns the api.DMChannel from the api.Cache func (e GenericDMEvent) DMChannel() *api.DMChannel { - return e.Disgo.Cache().DMChannel(e.DMChannelID) + return e.Disgo().Cache().DMChannel(e.DMChannelID) } diff --git a/api/events/dm_message_event.go b/api/events/dm_message_event.go index e1a325b4..5ca752ba 100644 --- a/api/events/dm_message_event.go +++ b/api/events/dm_message_event.go @@ -4,7 +4,7 @@ import ( "github.com/DisgoOrg/disgo/api" ) -// GenericDMMessageEvent generic api.DMChannel api.Message api.Event +// GenericDMMessageEvent generic api.DMChannel api.Message api.GenericEvent type GenericDMMessageEvent struct { GenericDMEvent GenericMessageEvent diff --git a/api/events/guild_events.go b/api/events/guild_events.go index 1939b943..351941c9 100644 --- a/api/events/guild_events.go +++ b/api/events/guild_events.go @@ -4,15 +4,15 @@ import ( "github.com/DisgoOrg/disgo/api" ) -// GenericGuildEvent generic api.Guild api.Event +// GenericGuildEvent generic api.Guild api.GenericEvent type GenericGuildEvent struct { - api.Event + api.GenericEvent GuildID api.Snowflake } // Guild returns the api.Guild from the api.Cache func (e GenericGuildEvent) Guild() *api.Guild { - return e.Disgo.Cache().Guild(e.GuildID) + return e.Disgo().Cache().Guild(e.GuildID) } // GuildUpdateEvent called upon receiving api.Guild updates diff --git a/api/events/guild_member_events.go b/api/events/guild_member_events.go index 862c56a0..cac2a6ac 100644 --- a/api/events/guild_member_events.go +++ b/api/events/guild_member_events.go @@ -10,7 +10,7 @@ type GenericGuildMemberEvent struct { // User gets the api.User form the api.Cache func (e GenericGuildMemberEvent) User() *api.User { - return e.Disgo.Cache().User(e.UserID) + return e.Disgo().Cache().User(e.UserID) } // GuildMemberJoinEvent indicates that a api.Member joined the api.Guild diff --git a/api/events/guild_message_events.go b/api/events/guild_message_events.go index de4772d7..2469c360 100644 --- a/api/events/guild_message_events.go +++ b/api/events/guild_message_events.go @@ -4,10 +4,15 @@ import ( "github.com/DisgoOrg/disgo/api" ) -// GenericGuildMessageEvent indicates that we received a api.Message api.Event in a api.Guild +// GenericGuildMessageEvent indicates that we received a api.Message api.GenericEvent in a api.Guild type GenericGuildMessageEvent struct { - GenericGuildEvent GenericMessageEvent + GuildID api.Snowflake +} + +// Guild returns the api.Guild from the api.Cache +func (e GenericGuildMessageEvent) Guild() *api.Guild { + return e.Disgo().Cache().Guild(e.GuildID) } // GuildMessageReceivedEvent indicates that we received a api.Message in a api.Guild diff --git a/api/events/interaction_events.go b/api/events/interaction_events.go index d8e737ba..73d19c4c 100644 --- a/api/events/interaction_events.go +++ b/api/events/interaction_events.go @@ -8,7 +8,7 @@ import ( // GenericInteractionEvent generic api.Interaction event type GenericInteractionEvent struct { - api.Event + api.GenericEvent Interaction api.Interaction } @@ -17,7 +17,7 @@ func (e GenericInteractionEvent) Guild() *api.Guild { if e.Interaction.GuildID == nil { return nil } - return e.Disgo.Cache().Guild(*e.Interaction.GuildID) + return e.Disgo().Cache().Guild(*e.Interaction.GuildID) } // DMChannel returns the api.DMChannel from the api.Cache @@ -25,7 +25,7 @@ func (e GenericInteractionEvent) DMChannel() *api.DMChannel { if e.Interaction.ChannelID == nil { return nil } - return e.Disgo.Cache().DMChannel(*e.Interaction.ChannelID) + return e.Disgo().Cache().DMChannel(*e.Interaction.ChannelID) } // MessageChannel returns the api.MessageChannel from the api.Cache @@ -33,7 +33,7 @@ func (e GenericInteractionEvent) MessageChannel() *api.MessageChannel { if e.Interaction.ChannelID == nil { return nil } - return e.Disgo.Cache().MessageChannel(*e.Interaction.ChannelID) + return e.Disgo().Cache().MessageChannel(*e.Interaction.ChannelID) } // TextChannel returns the api.TextChannel from the api.Cache @@ -41,7 +41,7 @@ func (e GenericInteractionEvent) TextChannel() *api.TextChannel { if e.Interaction.ChannelID == nil { return nil } - return e.Disgo.Cache().TextChannel(*e.Interaction.ChannelID) + return e.Disgo().Cache().TextChannel(*e.Interaction.ChannelID) } // GuildChannel returns the api.GuildChannel from the api.Cache @@ -49,20 +49,20 @@ func (e GenericInteractionEvent) GuildChannel() *api.GuildChannel { if e.Interaction.ChannelID == nil { return nil } - return e.Disgo.Cache().GuildChannel(*e.Interaction.ChannelID) + return e.Disgo().Cache().GuildChannel(*e.Interaction.ChannelID) } // SlashCommandEvent indicates a slash api.SlashCommand was ran in a api.Guild type SlashCommandEvent struct { GenericInteractionEvent - ResponseChannel chan interface{} - FromWebhook bool - CommandID api.Snowflake - Name string - SubCommandName *string - SubCommandGroup *string - Options []*Option - Replied bool + ResponseChannel chan interface{} + FromWebhook bool + CommandID api.Snowflake + CommandName string + SubCommandName *string + SubCommandGroupName *string + Options []*Option + Replied bool } // Option holds info about an Option.Value @@ -164,12 +164,12 @@ func (o Option) StoreChannel() *api.StoreChannel { // CommandPath returns the api.SlashCommand path func (e SlashCommandEvent) CommandPath() string { - path := e.Name + path := e.CommandName if e.SubCommandName != nil { path += "/" + *e.SubCommandName } - if e.SubCommandGroup != nil { - path += "/" + *e.SubCommandGroup + if e.SubCommandGroupName != nil { + path += "/" + *e.SubCommandGroupName } return path } @@ -222,31 +222,30 @@ func (e *SlashCommandEvent) Reply(response api.InteractionResponse) error { return nil } - return e.Disgo.RestClient().SendInteractionResponse(e.Interaction.ID, e.Interaction.Token, response) + return e.Disgo().RestClient().SendInteractionResponse(e.Interaction.ID, e.Interaction.Token, response) } // EditOriginal edits the original api.InteractionResponse func (e *SlashCommandEvent) EditOriginal(followupMessage api.FollowupMessage) (*api.Message, error) { - return e.Disgo.RestClient().EditInteractionResponse(e.Interaction.ID, e.Interaction.Token, followupMessage) + return e.Disgo().RestClient().EditInteractionResponse(e.Interaction.ID, e.Interaction.Token, followupMessage) } // DeleteOriginal deletes the original api.InteractionResponse func (e *SlashCommandEvent) DeleteOriginal() error { - return e.Disgo.RestClient().DeleteInteractionResponse(e.Interaction.ID, e.Interaction.Token) + return e.Disgo().RestClient().DeleteInteractionResponse(e.Interaction.ID, e.Interaction.Token) } // SendFollowup used to send a api.FollowupMessage to an api.Interaction func (e *SlashCommandEvent) SendFollowup(followupMessage api.FollowupMessage) (*api.Message, error) { - return e.Disgo.RestClient().SendFollowupMessage(e.Interaction.ID, e.Interaction.Token, followupMessage) + return e.Disgo().RestClient().SendFollowupMessage(e.Interaction.ID, e.Interaction.Token, followupMessage) } // EditFollowup used to edit a api.FollowupMessage from an api.Interaction func (e *SlashCommandEvent) EditFollowup(messageID api.Snowflake, followupMessage api.FollowupMessage) (*api.Message, error) { - return e.Disgo.RestClient().EditFollowupMessage(e.Interaction.ID, e.Interaction.Token, messageID, followupMessage) + return e.Disgo().RestClient().EditFollowupMessage(e.Interaction.ID, e.Interaction.Token, messageID, followupMessage) } // DeleteFollowup used to delete a api.FollowupMessage from an api.Interaction func (e *SlashCommandEvent) DeleteFollowup(messageID api.Snowflake) error { - return e.Disgo.RestClient().DeleteFollowupMessage(e.Interaction.ID, e.Interaction.Token, messageID) + return e.Disgo().RestClient().DeleteFollowupMessage(e.Interaction.ID, e.Interaction.Token, messageID) } - diff --git a/api/events/listener_adapter.go b/api/events/listener_adapter.go index 71becb9c..1e239212 100644 --- a/api/events/listener_adapter.go +++ b/api/events/listener_adapter.go @@ -6,7 +6,7 @@ import ( // ListenerAdapter lets you override the handles for receiving events type ListenerAdapter struct { - OnGenericEvent func(*api.GenericEvent) + OnGenericEvent func(*api.Event) // Guild Events OnGenericGuildEvent func(*GenericGuildEvent) @@ -33,7 +33,7 @@ type ListenerAdapter struct { // OnEvent is getting called everytime we receive an event func (l ListenerAdapter) OnEvent(event interface{}) { - if event, ok := event.(api.GenericEvent); ok { + if event, ok := event.(api.Event); ok { if l.OnGenericEvent != nil { l.OnGenericEvent(&event) } diff --git a/api/events/message_event.go b/api/events/message_event.go index 39d50f4b..d98e25d3 100644 --- a/api/events/message_event.go +++ b/api/events/message_event.go @@ -4,17 +4,14 @@ import "github.com/DisgoOrg/disgo/api" // GenericMessageEvent generic api.Message event type GenericMessageEvent struct { - api.Event + api.GenericEvent MessageID api.Snowflake MessageChannelID api.Snowflake } // MessageChannel returns the api.MessageChannel where this api.message got received func (e *GenericMessageEvent) MessageChannel() *api.MessageChannel { - return e. - Disgo. - Cache(). - MessageChannel(e.MessageChannelID) + return e.Disgo().Cache().MessageChannel(e.MessageChannelID) } // MessageDeleteEvent indicates a api.Message got deleted diff --git a/api/events/ready_events.go b/api/events/ready_events.go index 5b04d979..953d0812 100644 --- a/api/events/ready_events.go +++ b/api/events/ready_events.go @@ -4,6 +4,6 @@ import "github.com/DisgoOrg/disgo/api" // ReadyEvent indicates we received the ReadyEvent from the api.Gateway type ReadyEvent struct { - api.Event + api.GenericEvent api.ReadyEventData } diff --git a/api/gateway.go b/api/gateway.go index e234732d..318477db 100644 --- a/api/gateway.go +++ b/api/gateway.go @@ -46,48 +46,50 @@ const ( OpHeartbeatACK ) +type GatewayEvent string + // Constants for the gateway events const ( - ChannelCreateGatewayEvent = "CHANNEL_CREATE" - ChannelDeleteGatewayEvent = "CHANNEL_DELETE" - ChannelPinsUpdateGatewayEvent = "CHANNEL_PINS_UPDATE" - ChannelUpdateGatewayEvent = "CHANNEL_UPDATE" - GuildBanAddGatewayEvent = "GUILD_BAN_ADD" - GuildBanRemoveGatewayEvent = "GUILD_BAN_REMOVE" - GuildCreateGatewayEvent = "GUILD_CREATE" - GuildDeleteGatewayEvent = "GUILD_DELETE" - GuildEmojisUpdateGatewayEvent = "GUILD_EMOJIS_UPDATE" - GuildIntegrationsUpdateGatewayEvent = "GUILD_INTEGRATIONS_UPDATE" - GuildMemberAddGatewayEvent = "GUILD_MEMBER_ADD" - GuildMemberRemoveGatewayEvent = "GUILD_MEMBER_REMOVE" - GuildMemberUpdateGatewayEvent = "GUILD_MEMBER_UPDATE" - GuildMembersChunkGatewayEvent = "GUILD_MEMBERS_CHUNK" - GuildRoleCreateGatewayEvent = "GUILD_ROLE_CREATE" - GuildRoleDeleteGatewayEvent = "GUILD_ROLE_DELETE" - GuildRoleUpdateGatewayEvent = "GUILD_ROLE_UPDATE" - GuildUpdateGatewayEvent = "GUILD_UPDATE" - InteractionCreateGatewayEvent = "INTERACTION_CREATE" - InteractionCreateWebhookEvent = "INTERACTION_WEBHOOK_CREATE" - MessageAckGatewayEvent = "MESSAGE_ACK" - MessageCreateGatewayEvent = "MESSAGE_CREATE" - MessageDeleteGatewayEvent = "MESSAGE_DELETE" - MessageDeleteBulkGatewayEvent = "MESSAGE_DELETE_BULK" - MessageReactionAddGatewayEvent = "MESSAGE_REACTION_ADD" - MessageReactionRemoveGatewayEvent = "MESSAGE_REACTION_REMOVE" - MessageReactionRemoveAllGatewayEvent = "MESSAGE_REACTION_REMOVE_ALL" - MessageUpdateGatewayEvent = "MESSAGE_UPDATE" - PresenceUpdateGatewayEvent = "PRESENCE_UPDATE" - PresencesReplaceGatewayEvent = "PRESENCES_REPLACE" - ReadyGatewayEvent = "READY" - ResumedGatewayEvent = "RESUMED" - TypingStartGatewayEvent = "TYPING_START" - UserGuildSettingsUpdateGatewayEvent = "USER_GUILD_SETTINGS_UPDATE" - UserNoteUpdateGatewayEvent = "USER_NOTE_UPDATE" - UserSettingsUpdateGatewayEvent = "USER_SETTINGS_UPDATE" - UserUpdateGatewayEvent = "USER_UPDATE" - VoiceServerUpdateGatewayEvent = "VOICE_SERVER_UPDATE" - VoiceStateUpdateGatewayEvent = "VOICE_STATE_UPDATE" - WebhooksUpdateGatewayEvent = "WEBHOOKS_UPDATE" + GatewayEventChannelCreate GatewayEvent = "CHANNEL_CREATE" + GatewayEventChannelDelete GatewayEvent = "CHANNEL_DELETE" + GatewayEventChannelPinsUpdate GatewayEvent = "CHANNEL_PINS_UPDATE" + GatewayEventChannelUpdate GatewayEvent = "CHANNEL_UPDATE" + GatewayEventGuildBanAdd GatewayEvent = "GUILD_BAN_ADD" + GatewayEventGuildBanRemove GatewayEvent = "GUILD_BAN_REMOVE" + GatewayEventGuildCreate GatewayEvent = "GUILD_CREATE" + GatewayEventGuildDelete GatewayEvent = "GUILD_DELETE" + GatewayEventGuildEmojisUpdate GatewayEvent = "GUILD_EMOJIS_UPDATE" + GatewayEventGuildIntegrationsUpdate GatewayEvent = "GUILD_INTEGRATIONS_UPDATE" + GatewayEventGuildMemberAdd GatewayEvent = "GUILD_MEMBER_ADD" + GatewayEventGuildMemberRemove GatewayEvent = "GUILD_MEMBER_REMOVE" + GatewayEventGuildMemberUpdate GatewayEvent = "GUILD_MEMBER_UPDATE" + GatewayEventGuildMembersChunk GatewayEvent = "GUILD_MEMBERS_CHUNK" + GatewayEventGuildRoleCreate GatewayEvent = "GUILD_ROLE_CREATE" + GatewayEventGuildRoleDelete GatewayEvent = "GUILD_ROLE_DELETE" + GatewayEventGuildRoleUpdate GatewayEvent = "GUILD_ROLE_UPDATE" + GatewayEventGuildUpdate GatewayEvent = "GUILD_UPDATE" + GatewayEventInteractionCreate GatewayEvent = "INTERACTION_CREATE" + WebhookEventInteractionCreate GatewayEvent = "INTERACTION_WEBHOOK_CREATE" + GatewayEventMessageAck GatewayEvent = "MESSAGE_ACK" + GatewayEventMessageCreate GatewayEvent = "MESSAGE_CREATE" + GatewayEventMessageDelete GatewayEvent = "MESSAGE_DELETE" + GatewayEventMessageDeleteBulk GatewayEvent = "MESSAGE_DELETE_BULK" + GatewayEventMessageReactionAdd GatewayEvent = "MESSAGE_REACTION_ADD" + GatewayEventMessageReactionRemove GatewayEvent = "MESSAGE_REACTION_REMOVE" + GatewayEventMessageReactionRemoveAll GatewayEvent = "MESSAGE_REACTION_REMOVE_ALL" + GatewayEventMessageUpdate GatewayEvent = "MESSAGE_UPDATE" + GatewayEventPresenceUpdate GatewayEvent = "PRESENCE_UPDATE" + GatewayEventPresencesReplace GatewayEvent = "PRESENCES_REPLACE" + GatewayEventReady GatewayEvent = "READY" + GatewayEventResumed GatewayEvent = "RESUMED" + GatewayEventTypingStart GatewayEvent = "TYPING_START" + GatewayEventUserGuildSettingsUpdate GatewayEvent = "USER_GUILD_SETTINGS_UPDATE" + GatewayEventUserNoteUpdate GatewayEvent = "USER_NOTE_UPDATE" + GatewayEventUserSettingsUpdate GatewayEvent = "USER_SETTINGS_UPDATE" + GatewayEventUserUpdate GatewayEvent = "USER_UPDATE" + GatewayEventVoiceServerUpdate GatewayEvent = "VOICE_SERVER_UPDATE" + GatewayEventVoiceStateUpdate GatewayEvent = "VOICE_STATE_UPDATE" + GatewayEventWebhooksUpdate GatewayEvent = "WEBHOOKS_UPDATE" ) // GatewayRs contains the response for GET /gateway diff --git a/api/gateway_commands.go b/api/gateway_commands.go index 4d337020..f7078093 100644 --- a/api/gateway_commands.go +++ b/api/gateway_commands.go @@ -7,9 +7,9 @@ import ( // GatewayCommand object is used when sending data to discord's websocket, it's recommended that you don't use these type GatewayCommand struct { - Op GatewayOp `json:"op"` - S *int `json:"s,omitempty"` - T *string `json:"t,omitempty"` + Op GatewayOp `json:"op"` + S *int `json:"s,omitempty"` + T *GatewayEvent `json:"t,omitempty"` } // RawGatewayCommand specifies the data for the GatewayCommand payload that is being sent diff --git a/api/generic_event.go b/api/generic_event.go index e504aa1e..512bbec8 100644 --- a/api/generic_event.go +++ b/api/generic_event.go @@ -1,9 +1,21 @@ package api -// GenericEvent the basic interface each event implement -type GenericEvent interface{} +// Event the basic interface each event implement +type Event interface { + Disgo() Disgo +} + +// NewEvent constructs a new GenericEvent with the provided Disgo instance +func NewEvent(disgo Disgo) GenericEvent { + return GenericEvent{disgo: disgo} +} + +// GenericEvent the base event structure +type GenericEvent struct { + disgo Disgo +} -// Event the base event structure -type Event struct { - Disgo Disgo +// Disgo returns the Disgo instance for this event +func (d GenericEvent) Disgo() Disgo { + return d.disgo } diff --git a/api/interaction_followup.go b/api/interaction_followup.go index da3ce590..12a26cc8 100644 --- a/api/interaction_followup.go +++ b/api/interaction_followup.go @@ -2,9 +2,9 @@ package api // FollowupMessage is used to add additional messages to an Interaction after you've responded initially type FollowupMessage struct { - Content string `json:"content,omitempty"` - Username string `json:"username,omitempty"` - AvatarURL string `json:"avatar_url,omitempty"` + Content string `json:"content,omitempty"` + Username string `json:"username,omitempty"` + AvatarURL string `json:"avatar_url,omitempty"` TTS bool `json:"tts,omitempty"` Embeds []Embed `json:"embeds,omitempty"` AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` diff --git a/api/message.go b/api/message.go index 9a0ace89..e37de183 100644 --- a/api/message.go +++ b/api/message.go @@ -96,7 +96,7 @@ const ( MessageFlagUrgent _ MessageFlagEphemeral - MessageFlagLoading // Message is an interaction of type 5, awaiting further response + MessageFlagLoading // Message is an interaction of type 5, awaiting further response ) // Message is a struct for messages sent in discord text-based channels diff --git a/api/voice_dispatch_interceptor.go b/api/voice_dispatch_interceptor.go new file mode 100644 index 00000000..06a6f3c6 --- /dev/null +++ b/api/voice_dispatch_interceptor.go @@ -0,0 +1,39 @@ +package api + +// VoiceServerUpdate sent when a guilds voice server is updated +type VoiceServerUpdate struct { + Disgo Disgo + Token string `json:"token"` + GuildID Snowflake `json:"guild_id"` + Endpoint *string `json:"endpoint"` +} + +// Guild returns the Guild for this VoiceServerUpdate from the Cache +func (u VoiceServerUpdate) Guild() *Guild { + return u.Disgo.Cache().Guild(u.GuildID) +} + +// VoiceStateUpdate sent when someone joins/leaves/moves voice channels +type VoiceStateUpdate struct { + VoiceState + Member *Member `json:"member"` +} + +// Guild returns the Guild for this VoiceStateUpdate from the Cache +func (u VoiceStateUpdate) Guild() *Guild { + return u.Disgo.Cache().Guild(u.GuildID) +} + +// VoiceChannel returns the VoiceChannel for this VoiceStateUpdate from the Cache +func (u VoiceStateUpdate) VoiceChannel() *VoiceChannel { + if u.ChannelID == nil { + return nil + } + return u.Disgo.Cache().VoiceChannel(*u.ChannelID) +} + +// VoiceDispatchInterceptor lets you listen to VoiceServerUpdate & VoiceStateUpdate +type VoiceDispatchInterceptor interface { + OnVoiceServerUpdate(voiceServerUpdateEvent VoiceServerUpdate) + OnVoiceStateUpdate(voiceStateUpdateEvent VoiceStateUpdate) +} diff --git a/api/voice_state.go b/api/voice_state.go index 8fb900a5..9d7ca3a8 100644 --- a/api/voice_state.go +++ b/api/voice_state.go @@ -1,17 +1,48 @@ package api -// A VoiceState from Discord +// VoiceState from Discord type VoiceState struct { - GuildID *Snowflake `json:"guild_id,omitempty"` - ChannelID *Snowflake `json:"channel_id"` - UserID Snowflake `json:"user_id"` - Member *Member `json:"member,omitempty"` - SessionID string `json:"session_id"` - Deaf bool `json:"deaf"` - Mute bool `json:"mute"` - SelfDeaf bool `json:"self_deaf"` - SelfMute bool `json:"self_mute"` - SelfStream *bool `json:"self_stream,omitempty"` - SelfVideo bool `json:"self_video"` - Suppress bool `json:"suppress"` + Disgo Disgo + GuildID Snowflake `json:"guild_id"` + ChannelID *Snowflake `json:"channel_id"` + UserID Snowflake `json:"user_id"` + SessionID string `json:"session_id"` + GuildDeafened bool `json:"deaf"` + GuildMuted bool `json:"mute"` + SelfDeafened bool `json:"self_deaf"` + SelfMuted bool `json:"self_mute"` + Stream bool `json:"self_stream"` + Video bool `json:"self_video"` + Suppressed bool `json:"suppress"` +} + +func (s VoiceState) Muted() bool { + return s.GuildMuted || s.SelfMuted +} + +func (s VoiceState) Deafened() bool { + return s.GuildDeafened || s.SelfDeafened +} + +// Member returns the Member of this VoiceState from the Cache +func (s VoiceState) Member() *Member { + return s.Disgo.Cache().Member(s.GuildID, s.UserID) +} + +// User returns the User of this VoiceState from the Cache +func (s VoiceState) User() *User { + return s.Disgo.Cache().User(s.UserID) +} + +// Guild returns the Guild of this VoiceState from the Cache +func (s VoiceState) Guild() *Guild { + return s.Disgo.Cache().Guild(s.GuildID) +} + +// VoiceChannel returns the VoiceChannel of this VoiceState from the Cache +func (s VoiceState) VoiceChannel() *VoiceChannel { + if s.ChannelID == nil { + return nil + } + return s.Disgo.Cache().VoiceChannel(*s.ChannelID) } diff --git a/api/webhook_server.go b/api/webhook_server.go index 6852f5f6..29ba8da1 100644 --- a/api/webhook_server.go +++ b/api/webhook_server.go @@ -9,6 +9,7 @@ import ( "net/http" "github.com/gorilla/mux" + log "github.com/sirupsen/logrus" ) // WebhookServer is used for receiving an Interaction over http @@ -48,7 +49,12 @@ func Verify(r *http.Request, key ed25519.PublicKey) bool { msg.WriteString(timestamp) - defer r.Body.Close() + defer func() { + err = r.Body.Close() + if err != nil { + log.Errorf("error while closing request body: %s", err) + } + }() var body bytes.Buffer defer func() { diff --git a/internal/cache.go b/internal/cache_impl.go similarity index 93% rename from internal/cache.go rename to internal/cache_impl.go index 5f6aa8e6..32209209 100644 --- a/internal/cache.go +++ b/internal/cache_impl.go @@ -20,6 +20,7 @@ func newCacheImpl(disgo api.Disgo, memberCachePolicy api.MemberCachePolicy, mess users: map[api.Snowflake]*api.User{}, guilds: map[api.Snowflake]*api.Guild{}, members: map[api.Snowflake]map[api.Snowflake]*api.Member{}, + voiceStates: map[api.Snowflake]map[api.Snowflake]*api.VoiceState{}, roles: map[api.Snowflake]map[api.Snowflake]*api.Role{}, dmChannels: map[api.Snowflake]*api.DMChannel{}, categories: map[api.Snowflake]map[api.Snowflake]*api.Category{}, @@ -41,6 +42,7 @@ type CacheImpl struct { users map[api.Snowflake]*api.User guilds map[api.Snowflake]*api.Guild members map[api.Snowflake]map[api.Snowflake]*api.Member + voiceStates map[api.Snowflake]map[api.Snowflake]*api.VoiceState roles map[api.Snowflake]map[api.Snowflake]*api.Role dmChannels map[api.Snowflake]*api.DMChannel categories map[api.Snowflake]map[api.Snowflake]*api.Category @@ -49,6 +51,11 @@ type CacheImpl struct { storeChannels map[api.Snowflake]map[api.Snowflake]*api.StoreChannel } +// Disgo returns the current api.Disgo instance +func (c *CacheImpl) Disgo() api.Disgo { + return c.disgo +} + // Close cleans up the cache and it's internal tasks func (c *CacheImpl) Close() { log.Info("closing cache goroutines...") @@ -367,6 +374,53 @@ func (c *CacheImpl) FindMembers(guildID api.Snowflake, check func(u *api.Member) return members } +// VoiceState returns a Member's api.VoiceState for a api.Guild +func (c *CacheImpl) VoiceState(guildID api.Snowflake, userID api.Snowflake) *api.VoiceState { + if voiceStates, ok := c.voiceStates[guildID]; ok { + return voiceStates[userID] + } + return nil +} + +// VoiceStates returns the member cache of a guild by snowflake +func (c *CacheImpl) VoiceStates(guildID api.Snowflake) []*api.VoiceState { + if guildVoiceStates, ok := c.voiceStates[guildID]; ok { + voiceStates := make([]*api.VoiceState, len(guildVoiceStates)) + i := 0 + for _, voiceState := range guildVoiceStates { + voiceStates[i] = voiceState + i++ + } + return voiceStates + } + return nil +} + +// VoiceStateCache returns the api.VoiceState api.Cache of a api.Guild as a map +func (c *CacheImpl) VoiceStateCache(guildID api.Snowflake) map[api.Snowflake]*api.VoiceState { + return c.voiceStates[guildID] +} + +// CacheVoiceState adds a api.VoiceState from the api.Cache +func (c *CacheImpl) CacheVoiceState(voiceState *api.VoiceState) { + // only cache voice states for ourself or member is cached & cache flag activated + if voiceState.UserID != c.disgo.SelfUserID() && (!c.cacheFlags.Has(api.CacheFlagVoiceState) || c.Member(voiceState.GuildID, voiceState.UserID) == nil) { + return + } + if voiceStates, ok := c.voiceStates[voiceState.GuildID]; ok { + if _, ok = voiceStates[voiceState.UserID]; ok { + *voiceStates[voiceState.UserID] = *voiceState + return + } + voiceStates[voiceState.UserID] = voiceState + } +} + +// UncacheVoiceState removes a api.VoiceState from the api.Cache +func (c *CacheImpl) UncacheVoiceState(guildID api.Snowflake, userID api.Snowflake) { + delete(c.voiceStates[guildID], userID) +} + // Role returns a role from cache by guild ID and role ID func (c *CacheImpl) Role(guildID api.Snowflake, roleID api.Snowflake) *api.Role { if guildRoles, ok := c.roles[guildID]; ok { diff --git a/internal/disgo_builder.go b/internal/disgo_builder_impl.go similarity index 58% rename from internal/disgo_builder.go rename to internal/disgo_builder_impl.go index a49f2480..977cc244 100644 --- a/internal/disgo_builder.go +++ b/internal/disgo_builder_impl.go @@ -10,7 +10,7 @@ import ( // NewBuilder returns a new api.DisgoBuilder instance func NewBuilder(token string) api.DisgoBuilder { - return DisgoBuilderImpl{ + return &DisgoBuilderImpl{ logLevel: log.InfoLevel, token: &token, cacheFlags: api.CacheFlagsDefault, @@ -19,63 +19,70 @@ func NewBuilder(token string) api.DisgoBuilder { // DisgoBuilderImpl implementation of the api.DisgoBuilder interface type DisgoBuilderImpl struct { - logLevel log.Level - token *string - gateway api.Gateway - restClient api.RestClient - cache api.Cache - memberCachePolicy api.MemberCachePolicy - messageCachePolicy api.MessageCachePolicy - cacheFlags api.CacheFlags - intents api.Intents - eventManager api.EventManager - webhookServer api.WebhookServer - listenURL *string - listenPort *int - publicKey *string - eventListeners []api.EventListener + logLevel log.Level + token *string + gateway api.Gateway + restClient api.RestClient + cache api.Cache + memberCachePolicy api.MemberCachePolicy + messageCachePolicy api.MessageCachePolicy + cacheFlags api.CacheFlags + intents api.Intents + eventManager api.EventManager + voiceDispatchInterceptor api.VoiceDispatchInterceptor + webhookServer api.WebhookServer + listenURL *string + listenPort *int + publicKey *string + eventListeners []api.EventListener } // SetLogLevel sets logrus.Level of logrus -func (b DisgoBuilderImpl) SetLogLevel(logLevel log.Level) api.DisgoBuilder { +func (b *DisgoBuilderImpl) SetLogLevel(logLevel log.Level) api.DisgoBuilder { b.logLevel = logLevel return b } // SetToken sets the token to connect to discord -func (b DisgoBuilderImpl) SetToken(token string) api.DisgoBuilder { +func (b *DisgoBuilderImpl) SetToken(token string) api.DisgoBuilder { b.token = &token return b } // SetIntents sets the api.Intents to connect to discord -func (b DisgoBuilderImpl) SetIntents(intents api.Intents) api.DisgoBuilder { +func (b *DisgoBuilderImpl) SetIntents(intents api.Intents) api.DisgoBuilder { b.intents = intents return b } // SetEventManager lets you inject your own api.EventManager -func (b DisgoBuilderImpl) SetEventManager(eventManager api.EventManager) api.DisgoBuilder { +func (b *DisgoBuilderImpl) SetEventManager(eventManager api.EventManager) api.DisgoBuilder { b.eventManager = eventManager return b } // AddEventListeners lets you add an api.EventListener to your api.EventManager -func (b DisgoBuilderImpl) AddEventListeners(eventListeners ...api.EventListener) api.DisgoBuilder { +func (b *DisgoBuilderImpl) AddEventListeners(eventListeners ...api.EventListener) api.DisgoBuilder { for _, eventListener := range eventListeners { b.eventListeners = append(b.eventListeners, eventListener) } return b } +// SetVoiceDispatchInterceptor sets the api.VoiceDispatchInterceptor +func (b *DisgoBuilderImpl) SetVoiceDispatchInterceptor(voiceDispatchInterceptor api.VoiceDispatchInterceptor) api.DisgoBuilder { + b.voiceDispatchInterceptor = voiceDispatchInterceptor + return b +} + // SetWebhookServer lets you inject your own api.EventManager -func (b DisgoBuilderImpl) SetWebhookServer(webhookServer api.WebhookServer) api.DisgoBuilder { +func (b *DisgoBuilderImpl) SetWebhookServer(webhookServer api.WebhookServer) api.DisgoBuilder { b.webhookServer = webhookServer return b } // SetWebhookServerProperties sets the default api.WebhookServer properties -func (b DisgoBuilderImpl) SetWebhookServerProperties(listenURL string, listenPort int, publicKey string) api.DisgoBuilder { +func (b *DisgoBuilderImpl) SetWebhookServerProperties(listenURL string, listenPort int, publicKey string) api.DisgoBuilder { b.listenURL = &listenURL b.listenPort = &listenPort b.publicKey = &publicKey @@ -83,55 +90,55 @@ func (b DisgoBuilderImpl) SetWebhookServerProperties(listenURL string, listenPor } // SetRestClient lets you inject your own api.RestClient -func (b DisgoBuilderImpl) SetRestClient(restClient api.RestClient) api.DisgoBuilder { +func (b *DisgoBuilderImpl) SetRestClient(restClient api.RestClient) api.DisgoBuilder { b.restClient = restClient return b } // SetCache lets you inject your own api.Cache -func (b DisgoBuilderImpl) SetCache(cache api.Cache) api.DisgoBuilder { +func (b *DisgoBuilderImpl) SetCache(cache api.Cache) api.DisgoBuilder { b.cache = cache return b } // SetMemberCachePolicy lets you set your own api.MemberCachePolicy -func (b DisgoBuilderImpl) SetMemberCachePolicy(memberCachePolicy api.MemberCachePolicy) api.DisgoBuilder { +func (b *DisgoBuilderImpl) SetMemberCachePolicy(memberCachePolicy api.MemberCachePolicy) api.DisgoBuilder { b.memberCachePolicy = memberCachePolicy return b } // SetMessageCachePolicy lets you set your own api.MessageCachePolicy -func (b DisgoBuilderImpl) SetMessageCachePolicy(messageCachePolicy api.MessageCachePolicy) api.DisgoBuilder { +func (b *DisgoBuilderImpl) SetMessageCachePolicy(messageCachePolicy api.MessageCachePolicy) api.DisgoBuilder { b.messageCachePolicy = messageCachePolicy return b } // SetCacheFlags lets you set the api.CacheFlags -func (b DisgoBuilderImpl) SetCacheFlags(cacheFlags api.CacheFlags) api.DisgoBuilder { +func (b *DisgoBuilderImpl) SetCacheFlags(cacheFlags api.CacheFlags) api.DisgoBuilder { b.cacheFlags = cacheFlags return b } // EnableCacheFlags lets you enable certain api.CacheFlags -func (b DisgoBuilderImpl) EnableCacheFlags(cacheFlags api.CacheFlags) api.DisgoBuilder { +func (b *DisgoBuilderImpl) EnableCacheFlags(cacheFlags api.CacheFlags) api.DisgoBuilder { b.cacheFlags.Add(cacheFlags) return b } // DisableCacheFlags lets you disable certain api.CacheFlags -func (b DisgoBuilderImpl) DisableCacheFlags(cacheFlags api.CacheFlags) api.DisgoBuilder { +func (b *DisgoBuilderImpl) DisableCacheFlags(cacheFlags api.CacheFlags) api.DisgoBuilder { b.cacheFlags.Remove(cacheFlags) return b } // SetGateway lets you inject your own api.Gateway -func (b DisgoBuilderImpl) SetGateway(gateway api.Gateway) api.DisgoBuilder { +func (b *DisgoBuilderImpl) SetGateway(gateway api.Gateway) api.DisgoBuilder { b.gateway = gateway return b } // Build builds your api.Disgo instance -func (b DisgoBuilderImpl) Build() (api.Disgo, error) { +func (b *DisgoBuilderImpl) Build() (api.Disgo, error) { log.SetLevel(b.logLevel) disgo := &DisgoImpl{} @@ -146,7 +153,7 @@ func (b DisgoBuilderImpl) Build() (api.Disgo, error) { return nil, err } - disgo.applicationID = *id + disgo.selfUserID = *id if b.gateway == nil { b.gateway = newGatewayImpl(disgo) @@ -165,6 +172,8 @@ func (b DisgoBuilderImpl) Build() (api.Disgo, error) { } disgo.eventManager = b.eventManager + disgo.voiceDispatchInterceptor = b.voiceDispatchInterceptor + if b.webhookServer == nil && b.listenURL != nil && b.listenPort != nil && b.publicKey != nil { b.webhookServer = newWebhookServerImpl(disgo, *b.listenURL, *b.listenPort, *b.publicKey) } diff --git a/internal/disgo.go b/internal/disgo_impl.go similarity index 83% rename from internal/disgo.go rename to internal/disgo_impl.go index 961a526a..98505924 100644 --- a/internal/disgo.go +++ b/internal/disgo_impl.go @@ -38,14 +38,15 @@ func New(token string, options api.Options) (api.Disgo, error) { // DisgoImpl is the main discord client type DisgoImpl struct { - token string - gateway api.Gateway - restClient api.RestClient - intents api.Intents - eventManager api.EventManager - webhookServer api.WebhookServer - cache api.Cache - selfUserID api.Snowflake + token string + gateway api.Gateway + restClient api.RestClient + intents api.Intents + eventManager api.EventManager + voiceDispatchInterceptor api.VoiceDispatchInterceptor + webhookServer api.WebhookServer + cache api.Cache + selfUserID api.Snowflake } // Connect opens the gateway connection to discord @@ -95,6 +96,16 @@ func (d *DisgoImpl) EventManager() api.EventManager { return d.eventManager } +// VoiceDispatchInterceptor returns the api.VoiceDispatchInterceptor +func (d *DisgoImpl) VoiceDispatchInterceptor() api.VoiceDispatchInterceptor { + return d.voiceDispatchInterceptor +} + +// SetVoiceDispatchInterceptor sets the api.VoiceDispatchInterceptor +func (d *DisgoImpl) SetVoiceDispatchInterceptor(voiceDispatchInterceptor api.VoiceDispatchInterceptor) { + d.voiceDispatchInterceptor = voiceDispatchInterceptor +} + // WebhookServer returns the api.EventManager func (d *DisgoImpl) WebhookServer() api.WebhookServer { return d.webhookServer diff --git a/internal/event_manager.go b/internal/event_manager_impl.go similarity index 82% rename from internal/event_manager.go rename to internal/event_manager_impl.go index 0e9bcd5f..85414b97 100644 --- a/internal/event_manager.go +++ b/internal/event_manager_impl.go @@ -13,12 +13,12 @@ import ( func newEventManagerImpl(disgo api.Disgo, listeners []api.EventListener) api.EventManager { eventManager := &EventManagerImpl{ disgo: disgo, - channel: make(chan api.GenericEvent), + channel: make(chan api.Event), listeners: listeners, - handlers: map[string]api.EventHandler{}, + handlers: map[api.GatewayEvent]api.EventHandler{}, } for _, handler := range handlers.GetAllHandlers() { - eventManager.handlers[handler.Name()] = handler + eventManager.handlers[handler.Event()] = handler } go eventManager.ListenEvents() return eventManager @@ -28,12 +28,12 @@ func newEventManagerImpl(disgo api.Disgo, listeners []api.EventListener) api.Eve type EventManagerImpl struct { disgo api.Disgo listeners []api.EventListener - handlers map[string]api.EventHandler - channel chan api.GenericEvent + handlers map[api.GatewayEvent]api.EventHandler + channel chan api.Event } // Handle calls the correct api.EventHandler -func (e EventManagerImpl) Handle(name string, payload json.RawMessage, c chan interface{}) { +func (e EventManagerImpl) Handle(name api.GatewayEvent, payload json.RawMessage, c chan interface{}) { if handler, ok := e.handlers[name]; ok { eventPayload := handler.New() if err := json.Unmarshal(payload, &eventPayload); err != nil { @@ -49,7 +49,7 @@ func (e EventManagerImpl) Handle(name string, payload json.RawMessage, c chan in } // Dispatch dispatches a new event to the client -func (e EventManagerImpl) Dispatch(event api.GenericEvent) { +func (e EventManagerImpl) Dispatch(event api.Event) { e.channel <- event } diff --git a/internal/gateway.go b/internal/gateway_impl.go similarity index 99% rename from internal/gateway.go rename to internal/gateway_impl.go index 82505f94..5fea373c 100644 --- a/internal/gateway.go +++ b/internal/gateway_impl.go @@ -215,7 +215,7 @@ func (g *GatewayImpl) listen() { log.Debugf("received: %s", *event.T) - if event.T != nil && *event.T == api.ReadyGatewayEvent { + if event.T != nil && *event.T == api.GatewayEventReady { var readyEvent api.ReadyEventData if err := parseEventToStruct(event, &readyEvent); err != nil { log.Errorf("Error parsing ready event: %s", err) diff --git a/internal/handlers/all_handlers.go b/internal/handlers/all_handlers.go index e6a71d6d..cd62ee26 100644 --- a/internal/handlers/all_handlers.go +++ b/internal/handlers/all_handlers.go @@ -9,6 +9,9 @@ func GetAllHandlers() []api.EventHandler { return []api.EventHandler{ ReadyHandler{}, + VoiceServerUpdateHandler{}, + VoiceStateUpdateHandler{}, + GuildCreateHandler{}, GuildUpdateHandler{}, GuildDeleteHandler{}, diff --git a/internal/handlers/guild_create_handler.go b/internal/handlers/guild_create_handler.go index defa9fdc..e351c85e 100644 --- a/internal/handlers/guild_create_handler.go +++ b/internal/handlers/guild_create_handler.go @@ -8,9 +8,9 @@ import ( // GuildCreateHandler handles api.GuildCreateGatewayEvent type GuildCreateHandler struct{} -// Name returns the raw gateway event name -func (h GuildCreateHandler) Name() string { - return api.GuildCreateGatewayEvent +// Event returns the raw gateway event Event +func (h GuildCreateHandler) Event() api.GatewayEvent { + return api.GatewayEventGuildCreate } // New constructs a new payload receiver for the raw gateway event @@ -69,10 +69,8 @@ func (h GuildCreateHandler) Handle(disgo api.Disgo, eventManager api.EventManage } genericGuildEvent := events.GenericGuildEvent{ - Event: api.Event{ - Disgo: disgo, - }, - GuildID: guild.ID, + GenericEvent: api.NewEvent(disgo), + GuildID: guild.ID, } eventManager.Dispatch(genericGuildEvent) diff --git a/internal/handlers/guild_delete_handler.go b/internal/handlers/guild_delete_handler.go index ecd97c90..36b88e4b 100644 --- a/internal/handlers/guild_delete_handler.go +++ b/internal/handlers/guild_delete_handler.go @@ -8,9 +8,9 @@ import ( // GuildDeleteHandler handles api.GuildDeleteGatewayEvent type GuildDeleteHandler struct{} -// Name returns the raw gateway event name -func (h GuildDeleteHandler) Name() string { - return api.GuildDeleteGatewayEvent +// Event returns the raw gateway event Event +func (h GuildDeleteHandler) Event() api.GatewayEvent { + return api.GatewayEventGuildDelete } // New constructs a new payload receiver for the raw gateway event @@ -29,9 +29,7 @@ func (h GuildDeleteHandler) Handle(disgo api.Disgo, eventManager api.EventManage disgo.Cache().Guild(guild.ID).Unavailable = true eventManager.Dispatch(events.GuildUnavailableEvent{ GenericGuildEvent: events.GenericGuildEvent{ - Event: api.Event{ - Disgo: disgo, - }, + GenericEvent: api.NewEvent(disgo), GuildID: guild.ID, }, }) @@ -40,9 +38,7 @@ func (h GuildDeleteHandler) Handle(disgo api.Disgo, eventManager api.EventManage disgo.Cache().UncacheGuild(guild.ID) genericGuildEvent := events.GenericGuildEvent{ - Event: api.Event{ - Disgo: disgo, - }, + GenericEvent: api.NewEvent(disgo), GuildID: guild.ID, } diff --git a/internal/handlers/guild_member_add_handler.go b/internal/handlers/guild_member_add_handler.go index b587e5a4..effc8a9b 100644 --- a/internal/handlers/guild_member_add_handler.go +++ b/internal/handlers/guild_member_add_handler.go @@ -8,9 +8,9 @@ import ( // GuildMemberAddHandler handles api.GuildMemberAddGatewayEvent type GuildMemberAddHandler struct{} -// Name returns the raw gateway event name -func (h GuildMemberAddHandler) Name() string { - return api.GuildMemberAddGatewayEvent +// Event returns the raw gateway event Event +func (h GuildMemberAddHandler) Event() api.GatewayEvent { + return api.GatewayEventGuildMemberAdd } // New constructs a new payload receiver for the raw gateway event @@ -28,10 +28,8 @@ func (h GuildMemberAddHandler) Handle(disgo api.Disgo, eventManager api.EventMan disgo.Cache().CacheMember(member) genericGuildEvent := events.GenericGuildEvent{ - Event: api.Event{ - Disgo: disgo, - }, - GuildID: member.GuildID, + GenericEvent: api.NewEvent(disgo), + GuildID: member.GuildID, } eventManager.Dispatch(genericGuildEvent) diff --git a/internal/handlers/guild_member_remove_handler.go b/internal/handlers/guild_member_remove_handler.go index dd0566ea..8815a23a 100644 --- a/internal/handlers/guild_member_remove_handler.go +++ b/internal/handlers/guild_member_remove_handler.go @@ -13,9 +13,9 @@ type guildMemberRemoveData struct { // GuildMemberRemoveHandler handles api.GuildMemberRemoveGatewayEvent type GuildMemberRemoveHandler struct{} -// Name returns the raw gateway event name -func (h GuildMemberRemoveHandler) Name() string { - return api.GuildMemberRemoveGatewayEvent +// Event returns the raw gateway event Event +func (h GuildMemberRemoveHandler) Event() api.GatewayEvent { + return api.GatewayEventGuildMemberRemove } // New constructs a new payload receiver for the raw gateway event @@ -34,10 +34,8 @@ func (h GuildMemberRemoveHandler) Handle(disgo api.Disgo, eventManager api.Event disgo.Cache().UncacheMember(member.GuildID, member.User.ID) genericGuildEvent := events.GenericGuildEvent{ - Event: api.Event{ - Disgo: disgo, - }, - GuildID: member.GuildID, + GenericEvent: api.NewEvent(disgo), + GuildID: member.GuildID, } eventManager.Dispatch(genericGuildEvent) diff --git a/internal/handlers/guild_member_update_handler.go b/internal/handlers/guild_member_update_handler.go index b5e076b0..38d4ec3d 100644 --- a/internal/handlers/guild_member_update_handler.go +++ b/internal/handlers/guild_member_update_handler.go @@ -8,9 +8,9 @@ import ( // GuildMemberUpdateHandler handles api.GuildMemberUpdateGatewayEvent type GuildMemberUpdateHandler struct{} -// Name returns the raw gateway event name -func (h GuildMemberUpdateHandler) Name() string { - return api.GuildMemberUpdateGatewayEvent +// Event returns the raw gateway event Event +func (h GuildMemberUpdateHandler) Event() api.GatewayEvent { + return api.GatewayEventGuildMemberUpdate } // New constructs a new payload receiver for the raw gateway event @@ -26,13 +26,12 @@ func (h GuildMemberUpdateHandler) Handle(disgo api.Disgo, eventManager api.Event } oldMember := disgo.Cache().Member(member.GuildID, member.User.ID) + member.Disgo = disgo disgo.Cache().CacheMember(member) genericGuildEvent := events.GenericGuildEvent{ - Event: api.Event{ - Disgo: disgo, - }, - GuildID: member.GuildID, + GenericEvent: api.NewEvent(disgo), + GuildID: member.GuildID, } eventManager.Dispatch(genericGuildEvent) diff --git a/internal/handlers/guild_role_create_handler.go b/internal/handlers/guild_role_create_handler.go index a62699ac..31491e80 100644 --- a/internal/handlers/guild_role_create_handler.go +++ b/internal/handlers/guild_role_create_handler.go @@ -13,9 +13,9 @@ type roleCreateData struct { // GuildRoleCreateHandler handles api.GuildRoleCreateGatewayEvent type GuildRoleCreateHandler struct{} -// Name returns the raw gateway event name -func (h GuildRoleCreateHandler) Name() string { - return api.GuildRoleCreateGatewayEvent +// Event returns the raw gateway event Event +func (h GuildRoleCreateHandler) Event() api.GatewayEvent { + return api.GatewayEventGuildRoleCreate } // New constructs a new payload receiver for the raw gateway event @@ -34,10 +34,8 @@ func (h GuildRoleCreateHandler) Handle(disgo api.Disgo, eventManager api.EventMa disgo.Cache().CacheRole(roleCreateData.Role) genericGuildEvent := events.GenericGuildEvent{ - Event: api.Event{ - Disgo: disgo, - }, - GuildID: roleCreateData.GuildID, + GenericEvent: api.NewEvent(disgo), + GuildID: roleCreateData.GuildID, } eventManager.Dispatch(genericGuildEvent) diff --git a/internal/handlers/guild_role_delete_handler.go b/internal/handlers/guild_role_delete_handler.go index 20d0ac55..1fb06f08 100644 --- a/internal/handlers/guild_role_delete_handler.go +++ b/internal/handlers/guild_role_delete_handler.go @@ -13,9 +13,9 @@ type roleDeleteData struct { // GuildRoleDeleteHandler handles api.GuildRoleDeleteGatewayEvent type GuildRoleDeleteHandler struct{} -// Name returns the raw gateway event name -func (h GuildRoleDeleteHandler) Name() string { - return api.GuildRoleDeleteGatewayEvent +// Event returns the raw gateway event Event +func (h GuildRoleDeleteHandler) Event() api.GatewayEvent { + return api.GatewayEventGuildRoleDelete } // New constructs a new payload receiver for the raw gateway event @@ -34,10 +34,8 @@ func (h GuildRoleDeleteHandler) Handle(disgo api.Disgo, eventManager api.EventMa disgo.Cache().UncacheRole(roleDeleteData.GuildID, roleDeleteData.RoleID) genericGuildEvent := events.GenericGuildEvent{ - Event: api.Event{ - Disgo: disgo, - }, - GuildID: roleDeleteData.GuildID, + GenericEvent: api.NewEvent(disgo), + GuildID: roleDeleteData.GuildID, } eventManager.Dispatch(genericGuildEvent) diff --git a/internal/handlers/guild_role_update_handler.go b/internal/handlers/guild_role_update_handler.go index de9cb6df..8faf52be 100644 --- a/internal/handlers/guild_role_update_handler.go +++ b/internal/handlers/guild_role_update_handler.go @@ -13,9 +13,9 @@ type roleUpdateData struct { // GuildRoleUpdateHandler handles api.GuildRoleUpdateGatewayEvent type GuildRoleUpdateHandler struct{} -// Name returns the raw gateway event name -func (h GuildRoleUpdateHandler) Name() string { - return api.GuildRoleUpdateGatewayEvent +// Event returns the raw gateway event Event +func (h GuildRoleUpdateHandler) Event() api.GatewayEvent { + return api.GatewayEventGuildRoleUpdate } // New constructs a new payload receiver for the raw gateway event @@ -36,10 +36,8 @@ func (h GuildRoleUpdateHandler) Handle(disgo api.Disgo, eventManager api.EventMa disgo.Cache().CacheRole(roleUpdateData.Role) genericGuildEvent := events.GenericGuildEvent{ - Event: api.Event{ - Disgo: disgo, - }, - GuildID: roleUpdateData.GuildID, + GenericEvent: api.NewEvent(disgo), + GuildID: roleUpdateData.GuildID, } eventManager.Dispatch(genericGuildEvent) diff --git a/internal/handlers/guild_update_handler.go b/internal/handlers/guild_update_handler.go index 90def1e5..9f02922d 100644 --- a/internal/handlers/guild_update_handler.go +++ b/internal/handlers/guild_update_handler.go @@ -8,9 +8,9 @@ import ( // GuildUpdateHandler handles api.GuildUpdateGatewayEvent type GuildUpdateHandler struct{} -// Name returns the raw gateway event name -func (h GuildUpdateHandler) Name() string { - return api.GuildUpdateGatewayEvent +// Event returns the raw gateway event Event +func (h GuildUpdateHandler) Event() api.GatewayEvent { + return api.GatewayEventGuildUpdate } // New constructs a new payload receiver for the raw gateway event @@ -29,10 +29,8 @@ func (h GuildUpdateHandler) Handle(disgo api.Disgo, eventManager api.EventManage disgo.Cache().CacheGuild(guild) genericGuildEvent := events.GenericGuildEvent{ - Event: api.Event{ - Disgo: disgo, - }, - GuildID: guild.ID, + GenericEvent: api.NewEvent(disgo), + GuildID: guild.ID, } eventManager.Dispatch(genericGuildEvent) diff --git a/internal/handlers/interaction_create_handler.go b/internal/handlers/interaction_create_handler.go index 82072329..403b1d2a 100644 --- a/internal/handlers/interaction_create_handler.go +++ b/internal/handlers/interaction_create_handler.go @@ -8,9 +8,9 @@ import ( // InteractionCreateHandler handles api.InteractionCreateGatewayEvent type InteractionCreateHandler struct{} -// Name returns the raw gateway event name -func (h InteractionCreateHandler) Name() string { - return api.InteractionCreateGatewayEvent +// Event returns the raw gateway event Event +func (h InteractionCreateHandler) Event() api.GatewayEvent { + return api.GatewayEventInteractionCreate } // New constructs a new payload receiver for the raw gateway event @@ -24,14 +24,19 @@ func (h InteractionCreateHandler) Handle(disgo api.Disgo, eventManager api.Event if !ok { return } - handleInteractions(disgo, eventManager, nil, interaction) + handleInteraction(disgo, eventManager, nil, interaction) } -func handleInteractions(disgo api.Disgo, eventManager api.EventManager, c chan interface{}, interaction *api.Interaction) { +func handleInteraction(disgo api.Disgo, eventManager api.EventManager, c chan interface{}, interaction *api.Interaction) { if interaction.Member != nil { + interaction.Member.Disgo = disgo + if interaction.Member.User != nil { + interaction.Member.User.Disgo = disgo + } disgo.Cache().CacheMember(interaction.Member) } if interaction.User != nil { + interaction.User.Disgo = disgo disgo.Cache().CacheUser(interaction.User) } @@ -39,44 +44,46 @@ func handleInteractions(disgo api.Disgo, eventManager api.EventManager, c chan i resolved := interaction.Data.Resolved if resolved.Users != nil { for _, user := range resolved.Users { + user.Disgo = disgo disgo.Cache().CacheUser(user) } } if resolved.Members != nil { for id, member := range resolved.Members { member.User = resolved.Users[id] + member.Disgo = disgo disgo.Cache().CacheMember(member) } } if resolved.Roles != nil { for _, role := range resolved.Roles { + role.Disgo = disgo disgo.Cache().CacheRole(role) } } // TODO how do we cache partial channels? /*if resolved.Channels != nil { - for _, user := range resolved.Users { - disgo.Cache().CacheChannel(user) + for _, channel := range resolved.Channels { + channel.Disgo = disgo + disgo.Cache().CacheChannel(channel) } }*/ } genericInteractionEvent := events.GenericInteractionEvent{ - Event: api.Event{ - Disgo: disgo, - }, - Interaction: *interaction, + GenericEvent: api.NewEvent(disgo), + Interaction: *interaction, } eventManager.Dispatch(genericInteractionEvent) if interaction.Data != nil { options := interaction.Data.Options var subCommandName *string - var subCommandGroup *string + var subCommandGroupName *string if len(options) == 1 { option := interaction.Data.Options[0] if option.Type == api.OptionTypeSubCommandGroup { - subCommandGroup = &option.Name + subCommandGroupName = &option.Name options = option.Options option = option.Options[0] } @@ -100,9 +107,9 @@ func handleInteractions(disgo api.Disgo, eventManager api.EventManager, c chan i FromWebhook: c != nil, GenericInteractionEvent: genericInteractionEvent, CommandID: interaction.Data.ID, - Name: interaction.Data.Name, + CommandName: interaction.Data.Name, SubCommandName: subCommandName, - SubCommandGroup: subCommandGroup, + SubCommandGroupName: subCommandGroupName, Options: newOptions, Replied: false, }) diff --git a/internal/handlers/interaction_create_webhook_handler.go b/internal/handlers/interaction_create_webhook_handler.go index 35252071..da70cfe8 100644 --- a/internal/handlers/interaction_create_webhook_handler.go +++ b/internal/handlers/interaction_create_webhook_handler.go @@ -7,9 +7,9 @@ import ( // InteractionCreateWebhookHandler handles api.InteractionCreateWebhookEvent type InteractionCreateWebhookHandler struct{} -// Name returns the raw gateway event name -func (h InteractionCreateWebhookHandler) Name() string { - return api.InteractionCreateWebhookEvent +// Event returns the raw gateway event Event +func (h InteractionCreateWebhookHandler) Event() api.GatewayEvent { + return api.WebhookEventInteractionCreate } // New constructs a new payload receiver for the raw gateway event @@ -30,5 +30,5 @@ func (h InteractionCreateWebhookHandler) Handle(disgo api.Disgo, eventManager ap } return } - handleInteractions(disgo, eventManager, c, interaction) + handleInteraction(disgo, eventManager, c, interaction) } diff --git a/internal/handlers/message_create_handler.go b/internal/handlers/message_create_handler.go index b6d32590..ba1de01e 100644 --- a/internal/handlers/message_create_handler.go +++ b/internal/handlers/message_create_handler.go @@ -8,9 +8,9 @@ import ( // MessageCreateHandler handles api.MessageCreateGatewayEvent type MessageCreateHandler struct{} -// Name returns the raw gateway event name -func (h MessageCreateHandler) Name() string { - return api.MessageCreateGatewayEvent +// Event returns the raw gateway event Event +func (h MessageCreateHandler) Event() api.GatewayEvent { + return api.GatewayEventMessageCreate } // New constructs a new payload receiver for the raw gateway event @@ -26,19 +26,15 @@ func (h MessageCreateHandler) Handle(disgo api.Disgo, eventManager api.EventMana } genericMessageEvent := events.GenericMessageEvent{ - Event: api.Event{ - Disgo: disgo, - }, + GenericEvent: api.NewEvent(disgo), MessageChannelID: message.ChannelID, MessageID: message.ID, } eventManager.Dispatch(genericMessageEvent) genericGuildEvent := events.GenericGuildEvent{ - Event: api.Event{ - Disgo: disgo, - }, - GuildID: *message.GuildID, + GenericEvent: api.NewEvent(disgo), + GuildID: *message.GuildID, } eventManager.Dispatch(genericGuildEvent) @@ -56,7 +52,6 @@ func (h MessageCreateHandler) Handle(disgo api.Disgo, eventManager api.EventMana eventManager.Dispatch(events.GuildMessageReceivedEvent{ Message: *message, GenericGuildMessageEvent: events.GenericGuildMessageEvent{ - GenericGuildEvent: genericGuildEvent, GenericMessageEvent: genericMessageEvent, }, }) diff --git a/internal/handlers/ready_handler.go b/internal/handlers/ready_handler.go index 73531cce..e012eae2 100644 --- a/internal/handlers/ready_handler.go +++ b/internal/handlers/ready_handler.go @@ -16,9 +16,9 @@ type readyEventData struct { // ReadyHandler handles api.ReadyGatewayEvent type ReadyHandler struct{} -// Name returns the raw gateway event name -func (h ReadyHandler) Name() string { - return api.ReadyGatewayEvent +// Event returns the raw gateway event Event +func (h ReadyHandler) Event() api.GatewayEvent { + return api.GatewayEventReady } // New constructs a new payload receiver for the raw gateway event diff --git a/internal/handlers/voice_server_update_handler.go b/internal/handlers/voice_server_update_handler.go new file mode 100644 index 00000000..5b4d3242 --- /dev/null +++ b/internal/handlers/voice_server_update_handler.go @@ -0,0 +1,34 @@ +package handlers + +import "github.com/DisgoOrg/disgo/api" + +// InteractionCreateHandler handles api.VoiceServerUpdateGatewayEvent +type VoiceServerUpdateHandler struct{} + +// Event returns the raw gateway event Event +func (h VoiceServerUpdateHandler) Event() api.GatewayEvent { + return api.GatewayEventVoiceServerUpdate +} + +// New constructs a new payload receiver for the raw gateway event +func (h VoiceServerUpdateHandler) New() interface{} { + return &api.VoiceServerUpdate{} +} + +// Handle handles the specific raw gateway event +func (h VoiceServerUpdateHandler) Handle(disgo api.Disgo, eventManager api.EventManager, i interface{}) { + voiceServerUpdate, ok := i.(*api.VoiceServerUpdate) + if !ok { + return + } + + if voiceServerUpdate.Endpoint == nil { + return + } + + voiceServerUpdate.Disgo = disgo + + if interceptor := disgo.VoiceDispatchInterceptor(); interceptor != nil { + interceptor.OnVoiceServerUpdate(*voiceServerUpdate) + } +} diff --git a/internal/handlers/voice_state_update_handler.go b/internal/handlers/voice_state_update_handler.go new file mode 100644 index 00000000..ab919424 --- /dev/null +++ b/internal/handlers/voice_state_update_handler.go @@ -0,0 +1,43 @@ +package handlers + +import ( + "github.com/DisgoOrg/disgo/api" +) + +// VoiceStateUpdateHandler handles api.VoiceStateUpdateGatewayEvent +type VoiceStateUpdateHandler struct{} + +// Event returns the raw gateway event Event +func (h VoiceStateUpdateHandler) Event() api.GatewayEvent { + return api.GatewayEventVoiceStateUpdate +} + +// New constructs a new payload receiver for the raw gateway event +func (h VoiceStateUpdateHandler) New() interface{} { + return &api.VoiceStateUpdate{} +} + +// Handle handles the specific raw gateway event +func (h VoiceStateUpdateHandler) Handle(disgo api.Disgo, eventManager api.EventManager, i interface{}) { + voiceStateUpdate, ok := i.(*api.VoiceStateUpdate) + if !ok { + return + } + + voiceStateUpdate.Disgo = disgo + + //guild := disgo.Cache().Guild(voiceStateUpdate.GuildID) + + //oldMember := disgo.Cache().Member(voiceStateUpdate.GuildID, voiceStateUpdate.UserID) + //newMember := voiceStateUpdate.Member + + // TODO update voice state cache + // TODO fire several events + + if disgo.SelfUserID() == voiceStateUpdate.UserID { + if interceptor := disgo.VoiceDispatchInterceptor(); interceptor != nil { + interceptor.OnVoiceStateUpdate(*voiceStateUpdate) + } + } + +} diff --git a/internal/restclient.go b/internal/restclient_impl.go similarity index 99% rename from internal/restclient.go rename to internal/restclient_impl.go index 676d5f54..b7005de9 100644 --- a/internal/restclient.go +++ b/internal/restclient_impl.go @@ -152,7 +152,7 @@ func (r RestClientImpl) DeleteMessage(channelID api.Snowflake, messageID api.Sno } // BulkDeleteMessages lets you bulk delete api.Message(s) -func (r RestClientImpl) BulkDeleteMessages(channelID api.Snowflake, messageIDs... api.Snowflake) error { +func (r RestClientImpl) BulkDeleteMessages(channelID api.Snowflake, messageIDs ...api.Snowflake) error { return r.Request(endpoints.BulkDeleteMessage.Compile(channelID), api.MessageBulkDelete{Messages: messageIDs}, nil) } diff --git a/internal/webhook_server.go b/internal/webhook_server_impl.go similarity index 96% rename from internal/webhook_server.go rename to internal/webhook_server_impl.go index 637b0ad3..736bc26e 100644 --- a/internal/webhook_server.go +++ b/internal/webhook_server_impl.go @@ -90,7 +90,7 @@ func (h *webhookInteractionHandler) ServeHTTP(w http.ResponseWriter, r *http.Req w.WriteHeader(http.StatusBadRequest) } c := make(chan interface{}) - go h.webhookServer.Disgo().EventManager().Handle(api.InteractionCreateWebhookEvent, rawBody, c) + go h.webhookServer.Disgo().EventManager().Handle(api.WebhookEventInteractionCreate, rawBody, c) w.WriteHeader(http.StatusOK) w.Header().Set("Content-Type", "application/json") diff --git a/testbot/testbot.go b/testbot/testbot.go index 7e1823d3..bd9382f9 100644 --- a/testbot/testbot.go +++ b/testbot/testbot.go @@ -19,7 +19,7 @@ func main() { dgo, err := disgo.NewBuilder(token). SetLogLevel(log.InfoLevel). - SetIntents(api.IntentsGuilds|api.IntentsGuildMessages|api.IntentsGuildMembers). + SetIntents(api.IntentsGuilds | api.IntentsGuildMessages | api.IntentsGuildMembers). SetMemberCachePolicy(api.MemberCachePolicyAll). AddEventListeners(&events.ListenerAdapter{ OnGuildAvailable: guildAvailListener, @@ -129,7 +129,7 @@ func slashCommandListener(event *events.SlashCommandEvent) { case "addrole": user := event.OptionByName("member").User() role := event.OptionByName("role").Role() - err := event.Disgo.RestClient().AddMemberRole(*event.Interaction.GuildID, user.ID, role.ID) + err := event.Disgo().RestClient().AddMemberRole(*event.Interaction.GuildID, user.ID, role.ID) if err == nil { _ = event.Reply(api.NewInteractionResponseBuilder().AddEmbeds( api.NewEmbedBuilder().SetColor(65280).SetDescriptionf("Added %s to %s", role, user).Build(), @@ -142,7 +142,7 @@ func slashCommandListener(event *events.SlashCommandEvent) { case "removerole": user := event.OptionByName("member").User() role := event.OptionByName("role").Role() - err := event.Disgo.RestClient().RemoveMemberRole(*event.Interaction.GuildID, user.ID, role.ID) + err := event.Disgo().RestClient().RemoveMemberRole(*event.Interaction.GuildID, user.ID, role.ID) if err == nil { _ = event.Reply(api.NewInteractionResponseBuilder().AddEmbeds( api.NewEmbedBuilder().SetColor(65280).SetDescriptionf("Removed %s from %s", role, user).Build(), From b02b92b8993f9fda7bf1a78e14a7d94a67152d21 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Tue, 6 Apr 2021 13:33:37 +0200 Subject: [PATCH 19/65] added missing docu & missing cache on GUILD_CREATE --- api/cache_flags.go | 2 + api/gateway.go | 1 + api/guild.go | 17 +++++--- api/voice_state.go | 2 + internal/cache_impl.go | 1 + internal/handlers/guild_create_handler.go | 41 ++++++++++++++++--- .../handlers/voice_server_update_handler.go | 2 +- 7 files changed, 53 insertions(+), 13 deletions(-) diff --git a/api/cache_flags.go b/api/cache_flags.go index 8c9402e2..7157fcad 100644 --- a/api/cache_flags.go +++ b/api/cache_flags.go @@ -1,7 +1,9 @@ package api +// CacheFlags are used to enable/disable certain internal caches type CacheFlags int +// values for CacheFlags const ( CacheFlagDMChannels CacheFlags = 0 << iota CacheFlagCategories diff --git a/api/gateway.go b/api/gateway.go index 318477db..30429321 100644 --- a/api/gateway.go +++ b/api/gateway.go @@ -46,6 +46,7 @@ const ( OpHeartbeatACK ) +// GatewayEvent wraps all GatewayEvent types type GatewayEvent string // Constants for the gateway events diff --git a/api/guild.go b/api/guild.go index ab304baa..ed3a07ca 100644 --- a/api/guild.go +++ b/api/guild.go @@ -89,6 +89,17 @@ const ( GuildFeaturePreviewEnabled GuildFeature = "PREVIEW_ENABLED" ) +// FullGuild represents a Guild objects sent by discord with the GatewayEventGuildCreate +type FullGuild struct { + *Guild + Roles []*Role `json:"roles"` + Emotes []*Emote `json:"emojis"` + Members []*Member `json:"members"` + Channels []*GuildChannel `json:"channels"` + VoiceStates []*VoiceState `json:"voice_states"` + //Presences []*Presence `json:"presences"` +} + // Guild represents a discord guild_events type Guild struct { Disgo Disgo @@ -106,13 +117,8 @@ type Guild struct { VerificationLevel VerificationLevel `json:"verification_level"` Large *bool `json:"large"` DefaultMessageNotifications MessageNotifications `json:"default_message_notifications"` - Roles []*Role `json:"roles"` - Emojis []*Emote `json:"emojis"` - Members []*Member `json:"members"` MaxPresences *int `json:"max_presences"` MaxMembers *int `json:"max_members"` - Channels []*GuildChannel `json:"channels"` - VoiceStates []*VoiceState `json:"voice_states"` Unavailable bool `json:"unavailable"` ExplicitContentFilter ExplicitContentFilterLevel `json:"explicit_content_filter"` Features []GuildFeature `json:"features"` @@ -133,7 +139,6 @@ type Guild struct { MaxVideoChannelUsers *int `json:"max_video_channel_users"` ApproximateMemberCount *int `json:"approximate_member_count"` ApproximatePresenceCount *int `json:"approximate_presence_count"` - //Presences []*Presence `json:"presences"` } // CreateRole allows you to create a new Role diff --git a/api/voice_state.go b/api/voice_state.go index 9d7ca3a8..07d43c65 100644 --- a/api/voice_state.go +++ b/api/voice_state.go @@ -16,10 +16,12 @@ type VoiceState struct { Suppressed bool `json:"suppress"` } +// Muted returns if the Member is muted func (s VoiceState) Muted() bool { return s.GuildMuted || s.SelfMuted } +// Deafened returns if the Member is deafened func (s VoiceState) Deafened() bool { return s.GuildDeafened || s.SelfDeafened } diff --git a/internal/cache_impl.go b/internal/cache_impl.go index 32209209..d09b41ac 100644 --- a/internal/cache_impl.go +++ b/internal/cache_impl.go @@ -91,6 +91,7 @@ func (c *CacheImpl) DoCleanup() { // TODO cleanup cache } +// CacheFlags returns the current active api.CacheFlags func (c CacheImpl) CacheFlags() api.CacheFlags { return c.cacheFlags } diff --git a/internal/handlers/guild_create_handler.go b/internal/handlers/guild_create_handler.go index e351c85e..2f575796 100644 --- a/internal/handlers/guild_create_handler.go +++ b/internal/handlers/guild_create_handler.go @@ -15,15 +15,18 @@ func (h GuildCreateHandler) Event() api.GatewayEvent { // New constructs a new payload receiver for the raw gateway event func (h GuildCreateHandler) New() interface{} { - return &api.Guild{} + return &api.FullGuild{} } // Handle handles the specific raw gateway event func (h GuildCreateHandler) Handle(disgo api.Disgo, eventManager api.EventManager, i interface{}) { - guild, ok := i.(*api.Guild) + fullGuild, ok := i.(*api.FullGuild) if !ok { return } + + guild := fullGuild.Guild + guild.Disgo = disgo oldGuild := disgo.Cache().Guild(guild.ID) var wasUnavailable bool @@ -34,8 +37,8 @@ func (h GuildCreateHandler) Handle(disgo api.Disgo, eventManager api.EventManage } disgo.Cache().CacheGuild(guild) - for i := range guild.Channels { - channel := guild.Channels[i] + for i := range fullGuild.Channels { + channel := fullGuild.Channels[i] channel.Disgo = disgo channel.GuildID = guild.ID switch channel.Type { @@ -61,13 +64,39 @@ func (h GuildCreateHandler) Handle(disgo api.Disgo, eventManager api.EventManage } } - for i := range guild.Roles { - role := guild.Roles[i] + for i := range fullGuild.Roles { + role := fullGuild.Roles[i] role.Disgo = disgo role.GuildID = guild.ID disgo.Cache().CacheRole(role) } + for i := range fullGuild.Members { + member := fullGuild.Members[i] + member.Disgo = disgo + member.GuildID = guild.ID + disgo.Cache().CacheMember(member) + } + + for i := range fullGuild.VoiceStates { + voiceState := fullGuild.VoiceStates[i] + voiceState.Disgo = disgo + disgo.Cache().CacheVoiceState(voiceState) + } + + /*for i := range fullGuild.Emotes { + emote := fullGuild.Emotes[i] + emote.Disgo = disgo + emote.GuildID = guild.ID + disgo.Cache().CacheEmote(emote) + }*/ + + /*for i := range fullGuild.Presences { + presence := fullGuild.Presences[i] + presence.Disgo = disgo + disgo.Cache().CachePresence(presence) + }*/ + genericGuildEvent := events.GenericGuildEvent{ GenericEvent: api.NewEvent(disgo), GuildID: guild.ID, diff --git a/internal/handlers/voice_server_update_handler.go b/internal/handlers/voice_server_update_handler.go index 5b4d3242..25857475 100644 --- a/internal/handlers/voice_server_update_handler.go +++ b/internal/handlers/voice_server_update_handler.go @@ -2,7 +2,7 @@ package handlers import "github.com/DisgoOrg/disgo/api" -// InteractionCreateHandler handles api.VoiceServerUpdateGatewayEvent +// VoiceServerUpdateHandler handles api.GatewayEventVoiceServerUpdate type VoiceServerUpdateHandler struct{} // Event returns the raw gateway event Event From 1b3e35e246745b1f1afa0a373dccb9dc1d87971d Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Tue, 6 Apr 2021 18:04:44 +0200 Subject: [PATCH 20/65] implemented reconnect, added flags to followup messages, smol reformat & fixed general issues --- api/color.go | 2 +- api/disgo.go | 8 +- api/events/interaction_events.go | 10 +- api/events/ready_events.go | 2 +- api/gateway.go | 85 +++++----- api/gateway_commands.go | 78 +++------ api/gateway_events.go | 41 +++-- api/interaction_followup.go | 21 +++ api/interaction_response.go | 8 +- api/message.go | 19 ++- api/options.go | 1 + api/webhook_server.go | 2 +- internal/disgo_impl.go | 43 +++-- internal/event_manager_impl.go | 19 ++- internal/gateway_impl.go | 150 ++++++++++++------ internal/handlers/guild_create_handler.go | 2 +- internal/handlers/guild_delete_handler.go | 6 +- internal/handlers/guild_member_add_handler.go | 2 +- .../handlers/guild_member_remove_handler.go | 2 +- .../handlers/guild_member_update_handler.go | 2 +- .../handlers/guild_role_create_handler.go | 2 +- .../handlers/guild_role_delete_handler.go | 2 +- .../handlers/guild_role_update_handler.go | 2 +- internal/handlers/guild_update_handler.go | 2 +- .../handlers/interaction_create_handler.go | 2 +- .../interaction_create_webhook_handler.go | 2 +- internal/handlers/message_create_handler.go | 2 +- internal/handlers/ready_handler.go | 2 +- .../handlers/voice_server_update_handler.go | 2 +- .../handlers/voice_state_update_handler.go | 2 +- internal/restclient_impl.go | 6 +- internal/webhook_server_impl.go | 15 +- testbot/testbot.go | 22 ++- 33 files changed, 340 insertions(+), 226 deletions(-) diff --git a/api/color.go b/api/color.go index 42a73b06..f5012239 100644 --- a/api/color.go +++ b/api/color.go @@ -1,4 +1,4 @@ package api -// Color is used for specifying colors in an Embed +// Color is used for specifying colors in an Embed / Role type Color int diff --git a/api/disgo.go b/api/disgo.go index 8dc3216c..c2717a79 100644 --- a/api/disgo.go +++ b/api/disgo.go @@ -10,7 +10,7 @@ import ( // Disgo is the main discord interface type Disgo interface { Connect() error - Start() error + Start() Close() Token() string Gateway() Gateway @@ -24,6 +24,7 @@ type Disgo interface { VoiceDispatchInterceptor() VoiceDispatchInterceptor SetVoiceDispatchInterceptor(voiceInterceptor VoiceDispatchInterceptor) HeartbeatLatency() time.Duration + LargeThreshold() int GetCommand(commandID Snowflake) (*SlashCommand, error) GetCommands() ([]*SlashCommand, error) @@ -35,7 +36,7 @@ type Disgo interface { // EventHandler provides info about the EventHandler type EventHandler interface { - Event() GatewayEvent + Event() GatewayEventName New() interface{} } @@ -58,8 +59,9 @@ type EventListener interface { // EventManager lets you listen for specific events triggered by raw gateway events type EventManager interface { + Close() AddEventListeners(...EventListener) - Handle(GatewayEvent, json.RawMessage, chan interface{}) + Handle(GatewayEventName, json.RawMessage, chan interface{}) Dispatch(Event) } diff --git a/api/events/interaction_events.go b/api/events/interaction_events.go index 73d19c4c..6b0ed71a 100644 --- a/api/events/interaction_events.go +++ b/api/events/interaction_events.go @@ -227,25 +227,25 @@ func (e *SlashCommandEvent) Reply(response api.InteractionResponse) error { // EditOriginal edits the original api.InteractionResponse func (e *SlashCommandEvent) EditOriginal(followupMessage api.FollowupMessage) (*api.Message, error) { - return e.Disgo().RestClient().EditInteractionResponse(e.Interaction.ID, e.Interaction.Token, followupMessage) + return e.Disgo().RestClient().EditInteractionResponse(e.Disgo().SelfUserID(), e.Interaction.Token, followupMessage) } // DeleteOriginal deletes the original api.InteractionResponse func (e *SlashCommandEvent) DeleteOriginal() error { - return e.Disgo().RestClient().DeleteInteractionResponse(e.Interaction.ID, e.Interaction.Token) + return e.Disgo().RestClient().DeleteInteractionResponse(e.Disgo().SelfUserID(), e.Interaction.Token) } // SendFollowup used to send a api.FollowupMessage to an api.Interaction func (e *SlashCommandEvent) SendFollowup(followupMessage api.FollowupMessage) (*api.Message, error) { - return e.Disgo().RestClient().SendFollowupMessage(e.Interaction.ID, e.Interaction.Token, followupMessage) + return e.Disgo().RestClient().SendFollowupMessage(e.Disgo().SelfUserID(), e.Interaction.Token, followupMessage) } // EditFollowup used to edit a api.FollowupMessage from an api.Interaction func (e *SlashCommandEvent) EditFollowup(messageID api.Snowflake, followupMessage api.FollowupMessage) (*api.Message, error) { - return e.Disgo().RestClient().EditFollowupMessage(e.Interaction.ID, e.Interaction.Token, messageID, followupMessage) + return e.Disgo().RestClient().EditFollowupMessage(e.Disgo().SelfUserID(), e.Interaction.Token, messageID, followupMessage) } // DeleteFollowup used to delete a api.FollowupMessage from an api.Interaction func (e *SlashCommandEvent) DeleteFollowup(messageID api.Snowflake) error { - return e.Disgo().RestClient().DeleteFollowupMessage(e.Interaction.ID, e.Interaction.Token, messageID) + return e.Disgo().RestClient().DeleteFollowupMessage(e.Disgo().SelfUserID(), e.Interaction.Token, messageID) } diff --git a/api/events/ready_events.go b/api/events/ready_events.go index 953d0812..d81fc47f 100644 --- a/api/events/ready_events.go +++ b/api/events/ready_events.go @@ -5,5 +5,5 @@ import "github.com/DisgoOrg/disgo/api" // ReadyEvent indicates we received the ReadyEvent from the api.Gateway type ReadyEvent struct { api.GenericEvent - api.ReadyEventData + api.ReadyGatewayEvent } diff --git a/api/gateway.go b/api/gateway.go index 30429321..bd95cb8e 100644 --- a/api/gateway.go +++ b/api/gateway.go @@ -8,6 +8,7 @@ type ConnectionStatus int // Indicates how far along the client is to connecting const ( Ready ConnectionStatus = iota + Unconnected Connecting Reconnecting WaitingForHello @@ -46,51 +47,51 @@ const ( OpHeartbeatACK ) -// GatewayEvent wraps all GatewayEvent types -type GatewayEvent string +// GatewayEventName wraps all GatewayEventName types +type GatewayEventName string // Constants for the gateway events const ( - GatewayEventChannelCreate GatewayEvent = "CHANNEL_CREATE" - GatewayEventChannelDelete GatewayEvent = "CHANNEL_DELETE" - GatewayEventChannelPinsUpdate GatewayEvent = "CHANNEL_PINS_UPDATE" - GatewayEventChannelUpdate GatewayEvent = "CHANNEL_UPDATE" - GatewayEventGuildBanAdd GatewayEvent = "GUILD_BAN_ADD" - GatewayEventGuildBanRemove GatewayEvent = "GUILD_BAN_REMOVE" - GatewayEventGuildCreate GatewayEvent = "GUILD_CREATE" - GatewayEventGuildDelete GatewayEvent = "GUILD_DELETE" - GatewayEventGuildEmojisUpdate GatewayEvent = "GUILD_EMOJIS_UPDATE" - GatewayEventGuildIntegrationsUpdate GatewayEvent = "GUILD_INTEGRATIONS_UPDATE" - GatewayEventGuildMemberAdd GatewayEvent = "GUILD_MEMBER_ADD" - GatewayEventGuildMemberRemove GatewayEvent = "GUILD_MEMBER_REMOVE" - GatewayEventGuildMemberUpdate GatewayEvent = "GUILD_MEMBER_UPDATE" - GatewayEventGuildMembersChunk GatewayEvent = "GUILD_MEMBERS_CHUNK" - GatewayEventGuildRoleCreate GatewayEvent = "GUILD_ROLE_CREATE" - GatewayEventGuildRoleDelete GatewayEvent = "GUILD_ROLE_DELETE" - GatewayEventGuildRoleUpdate GatewayEvent = "GUILD_ROLE_UPDATE" - GatewayEventGuildUpdate GatewayEvent = "GUILD_UPDATE" - GatewayEventInteractionCreate GatewayEvent = "INTERACTION_CREATE" - WebhookEventInteractionCreate GatewayEvent = "INTERACTION_WEBHOOK_CREATE" - GatewayEventMessageAck GatewayEvent = "MESSAGE_ACK" - GatewayEventMessageCreate GatewayEvent = "MESSAGE_CREATE" - GatewayEventMessageDelete GatewayEvent = "MESSAGE_DELETE" - GatewayEventMessageDeleteBulk GatewayEvent = "MESSAGE_DELETE_BULK" - GatewayEventMessageReactionAdd GatewayEvent = "MESSAGE_REACTION_ADD" - GatewayEventMessageReactionRemove GatewayEvent = "MESSAGE_REACTION_REMOVE" - GatewayEventMessageReactionRemoveAll GatewayEvent = "MESSAGE_REACTION_REMOVE_ALL" - GatewayEventMessageUpdate GatewayEvent = "MESSAGE_UPDATE" - GatewayEventPresenceUpdate GatewayEvent = "PRESENCE_UPDATE" - GatewayEventPresencesReplace GatewayEvent = "PRESENCES_REPLACE" - GatewayEventReady GatewayEvent = "READY" - GatewayEventResumed GatewayEvent = "RESUMED" - GatewayEventTypingStart GatewayEvent = "TYPING_START" - GatewayEventUserGuildSettingsUpdate GatewayEvent = "USER_GUILD_SETTINGS_UPDATE" - GatewayEventUserNoteUpdate GatewayEvent = "USER_NOTE_UPDATE" - GatewayEventUserSettingsUpdate GatewayEvent = "USER_SETTINGS_UPDATE" - GatewayEventUserUpdate GatewayEvent = "USER_UPDATE" - GatewayEventVoiceServerUpdate GatewayEvent = "VOICE_SERVER_UPDATE" - GatewayEventVoiceStateUpdate GatewayEvent = "VOICE_STATE_UPDATE" - GatewayEventWebhooksUpdate GatewayEvent = "WEBHOOKS_UPDATE" + GatewayEventChannelCreate GatewayEventName = "CHANNEL_CREATE" + GatewayEventChannelDelete GatewayEventName = "CHANNEL_DELETE" + GatewayEventChannelPinsUpdate GatewayEventName = "CHANNEL_PINS_UPDATE" + GatewayEventChannelUpdate GatewayEventName = "CHANNEL_UPDATE" + GatewayEventGuildBanAdd GatewayEventName = "GUILD_BAN_ADD" + GatewayEventGuildBanRemove GatewayEventName = "GUILD_BAN_REMOVE" + GatewayEventGuildCreate GatewayEventName = "GUILD_CREATE" + GatewayEventGuildDelete GatewayEventName = "GUILD_DELETE" + GatewayEventGuildEmojisUpdate GatewayEventName = "GUILD_EMOJIS_UPDATE" + GatewayEventGuildIntegrationsUpdate GatewayEventName = "GUILD_INTEGRATIONS_UPDATE" + GatewayEventGuildMemberAdd GatewayEventName = "GUILD_MEMBER_ADD" + GatewayEventGuildMemberRemove GatewayEventName = "GUILD_MEMBER_REMOVE" + GatewayEventGuildMemberUpdate GatewayEventName = "GUILD_MEMBER_UPDATE" + GatewayEventGuildMembersChunk GatewayEventName = "GUILD_MEMBERS_CHUNK" + GatewayEventGuildRoleCreate GatewayEventName = "GUILD_ROLE_CREATE" + GatewayEventGuildRoleDelete GatewayEventName = "GUILD_ROLE_DELETE" + GatewayEventGuildRoleUpdate GatewayEventName = "GUILD_ROLE_UPDATE" + GatewayEventGuildUpdate GatewayEventName = "GUILD_UPDATE" + GatewayEventInteractionCreate GatewayEventName = "INTERACTION_CREATE" + WebhookEventInteractionCreate GatewayEventName = "INTERACTION_WEBHOOK_CREATE" + GatewayEventMessageAck GatewayEventName = "MESSAGE_ACK" + GatewayEventMessageCreate GatewayEventName = "MESSAGE_CREATE" + GatewayEventMessageDelete GatewayEventName = "MESSAGE_DELETE" + GatewayEventMessageDeleteBulk GatewayEventName = "MESSAGE_DELETE_BULK" + GatewayEventMessageReactionAdd GatewayEventName = "MESSAGE_REACTION_ADD" + GatewayEventMessageReactionRemove GatewayEventName = "MESSAGE_REACTION_REMOVE" + GatewayEventMessageReactionRemoveAll GatewayEventName = "MESSAGE_REACTION_REMOVE_ALL" + GatewayEventMessageUpdate GatewayEventName = "MESSAGE_UPDATE" + GatewayEventPresenceUpdate GatewayEventName = "PRESENCE_UPDATE" + GatewayEventPresencesReplace GatewayEventName = "PRESENCES_REPLACE" + GatewayEventReady GatewayEventName = "READY" + GatewayEventResumed GatewayEventName = "RESUMED" + GatewayEventTypingStart GatewayEventName = "TYPING_START" + GatewayEventUserGuildSettingsUpdate GatewayEventName = "USER_GUILD_SETTINGS_UPDATE" + GatewayEventUserNoteUpdate GatewayEventName = "USER_NOTE_UPDATE" + GatewayEventUserSettingsUpdate GatewayEventName = "USER_SETTINGS_UPDATE" + GatewayEventUserUpdate GatewayEventName = "USER_UPDATE" + GatewayEventVoiceServerUpdate GatewayEventName = "VOICE_SERVER_UPDATE" + GatewayEventVoiceStateUpdate GatewayEventName = "VOICE_STATE_UPDATE" + GatewayEventWebhooksUpdate GatewayEventName = "WEBHOOKS_UPDATE" ) // GatewayRs contains the response for GET /gateway diff --git a/api/gateway_commands.go b/api/gateway_commands.go index f7078093..a7f05ee8 100644 --- a/api/gateway_commands.go +++ b/api/gateway_commands.go @@ -1,37 +1,29 @@ package api -import ( - "encoding/json" - "time" -) +func NewGatewayCommand(op GatewayOp, d interface{}) GatewayCommand { + return GatewayCommand{ + GatewayPacket: GatewayPacket{ + Op: op, + S: nil, + T: nil, + }, + D: d, + } +} // GatewayCommand object is used when sending data to discord's websocket, it's recommended that you don't use these type GatewayCommand struct { - Op GatewayOp `json:"op"` - S *int `json:"s,omitempty"` - T *GatewayEvent `json:"t,omitempty"` -} - -// RawGatewayCommand specifies the data for the GatewayCommand payload that is being sent -type RawGatewayCommand struct { - GatewayCommand - D json.RawMessage `json:"d"` + GatewayPacket + D interface{} `json:"d"` } -// IdentifyCommand is used for Identifying to discord +// IdentifyCommand is the data used in IdentifyCommand type IdentifyCommand struct { - GatewayCommand - D IdentifyCommandData `json:"d"` -} - -// IdentifyCommandData is the data used in IdentifyCommand -type IdentifyCommandData struct { - Token string `json:"token"` - Properties IdentifyCommandDataProperties `json:"properties"` - Compress bool `json:"compress,omitempty"` - LargeThreshold int `json:"large_threshold,omitempty"` - GuildSubscriptions bool `json:"guild_subscriptions,omitempty"` // Deprecated, should not be specified when using intents - Intents Intents `json:"intents"` + Token string `json:"token"` + Properties IdentifyCommandDataProperties `json:"properties"` + Compress bool `json:"compress,omitempty"` + LargeThreshold int `json:"large_threshold,omitempty"` + Intents Intents `json:"intents"` // Todo: Add presence property here, need presence methods/struct // Todo: Add shard property here, need to discuss } @@ -47,29 +39,19 @@ type IdentifyCommandDataProperties struct { // ResumeCommand is used to resume a connection to discord in the case that you are disconnected. Is automatically // handled by the library and should rarely be used. type ResumeCommand struct { - GatewayCommand - D struct { - Token string `json:"token"` - SessionID string `json:"session_id"` - Seq int `json:"seq"` - } `json:"d"` + Token string `json:"token"` + SessionID string `json:"session_id"` + Seq int `json:"seq"` } // HeartbeatCommand is used to ensure the websocket connection remains open, and disconnect if not. type HeartbeatCommand struct { - GatewayCommand D *int `json:"d"` } // RequestGuildMembersCommand is used for fetching all of the members of a guild_events. It is recommended you have a strict // member caching policy when using this. type RequestGuildMembersCommand struct { - GatewayCommand - D RequestGuildMembersCommandData `json:"d"` -} - -// RequestGuildMembersCommandData is the RequestGuildMembersCommand.D payload -type RequestGuildMembersCommandData struct { GuildID Snowflake `json:"guild_id"` Query string `json:"query"` //If specified, user_ids must not be entered Limit int `json:"limit"` //Must be >=1 if query/user_ids is used, otherwise 0 @@ -80,12 +62,6 @@ type RequestGuildMembersCommandData struct { // UpdateVoiceStateCommand is used for updating the bots voice state in a guild_events type UpdateVoiceStateCommand struct { - GatewayCommand - D UpdateVoiceStateCommandData `json:"d"` -} - -// UpdateVoiceStateCommandData is the UpdateVoiceStateCommand.D payload -type UpdateVoiceStateCommandData struct { GuildID Snowflake `json:"guild_id"` ChannelID Snowflake `json:"channel_id"` SelfMute bool `json:"self_mute"` @@ -94,20 +70,8 @@ type UpdateVoiceStateCommandData struct { // UpdateStatusCommand is used for updating Disgo's presence type UpdateStatusCommand struct { - GatewayCommand - D UpdateStatusCommandData `json:"d"` -} - -// UpdateStatusCommandData is the UpdateStatusCommand.D payload -type UpdateStatusCommandData struct { Since *int `json:"since"` Activities []Activity `json:"activities"` Status bool `json:"status"` AFK bool `json:"afk"` } - -// HelloEvent is used when -type HelloEvent struct { - GatewayCommand - HeartbeatInterval time.Duration `json:"heartbeat_interval"` -} diff --git a/api/gateway_events.go b/api/gateway_events.go index 304a10df..35981075 100644 --- a/api/gateway_events.go +++ b/api/gateway_events.go @@ -1,16 +1,35 @@ package api -// ReadyEvent is the event sent by discord when you successfully Identify -type ReadyEvent struct { - GatewayCommand - D ReadyEventData `json:"d"` +import ( + "encoding/json" + "time" +) + +type GatewayPacket struct { + Op GatewayOp `json:"op"` + S *int `json:"s,omitempty"` + T *GatewayEventName `json:"t,omitempty"` +} + +// RawGatewayEvent specifies the data for the GatewayCommand payload that is being sent +type RawGatewayEvent struct { + GatewayPacket + D json.RawMessage `json:"d"` +} + +// ReadyGatewayEvent is the event sent by discord when you successfully Identify +type ReadyGatewayEvent struct { + GatewayPacket + D struct { + User User `json:"user"` + PrivateChannels []DMChannel `json:"channel"` + Guilds []Guild `json:"guild_events"` + SessionID string `json:"session_id"` + Shard [2]int `json:"shard,omitempty"` + } `json:"d"` } -// ReadyEventData is the ReadyEvent.D payload -type ReadyEventData struct { - User User `json:"user"` - PrivateChannels []DMChannel `json:"channel"` - Guilds []Guild `json:"guild_events"` - SessionID string `json:"session_id"` - Shard [2]int `json:"shard,omitempty"` +// HelloGatewayEventData is sent when we connect to the gateway +type HelloGatewayEventData struct { + HeartbeatInterval time.Duration `json:"heartbeat_interval"` } diff --git a/api/interaction_followup.go b/api/interaction_followup.go index 12a26cc8..2cd7bb7f 100644 --- a/api/interaction_followup.go +++ b/api/interaction_followup.go @@ -8,6 +8,7 @@ type FollowupMessage struct { TTS bool `json:"tts,omitempty"` Embeds []Embed `json:"embeds,omitempty"` AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` + Flags MessageFlags `json:"flags,omitempty"` //PayloadJSON string `json:"payload_json"` //File FileContents `json:"file"` } @@ -75,6 +76,26 @@ func (b *FollowupMessageBuilder) SetAllowedMentionsEmpty() *FollowupMessageBuild return b.SetAllowedMentions(&AllowedMentions{}) } +// SetFlags sets the message flags of the FollowupMessage +func (b *FollowupMessageBuilder) SetFlags(flags MessageFlags) *FollowupMessageBuilder { + b.Flags = flags + return b +} + +// SetEphemeral adds/removes MessageFlagEphemeral to the message flags +func (b *FollowupMessageBuilder) SetEphemeral(ephemeral bool) *FollowupMessageBuilder { + if ephemeral { + if !b.Flags.Has(MessageFlagEphemeral) { + b.Flags = b.Flags.Add(MessageFlagEphemeral) + } + } else { + if b.Flags.Has(MessageFlagEphemeral) { + b.Flags = b.Flags.Remove(MessageFlagEphemeral) + } + } + return b +} + // Build returns your built FollowupMessage func (b *FollowupMessageBuilder) Build() FollowupMessage { return b.FollowupMessage diff --git a/api/interaction_response.go b/api/interaction_response.go index c0918e3e..02546ac3 100644 --- a/api/interaction_response.go +++ b/api/interaction_response.go @@ -137,9 +137,13 @@ func (b *InteractionResponseBuilder) SetEphemeral(ephemeral bool) *InteractionRe b.Data = &InteractionResponseData{} } if ephemeral { - b.Data.Flags |= MessageFlagEphemeral + if !b.Data.Flags.Has(MessageFlagEphemeral) { + b.Data.Flags.Add(MessageFlagEphemeral) + } } else { - b.Data.Flags &^= MessageFlagEphemeral + if b.Data.Flags.Has(MessageFlagEphemeral) { + b.Data.Flags.Remove(MessageFlagEphemeral) + } } return b } diff --git a/api/message.go b/api/message.go index e37de183..d30114e5 100644 --- a/api/message.go +++ b/api/message.go @@ -37,27 +37,27 @@ const ( type MessageFlags int64 // Add allows you to add multiple bits together, producing a new bit -func (f MessageFlags) Add(bits ...Bit) Bit { +func (f MessageFlags) Add(bits ...MessageFlags) MessageFlags { total := MessageFlags(0) for _, bit := range bits { - total |= bit.(MessageFlags) + total |= bit } f |= total return f } // Remove allows you to subtract multiple bits from the first, producing a new bit -func (f MessageFlags) Remove(bits ...Bit) Bit { +func (f MessageFlags) Remove(bits ...MessageFlags) MessageFlags { total := MessageFlags(0) for _, bit := range bits { - total |= bit.(MessageFlags) + total |= bit } f &^= total return f } // HasAll will ensure that the bit includes all of the bits entered -func (f MessageFlags) HasAll(bits ...Bit) bool { +func (f MessageFlags) HasAll(bits ...MessageFlags) bool { for _, bit := range bits { if !f.Has(bit) { return false @@ -67,12 +67,12 @@ func (f MessageFlags) HasAll(bits ...Bit) bool { } // Has will check whether the Bit contains another bit -func (f MessageFlags) Has(bit Bit) bool { - return (f & bit.(MessageFlags)) == bit +func (f MessageFlags) Has(bit MessageFlags) bool { + return (f & bit) == bit } // MissingAny will check whether the bit is missing any one of the bits -func (f MessageFlags) MissingAny(bits ...Bit) bool { +func (f MessageFlags) MissingAny(bits ...MessageFlags) bool { for _, bit := range bits { if !f.Has(bit) { return true @@ -82,7 +82,7 @@ func (f MessageFlags) MissingAny(bits ...Bit) bool { } // Missing will do the inverse of Bit.Has -func (f MessageFlags) Missing(bit Bit) bool { +func (f MessageFlags) Missing(bit MessageFlags) bool { return !f.Has(bit) } @@ -94,7 +94,6 @@ const ( MessageFlagSuppressEmbeds MessageFlagSourceMessageDeleted MessageFlagUrgent - _ MessageFlagEphemeral MessageFlagLoading // Message is an interaction of type 5, awaiting further response ) diff --git a/api/options.go b/api/options.go index 75b3b660..062e8d80 100644 --- a/api/options.go +++ b/api/options.go @@ -8,4 +8,5 @@ type Options struct { ListenPort int ListenURL string PublicKey string + LargeThreshold int } diff --git a/api/webhook_server.go b/api/webhook_server.go index 29ba8da1..34c3d5b2 100644 --- a/api/webhook_server.go +++ b/api/webhook_server.go @@ -18,7 +18,7 @@ type WebhookServer interface { PublicKey() ed25519.PublicKey ListenURL() string Router() *mux.Router - Start() error + Start() Close() } diff --git a/internal/disgo_impl.go b/internal/disgo_impl.go index 98505924..a5f3ae40 100644 --- a/internal/disgo_impl.go +++ b/internal/disgo_impl.go @@ -10,9 +10,15 @@ import ( // New creates a new api.Disgo instance func New(token string, options api.Options) (api.Disgo, error) { + if options.LargeThreshold < 50 { + options.LargeThreshold = 50 + } else if options.LargeThreshold > 250 { + options.LargeThreshold = 250 + } disgo := &DisgoImpl{ - token: token, - intents: options.Intents, + token: token, + intents: options.Intents, + largeThreshold: options.LargeThreshold, } id, err := IDFromToken(token) @@ -47,6 +53,7 @@ type DisgoImpl struct { webhookServer api.WebhookServer cache api.Cache selfUserID api.Snowflake + largeThreshold int } // Connect opens the gateway connection to discord @@ -60,20 +67,27 @@ func (d *DisgoImpl) Connect() error { } // Start starts the interaction webhook server -func (d *DisgoImpl) Start() error { - err := d.WebhookServer().Start() - if err != nil { - log.Errorf("Unable to connect to gateway. error: %s", err) - return err - } - return nil +func (d *DisgoImpl) Start() { + d.WebhookServer().Start() } // Close will cleanup all disgo internals and close the discord connection safely func (d *DisgoImpl) Close() { - d.RestClient().Close() - d.Gateway().Close() - d.Cache().Close() + if d.RestClient() != nil { + d.RestClient().Close() + } + if d.WebhookServer() != nil { + d.WebhookServer().Close() + } + if d.Gateway() != nil { + d.Gateway().Close() + } + if d.EventManager() != nil { + d.EventManager().Close() + } + if d.Cache() != nil { + d.Cache().Close() + } } // Token returns the token of the client @@ -138,6 +152,11 @@ func (d *DisgoImpl) HeartbeatLatency() time.Duration { return d.Gateway().Latency() } +// HeartbeatLatency returns the heartbeat latency +func (d *DisgoImpl) LargeThreshold() int { + return d.largeThreshold +} + // GetCommand fetches a specific guild command func (d DisgoImpl) GetCommand(commandID api.Snowflake) (*api.SlashCommand, error) { return d.RestClient().GetGlobalCommand(d.SelfUserID(), commandID) diff --git a/internal/event_manager_impl.go b/internal/event_manager_impl.go index 85414b97..644a63ce 100644 --- a/internal/event_manager_impl.go +++ b/internal/event_manager_impl.go @@ -15,7 +15,7 @@ func newEventManagerImpl(disgo api.Disgo, listeners []api.EventListener) api.Eve disgo: disgo, channel: make(chan api.Event), listeners: listeners, - handlers: map[api.GatewayEvent]api.EventHandler{}, + handlers: map[api.GatewayEventName]api.EventHandler{}, } for _, handler := range handlers.GetAllHandlers() { eventManager.handlers[handler.Event()] = handler @@ -28,12 +28,17 @@ func newEventManagerImpl(disgo api.Disgo, listeners []api.EventListener) api.Eve type EventManagerImpl struct { disgo api.Disgo listeners []api.EventListener - handlers map[api.GatewayEvent]api.EventHandler + handlers map[api.GatewayEventName]api.EventHandler channel chan api.Event } +func (e EventManagerImpl) Close() { + log.Info("closing eventManager goroutines...") + close(e.channel) +} + // Handle calls the correct api.EventHandler -func (e EventManagerImpl) Handle(name api.GatewayEvent, payload json.RawMessage, c chan interface{}) { +func (e EventManagerImpl) Handle(name api.GatewayEventName, payload json.RawMessage, c chan interface{}) { if handler, ok := e.handlers[name]; ok { eventPayload := handler.New() if err := json.Unmarshal(payload, &eventPayload); err != nil { @@ -69,11 +74,13 @@ func (e EventManagerImpl) ListenEvents() { e.ListenEvents() return } - log.Infof("closing event channel...") - close(e.channel) + log.Infof("closed event goroutine") }() for { - event := <-e.channel + event, ok := <-e.channel + if !ok { + return + } for _, listener := range e.listeners { listener.OnEvent(event) } diff --git a/internal/gateway_impl.go b/internal/gateway_impl.go index 5fea373c..45eae0db 100644 --- a/internal/gateway_impl.go +++ b/internal/gateway_impl.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "io" + "io/ioutil" "runtime/debug" "time" @@ -18,7 +19,8 @@ import ( func newGatewayImpl(disgo api.Disgo) api.Gateway { return &GatewayImpl{ - disgo: disgo, + disgo: disgo, + connectionStatus: api.Unconnected, } } @@ -31,7 +33,7 @@ type GatewayImpl struct { heartbeatInterval time.Duration lastHeartbeatSent time.Time lastHeartbeatReceived time.Time - sessionID string + sessionID *string lastSequenceReceived *int url *string } @@ -41,13 +43,36 @@ func (g *GatewayImpl) Disgo() api.Disgo { return g.disgo } +func (g *GatewayImpl) reconnect(delay time.Duration) { + go func() { + g.Close() + + time.Sleep(delay) + + if g.Status() != api.Connecting && g.Status() != api.Reconnecting { + log.Error("tried to reconnect gateway while connecting/reconnecting") + return + } + log.Info("reconnecting gateway...") + if err := g.Open(); err != nil { + log.Errorf("failed to reconnect gateway: %s", err) + g.reconnect(delay * 2) + } + }() +} + // Open initializes the client and connection to discord func (g *GatewayImpl) Open() error { - g.connectionStatus = api.Connecting + if g.lastSequenceReceived == nil || g.sessionID == nil { + g.connectionStatus = api.Connecting + } else { + g.connectionStatus = api.Reconnecting + } + log.Info("starting ws...") if g.url == nil { - log.Debug("gateway url is nil, fetching...") + log.Debug("gateway url empty, fetching...") gatewayRs := api.GatewayRs{} if err := g.Disgo().RestClient().Request(endpoints.GetGateway.Compile(), nil, &gatewayRs); err != nil { return err @@ -56,9 +81,23 @@ func (g *GatewayImpl) Open() error { } gatewayURL := *g.url + "?v=" + endpoints.APIVersion + "&encoding=json" - wsConn, _, err := websocket.DefaultDialer.Dial(gatewayURL, nil) + wsConn, rs, err := websocket.DefaultDialer.Dial(gatewayURL, nil) if err != nil { - log.Errorf("error connecting to gateway. url: %s, error: %s", gatewayURL, err.Error()) + g.Close() + var body string + if rs != nil && rs.Body != nil { + rawBody, err := ioutil.ReadAll(rs.Body) + if err != nil { + log.Errorf("error while reading response body: %s", err) + g.url = nil + return err + } + body = string(rawBody) + } else { + body = "null" + } + + log.Errorf("error connecting to gateway. url: %s, error: %s, body: %s", gatewayURL, err.Error(), body) return err } wsConn.SetCloseHandler(func(code int, error string) error { @@ -83,31 +122,41 @@ func (g *GatewayImpl) Open() error { g.lastHeartbeatReceived = time.Now().UTC() - var eventData api.HelloEvent + var eventData api.HelloGatewayEventData if err = json.Unmarshal(event.D, &eventData); err != nil { return err } - g.connectionStatus = api.Identifying g.heartbeatInterval = eventData.HeartbeatInterval * time.Millisecond - if err = wsConn.WriteJSON(api.IdentifyCommand{ - GatewayCommand: api.GatewayCommand{ - Op: api.OpIdentify, - }, - D: api.IdentifyCommandData{ - Token: g.Disgo().Token(), - Properties: api.IdentifyCommandDataProperties{ - OS: api.GetOS(), - Browser: "disgo", - Device: "disgo", - }, - Compress: false, - LargeThreshold: 50, - Intents: g.Disgo().Intents(), - }, - }); err != nil { - return err + if g.lastSequenceReceived == nil || g.sessionID == nil { + g.connectionStatus = api.Identifying + if err = wsConn.WriteJSON( + api.NewGatewayCommand(api.OpIdentify, api.IdentifyCommand{ + Token: g.Disgo().Token(), + Properties: api.IdentifyCommandDataProperties{ + OS: api.GetOS(), + Browser: "disgo", + Device: "disgo", + }, + Compress: false, + LargeThreshold: g.Disgo().LargeThreshold(), + Intents: g.Disgo().Intents(), + }), + ); err != nil { + return err + } + } else { + g.connectionStatus = api.Resuming + if err = wsConn.WriteJSON( + api.NewGatewayCommand(api.OpIdentify, api.ResumeCommand{ + Token: g.Disgo().Token(), + SessionID: *g.sessionID, + Seq: *g.lastSequenceReceived, + }), + ); err != nil { + return err + } } g.connectionStatus = api.WaitingForReady @@ -140,21 +189,25 @@ func (g *GatewayImpl) heartbeat() { select { case <-ticker.C: g.sendHeartbeat() - case <-g.quit: - ticker.Stop() - return + case _, ok := <-g.quit: + if !ok { + ticker.Stop() + return + } } } } // Close cleans up the gateway internals func (g *GatewayImpl) Close() { - if g.quit == nil { - return + if g.quit != nil { + log.Info("closing gateway goroutines...") + close(g.quit) + log.Info("closed gateway goroutines") + } + if g.conn != nil { + _ = g.conn.Close() } - log.Info("closing gateway goroutines...") - g.quit <- true - log.Info("closed gateway goroutines") } // Latency returns the api.Gateway latency @@ -165,16 +218,10 @@ func (g *GatewayImpl) Latency() time.Duration { func (g *GatewayImpl) sendHeartbeat() { log.Debug("sending heartbeat...") - err := g.conn.WriteJSON(api.HeartbeatCommand{ - GatewayCommand: api.GatewayCommand{ - Op: api.OpHeartbeat, - }, - D: g.lastSequenceReceived, - }) - if err != nil { + if err := g.conn.WriteJSON(api.NewGatewayCommand(api.OpHeartbeat, g.lastSequenceReceived)); err != nil { log.Errorf("failed to send heartbeat with error: %s", err) - _ = g.conn.Close() - // Todo: reconnect + + g.reconnect(1 * time.Second) } g.lastHeartbeatSent = time.Now().UTC() } @@ -191,13 +238,16 @@ func (g *GatewayImpl) listen() { }() for { select { - case <-g.quit: - _ = g.conn.Close() - return + case _, ok := <-g.quit: + if !ok { + return + } default: mt, data, err := g.conn.ReadMessage() if err != nil { log.Errorf("error while reading from ws. error: %s", err) + g.reconnect(1 * time.Second) + return } event, err := parseGatewayEvent(mt, data) @@ -216,12 +266,12 @@ func (g *GatewayImpl) listen() { log.Debugf("received: %s", *event.T) if event.T != nil && *event.T == api.GatewayEventReady { - var readyEvent api.ReadyEventData + var readyEvent api.ReadyGatewayEvent if err := parseEventToStruct(event, &readyEvent); err != nil { log.Errorf("Error parsing ready event: %s", err) continue } - g.sessionID = readyEvent.SessionID + g.sessionID = &readyEvent.D.SessionID log.Info("ready event received") } @@ -254,7 +304,7 @@ func (g *GatewayImpl) listen() { } } -func parseEventToStruct(event *api.RawGatewayCommand, v interface{}) error { +func parseEventToStruct(event *api.RawGatewayEvent, v interface{}) error { if err := json.Unmarshal(event.D, v); err != nil { log.Errorf("error while unmarshaling event. error: %s", err) return err @@ -262,7 +312,7 @@ func parseEventToStruct(event *api.RawGatewayCommand, v interface{}) error { return nil } -func parseGatewayEvent(mt int, data []byte) (*api.RawGatewayCommand, error) { +func parseGatewayEvent(mt int, data []byte) (*api.RawGatewayEvent, error) { var reader io.Reader = bytes.NewBuffer(data) @@ -272,7 +322,7 @@ func parseGatewayEvent(mt int, data []byte) (*api.RawGatewayCommand, error) { if mt != websocket.TextMessage { return nil, fmt.Errorf("recieved unexpected message_events type: %d", mt) } - var event api.RawGatewayCommand + var event api.RawGatewayEvent decoder := json.NewDecoder(reader) if err := decoder.Decode(&event); err != nil { diff --git a/internal/handlers/guild_create_handler.go b/internal/handlers/guild_create_handler.go index 2f575796..ea2ffa73 100644 --- a/internal/handlers/guild_create_handler.go +++ b/internal/handlers/guild_create_handler.go @@ -9,7 +9,7 @@ import ( type GuildCreateHandler struct{} // Event returns the raw gateway event Event -func (h GuildCreateHandler) Event() api.GatewayEvent { +func (h GuildCreateHandler) Event() api.GatewayEventName { return api.GatewayEventGuildCreate } diff --git a/internal/handlers/guild_delete_handler.go b/internal/handlers/guild_delete_handler.go index 36b88e4b..4311ccd4 100644 --- a/internal/handlers/guild_delete_handler.go +++ b/internal/handlers/guild_delete_handler.go @@ -9,7 +9,7 @@ import ( type GuildDeleteHandler struct{} // Event returns the raw gateway event Event -func (h GuildDeleteHandler) Event() api.GatewayEvent { +func (h GuildDeleteHandler) Event() api.GatewayEventName { return api.GatewayEventGuildDelete } @@ -30,7 +30,7 @@ func (h GuildDeleteHandler) Handle(disgo api.Disgo, eventManager api.EventManage eventManager.Dispatch(events.GuildUnavailableEvent{ GenericGuildEvent: events.GenericGuildEvent{ GenericEvent: api.NewEvent(disgo), - GuildID: guild.ID, + GuildID: guild.ID, }, }) } else { @@ -39,7 +39,7 @@ func (h GuildDeleteHandler) Handle(disgo api.Disgo, eventManager api.EventManage genericGuildEvent := events.GenericGuildEvent{ GenericEvent: api.NewEvent(disgo), - GuildID: guild.ID, + GuildID: guild.ID, } eventManager.Dispatch(genericGuildEvent) diff --git a/internal/handlers/guild_member_add_handler.go b/internal/handlers/guild_member_add_handler.go index effc8a9b..8bd174e6 100644 --- a/internal/handlers/guild_member_add_handler.go +++ b/internal/handlers/guild_member_add_handler.go @@ -9,7 +9,7 @@ import ( type GuildMemberAddHandler struct{} // Event returns the raw gateway event Event -func (h GuildMemberAddHandler) Event() api.GatewayEvent { +func (h GuildMemberAddHandler) Event() api.GatewayEventName { return api.GatewayEventGuildMemberAdd } diff --git a/internal/handlers/guild_member_remove_handler.go b/internal/handlers/guild_member_remove_handler.go index 8815a23a..d0602d57 100644 --- a/internal/handlers/guild_member_remove_handler.go +++ b/internal/handlers/guild_member_remove_handler.go @@ -14,7 +14,7 @@ type guildMemberRemoveData struct { type GuildMemberRemoveHandler struct{} // Event returns the raw gateway event Event -func (h GuildMemberRemoveHandler) Event() api.GatewayEvent { +func (h GuildMemberRemoveHandler) Event() api.GatewayEventName { return api.GatewayEventGuildMemberRemove } diff --git a/internal/handlers/guild_member_update_handler.go b/internal/handlers/guild_member_update_handler.go index 38d4ec3d..e21bd06b 100644 --- a/internal/handlers/guild_member_update_handler.go +++ b/internal/handlers/guild_member_update_handler.go @@ -9,7 +9,7 @@ import ( type GuildMemberUpdateHandler struct{} // Event returns the raw gateway event Event -func (h GuildMemberUpdateHandler) Event() api.GatewayEvent { +func (h GuildMemberUpdateHandler) Event() api.GatewayEventName { return api.GatewayEventGuildMemberUpdate } diff --git a/internal/handlers/guild_role_create_handler.go b/internal/handlers/guild_role_create_handler.go index 31491e80..4e59bb0b 100644 --- a/internal/handlers/guild_role_create_handler.go +++ b/internal/handlers/guild_role_create_handler.go @@ -14,7 +14,7 @@ type roleCreateData struct { type GuildRoleCreateHandler struct{} // Event returns the raw gateway event Event -func (h GuildRoleCreateHandler) Event() api.GatewayEvent { +func (h GuildRoleCreateHandler) Event() api.GatewayEventName { return api.GatewayEventGuildRoleCreate } diff --git a/internal/handlers/guild_role_delete_handler.go b/internal/handlers/guild_role_delete_handler.go index 1fb06f08..cc756d6b 100644 --- a/internal/handlers/guild_role_delete_handler.go +++ b/internal/handlers/guild_role_delete_handler.go @@ -14,7 +14,7 @@ type roleDeleteData struct { type GuildRoleDeleteHandler struct{} // Event returns the raw gateway event Event -func (h GuildRoleDeleteHandler) Event() api.GatewayEvent { +func (h GuildRoleDeleteHandler) Event() api.GatewayEventName { return api.GatewayEventGuildRoleDelete } diff --git a/internal/handlers/guild_role_update_handler.go b/internal/handlers/guild_role_update_handler.go index 8faf52be..cd790aaa 100644 --- a/internal/handlers/guild_role_update_handler.go +++ b/internal/handlers/guild_role_update_handler.go @@ -14,7 +14,7 @@ type roleUpdateData struct { type GuildRoleUpdateHandler struct{} // Event returns the raw gateway event Event -func (h GuildRoleUpdateHandler) Event() api.GatewayEvent { +func (h GuildRoleUpdateHandler) Event() api.GatewayEventName { return api.GatewayEventGuildRoleUpdate } diff --git a/internal/handlers/guild_update_handler.go b/internal/handlers/guild_update_handler.go index 9f02922d..f7a08a71 100644 --- a/internal/handlers/guild_update_handler.go +++ b/internal/handlers/guild_update_handler.go @@ -9,7 +9,7 @@ import ( type GuildUpdateHandler struct{} // Event returns the raw gateway event Event -func (h GuildUpdateHandler) Event() api.GatewayEvent { +func (h GuildUpdateHandler) Event() api.GatewayEventName { return api.GatewayEventGuildUpdate } diff --git a/internal/handlers/interaction_create_handler.go b/internal/handlers/interaction_create_handler.go index 403b1d2a..9856c655 100644 --- a/internal/handlers/interaction_create_handler.go +++ b/internal/handlers/interaction_create_handler.go @@ -9,7 +9,7 @@ import ( type InteractionCreateHandler struct{} // Event returns the raw gateway event Event -func (h InteractionCreateHandler) Event() api.GatewayEvent { +func (h InteractionCreateHandler) Event() api.GatewayEventName { return api.GatewayEventInteractionCreate } diff --git a/internal/handlers/interaction_create_webhook_handler.go b/internal/handlers/interaction_create_webhook_handler.go index da70cfe8..ea436cb1 100644 --- a/internal/handlers/interaction_create_webhook_handler.go +++ b/internal/handlers/interaction_create_webhook_handler.go @@ -8,7 +8,7 @@ import ( type InteractionCreateWebhookHandler struct{} // Event returns the raw gateway event Event -func (h InteractionCreateWebhookHandler) Event() api.GatewayEvent { +func (h InteractionCreateWebhookHandler) Event() api.GatewayEventName { return api.WebhookEventInteractionCreate } diff --git a/internal/handlers/message_create_handler.go b/internal/handlers/message_create_handler.go index ba1de01e..175f0ead 100644 --- a/internal/handlers/message_create_handler.go +++ b/internal/handlers/message_create_handler.go @@ -9,7 +9,7 @@ import ( type MessageCreateHandler struct{} // Event returns the raw gateway event Event -func (h MessageCreateHandler) Event() api.GatewayEvent { +func (h MessageCreateHandler) Event() api.GatewayEventName { return api.GatewayEventMessageCreate } diff --git a/internal/handlers/ready_handler.go b/internal/handlers/ready_handler.go index e012eae2..8a3d6cca 100644 --- a/internal/handlers/ready_handler.go +++ b/internal/handlers/ready_handler.go @@ -17,7 +17,7 @@ type readyEventData struct { type ReadyHandler struct{} // Event returns the raw gateway event Event -func (h ReadyHandler) Event() api.GatewayEvent { +func (h ReadyHandler) Event() api.GatewayEventName { return api.GatewayEventReady } diff --git a/internal/handlers/voice_server_update_handler.go b/internal/handlers/voice_server_update_handler.go index 25857475..94162e14 100644 --- a/internal/handlers/voice_server_update_handler.go +++ b/internal/handlers/voice_server_update_handler.go @@ -6,7 +6,7 @@ import "github.com/DisgoOrg/disgo/api" type VoiceServerUpdateHandler struct{} // Event returns the raw gateway event Event -func (h VoiceServerUpdateHandler) Event() api.GatewayEvent { +func (h VoiceServerUpdateHandler) Event() api.GatewayEventName { return api.GatewayEventVoiceServerUpdate } diff --git a/internal/handlers/voice_state_update_handler.go b/internal/handlers/voice_state_update_handler.go index ab919424..9fcb2aac 100644 --- a/internal/handlers/voice_state_update_handler.go +++ b/internal/handlers/voice_state_update_handler.go @@ -8,7 +8,7 @@ import ( type VoiceStateUpdateHandler struct{} // Event returns the raw gateway event Event -func (h VoiceStateUpdateHandler) Event() api.GatewayEvent { +func (h VoiceStateUpdateHandler) Event() api.GatewayEventName { return api.GatewayEventVoiceStateUpdate } diff --git a/internal/restclient_impl.go b/internal/restclient_impl.go index b7005de9..c4bbad54 100644 --- a/internal/restclient_impl.go +++ b/internal/restclient_impl.go @@ -449,17 +449,17 @@ func (r RestClientImpl) DeleteInteractionResponse(applicationID api.Snowflake, i // SendFollowupMessage used to send a followup message_events to an interaction func (r RestClientImpl) SendFollowupMessage(applicationID api.Snowflake, interactionToken string, followupMessage api.FollowupMessage) (message *api.Message, err error) { - return message, r.Request(endpoints.CreateInteractionResponse.Compile(applicationID, interactionToken), followupMessage, &message) + return message, r.Request(endpoints.CreateFollowupMessage.Compile(applicationID, interactionToken), followupMessage, &message) } // EditFollowupMessage used to edit a api.FollowupMessage from an api.Interaction func (r RestClientImpl) EditFollowupMessage(applicationID api.Snowflake, interactionToken string, messageID api.Snowflake, followupMessage api.FollowupMessage) (message *api.Message, err error) { - return message, r.Request(endpoints.CreateInteractionResponse.Compile(applicationID, interactionToken, messageID), followupMessage, &message) + return message, r.Request(endpoints.EditFollowupMessage.Compile(applicationID, interactionToken, messageID), followupMessage, &message) } // DeleteFollowupMessage used to delete a api.FollowupMessage from an api.Interaction func (r RestClientImpl) DeleteFollowupMessage(applicationID api.Snowflake, interactionToken string, messageID api.Snowflake) error { - return r.Request(endpoints.CreateInteractionResponse.Compile(applicationID, interactionToken, messageID), nil, nil) + return r.Request(endpoints.DeleteFollowupMessage.Compile(applicationID, interactionToken, messageID), nil, nil) } func normalizeEmoji(emoji string) string { diff --git a/internal/webhook_server_impl.go b/internal/webhook_server_impl.go index 736bc26e..54ea1609 100644 --- a/internal/webhook_server_impl.go +++ b/internal/webhook_server_impl.go @@ -62,12 +62,15 @@ func (w *WebhookServerImpl) Router() *mux.Router { } // Start makes the WebhookServerImpl listen on the specified port and handle requests -func (w *WebhookServerImpl) Start() error { +func (w *WebhookServerImpl) Start() { w.router = mux.NewRouter() w.router.Handle(w.ListenURL(), w.interactionHandler).Methods("POST") - go http.ListenAndServe(":"+strconv.Itoa(w.listenPort), w.router) - return nil + go func() { + if err := http.ListenAndServe(":"+strconv.Itoa(w.listenPort), w.router); err != nil { + log.Errorf("error starting webhook server: %s", err) + } + }() } // Close shuts down the WebhookServerImpl @@ -84,7 +87,11 @@ func (h *webhookInteractionHandler) ServeHTTP(w http.ResponseWriter, r *http.Req w.WriteHeader(http.StatusUnauthorized) return } - defer r.Body.Close() + defer func() { + if err := r.Body.Close(); err != nil { + log.Errorf("error closing request body in WebhookServer: %s", err) + } + }() rawBody, err := ioutil.ReadAll(r.Body) if err != nil { w.WriteHeader(http.StatusBadRequest) diff --git a/testbot/testbot.go b/testbot/testbot.go index bd9382f9..6141fb15 100644 --- a/testbot/testbot.go +++ b/testbot/testbot.go @@ -115,17 +115,35 @@ func slashCommandListener(event *events.SlashCommandEvent) { SetAllowedMentionsEmpty(). Build(), ) + case "test": go func() { _ = event.Acknowledge() + time.Sleep(2 * time.Second) _, _ = event.EditOriginal(api.NewFollowupMessageBuilder(). SetEmbeds(api.NewEmbedBuilder(). - SetDescription("Edited Original"). + SetDescription("finished with thinking"). + Build(), + ).Build(), + ) + + time.Sleep(1 * time.Second) + _, _ = event.SendFollowup(api.NewFollowupMessageBuilder(). + SetEmbeds(api.NewEmbedBuilder(). + SetDescription("followup 1"). Build(), ).Build(), ) + + time.Sleep(1 * time.Second) + _, _ = event.SendFollowup(api.NewFollowupMessageBuilder(). + SetEphemeral(true). + SetContent("followup 4 only you can see"). + Build(), + ) }() + case "addrole": user := event.OptionByName("member").User() role := event.OptionByName("role").Role() @@ -139,6 +157,7 @@ func slashCommandListener(event *events.SlashCommandEvent) { api.NewEmbedBuilder().SetColor(16711680).SetDescriptionf("Failed to add %s to %s", role, user).Build(), ).Build()) } + case "removerole": user := event.OptionByName("member").User() role := event.OptionByName("role").Role() @@ -152,6 +171,7 @@ func slashCommandListener(event *events.SlashCommandEvent) { api.NewEmbedBuilder().SetColor(16711680).SetDescriptionf("Failed to remove %s from %s", role, user).Build(), ).Build()) } + } } From 5545b391e16dd4037e7fae231e311b1d78208e47 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Tue, 6 Apr 2021 18:07:19 +0200 Subject: [PATCH 21/65] added missing docu --- api/gateway_commands.go | 1 + api/gateway_events.go | 1 + internal/disgo_impl.go | 2 +- internal/event_manager_impl.go | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/api/gateway_commands.go b/api/gateway_commands.go index a7f05ee8..d06342ab 100644 --- a/api/gateway_commands.go +++ b/api/gateway_commands.go @@ -1,5 +1,6 @@ package api +// NewGatewayCommand returns a new GatewayCommand struct with the given payload func NewGatewayCommand(op GatewayOp, d interface{}) GatewayCommand { return GatewayCommand{ GatewayPacket: GatewayPacket{ diff --git a/api/gateway_events.go b/api/gateway_events.go index 35981075..e568118b 100644 --- a/api/gateway_events.go +++ b/api/gateway_events.go @@ -5,6 +5,7 @@ import ( "time" ) +// GatewayPacket raw GatewayEvent type type GatewayPacket struct { Op GatewayOp `json:"op"` S *int `json:"s,omitempty"` diff --git a/internal/disgo_impl.go b/internal/disgo_impl.go index a5f3ae40..9062ed60 100644 --- a/internal/disgo_impl.go +++ b/internal/disgo_impl.go @@ -152,7 +152,7 @@ func (d *DisgoImpl) HeartbeatLatency() time.Duration { return d.Gateway().Latency() } -// HeartbeatLatency returns the heartbeat latency +// LargeThreshold returns the large threshold set func (d *DisgoImpl) LargeThreshold() int { return d.largeThreshold } diff --git a/internal/event_manager_impl.go b/internal/event_manager_impl.go index 644a63ce..f80ea166 100644 --- a/internal/event_manager_impl.go +++ b/internal/event_manager_impl.go @@ -32,6 +32,7 @@ type EventManagerImpl struct { channel chan api.Event } +// Close closes all goroutines created by the api.EventManager func (e EventManagerImpl) Close() { log.Info("closing eventManager goroutines...") close(e.channel) From a3567e6c41b9189b996514a91ac3da2f4ba33e2e Mon Sep 17 00:00:00 2001 From: Alex <46286597+Alex-R-31@users.noreply.github.com> Date: Tue, 6 Apr 2021 23:52:57 +0100 Subject: [PATCH 22/65] No duplicate iotas --- api/message.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/message.go b/api/message.go index d30114e5..21dd7e96 100644 --- a/api/message.go +++ b/api/message.go @@ -88,8 +88,8 @@ func (f MessageFlags) Missing(bit MessageFlags) bool { // Constants for MessageFlags const ( - MessageFlagNone MessageFlags = 0 - MessageFlagCrossposted MessageFlags = 1 << iota + MessageFlagNone MessageFlags = 0 << iota + MessageFlagCrossposted MessageFlagIsCrosspost MessageFlagSuppressEmbeds MessageFlagSourceMessageDeleted From 5d04445b7d68b95e10f4a42efcbb288461bdb310 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Wed, 7 Apr 2021 02:25:16 +0200 Subject: [PATCH 23/65] not quite fixed reconnecting & tweaked a lot other stuff --- api/cache.go | 11 +-- api/cache_flags.go | 3 +- api/disgo.go | 5 ++ api/emote.go | 7 ++ api/endpoints/endpoints.go | 2 +- api/events/channel_events.go | 2 +- api/events/dm_event.go | 2 +- api/{ => events}/generic_event.go | 13 ++- api/events/guild_events.go | 2 +- api/events/interaction_events.go | 2 +- api/events/listener_adapter.go | 32 +++---- api/events/message_event.go | 2 +- api/events/ready_events.go | 2 +- api/guild.go | 30 +++++++ ...che_policies.go => member_cache_policy.go} | 48 ----------- api/message.go | 46 +++++----- api/message_cache_policy.go | 49 +++++++++++ api/permissions.go | 3 +- internal/cache_impl.go | 85 +++++++++++++++++-- internal/disgo_impl.go | 2 +- internal/gateway_impl.go | 67 ++++++++------- internal/handlers/guild_create_handler.go | 2 +- internal/handlers/guild_delete_handler.go | 4 +- internal/handlers/guild_member_add_handler.go | 2 +- .../handlers/guild_member_remove_handler.go | 2 +- .../handlers/guild_member_update_handler.go | 2 +- .../handlers/guild_role_create_handler.go | 2 +- .../handlers/guild_role_delete_handler.go | 2 +- .../handlers/guild_role_update_handler.go | 2 +- internal/handlers/guild_update_handler.go | 2 +- .../handlers/interaction_create_handler.go | 2 +- internal/handlers/message_create_handler.go | 4 +- testbot/testbot.go | 6 +- 33 files changed, 283 insertions(+), 164 deletions(-) rename api/{ => events}/generic_event.go (56%) rename api/{cache_policies.go => member_cache_policy.go} (52%) create mode 100644 api/message_cache_policy.go diff --git a/api/cache.go b/api/cache.go index db246dc0..c8da9a36 100644 --- a/api/cache.go +++ b/api/cache.go @@ -111,10 +111,11 @@ type Cache interface { FindCategory(Snowflake, func(*Category) bool) *Category FindCategories(Snowflake, func(*Category) bool) []*Category - /*Emote(Snowflake) *Emote - EmotesByName(string, bool) []*Emote - Emotes() []*Emote - EmoteCache() map[Snowflake]*Emote + Emote(emoteID Snowflake) *Emote + EmotesByName(guildID Snowflake, name string, ignoreCase bool) []*Emote + Emotes(guildID Snowflake) []*Emote + EmoteCache(guildID Snowflake) map[Snowflake]*Emote + AllEmoteCache() map[Snowflake]map[Snowflake]*Emote CacheEmote(*Emote) - UncacheEmote(Snowflake)*/ + UncacheEmote(guildID Snowflake, emoteID Snowflake) } diff --git a/api/cache_flags.go b/api/cache_flags.go index 7157fcad..01a2a783 100644 --- a/api/cache_flags.go +++ b/api/cache_flags.go @@ -5,7 +5,8 @@ type CacheFlags int // values for CacheFlags const ( - CacheFlagDMChannels CacheFlags = 0 << iota + CacheFlagsNone CacheFlags = 0 + CacheFlagDMChannels CacheFlags = 1 << iota CacheFlagCategories CacheFlagTextChannels CacheFlagVoiceChannels diff --git a/api/disgo.go b/api/disgo.go index c2717a79..0953fe73 100644 --- a/api/disgo.go +++ b/api/disgo.go @@ -57,6 +57,11 @@ type EventListener interface { OnEvent(interface{}) } +// Event the basic interface each event implement +type Event interface { + Disgo() Disgo +} + // EventManager lets you listen for specific events triggered by raw gateway events type EventManager interface { Close() diff --git a/api/emote.go b/api/emote.go index f2e84ff9..7cbe613f 100644 --- a/api/emote.go +++ b/api/emote.go @@ -2,11 +2,17 @@ package api // An Emote allows you to interact with custom emojis in discord. type Emote struct { + Disgo Disgo ID Snowflake + GuildID Snowflake Name string Animated bool } +func (e Emote) Guild() *Guild { + return e.Disgo.Cache().Guild(e.GuildID) +} + // Mention returns the string used to send the emoji func (e Emote) Mention() string { start := "<:" @@ -16,6 +22,7 @@ func (e Emote) Mention() string { return start + e.Name + ":" + e.ID.String() + ">" } +// String formats the Emote as string func (e Emote) String() string { return e.Mention() } diff --git a/api/endpoints/endpoints.go b/api/endpoints/endpoints.go index 264458cd..1b8919e4 100644 --- a/api/endpoints/endpoints.go +++ b/api/endpoints/endpoints.go @@ -85,7 +85,7 @@ var ( GetGuildWebhooks = NewAPIRoute(GET, "/guilds/{guild.id}/webhooks") - GetAudiotLogs = NewAPIRoute(GET, "/guilds/{guild.id}/audit-logs") + GetAuditLogs = NewAPIRoute(GET, "/guilds/{guild.id}/audit-logs") GetVoiceRegions = NewAPIRoute(GET, "guilds/{guild.id}/regions") diff --git a/api/events/channel_events.go b/api/events/channel_events.go index 067c9a16..c75139de 100644 --- a/api/events/channel_events.go +++ b/api/events/channel_events.go @@ -4,7 +4,7 @@ import "github.com/DisgoOrg/disgo/api" // GenericChannelEvent is called upon receiving an event in a api.Channel type GenericChannelEvent struct { - api.GenericEvent + GenericEvent ChannelID api.Snowflake } diff --git a/api/events/dm_event.go b/api/events/dm_event.go index 0f9d048b..4233cf76 100644 --- a/api/events/dm_event.go +++ b/api/events/dm_event.go @@ -4,7 +4,7 @@ import "github.com/DisgoOrg/disgo/api" // GenericDMEvent is a generic dm channel event type GenericDMEvent struct { - api.GenericEvent + GenericEvent UserID api.Snowflake DMChannelID api.Snowflake } diff --git a/api/generic_event.go b/api/events/generic_event.go similarity index 56% rename from api/generic_event.go rename to api/events/generic_event.go index 512bbec8..c15f80c6 100644 --- a/api/generic_event.go +++ b/api/events/generic_event.go @@ -1,21 +1,18 @@ -package api +package events -// Event the basic interface each event implement -type Event interface { - Disgo() Disgo -} +import "github.com/DisgoOrg/disgo/api" // NewEvent constructs a new GenericEvent with the provided Disgo instance -func NewEvent(disgo Disgo) GenericEvent { +func NewEvent(disgo api.Disgo) GenericEvent { return GenericEvent{disgo: disgo} } // GenericEvent the base event structure type GenericEvent struct { - disgo Disgo + disgo api.Disgo } // Disgo returns the Disgo instance for this event -func (d GenericEvent) Disgo() Disgo { +func (d GenericEvent) Disgo() api.Disgo { return d.disgo } diff --git a/api/events/guild_events.go b/api/events/guild_events.go index 351941c9..0fb7778d 100644 --- a/api/events/guild_events.go +++ b/api/events/guild_events.go @@ -6,7 +6,7 @@ import ( // GenericGuildEvent generic api.Guild api.GenericEvent type GenericGuildEvent struct { - api.GenericEvent + GenericEvent GuildID api.Snowflake } diff --git a/api/events/interaction_events.go b/api/events/interaction_events.go index 6b0ed71a..fc0d5406 100644 --- a/api/events/interaction_events.go +++ b/api/events/interaction_events.go @@ -8,7 +8,7 @@ import ( // GenericInteractionEvent generic api.Interaction event type GenericInteractionEvent struct { - api.GenericEvent + GenericEvent Interaction api.Interaction } diff --git a/api/events/listener_adapter.go b/api/events/listener_adapter.go index 1e239212..a193eeb6 100644 --- a/api/events/listener_adapter.go +++ b/api/events/listener_adapter.go @@ -9,33 +9,33 @@ type ListenerAdapter struct { OnGenericEvent func(*api.Event) // Guild Events - OnGenericGuildEvent func(*GenericGuildEvent) - OnGuildJoin func(*GuildJoinEvent) - OnGuildUpdate func(*GuildUpdateEvent) - OnGuildLeave func(*GuildLeaveEvent) - OnGuildAvailable func(*GuildAvailableEvent) - OnGuildUnavailable func(*GuildUnavailableEvent) + OnGenericGuildEvent func(event *GenericGuildEvent) + OnGuildJoin func(event *GuildJoinEvent) + OnGuildUpdate func(event *GuildUpdateEvent) + OnGuildLeave func(event *GuildLeaveEvent) + OnGuildAvailable func(event *GuildAvailableEvent) + OnGuildUnavailable func(event *GuildUnavailableEvent) // Guild Role Events - OnGenericGuildRole func(*GenericGuildRoleEvent) - OnGuildRoleCreate func(*GuildRoleCreateEvent) - OnGuildRoleUpdate func(*GuildRoleUpdateEvent) - OnGuildRoleDelete func(*GuildRoleDeleteEvent) + OnGenericGuildRole func(event *GenericGuildRoleEvent) + OnGuildRoleCreate func(event *GuildRoleCreateEvent) + OnGuildRoleUpdate func(event *GuildRoleUpdateEvent) + OnGuildRoleDelete func(event *GuildRoleDeleteEvent) // Message Events - OnMessageReceived func(*MessageReceivedEvent) - OnGuildMessageReceived func(*GuildMessageReceivedEvent) + OnMessageReceived func(event *MessageReceivedEvent) + OnGuildMessageReceived func(event *GuildMessageReceivedEvent) // Interaction Events - OnGenericInteraction func(*GenericInteractionEvent) - OnSlashCommand func(*SlashCommandEvent) + OnGenericInteraction func(event *GenericInteractionEvent) + OnSlashCommand func(event *SlashCommandEvent) } // OnEvent is getting called everytime we receive an event func (l ListenerAdapter) OnEvent(event interface{}) { - if event, ok := event.(api.Event); ok { + if e, ok := event.(api.Event); ok { if l.OnGenericEvent != nil { - l.OnGenericEvent(&event) + l.OnGenericEvent(&e) } } switch e := event.(type) { diff --git a/api/events/message_event.go b/api/events/message_event.go index d98e25d3..71db6fc4 100644 --- a/api/events/message_event.go +++ b/api/events/message_event.go @@ -4,7 +4,7 @@ import "github.com/DisgoOrg/disgo/api" // GenericMessageEvent generic api.Message event type GenericMessageEvent struct { - api.GenericEvent + GenericEvent MessageID api.Snowflake MessageChannelID api.Snowflake } diff --git a/api/events/ready_events.go b/api/events/ready_events.go index d81fc47f..77bcb301 100644 --- a/api/events/ready_events.go +++ b/api/events/ready_events.go @@ -4,6 +4,6 @@ import "github.com/DisgoOrg/disgo/api" // ReadyEvent indicates we received the ReadyEvent from the api.Gateway type ReadyEvent struct { - api.GenericEvent + GenericEvent api.ReadyGatewayEvent } diff --git a/api/guild.go b/api/guild.go index ed3a07ca..0d3c9275 100644 --- a/api/guild.go +++ b/api/guild.go @@ -89,6 +89,35 @@ const ( GuildFeaturePreviewEnabled GuildFeature = "PREVIEW_ENABLED" ) +// GuildWelcomeScreen is the Welcome Screen of a Guild +type GuildWelcomeScreen struct { + Description *string `json:"description,omitempty"` + WelcomeChannels []*GuildWelcomeChannel `json:"welcome_channels"` +} + +// GuildWelcomeChannel is one of the channels in a GuildWelcomeScreen +type GuildWelcomeChannel struct { + ChannelID Snowflake `json:"channel_id"` + Description string `json:"description"` + EmojiID *Snowflake `json:"emoji_id,omitempty"` + EmojiName *string `json:"emoji_name,omitempty"` +} + +// GuildPreview is used for previewing public guilds before joining them +type GuildPreview struct { + Disgo Disgo + ID Snowflake `json:"id"` + Name string `json:"name"` + Icon *string `json:"icon"` + DiscoverySplash *string `json:"discovery_splash"` + Splash *string `json:"splash"` + Features []GuildFeature `json:"features"` + Description *string `json:"description"` + ApproximateMemberCount *int `json:"approximate_member_count"` + ApproximatePresenceCount *int `json:"approximate_presence_count"` + Emojis []*Emote `json:"emojis"` +} + // FullGuild represents a Guild objects sent by discord with the GatewayEventGuildCreate type FullGuild struct { *Guild @@ -139,6 +168,7 @@ type Guild struct { MaxVideoChannelUsers *int `json:"max_video_channel_users"` ApproximateMemberCount *int `json:"approximate_member_count"` ApproximatePresenceCount *int `json:"approximate_presence_count"` + WelcomeScreen *GuildWelcomeScreen `json:"welcome_screen"` } // CreateRole allows you to create a new Role diff --git a/api/cache_policies.go b/api/member_cache_policy.go similarity index 52% rename from api/cache_policies.go rename to api/member_cache_policy.go index 588a8624..cdd773c9 100644 --- a/api/cache_policies.go +++ b/api/member_cache_policy.go @@ -1,7 +1,5 @@ package api -import "time" - // MemberCachePolicy can be used to define your own policy for caching members type MemberCachePolicy func(*Member) bool @@ -45,49 +43,3 @@ func MemberCachePolicyAllOf(policy MemberCachePolicy, policies ...MemberCachePol } return policy } - -// MessageCachePolicy can be used to define your own policy for caching messages -type MessageCachePolicy func(*Message) bool - -// Default member cache policies -var ( - MessageCachePolicyNone MessageCachePolicy = func(_ *Message) bool { return false } - MessageCachePolicyDefault = MessageCachePolicyNone -) - -// Or allows you to combine that policy with another, meaning either needs to be true -func (p MessageCachePolicy) Or(policy MessageCachePolicy) MessageCachePolicy { - return func(message *Message) bool { - return p(message) || policy(message) - } -} - -// And allows you to require both policies to be true for the member to be cached -func (p MessageCachePolicy) And(policy MessageCachePolicy) MessageCachePolicy { - return func(message *Message) bool { - return p(message) && policy(message) - } -} - -// MessageCachePolicyDuration creates a new MessageCachePolicy which caches messages for the give duration -func MessageCachePolicyDuration(duration time.Duration) MessageCachePolicy { - return func(message *Message) bool { - return message.CreatedAt.Add(duration).After(time.Now()) - } -} - -// MessageCachePolicyAny is a shorthand for MessageCachePolicy.Or(MessageCachePolicy).Or(MessageCachePolicy) etc. -func MessageCachePolicyAny(policy MessageCachePolicy, policies ...MessageCachePolicy) MessageCachePolicy { - for _, p := range policies { - policy = policy.Or(p) - } - return policy -} - -// MessageCachePolicyAll is a shorthand for MessageCachePolicy.And(MessageCachePolicy).And(MessageCachePolicy) etc. -func MessageCachePolicyAll(policy MessageCachePolicy, policies ...MessageCachePolicy) MessageCachePolicy { - for _, p := range policies { - policy = policy.And(p) - } - return policy -} diff --git a/api/message.go b/api/message.go index 21dd7e96..ebf5b7cf 100644 --- a/api/message.go +++ b/api/message.go @@ -88,8 +88,8 @@ func (f MessageFlags) Missing(bit MessageFlags) bool { // Constants for MessageFlags const ( - MessageFlagNone MessageFlags = 0 << iota - MessageFlagCrossposted + MessageFlagNone MessageFlags = 0 + MessageFlagCrossposted MessageFlags = 1 << iota MessageFlagIsCrosspost MessageFlagSuppressEmbeds MessageFlagSourceMessageDeleted @@ -99,25 +99,29 @@ const ( ) // Message is a struct for messages sent in discord text-based channels +// todo: missing Member, mention channels, webhook id, activity, application, stickers, referenced_message +// https://discord.com/developers/docs/resources/channel#message-object type Message struct { Disgo Disgo - ID Snowflake `json:"id"` - GuildID *Snowflake `json:"guild_id"` - Reactions []Reactions `json:"reactions"` - Attachments []interface{} `json:"attachments"` - Tts bool `json:"tts"` - Embeds []*Embed `json:"embeds,omitempty"` - CreatedAt time.Time `json:"timestamp"` - MentionEveryone bool `json:"mention_everyone"` - Pinned bool `json:"pinned"` - EditedTimestamp interface{} `json:"edited_timestamp"` - Author User `json:"author"` - MentionRoles []interface{} `json:"mention_roles"` - Content *string `json:"content,omitempty"` - ChannelID Snowflake `json:"channel_id"` - Mentions []interface{} `json:"mentions"` - MessageType MessageType `json:"type"` - MessageReference *MessageReference `json:"message_reference,omitempty"` + ID Snowflake `json:"id"` + GuildID *Snowflake `json:"guild_id"` + Reactions []Reactions `json:"reactions"` + Attachments []interface{} `json:"attachments"` + TTS bool `json:"tts"` + Embeds []*Embed `json:"embeds,omitempty"` + CreatedAt time.Time `json:"timestamp"` + MentionEveryone bool `json:"mention_everyone"` + Pinned bool `json:"pinned"` + EditedTimestamp interface{} `json:"edited_timestamp"` + Author User `json:"author"` + MentionRoles []interface{} `json:"mention_roles"` + Content *string `json:"content,omitempty"` + ChannelID Snowflake `json:"channel_id"` + Mentions []interface{} `json:"mentions"` + Type MessageType `json:"type"` + Flags *MessageFlags `json:"flags"` + MessageReference *MessageReference `json:"message_reference,omitempty"` + Interaction *MessageInteraction `json:"message_interaction,omitempty"` LastUpdated *time.Time } @@ -137,10 +141,6 @@ type MessageInteraction struct { User User `json:"user"` } -// missing Member, mention channels, nonce, webhook id, type, activity, application, message_reference, flags, stickers -// referenced_message, interaction -// https://discord.com/developers/docs/resources/channel#message-object - // Guild gets the guild_events the message_events was sent in func (m Message) Guild() *Guild { if m.GuildID == nil { diff --git a/api/message_cache_policy.go b/api/message_cache_policy.go new file mode 100644 index 00000000..17b4c72f --- /dev/null +++ b/api/message_cache_policy.go @@ -0,0 +1,49 @@ +package api + +import "time" + +// MessageCachePolicy can be used to define your own policy for caching messages +type MessageCachePolicy func(*Message) bool + +// Default member cache policies +var ( + MessageCachePolicyNone MessageCachePolicy = func(_ *Message) bool { return false } + MessageCachePolicyDefault = MessageCachePolicyNone +) + +// Or allows you to combine that policy with another, meaning either needs to be true +func (p MessageCachePolicy) Or(policy MessageCachePolicy) MessageCachePolicy { + return func(message *Message) bool { + return p(message) || policy(message) + } +} + +// And allows you to require both policies to be true for the member to be cached +func (p MessageCachePolicy) And(policy MessageCachePolicy) MessageCachePolicy { + return func(message *Message) bool { + return p(message) && policy(message) + } +} + +// MessageCachePolicyDuration creates a new MessageCachePolicy which caches messages for the give duration +func MessageCachePolicyDuration(duration time.Duration) MessageCachePolicy { + return func(message *Message) bool { + return message.CreatedAt.Add(duration).After(time.Now()) + } +} + +// MessageCachePolicyAny is a shorthand for MessageCachePolicy.Or(MessageCachePolicy).Or(MessageCachePolicy) etc. +func MessageCachePolicyAny(policy MessageCachePolicy, policies ...MessageCachePolicy) MessageCachePolicy { + for _, p := range policies { + policy = policy.Or(p) + } + return policy +} + +// MessageCachePolicyAll is a shorthand for MessageCachePolicy.And(MessageCachePolicy).And(MessageCachePolicy) etc. +func MessageCachePolicyAll(policy MessageCachePolicy, policies ...MessageCachePolicy) MessageCachePolicy { + for _, p := range policies { + policy = policy.And(p) + } + return policy +} diff --git a/api/permissions.go b/api/permissions.go index 0dc051d4..9873e1ec 100644 --- a/api/permissions.go +++ b/api/permissions.go @@ -20,7 +20,7 @@ func (p Permissions) MarshalJSON() ([]byte, error) { return jsonValue, nil } -// UnmarshalJSON unmarshals permissions into a int64 +// UnmarshalJSON unmarshals permissions into an int64 func (p *Permissions) UnmarshalJSON(b []byte) error { var strPermissions string err := json.Unmarshal(b, &strPermissions) @@ -116,6 +116,7 @@ const ( PermissionManageRoles PermissionManageWebhooks PermissionManageEmojis + PermissionUseSlashCommands ) // Constants for the different bit offsets of general permissions diff --git a/internal/cache_impl.go b/internal/cache_impl.go index d09b41ac..1378ec55 100644 --- a/internal/cache_impl.go +++ b/internal/cache_impl.go @@ -27,6 +27,7 @@ func newCacheImpl(disgo api.Disgo, memberCachePolicy api.MemberCachePolicy, mess textChannels: map[api.Snowflake]map[api.Snowflake]*api.TextChannel{}, voiceChannels: map[api.Snowflake]map[api.Snowflake]*api.VoiceChannel{}, storeChannels: map[api.Snowflake]map[api.Snowflake]*api.StoreChannel{}, + emotes: map[api.Snowflake]map[api.Snowflake]*api.Emote{}, } go cache.startCleanup(10 * time.Second) return cache @@ -49,6 +50,7 @@ type CacheImpl struct { textChannels map[api.Snowflake]map[api.Snowflake]*api.TextChannel voiceChannels map[api.Snowflake]map[api.Snowflake]*api.VoiceChannel storeChannels map[api.Snowflake]map[api.Snowflake]*api.StoreChannel + emotes map[api.Snowflake]map[api.Snowflake]*api.Emote } // Disgo returns the current api.Disgo instance @@ -234,6 +236,7 @@ func (c *CacheImpl) CacheGuild(guild *api.Guild) { func (c *CacheImpl) UncacheGuild(guildID api.Snowflake) { delete(c.guilds, guildID) delete(c.members, guildID) + delete(c.voiceStates, guildID) delete(c.roles, guildID) delete(c.categories, guildID) delete(c.textChannels, guildID) @@ -948,8 +951,8 @@ func (c *CacheImpl) FindVoiceChannels(guildID api.Snowflake, check func(u *api.V // Category returns a category from cache by ID func (c *CacheImpl) Category(categoryID api.Snowflake) *api.Category { - for _, guild := range c.categories { - if channel, ok := guild[categoryID]; ok { + for _, guildCategories := range c.categories { + if channel, ok := guildCategories[categoryID]; ok { return channel } } @@ -1008,7 +1011,7 @@ func (c *CacheImpl) AllCategoryCache() map[api.Snowflake]map[api.Snowflake]*api. return c.categories } -//CacheCategory adds a category to the cache +// CacheCategory adds a category to the cache func (c *CacheImpl) CacheCategory(category *api.Category) { if !c.cacheFlags.Has(api.CacheFlagCategories) { return @@ -1022,12 +1025,12 @@ func (c *CacheImpl) CacheCategory(category *api.Category) { } } -//UncacheCategory removes a category from cache +// UncacheCategory removes a category from cache func (c *CacheImpl) UncacheCategory(guildID api.Snowflake, categoryID api.Snowflake) { delete(c.categories[guildID], categoryID) } -//FindCategory finds a category in a guild by custom method +// FindCategory finds a category in a guild by custom method func (c *CacheImpl) FindCategory(guildID api.Snowflake, check func(u *api.Category) bool) *api.Category { for _, category := range c.CategoryCache(guildID) { if check(category) { @@ -1037,7 +1040,7 @@ func (c *CacheImpl) FindCategory(guildID api.Snowflake, check func(u *api.Catego return nil } -//FindCategories finds categories in a guild by custom method +// FindCategories finds categories in a guild by custom method func (c *CacheImpl) FindCategories(guildID api.Snowflake, check func(u *api.Category) bool) []*api.Category { categories := make([]*api.Category, 1) for _, category := range c.CategoryCache(guildID) { @@ -1047,3 +1050,73 @@ func (c *CacheImpl) FindCategories(guildID api.Snowflake, check func(u *api.Cate } return categories } + +// Emote returns a specific emote from the cache +func (c *CacheImpl) Emote(emoteID api.Snowflake) *api.Emote { + for _, guildEmotes := range c.emotes { + if emote, ok := guildEmotes[emoteID]; ok { + return emote + } + } + return nil +} + +// EmotesByName returns all emotes for a guild by name +func (c *CacheImpl) EmotesByName(guildID api.Snowflake, name string, ignoreCase bool) []*api.Emote { + if guildEmotes, ok := c.emotes[guildID]; ok { + if ignoreCase { + name = strings.ToLower(name) + } + emotes := make([]*api.Emote, 1) + for _, emote := range guildEmotes { + if ignoreCase && strings.ToLower(emote.Name) == name || !ignoreCase && emote.Name == name { + emotes = append(emotes, emote) + } + } + return emotes + } + return nil +} + +// Emotes returns all cached emotes for a guild +func (c *CacheImpl) Emotes(guildID api.Snowflake) []*api.Emote { + if guildEmotes, ok := c.emotes[guildID]; ok { + emotes := make([]*api.Emote, len(guildEmotes)) + i := 0 + for _, emote := range guildEmotes { + emotes[i] = emote + i++ + } + return emotes + } + return nil +} + +// EmoteCache returns the emote cache for a specific guild +func (c *CacheImpl) EmoteCache(guildID api.Snowflake) map[api.Snowflake]*api.Emote { + return c.emotes[guildID] +} + +// AllEmoteCache returns the full emote cache +func (c *CacheImpl) AllEmoteCache() map[api.Snowflake]map[api.Snowflake]*api.Emote { + return c.emotes +} + +// CacheEmote adds an Emote to the api.Cache if emoji caches are used +func (c *CacheImpl) CacheEmote(emote *api.Emote) { + if !c.cacheFlags.Has(api.CacheFlagEmotes) { + return + } + if guildEmotes, ok := c.emotes[emote.GuildID]; ok { + if guildEmote, ok := guildEmotes[emote.ID]; ok { + *guildEmote = *emote + return + } + guildEmotes[emote.ID] = emote + } +} + +// UncacheEmote removes an Emote from api.Cache +func (c *CacheImpl) UncacheEmote(guildID api.Snowflake, emoteID api.Snowflake) { + delete(c.emotes[guildID], emoteID) +} diff --git a/internal/disgo_impl.go b/internal/disgo_impl.go index 9062ed60..31cda350 100644 --- a/internal/disgo_impl.go +++ b/internal/disgo_impl.go @@ -31,7 +31,7 @@ func New(token string, options api.Options) (api.Disgo, error) { disgo.restClient = newRestClientImpl(disgo, token) - disgo.eventManager = newEventManagerImpl(disgo, make([]api.EventListener, 0)) + disgo.eventManager = newEventManagerImpl(disgo, []api.EventListener{}) if options.EnableWebhookInteractions { disgo.webhookServer = newWebhookServerImpl(disgo, options.ListenURL, options.ListenPort, options.PublicKey) diff --git a/internal/gateway_impl.go b/internal/gateway_impl.go index 45eae0db..f1944dab 100644 --- a/internal/gateway_impl.go +++ b/internal/gateway_impl.go @@ -19,8 +19,8 @@ import ( func newGatewayImpl(disgo api.Disgo) api.Gateway { return &GatewayImpl{ - disgo: disgo, - connectionStatus: api.Unconnected, + disgo: disgo, + status: api.Unconnected, } } @@ -29,7 +29,7 @@ type GatewayImpl struct { disgo api.Disgo conn *websocket.Conn quit chan interface{} - connectionStatus api.ConnectionStatus + status api.ConnectionStatus heartbeatInterval time.Duration lastHeartbeatSent time.Time lastHeartbeatReceived time.Time @@ -45,17 +45,16 @@ func (g *GatewayImpl) Disgo() api.Disgo { func (g *GatewayImpl) reconnect(delay time.Duration) { go func() { - g.Close() - time.Sleep(delay) - if g.Status() != api.Connecting && g.Status() != api.Reconnecting { + if g.Status() == api.Connecting || g.Status() == api.Reconnecting { log.Error("tried to reconnect gateway while connecting/reconnecting") return } log.Info("reconnecting gateway...") if err := g.Open(); err != nil { log.Errorf("failed to reconnect gateway: %s", err) + g.status = api.Disconnected g.reconnect(delay * 2) } }() @@ -64,9 +63,9 @@ func (g *GatewayImpl) reconnect(delay time.Duration) { // Open initializes the client and connection to discord func (g *GatewayImpl) Open() error { if g.lastSequenceReceived == nil || g.sessionID == nil { - g.connectionStatus = api.Connecting + g.status = api.Connecting } else { - g.connectionStatus = api.Reconnecting + g.status = api.Reconnecting } log.Info("starting ws...") @@ -106,7 +105,7 @@ func (g *GatewayImpl) Open() error { }) g.conn = wsConn - g.connectionStatus = api.WaitingForHello + g.status = api.WaitingForHello mt, data, err := g.conn.ReadMessage() if err != nil { @@ -130,7 +129,7 @@ func (g *GatewayImpl) Open() error { g.heartbeatInterval = eventData.HeartbeatInterval * time.Millisecond if g.lastSequenceReceived == nil || g.sessionID == nil { - g.connectionStatus = api.Identifying + g.status = api.Identifying if err = wsConn.WriteJSON( api.NewGatewayCommand(api.OpIdentify, api.IdentifyCommand{ Token: g.Disgo().Token(), @@ -147,7 +146,7 @@ func (g *GatewayImpl) Open() error { return err } } else { - g.connectionStatus = api.Resuming + g.status = api.Resuming if err = wsConn.WriteJSON( api.NewGatewayCommand(api.OpIdentify, api.ResumeCommand{ Token: g.Disgo().Token(), @@ -159,7 +158,7 @@ func (g *GatewayImpl) Open() error { } } - g.connectionStatus = api.WaitingForReady + g.status = api.WaitingForReady g.quit = make(chan interface{}) go g.heartbeat() @@ -170,7 +169,27 @@ func (g *GatewayImpl) Open() error { // Status returns the gateway connection status func (g *GatewayImpl) Status() api.ConnectionStatus { - return g.connectionStatus + return g.status +} + +// Latency returns the api.Gateway latency +func (g *GatewayImpl) Latency() time.Duration { + return g.lastHeartbeatSent.Sub(g.lastHeartbeatReceived) +} + +// Close cleans up the gateway internals +func (g *GatewayImpl) Close() { + g.status = api.Disconnected + if g.quit != nil { + log.Info("closing gateway goroutines...") + close(g.quit) + log.Info("closed gateway goroutines") + } + if g.conn != nil { + if err := g.conn.Close(); err != nil { + log.Errorf("error while closing wsconn: %s", err) + } + } } func (g *GatewayImpl) heartbeat() { @@ -198,29 +217,12 @@ func (g *GatewayImpl) heartbeat() { } } -// Close cleans up the gateway internals -func (g *GatewayImpl) Close() { - if g.quit != nil { - log.Info("closing gateway goroutines...") - close(g.quit) - log.Info("closed gateway goroutines") - } - if g.conn != nil { - _ = g.conn.Close() - } -} - -// Latency returns the api.Gateway latency -func (g *GatewayImpl) Latency() time.Duration { - return g.lastHeartbeatSent.Sub(g.lastHeartbeatReceived) -} - func (g *GatewayImpl) sendHeartbeat() { log.Debug("sending heartbeat...") if err := g.conn.WriteJSON(api.NewGatewayCommand(api.OpHeartbeat, g.lastSequenceReceived)); err != nil { log.Errorf("failed to send heartbeat with error: %s", err) - + g.Close() g.reconnect(1 * time.Second) } g.lastHeartbeatSent = time.Now().UTC() @@ -246,6 +248,7 @@ func (g *GatewayImpl) listen() { mt, data, err := g.conn.ReadMessage() if err != nil { log.Errorf("error while reading from ws. error: %s", err) + g.Close() g.reconnect(1 * time.Second) return } @@ -289,6 +292,8 @@ func (g *GatewayImpl) listen() { g.sendHeartbeat() case api.OpReconnect: + g.Close() + g.reconnect(0) log.Debugf("received: OpReconnect") case api.OpInvalidSession: diff --git a/internal/handlers/guild_create_handler.go b/internal/handlers/guild_create_handler.go index ea2ffa73..20e295ec 100644 --- a/internal/handlers/guild_create_handler.go +++ b/internal/handlers/guild_create_handler.go @@ -98,7 +98,7 @@ func (h GuildCreateHandler) Handle(disgo api.Disgo, eventManager api.EventManage }*/ genericGuildEvent := events.GenericGuildEvent{ - GenericEvent: api.NewEvent(disgo), + GenericEvent: events.NewEvent(disgo), GuildID: guild.ID, } diff --git a/internal/handlers/guild_delete_handler.go b/internal/handlers/guild_delete_handler.go index 4311ccd4..c3188b17 100644 --- a/internal/handlers/guild_delete_handler.go +++ b/internal/handlers/guild_delete_handler.go @@ -29,7 +29,7 @@ func (h GuildDeleteHandler) Handle(disgo api.Disgo, eventManager api.EventManage disgo.Cache().Guild(guild.ID).Unavailable = true eventManager.Dispatch(events.GuildUnavailableEvent{ GenericGuildEvent: events.GenericGuildEvent{ - GenericEvent: api.NewEvent(disgo), + GenericEvent: events.NewEvent(disgo), GuildID: guild.ID, }, }) @@ -38,7 +38,7 @@ func (h GuildDeleteHandler) Handle(disgo api.Disgo, eventManager api.EventManage disgo.Cache().UncacheGuild(guild.ID) genericGuildEvent := events.GenericGuildEvent{ - GenericEvent: api.NewEvent(disgo), + GenericEvent: events.NewEvent(disgo), GuildID: guild.ID, } diff --git a/internal/handlers/guild_member_add_handler.go b/internal/handlers/guild_member_add_handler.go index 8bd174e6..c21766b7 100644 --- a/internal/handlers/guild_member_add_handler.go +++ b/internal/handlers/guild_member_add_handler.go @@ -28,7 +28,7 @@ func (h GuildMemberAddHandler) Handle(disgo api.Disgo, eventManager api.EventMan disgo.Cache().CacheMember(member) genericGuildEvent := events.GenericGuildEvent{ - GenericEvent: api.NewEvent(disgo), + GenericEvent: events.NewEvent(disgo), GuildID: member.GuildID, } eventManager.Dispatch(genericGuildEvent) diff --git a/internal/handlers/guild_member_remove_handler.go b/internal/handlers/guild_member_remove_handler.go index d0602d57..b9837c45 100644 --- a/internal/handlers/guild_member_remove_handler.go +++ b/internal/handlers/guild_member_remove_handler.go @@ -34,7 +34,7 @@ func (h GuildMemberRemoveHandler) Handle(disgo api.Disgo, eventManager api.Event disgo.Cache().UncacheMember(member.GuildID, member.User.ID) genericGuildEvent := events.GenericGuildEvent{ - GenericEvent: api.NewEvent(disgo), + GenericEvent: events.NewEvent(disgo), GuildID: member.GuildID, } eventManager.Dispatch(genericGuildEvent) diff --git a/internal/handlers/guild_member_update_handler.go b/internal/handlers/guild_member_update_handler.go index e21bd06b..18f190a5 100644 --- a/internal/handlers/guild_member_update_handler.go +++ b/internal/handlers/guild_member_update_handler.go @@ -30,7 +30,7 @@ func (h GuildMemberUpdateHandler) Handle(disgo api.Disgo, eventManager api.Event disgo.Cache().CacheMember(member) genericGuildEvent := events.GenericGuildEvent{ - GenericEvent: api.NewEvent(disgo), + GenericEvent: events.NewEvent(disgo), GuildID: member.GuildID, } eventManager.Dispatch(genericGuildEvent) diff --git a/internal/handlers/guild_role_create_handler.go b/internal/handlers/guild_role_create_handler.go index 4e59bb0b..b4e141e8 100644 --- a/internal/handlers/guild_role_create_handler.go +++ b/internal/handlers/guild_role_create_handler.go @@ -34,7 +34,7 @@ func (h GuildRoleCreateHandler) Handle(disgo api.Disgo, eventManager api.EventMa disgo.Cache().CacheRole(roleCreateData.Role) genericGuildEvent := events.GenericGuildEvent{ - GenericEvent: api.NewEvent(disgo), + GenericEvent: events.NewEvent(disgo), GuildID: roleCreateData.GuildID, } eventManager.Dispatch(genericGuildEvent) diff --git a/internal/handlers/guild_role_delete_handler.go b/internal/handlers/guild_role_delete_handler.go index cc756d6b..175579c2 100644 --- a/internal/handlers/guild_role_delete_handler.go +++ b/internal/handlers/guild_role_delete_handler.go @@ -34,7 +34,7 @@ func (h GuildRoleDeleteHandler) Handle(disgo api.Disgo, eventManager api.EventMa disgo.Cache().UncacheRole(roleDeleteData.GuildID, roleDeleteData.RoleID) genericGuildEvent := events.GenericGuildEvent{ - GenericEvent: api.NewEvent(disgo), + GenericEvent: events.NewEvent(disgo), GuildID: roleDeleteData.GuildID, } eventManager.Dispatch(genericGuildEvent) diff --git a/internal/handlers/guild_role_update_handler.go b/internal/handlers/guild_role_update_handler.go index cd790aaa..07b32574 100644 --- a/internal/handlers/guild_role_update_handler.go +++ b/internal/handlers/guild_role_update_handler.go @@ -36,7 +36,7 @@ func (h GuildRoleUpdateHandler) Handle(disgo api.Disgo, eventManager api.EventMa disgo.Cache().CacheRole(roleUpdateData.Role) genericGuildEvent := events.GenericGuildEvent{ - GenericEvent: api.NewEvent(disgo), + GenericEvent: events.NewEvent(disgo), GuildID: roleUpdateData.GuildID, } eventManager.Dispatch(genericGuildEvent) diff --git a/internal/handlers/guild_update_handler.go b/internal/handlers/guild_update_handler.go index f7a08a71..e1e14f3b 100644 --- a/internal/handlers/guild_update_handler.go +++ b/internal/handlers/guild_update_handler.go @@ -29,7 +29,7 @@ func (h GuildUpdateHandler) Handle(disgo api.Disgo, eventManager api.EventManage disgo.Cache().CacheGuild(guild) genericGuildEvent := events.GenericGuildEvent{ - GenericEvent: api.NewEvent(disgo), + GenericEvent: events.NewEvent(disgo), GuildID: guild.ID, } diff --git a/internal/handlers/interaction_create_handler.go b/internal/handlers/interaction_create_handler.go index 9856c655..535a393a 100644 --- a/internal/handlers/interaction_create_handler.go +++ b/internal/handlers/interaction_create_handler.go @@ -71,7 +71,7 @@ func handleInteraction(disgo api.Disgo, eventManager api.EventManager, c chan in } genericInteractionEvent := events.GenericInteractionEvent{ - GenericEvent: api.NewEvent(disgo), + GenericEvent: events.NewEvent(disgo), Interaction: *interaction, } eventManager.Dispatch(genericInteractionEvent) diff --git a/internal/handlers/message_create_handler.go b/internal/handlers/message_create_handler.go index 175f0ead..f2c7fbb3 100644 --- a/internal/handlers/message_create_handler.go +++ b/internal/handlers/message_create_handler.go @@ -26,14 +26,14 @@ func (h MessageCreateHandler) Handle(disgo api.Disgo, eventManager api.EventMana } genericMessageEvent := events.GenericMessageEvent{ - GenericEvent: api.NewEvent(disgo), + GenericEvent: events.NewEvent(disgo), MessageChannelID: message.ChannelID, MessageID: message.ID, } eventManager.Dispatch(genericMessageEvent) genericGuildEvent := events.GenericGuildEvent{ - GenericEvent: api.NewEvent(disgo), + GenericEvent: events.NewEvent(disgo), GuildID: *message.GuildID, } eventManager.Dispatch(genericGuildEvent) diff --git a/testbot/testbot.go b/testbot/testbot.go index 6141fb15..7aedc653 100644 --- a/testbot/testbot.go +++ b/testbot/testbot.go @@ -15,9 +15,8 @@ import ( func main() { log.Infof("starting testbot...") - token := os.Getenv("token") - dgo, err := disgo.NewBuilder(token). + dgo, err := disgo.NewBuilder(os.Getenv("token")). SetLogLevel(log.InfoLevel). SetIntents(api.IntentsGuilds | api.IntentsGuildMessages | api.IntentsGuildMembers). SetMemberCachePolicy(api.MemberCachePolicyAll). @@ -139,7 +138,7 @@ func slashCommandListener(event *events.SlashCommandEvent) { time.Sleep(1 * time.Second) _, _ = event.SendFollowup(api.NewFollowupMessageBuilder(). SetEphemeral(true). - SetContent("followup 4 only you can see"). + SetContent("followup 2 only you can see"). Build(), ) }() @@ -171,7 +170,6 @@ func slashCommandListener(event *events.SlashCommandEvent) { api.NewEmbedBuilder().SetColor(16711680).SetDescriptionf("Failed to remove %s from %s", role, user).Build(), ).Build()) } - } } From df9f67277710541176c17b1e4e49250669413bd1 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Wed, 7 Apr 2021 02:27:21 +0200 Subject: [PATCH 24/65] added missing docu --- api/emote.go | 1 + 1 file changed, 1 insertion(+) diff --git a/api/emote.go b/api/emote.go index 7cbe613f..5df8157f 100644 --- a/api/emote.go +++ b/api/emote.go @@ -9,6 +9,7 @@ type Emote struct { Animated bool } +// Guild returns the Guild of the Emote from the Cache func (e Emote) Guild() *Guild { return e.Disgo.Cache().Guild(e.GuildID) } From a9700be39c21d6414aabdd9fff54d3404eaf85e2 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Wed, 7 Apr 2021 19:32:20 +0200 Subject: [PATCH 25/65] added slash command permissions, convenient command funcs and token protection --- api/activity.go | 4 +- api/command.go | 148 ++++++++++++++++ api/command_thread.go | 17 -- api/disgo.go | 16 +- api/disgo_builder.go | 8 +- api/embed.go | 8 + api/endpoints/endpoints.go | 7 +- api/endpoints/route.go | 8 +- api/endpoints/token.go | 24 +++ api/events/interaction_events.go | 20 +-- api/gateway_commands.go | 10 +- api/guild.go | 36 +++- api/interaction.go | 12 +- api/restclient.go | 37 ++-- api/slash_command.go | 41 ----- disgo.go | 5 +- go.mod | 1 + go.sum | 4 + internal/disgo_builder_impl.go | 28 ++-- internal/disgo_impl.go | 30 ++-- .../handlers/interaction_create_handler.go | 4 +- internal/restclient_impl.go | 62 ++++--- internal/util.go | 9 +- testbot/testbot.go | 158 ++++++++++++++---- 24 files changed, 499 insertions(+), 198 deletions(-) create mode 100644 api/command.go delete mode 100644 api/command_thread.go create mode 100644 api/endpoints/token.go delete mode 100644 api/slash_command.go diff --git a/api/activity.go b/api/activity.go index c13c6e67..dba05130 100644 --- a/api/activity.go +++ b/api/activity.go @@ -2,7 +2,7 @@ package api import "time" -// ActivityType represents the status of a user, one of Game, Streaming, Listening, Custom or Competing +// ActivityType represents the status of a user, one of Game, Streaming, Listening, Watching, Custom or Competing type ActivityType int // Constants for activities @@ -10,7 +10,7 @@ const ( Game ActivityType = iota Streaming Listening - _ + Watching Custom Competing ) diff --git a/api/command.go b/api/command.go new file mode 100644 index 00000000..38c10a27 --- /dev/null +++ b/api/command.go @@ -0,0 +1,148 @@ +package api + +import "errors" + +var noDisgoInstance = errors.New("no disgo instance injected") + +// Command is the base "command" model that belongs to an application. +type Command struct { + Disgo Disgo + GuildID *Snowflake + ID Snowflake `json:"id,omitempty"` + ApplicationID Snowflake `json:"application_id,omitempty"` + Name string `json:"name"` + Description string `json:"description"` + DefaultPermission bool `json:"default_permission"` + Options []*CommandOption `json:"options,omitempty"` +} + +func (c *Command) Create() error { + if c.Disgo == nil { + return noDisgoInstance + } + var rC *Command + var err error + if c.GuildID == nil { + rC, err = c.Disgo.RestClient().CreateGlobalCommand(c.Disgo.SelfUserID(), *c) + + } else { + rC, err = c.Disgo.RestClient().CreateGuildCommand(c.Disgo.SelfUserID(), *c.GuildID, *c) + } + if err != nil { + return err + } + *c = *rC + return nil +} + +func (c *Command) Get() error { + if c.Disgo == nil { + return noDisgoInstance + } + var rC *Command + var err error + if c.GuildID == nil { + rC, err = c.Disgo.RestClient().GetGlobalCommand(c.Disgo.SelfUserID(), c.ID) + + } else { + rC, err = c.Disgo.RestClient().GetGuildCommand(c.Disgo.SelfUserID(), *c.GuildID, c.ID) + } + if err != nil { + return err + } + *c = *rC + return nil +} + +func (c *Command) Update() error { + if c.Disgo == nil { + return noDisgoInstance + } + var rC *Command + var err error + if c.GuildID == nil { + rC, err = c.Disgo.RestClient().EditGlobalCommand(c.Disgo.SelfUserID(), c.ID, *c) + + } else { + rC, err = c.Disgo.RestClient().EditGuildCommand(c.Disgo.SelfUserID(), *c.GuildID, c.ID, *c) + } + if err != nil { + return err + } + *c = *rC + return nil +} + +func (c Command) Delete() error { + if c.Disgo == nil { + return noDisgoInstance + } + if c.GuildID == nil { + return c.Disgo.RestClient().DeleteGlobalCommand(c.Disgo.SelfUserID(), c.ID) + + } + return c.Disgo.RestClient().DeleteGuildCommand(c.Disgo.SelfUserID(), *c.GuildID, c.ID) +} + +// CommandOptionType specifies the type of the arguments used in Command.Options +type CommandOptionType int + +// Constants for each slash command option type +const ( + CommandOptionTypeSubCommand CommandOptionType = iota + 1 + CommandOptionTypeSubCommandGroup + CommandOptionTypeString + CommandOptionTypeInteger + CommandOptionTypeBoolean + CommandOptionTypeUser + CommandOptionTypeChannel + CommandOptionTypeRole +) + +// CommandOption are the arguments used in Command.Options +type CommandOption struct { + Type CommandOptionType `json:"type"` + Name string `json:"name"` + Description string `json:"description"` + Required bool `json:"required,omitempty"` + Choices []OptionChoice `json:"choices,omitempty"` + Options []CommandOption `json:"options,omitempty"` +} + +// OptionChoice contains the data for a user using your command +type OptionChoice struct { + Name string `json:"name"` + Value interface{} `json:"value"` +} + +// GuildCommandPermissions holds all permissions for a Command +type GuildCommandPermissions struct { + ID Snowflake `json:"id"` + ApplicationID Snowflake `json:"application_id"` + GuildID Snowflake `json:"guild_id"` + Permissions []CommandPermission `json:"permissions"` +} + +// CommandPermissionType is the type of the CommandPermission +type CommandPermissionType int + +const ( + CommandPermissionTypeRole = iota + 1 + CommandPermissionTypeUser +) + +// CommandPermission holds a User or Role and if they are allowed to use the Command +type CommandPermission struct { + ID Snowflake `json:"id"` + Type CommandPermissionType `json:"type"` + Permission bool `json:"permission"` +} + +// SetGuildCommandsPermissions holds a slice of SetGuildCommandPermissions +type SetGuildCommandsPermissions []SetGuildCommandPermissions + +// SetGuildCommandPermissions is used to update CommandPermission ID should be omitted fro bulk update +type SetGuildCommandPermissions struct { + ID Snowflake `json:"id,omitempty"` + Permissions []CommandPermission `json:"permissions"` +} diff --git a/api/command_thread.go b/api/command_thread.go deleted file mode 100644 index a73c69b2..00000000 --- a/api/command_thread.go +++ /dev/null @@ -1,17 +0,0 @@ -package api - -/*import ( - "github.com/chebyrash/promise" - - "github.com/DisgoOrg/disgo/internal/events" -) - -// CommandThread allows you to follow up Interactions (https://discord.com/developers/docs/interactions/slash-commands) -type CommandThread interface { - Disgo() Disgo - GenericEvent() events.SlashCommandEvent - Ephemeral(ephemeral bool) CommandThread - SendMessage() *promise.Promise - EditOriginal(message_events string) *promise.Promise - DeleteOriginal() *promise.Promise -}*/ diff --git a/api/disgo.go b/api/disgo.go index 0953fe73..4caf5072 100644 --- a/api/disgo.go +++ b/api/disgo.go @@ -5,6 +5,8 @@ import ( "runtime" "strings" "time" + + "github.com/DisgoOrg/disgo/api/endpoints" ) // Disgo is the main discord interface @@ -12,7 +14,7 @@ type Disgo interface { Connect() error Start() Close() - Token() string + Token() endpoints.Token Gateway() Gateway RestClient() RestClient WebhookServer() WebhookServer @@ -26,12 +28,12 @@ type Disgo interface { HeartbeatLatency() time.Duration LargeThreshold() int - GetCommand(commandID Snowflake) (*SlashCommand, error) - GetCommands() ([]*SlashCommand, error) - CreateCommand(command SlashCommand) (*SlashCommand, error) - EditCommand(commandID Snowflake, command SlashCommand) (*SlashCommand, error) - DeleteCommand(command SlashCommand) (*SlashCommand, error) - SetCommands(commands ...SlashCommand) ([]*SlashCommand, error) + GetCommand(commandID Snowflake) (*Command, error) + GetCommands() ([]*Command, error) + CreateCommand(command Command) (*Command, error) + EditCommand(commandID Snowflake, command Command) (*Command, error) + DeleteCommand(command Command) (*Command, error) + SetCommands(commands ...Command) ([]*Command, error) } // EventHandler provides info about the EventHandler diff --git a/api/disgo_builder.go b/api/disgo_builder.go index f4b47310..0407c9c4 100644 --- a/api/disgo_builder.go +++ b/api/disgo_builder.go @@ -1,11 +1,15 @@ package api -import log "github.com/sirupsen/logrus" +import ( + log "github.com/sirupsen/logrus" + + "github.com/DisgoOrg/disgo/api/endpoints" +) // DisgoBuilder allows you to create a Disgo client through a series of methods type DisgoBuilder interface { SetLogLevel(level log.Level) DisgoBuilder - SetToken(token string) DisgoBuilder + SetToken(token endpoints.Token) DisgoBuilder SetIntents(intents Intents) DisgoBuilder SetVoiceDispatchInterceptor(VoiceDispatchInterceptor) DisgoBuilder SetEventManager(eventManager EventManager) DisgoBuilder diff --git a/api/embed.go b/api/embed.go index c6d7aa17..78626f05 100644 --- a/api/embed.go +++ b/api/embed.go @@ -155,6 +155,14 @@ func (b *EmbedBuilder) AddField(name string, value string, inline bool) *EmbedBu return b } +// SetField sets a field to the EmbedBuilder by name and value +func (b *EmbedBuilder) SetField(index int, name string, value string, inline bool) *EmbedBuilder { + if len(b.Fields) > index { + b.Fields[index] = &EmbedField{name, value, &inline} + } + return b +} + // AddFields adds multiple fields to the EmbedBuilder func (b *EmbedBuilder) AddFields(f *EmbedField, fs ...*EmbedField) *EmbedBuilder { b.Fields = append(b.Fields, f) diff --git a/api/endpoints/endpoints.go b/api/endpoints/endpoints.go index 1b8919e4..c3be81db 100644 --- a/api/endpoints/endpoints.go +++ b/api/endpoints/endpoints.go @@ -32,6 +32,11 @@ var ( EditGuildCommand = NewAPIRoute(PATCH, "/applications/{application.id}/guilds/{guild.id}/commands/{command.id}") DeleteGuildCommand = NewAPIRoute(DELETE, "/applications/{application.id}/guilds/{guild.id}/commands") + GetGuildCommandPermissions = NewAPIRoute(GET, "/applications/{application.id}/guilds/{guild.id}/commands/permissions") + GetGuildCommandPermission = NewAPIRoute(GET, "/applications/{application.id}/guilds/{guild.id}/commands/{command.id}/permissions") + SetGuildCommandsPermissions = NewAPIRoute(PUT, "/applications/{application.id}/guilds/{guild.id}/commands/permissions") + SetGuildCommandPermissions = NewAPIRoute(PUT, "/applications/{application.id}/guilds/{guild.id}/commands/{command.id}/permissions") + CreateInteractionResponse = NewAPIRoute(POST, "/interactions/{interaction.id}/{interaction.token}/callback") EditInteractionResponse = NewAPIRoute(PATCH, "/webhooks/{application.id}/{interaction.token}/messages/@original") DeleteInteractionResponse = NewAPIRoute(DELETE, "/webhooks/{application.id}/{interaction.token}/messages/@original") @@ -87,7 +92,7 @@ var ( GetAuditLogs = NewAPIRoute(GET, "/guilds/{guild.id}/audit-logs") - GetVoiceRegions = NewAPIRoute(GET, "guilds/{guild.id}/regions") + GetVoiceRegions = NewAPIRoute(GET, "/guilds/{guild.id}/regions") GetIntegrations = NewAPIRoute(GET, "/guilds/{guild.id}/integrations") CreateIntegration = NewAPIRoute(POST, "/guilds/{guild.id}/integrations") diff --git a/api/endpoints/route.go b/api/endpoints/route.go index c68d6538..234ec17c 100644 --- a/api/endpoints/route.go +++ b/api/endpoints/route.go @@ -24,7 +24,13 @@ func (r Route) Compile(args ...interface{}) CompiledRoute { for _, arg := range args { start := strings.Index(route, "{") end := strings.Index(route, "}") - route = route[:start] + fmt.Sprint(arg) + route[end+1:] + var value string + if t, ok := arg.(Token); ok { + value = string(t) + } else { + value = fmt.Sprint(arg) + } + route = route[:start] + value + route[end+1:] } } diff --git a/api/endpoints/token.go b/api/endpoints/token.go new file mode 100644 index 00000000..8fa9f5a8 --- /dev/null +++ b/api/endpoints/token.go @@ -0,0 +1,24 @@ +package endpoints + +import ( + "strings" +) + +type Token string + +func (t Token) MarshalJSON() ([]byte, error) { + return []byte("\""+t+"\""), nil +} + +func (t *Token) UnmarshalJSON(raw []byte) error { + *t = Token(strings.ReplaceAll(string(raw), "\"", "")) + return nil +} + +func (t Token) String() string { + return strings.Repeat("*", len(t)) +} + +func (t Token) GoString() string { + return t.String() +} diff --git a/api/events/interaction_events.go b/api/events/interaction_events.go index fc0d5406..fd50cf75 100644 --- a/api/events/interaction_events.go +++ b/api/events/interaction_events.go @@ -52,7 +52,7 @@ func (e GenericInteractionEvent) GuildChannel() *api.GuildChannel { return e.Disgo().Cache().GuildChannel(*e.Interaction.ChannelID) } -// SlashCommandEvent indicates a slash api.SlashCommand was ran in a api.Guild +// SlashCommandEvent indicates a slash api.Command was ran in a api.Guild type SlashCommandEvent struct { GenericInteractionEvent ResponseChannel chan interface{} @@ -69,7 +69,7 @@ type SlashCommandEvent struct { type Option struct { Resolved *api.Resolved Name string - Type api.SlashCommandOptionType + Type api.CommandOptionType Value interface{} } @@ -162,7 +162,7 @@ func (o Option) StoreChannel() *api.StoreChannel { return &api.StoreChannel{GuildChannel: api.GuildChannel{Channel: *channel}} } -// CommandPath returns the api.SlashCommand path +// CommandPath returns the api.Command path func (e SlashCommandEvent) CommandPath() string { path := e.CommandName if e.SubCommandName != nil { @@ -174,17 +174,17 @@ func (e SlashCommandEvent) CommandPath() string { return path } -// OptionByName returns an Option by name -func (e SlashCommandEvent) OptionByName(name string) *Option { - options := e.OptionsByName(name) +// Option returns an Option by name +func (e SlashCommandEvent) Option(name string) *Option { + options := e.OptionN(name) if len(options) == 0 { return nil } return options[0] } -// OptionsByName returns Option(s) by name -func (e SlashCommandEvent) OptionsByName(name string) []*Option { +// OptionN returns Option(s) by name +func (e SlashCommandEvent) OptionN(name string) []*Option { options := make([]*Option, 0) for _, option := range e.Options { if option.Name == name { @@ -194,8 +194,8 @@ func (e SlashCommandEvent) OptionsByName(name string) []*Option { return options } -// OptionsByType returns Option(s) by api.SlashCommandOptionType -func (e SlashCommandEvent) OptionsByType(optionType api.SlashCommandOptionType) []*Option { +// OptionsT returns Option(s) by api.CommandOptionType +func (e SlashCommandEvent) OptionsT(optionType api.CommandOptionType) []*Option { options := make([]*Option, 0) for _, option := range e.Options { if option.Type == optionType { diff --git a/api/gateway_commands.go b/api/gateway_commands.go index d06342ab..ced112df 100644 --- a/api/gateway_commands.go +++ b/api/gateway_commands.go @@ -1,5 +1,7 @@ package api +import "github.com/DisgoOrg/disgo/api/endpoints" + // NewGatewayCommand returns a new GatewayCommand struct with the given payload func NewGatewayCommand(op GatewayOp, d interface{}) GatewayCommand { return GatewayCommand{ @@ -20,7 +22,7 @@ type GatewayCommand struct { // IdentifyCommand is the data used in IdentifyCommand type IdentifyCommand struct { - Token string `json:"token"` + Token endpoints.Token `json:"token"` Properties IdentifyCommandDataProperties `json:"properties"` Compress bool `json:"compress,omitempty"` LargeThreshold int `json:"large_threshold,omitempty"` @@ -40,9 +42,9 @@ type IdentifyCommandDataProperties struct { // ResumeCommand is used to resume a connection to discord in the case that you are disconnected. Is automatically // handled by the library and should rarely be used. type ResumeCommand struct { - Token string `json:"token"` - SessionID string `json:"session_id"` - Seq int `json:"seq"` + Token endpoints.Token `json:"token"` + SessionID string `json:"session_id"` + Seq int `json:"seq"` } // HeartbeatCommand is used to ensure the websocket connection remains open, and disconnect if not. diff --git a/api/guild.go b/api/guild.go index 0d3c9275..d2b8f234 100644 --- a/api/guild.go +++ b/api/guild.go @@ -196,31 +196,51 @@ func (g Guild) IconURL() *string { } // GetCommand fetches a specific guild command -func (g Guild) GetCommand(commandID Snowflake) (*SlashCommand, error) { +func (g Guild) GetCommand(commandID Snowflake) (*Command, error) { return g.Disgo.RestClient().GetGuildCommand(g.Disgo.SelfUserID(), g.ID, commandID) } // GetCommands fetches all guild commands -func (g Guild) GetCommands() ([]*SlashCommand, error) { +func (g Guild) GetCommands() ([]*Command, error) { return g.Disgo.RestClient().GetGuildCommands(g.Disgo.SelfUserID(), g.ID) } // CreateCommand creates a new command for this guild -func (g Guild) CreateCommand(command SlashCommand) (*SlashCommand, error) { - return g.Disgo.RestClient().CreateGuildGuildCommand(g.Disgo.SelfUserID(), g.ID, command) +func (g Guild) CreateCommand(command Command) (*Command, error) { + return g.Disgo.RestClient().CreateGuildCommand(g.Disgo.SelfUserID(), g.ID, command) } // EditCommand edits a specific guild command -func (g Guild) EditCommand(commandID Snowflake, command SlashCommand) (*SlashCommand, error) { +func (g Guild) EditCommand(commandID Snowflake, command Command) (*Command, error) { return g.Disgo.RestClient().EditGuildCommand(g.Disgo.SelfUserID(), g.ID, commandID, command) } // DeleteCommand creates a new command for this guild -func (g Guild) DeleteCommand(command SlashCommand) (*SlashCommand, error) { - return g.Disgo.RestClient().CreateGuildGuildCommand(g.Disgo.SelfUserID(), g.ID, command) +func (g Guild) DeleteCommand(command Command) (*Command, error) { + return g.Disgo.RestClient().CreateGuildCommand(g.Disgo.SelfUserID(), g.ID, command) } // SetCommands overrides all commands for this guild -func (g Guild) SetCommands(commands ...SlashCommand) ([]*SlashCommand, error) { +func (g Guild) SetCommands(commands ...Command) ([]*Command, error) { return g.Disgo.RestClient().SetGuildCommands(g.Disgo.SelfUserID(), g.ID, commands...) } + +// GetCommandsPermissions returns the CommandPermission for a all Command(s) in a guild +func (g Guild) GetCommandsPermissions() ([]*CommandPermission, error) { + return g.Disgo.RestClient().GetGuildCommandsPermissions(g.Disgo.SelfUserID(), g.ID) +} + +// GetCommandPermissions returns the CommandPermission for a specific Command in a guild +func (g Guild) GetCommandPermissions(commandID Snowflake) (*CommandPermission, error) { + return g.Disgo.RestClient().GetGuildCommandPermissions(g.Disgo.SelfUserID(), g.ID, commandID) +} + +// SetCommandsPermissions sets the GuildCommandPermissions for a all Command(s) +func (g Guild) SetCommandsPermissions(commandPermissions ...SetGuildCommandPermissions) ([]*GuildCommandPermissions, error) { + return g.Disgo.RestClient().SetGuildCommandsPermissions(g.Disgo.SelfUserID(), g.ID, commandPermissions...) +} + +// SetCommandPermissions sets the GuildCommandPermissions for a specific Command +func (g Guild) SetCommandPermissions(commandID Snowflake, permissions SetGuildCommandPermissions) (*GuildCommandPermissions, error) { + return g.Disgo.RestClient().SetGuildCommandPermissions(g.Disgo.SelfUserID(), g.ID, commandID, permissions) +} diff --git a/api/interaction.go b/api/interaction.go index 39fee1fc..96f2bee8 100644 --- a/api/interaction.go +++ b/api/interaction.go @@ -1,5 +1,7 @@ package api +import "github.com/DisgoOrg/disgo/api/endpoints" + // InteractionType is the type of Interaction type InteractionType int @@ -18,7 +20,7 @@ type Interaction struct { ChannelID *Snowflake `json:"channel_id,omitempty"` Member *Member `json:"member,omitempty"` User *User `json:"User,omitempty"` - Token string `json:"token"` + Token endpoints.Token `json:"token"` Version int `json:"version"` } @@ -40,8 +42,8 @@ type Resolved struct { // OptionData is used for options or subcommands in your slash commands type OptionData struct { - Name string `json:"name"` - Type SlashCommandOptionType `json:"type"` - Value interface{} `json:"value,omitempty"` - Options []*OptionData `json:"options,omitempty"` + Name string `json:"name"` + Type CommandOptionType `json:"type"` + Value interface{} `json:"value,omitempty"` + Options []*OptionData `json:"options,omitempty"` } diff --git a/api/restclient.go b/api/restclient.go index 2db18690..ac820869 100644 --- a/api/restclient.go +++ b/api/restclient.go @@ -53,27 +53,32 @@ type RestClient interface { RemoveOwnReaction(channelID Snowflake, messageID Snowflake, emoji string) error RemoveUserReaction(channelID Snowflake, messageID Snowflake, emoji string, userID Snowflake) error - GetGlobalCommands(applicationID Snowflake) ([]*SlashCommand, error) - CreateGlobalCommand(applicationID Snowflake, command SlashCommand) (*SlashCommand, error) - SetGlobalCommands(applicationID Snowflake, commands ...SlashCommand) ([]*SlashCommand, error) - GetGlobalCommand(applicationID Snowflake, commandID Snowflake) (*SlashCommand, error) - EditGlobalCommand(applicationID Snowflake, commandID Snowflake, command SlashCommand) (*SlashCommand, error) + GetGlobalCommands(applicationID Snowflake) ([]*Command, error) + GetGlobalCommand(applicationID Snowflake, commandID Snowflake) (*Command, error) + CreateGlobalCommand(applicationID Snowflake, command Command) (*Command, error) + SetGlobalCommands(applicationID Snowflake, commands ...Command) ([]*Command, error) + EditGlobalCommand(applicationID Snowflake, commandID Snowflake, command Command) (*Command, error) DeleteGlobalCommand(applicationID Snowflake, commandID Snowflake) error - GetGuildCommands(applicationID Snowflake, guildID Snowflake) ([]*SlashCommand, error) - CreateGuildGuildCommand(applicationID Snowflake, guildID Snowflake, command SlashCommand) (*SlashCommand, error) - SetGuildCommands(applicationID Snowflake, guildID Snowflake, commands ...SlashCommand) ([]*SlashCommand, error) - GetGuildCommand(applicationID Snowflake, guildID Snowflake, commandID Snowflake) (*SlashCommand, error) - EditGuildCommand(applicationID Snowflake, guildID Snowflake, commandID Snowflake, command SlashCommand) (*SlashCommand, error) + GetGuildCommands(applicationID Snowflake, guildID Snowflake) ([]*Command, error) + CreateGuildCommand(applicationID Snowflake, guildID Snowflake, command Command) (*Command, error) + SetGuildCommands(applicationID Snowflake, guildID Snowflake, commands ...Command) ([]*Command, error) + GetGuildCommand(applicationID Snowflake, guildID Snowflake, commandID Snowflake) (*Command, error) + EditGuildCommand(applicationID Snowflake, guildID Snowflake, commandID Snowflake, command Command) (*Command, error) DeleteGuildCommand(applicationID Snowflake, guildID Snowflake, commandID Snowflake) error - SendInteractionResponse(interactionID Snowflake, interactionToken string, interactionResponse InteractionResponse) error - EditInteractionResponse(applicationID Snowflake, interactionToken string, followupMessage FollowupMessage) (*Message, error) - DeleteInteractionResponse(applicationID Snowflake, interactionToken string) error + GetGuildCommandsPermissions(applicationID Snowflake, guildID Snowflake) ([]*CommandPermission, error) + GetGuildCommandPermissions(applicationID Snowflake, guildID Snowflake, commandID Snowflake) (*CommandPermission, error) + SetGuildCommandsPermissions(applicationID Snowflake, guildID Snowflake, commandPermissions ...SetGuildCommandPermissions) ([]*GuildCommandPermissions, error) + SetGuildCommandPermissions(applicationID Snowflake, guildID Snowflake, commandID Snowflake, permissions SetGuildCommandPermissions) (*GuildCommandPermissions, error) - SendFollowupMessage(applicationID Snowflake, interactionToken string, followupMessage FollowupMessage) (*Message, error) - EditFollowupMessage(applicationID Snowflake, interactionToken string, messageID Snowflake, followupMessage FollowupMessage) (*Message, error) - DeleteFollowupMessage(applicationID Snowflake, interactionToken string, followupMessageID Snowflake) error + SendInteractionResponse(interactionID Snowflake, interactionToken endpoints.Token, interactionResponse InteractionResponse) error + EditInteractionResponse(applicationID Snowflake, interactionToken endpoints.Token, followupMessage FollowupMessage) (*Message, error) + DeleteInteractionResponse(applicationID Snowflake, interactionToken endpoints.Token) error + + SendFollowupMessage(applicationID Snowflake, interactionToken endpoints.Token, followupMessage FollowupMessage) (*Message, error) + EditFollowupMessage(applicationID Snowflake, interactionToken endpoints.Token, messageID Snowflake, followupMessage FollowupMessage) (*Message, error) + DeleteFollowupMessage(applicationID Snowflake, interactionToken endpoints.Token, followupMessageID Snowflake) error } // ErrorResponse contains custom errors from discord diff --git a/api/slash_command.go b/api/slash_command.go deleted file mode 100644 index 7d556ef1..00000000 --- a/api/slash_command.go +++ /dev/null @@ -1,41 +0,0 @@ -package api - -// SlashCommand is the base "command" model that belongs to an application. -type SlashCommand struct { - ID Snowflake `json:"id,omitempty"` - ApplicationID Snowflake `json:"application_id,omitempty"` - Name string `json:"name"` - Description string `json:"description"` - Options []*CommandOption `json:"options,omitempty"` -} - -// SlashCommandOptionType specifies the type of the arguments used in SlashCommand.Options -type SlashCommandOptionType int - -// Constants for each slash command option type -const ( - OptionTypeSubCommand SlashCommandOptionType = iota + 1 - OptionTypeSubCommandGroup - OptionTypeString - OptionTypeInteger - OptionTypeBoolean - OptionTypeUser - OptionTypeChannel - OptionTypeRole -) - -// CommandOption are the arguments used in SlashCommand.Options -type CommandOption struct { - Type SlashCommandOptionType `json:"type"` - Name string `json:"name"` - Description string `json:"description"` - Required bool `json:"required,omitempty"` - Choices []OptionChoice `json:"choices,omitempty"` - Options []CommandOption `json:"options,omitempty"` -} - -// OptionChoice contains the data for a user using your command -type OptionChoice struct { - Name string `json:"name"` - Value interface{} `json:"value"` -} diff --git a/disgo.go b/disgo.go index 1e61da43..8f708591 100644 --- a/disgo.go +++ b/disgo.go @@ -2,15 +2,16 @@ package disgo import ( "github.com/DisgoOrg/disgo/api" + "github.com/DisgoOrg/disgo/api/endpoints" "github.com/DisgoOrg/disgo/internal" ) // New Initialises a new Disgo client -func New(token string, options api.Options) (api.Disgo, error) { +func New(token endpoints.Token, options api.Options) (api.Disgo, error) { return internal.New(token, options) } // NewBuilder creates an api.DisgoBuilder for the client -func NewBuilder(token string) api.DisgoBuilder { +func NewBuilder(token endpoints.Token) api.DisgoBuilder { return internal.NewBuilder(token) } diff --git a/go.mod b/go.mod index 72783e3e..64333e50 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/DisgoOrg/disgo go 1.16 require ( + github.com/PaesslerAG/gval v1.1.0 github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.4.2 github.com/sirupsen/logrus v1.8.1 diff --git a/go.sum b/go.sum index 5af0c914..45356e1d 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,7 @@ +github.com/PaesslerAG/gval v1.1.0 h1:k3RuxeZDO3eejD4cMPSt+74tUSvTnbGvLx0df4mdwFc= +github.com/PaesslerAG/gval v1.1.0/go.mod h1:y/nm5yEyTeX6av0OfKJNp9rBNj2XrGhAf5+v24IBN1I= +github.com/PaesslerAG/jsonpath v0.1.0 h1:gADYeifvlqK3R3i2cR5B4DGgxLXIPb3TRTH1mGi0jPI= +github.com/PaesslerAG/jsonpath v0.1.0/go.mod h1:4BzmtoM/PI8fPO4aQGIusjGxGir2BzcV0grWtFzq1Y8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/internal/disgo_builder_impl.go b/internal/disgo_builder_impl.go index 977cc244..c12c06e5 100644 --- a/internal/disgo_builder_impl.go +++ b/internal/disgo_builder_impl.go @@ -6,21 +6,23 @@ import ( log "github.com/sirupsen/logrus" "github.com/DisgoOrg/disgo/api" + "github.com/DisgoOrg/disgo/api/endpoints" ) // NewBuilder returns a new api.DisgoBuilder instance -func NewBuilder(token string) api.DisgoBuilder { +func NewBuilder(token endpoints.Token) api.DisgoBuilder { return &DisgoBuilderImpl{ logLevel: log.InfoLevel, - token: &token, + BotToken: token, cacheFlags: api.CacheFlagsDefault, } } // DisgoBuilderImpl implementation of the api.DisgoBuilder interface type DisgoBuilderImpl struct { - logLevel log.Level - token *string + logLevel log.Level + // make this public so it does not print in fmt.Sprint("%+v, DisgoBuilderImpl{}) + BotToken endpoints.Token gateway api.Gateway restClient api.RestClient cache api.Cache @@ -43,9 +45,9 @@ func (b *DisgoBuilderImpl) SetLogLevel(logLevel log.Level) api.DisgoBuilder { return b } -// SetToken sets the token to connect to discord -func (b *DisgoBuilderImpl) SetToken(token string) api.DisgoBuilder { - b.token = &token +// SetToken sets the BotToken to connect to discord +func (b *DisgoBuilderImpl) SetToken(token endpoints.Token) api.DisgoBuilder { + b.BotToken = token return b } @@ -142,14 +144,14 @@ func (b *DisgoBuilderImpl) Build() (api.Disgo, error) { log.SetLevel(b.logLevel) disgo := &DisgoImpl{} - if b.token == nil { - return nil, errors.New("please specify the token") + if b.BotToken == "" { + return nil, errors.New("please specify the BotToken") } - disgo.token = *b.token + disgo.BotToken = b.BotToken - id, err := IDFromToken(disgo.token) + id, err := IDFromToken(disgo.BotToken) if err != nil { - log.Errorf("error while getting application id from token: %s", err) + log.Errorf("error while getting application id from BotToken: %s", err) return nil, err } @@ -161,7 +163,7 @@ func (b *DisgoBuilderImpl) Build() (api.Disgo, error) { disgo.gateway = b.gateway if b.restClient == nil { - b.restClient = newRestClientImpl(disgo, *b.token) + b.restClient = newRestClientImpl(disgo) } disgo.restClient = b.restClient diff --git a/internal/disgo_impl.go b/internal/disgo_impl.go index 31cda350..f9ac1720 100644 --- a/internal/disgo_impl.go +++ b/internal/disgo_impl.go @@ -6,30 +6,31 @@ import ( log "github.com/sirupsen/logrus" "github.com/DisgoOrg/disgo/api" + "github.com/DisgoOrg/disgo/api/endpoints" ) // New creates a new api.Disgo instance -func New(token string, options api.Options) (api.Disgo, error) { +func New(token endpoints.Token, options api.Options) (api.Disgo, error) { if options.LargeThreshold < 50 { options.LargeThreshold = 50 } else if options.LargeThreshold > 250 { options.LargeThreshold = 250 } disgo := &DisgoImpl{ - token: token, + BotToken: token, intents: options.Intents, largeThreshold: options.LargeThreshold, } id, err := IDFromToken(token) if err != nil { - log.Errorf("error while getting application id from token: %s", err) + log.Errorf("error while getting application id from BotToken: %s", err) return nil, err } disgo.selfUserID = *id - disgo.restClient = newRestClientImpl(disgo, token) + disgo.restClient = newRestClientImpl(disgo) disgo.eventManager = newEventManagerImpl(disgo, []api.EventListener{}) @@ -44,7 +45,8 @@ func New(token string, options api.Options) (api.Disgo, error) { // DisgoImpl is the main discord client type DisgoImpl struct { - token string + // make this public so it does not print in fmt.Sprint("%+v, DisgoImpl{}) + BotToken endpoints.Token gateway api.Gateway restClient api.RestClient intents api.Intents @@ -90,9 +92,9 @@ func (d *DisgoImpl) Close() { } } -// Token returns the token of the client -func (d *DisgoImpl) Token() string { - return d.token +// Token returns the BotToken of the client +func (d *DisgoImpl) Token() endpoints.Token { + return d.BotToken } // Gateway returns the websocket information @@ -158,31 +160,31 @@ func (d *DisgoImpl) LargeThreshold() int { } // GetCommand fetches a specific guild command -func (d DisgoImpl) GetCommand(commandID api.Snowflake) (*api.SlashCommand, error) { +func (d DisgoImpl) GetCommand(commandID api.Snowflake) (*api.Command, error) { return d.RestClient().GetGlobalCommand(d.SelfUserID(), commandID) } // GetCommands fetches all guild commands -func (d DisgoImpl) GetCommands() ([]*api.SlashCommand, error) { +func (d DisgoImpl) GetCommands() ([]*api.Command, error) { return d.RestClient().GetGlobalCommands(d.SelfUserID()) } // CreateCommand creates a new command for this guild -func (d DisgoImpl) CreateCommand(command api.SlashCommand) (*api.SlashCommand, error) { +func (d DisgoImpl) CreateCommand(command api.Command) (*api.Command, error) { return d.RestClient().CreateGlobalCommand(d.SelfUserID(), command) } // EditCommand edits a specific guild command -func (d DisgoImpl) EditCommand(commandID api.Snowflake, command api.SlashCommand) (*api.SlashCommand, error) { +func (d DisgoImpl) EditCommand(commandID api.Snowflake, command api.Command) (*api.Command, error) { return d.RestClient().EditGlobalCommand(d.SelfUserID(), commandID, command) } // DeleteCommand creates a new command for this guild -func (d DisgoImpl) DeleteCommand(command api.SlashCommand) (*api.SlashCommand, error) { +func (d DisgoImpl) DeleteCommand(command api.Command) (*api.Command, error) { return d.RestClient().CreateGlobalCommand(d.SelfUserID(), command) } // SetCommands overrides all commands for this guild -func (d DisgoImpl) SetCommands(commands ...api.SlashCommand) ([]*api.SlashCommand, error) { +func (d DisgoImpl) SetCommands(commands ...api.Command) ([]*api.Command, error) { return d.RestClient().SetGlobalCommands(d.SelfUserID(), commands...) } diff --git a/internal/handlers/interaction_create_handler.go b/internal/handlers/interaction_create_handler.go index 535a393a..c224b6ee 100644 --- a/internal/handlers/interaction_create_handler.go +++ b/internal/handlers/interaction_create_handler.go @@ -82,12 +82,12 @@ func handleInteraction(disgo api.Disgo, eventManager api.EventManager, c chan in var subCommandGroupName *string if len(options) == 1 { option := interaction.Data.Options[0] - if option.Type == api.OptionTypeSubCommandGroup { + if option.Type == api.CommandOptionTypeSubCommandGroup { subCommandGroupName = &option.Name options = option.Options option = option.Options[0] } - if option.Type == api.OptionTypeSubCommand { + if option.Type == api.CommandOptionTypeSubCommand { subCommandName = &option.Name options = option.Options } diff --git a/internal/restclient_impl.go b/internal/restclient_impl.go index c4bbad54..bd91bdf2 100644 --- a/internal/restclient_impl.go +++ b/internal/restclient_impl.go @@ -15,11 +15,10 @@ import ( "github.com/DisgoOrg/disgo/api/endpoints" ) -func newRestClientImpl(disgo api.Disgo, token string) api.RestClient { +func newRestClientImpl(disgo api.Disgo) api.RestClient { return &RestClientImpl{ disgo: disgo, Client: &http.Client{}, - token: token, } } @@ -54,6 +53,7 @@ func (r RestClientImpl) Request(route endpoints.CompiledAPIRoute, rqBody interfa if err != nil { return err } + log.Debugf("request json: \"%s\"", string(rqJSON)) reader = bytes.NewBuffer(rqJSON) } else { reader = nil @@ -65,7 +65,7 @@ func (r RestClientImpl) Request(route endpoints.CompiledAPIRoute, rqBody interfa } rq.Header.Set("User-Agent", r.UserAgent()) - rq.Header.Set("Authorization", "Bot "+r.token) + rq.Header.Set("Authorization", string("Bot "+r.disgo.Token())) rq.Header.Set("Content-Type", "application/json") rs, err := r.Client.Do(rq) @@ -74,7 +74,7 @@ func (r RestClientImpl) Request(route endpoints.CompiledAPIRoute, rqBody interfa } defer func() { - err := rs.Body.Close() + err = rs.Body.Close() if err != nil { log.Error("error closing response body", err.Error()) } @@ -220,7 +220,7 @@ func (r RestClientImpl) GetMembers(guildID api.Snowflake) (members []*api.Member return } -// AddMember adds a member to the guild with the oauth2 access token. requires api.PermissionCreateInstantInvite +// AddMember adds a member to the guild with the oauth2 access BotToken. requires api.PermissionCreateInstantInvite func (r RestClientImpl) AddMember(guildID api.Snowflake, userID api.Snowflake, addGuildMemberData api.AddGuildMemberData) (member *api.Member, err error) { err = r.Request(endpoints.AddMember.Compile(guildID, userID), addGuildMemberData, &member) if member != nil { @@ -365,17 +365,17 @@ func (r RestClientImpl) RemoveUserReaction(channelID api.Snowflake, messageID ap } // GetGlobalCommands gets you all global commands -func (r RestClientImpl) GetGlobalCommands(applicationID api.Snowflake) (commands []*api.SlashCommand, err error) { +func (r RestClientImpl) GetGlobalCommands(applicationID api.Snowflake) (commands []*api.Command, err error) { return commands, r.Request(endpoints.GetGlobalCommands.Compile(applicationID), nil, &commands) } // CreateGlobalCommand lets you create a new global command -func (r RestClientImpl) CreateGlobalCommand(applicationID api.Snowflake, command api.SlashCommand) (rCommand *api.SlashCommand, err error) { +func (r RestClientImpl) CreateGlobalCommand(applicationID api.Snowflake, command api.Command) (rCommand *api.Command, err error) { return rCommand, r.Request(endpoints.CreateGlobalCommand.Compile(applicationID), command, &rCommand) } // SetGlobalCommands lets you override all global commands -func (r RestClientImpl) SetGlobalCommands(applicationID api.Snowflake, commands ...api.SlashCommand) (rCommands []*api.SlashCommand, err error) { +func (r RestClientImpl) SetGlobalCommands(applicationID api.Snowflake, commands ...api.Command) (rCommands []*api.Command, err error) { if len(commands) > 100 { err = api.ErrTooMuchApplicationCommands return @@ -384,12 +384,12 @@ func (r RestClientImpl) SetGlobalCommands(applicationID api.Snowflake, commands } // GetGlobalCommand gets you a specific global global command -func (r RestClientImpl) GetGlobalCommand(applicationID api.Snowflake, commandID api.Snowflake) (rCommand *api.SlashCommand, err error) { +func (r RestClientImpl) GetGlobalCommand(applicationID api.Snowflake, commandID api.Snowflake) (rCommand *api.Command, err error) { return rCommand, r.Request(endpoints.GetGlobalCommand.Compile(applicationID, commandID), nil, &rCommand) } // EditGlobalCommand lets you edit a specific global command -func (r RestClientImpl) EditGlobalCommand(applicationID api.Snowflake, commandID api.Snowflake, command api.SlashCommand) (rCommand *api.SlashCommand, err error) { +func (r RestClientImpl) EditGlobalCommand(applicationID api.Snowflake, commandID api.Snowflake, command api.Command) (rCommand *api.Command, err error) { return rCommand, r.Request(endpoints.EditGlobalCommand.Compile(applicationID, commandID), command, &rCommand) } @@ -399,17 +399,17 @@ func (r RestClientImpl) DeleteGlobalCommand(applicationID api.Snowflake, command } // GetGuildCommands gets you all guild_events commands -func (r RestClientImpl) GetGuildCommands(applicationID api.Snowflake, guildID api.Snowflake) (commands []*api.SlashCommand, err error) { +func (r RestClientImpl) GetGuildCommands(applicationID api.Snowflake, guildID api.Snowflake) (commands []*api.Command, err error) { return commands, r.Request(endpoints.GetGuildCommands.Compile(applicationID, guildID), nil, &commands) } // CreateGuildGuildCommand lets you create a new guild_events command -func (r RestClientImpl) CreateGuildGuildCommand(applicationID api.Snowflake, guildID api.Snowflake, command api.SlashCommand) (rCommand *api.SlashCommand, err error) { +func (r RestClientImpl) CreateGuildCommand(applicationID api.Snowflake, guildID api.Snowflake, command api.Command) (rCommand *api.Command, err error) { return rCommand, r.Request(endpoints.CreateGuildCommand.Compile(applicationID, guildID), command, &rCommand) } // SetGuildCommands lets you override all guild_events commands -func (r RestClientImpl) SetGuildCommands(applicationID api.Snowflake, guildID api.Snowflake, commands ...api.SlashCommand) (rCommands []*api.SlashCommand, err error) { +func (r RestClientImpl) SetGuildCommands(applicationID api.Snowflake, guildID api.Snowflake, commands ...api.Command) (rCommands []*api.Command, err error) { if len(commands) > 100 { err = api.ErrTooMuchApplicationCommands return @@ -418,12 +418,12 @@ func (r RestClientImpl) SetGuildCommands(applicationID api.Snowflake, guildID ap } // GetGuildCommand gets you a specific guild_events command -func (r RestClientImpl) GetGuildCommand(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake) (rCommand *api.SlashCommand, err error) { +func (r RestClientImpl) GetGuildCommand(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake) (rCommand *api.Command, err error) { return rCommand, r.Request(endpoints.GetGuildCommand.Compile(applicationID, guildID, commandID), nil, &rCommand) } // EditGuildCommand lets you edit a specific guild_events command -func (r RestClientImpl) EditGuildCommand(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake, command api.SlashCommand) (rCommand *api.SlashCommand, err error) { +func (r RestClientImpl) EditGuildCommand(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake, command api.Command) (rCommand *api.Command, err error) { return rCommand, r.Request(endpoints.EditGuildCommand.Compile(applicationID, guildID, commandID), command, &rCommand) } @@ -432,33 +432,53 @@ func (r RestClientImpl) DeleteGuildCommand(applicationID api.Snowflake, guildID return r.Request(endpoints.DeleteGuildCommand.Compile(applicationID, guildID, commandID), nil, nil) } +// GetGuildCommandsPermissions returns the api.CommandPermission for a all api.Command(s) in a guild +func (r RestClientImpl) GetGuildCommandsPermissions(applicationID api.Snowflake, guildID api.Snowflake) (rCommandsPermissions []*api.CommandPermission, err error) { + return rCommandsPermissions, r.Request(endpoints.GetGuildCommandPermissions.Compile(applicationID, guildID), nil, &rCommandsPermissions) +} + +// GetGuildCommandPermissions returns the api.CommandPermission for a specific api.Command in a guild +func (r RestClientImpl) GetGuildCommandPermissions(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake) (rCommandPermissions *api.CommandPermission, err error) { + return rCommandPermissions, r.Request(endpoints.GetGuildCommandPermission.Compile(applicationID, guildID, commandID), nil, &rCommandPermissions) +} + +// SetGuildCommandsPermissions sets the api.GuildCommandPermissions for a all api.Command(s) +func (r RestClientImpl) SetGuildCommandsPermissions(applicationID api.Snowflake, guildID api.Snowflake, commandsPermissions ...api.SetGuildCommandPermissions) (rCommandsPermissions []*api.GuildCommandPermissions, err error) { + return rCommandsPermissions, r.Request(endpoints.SetGuildCommandsPermissions.Compile(applicationID, guildID), api.SetGuildCommandsPermissions(commandsPermissions), &rCommandsPermissions) +} + +// SetGuildCommandPermissions sets the api.GuildCommandPermissions for a specific api.Command +func (r RestClientImpl) SetGuildCommandPermissions(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake, commandPermissions api.SetGuildCommandPermissions) (rCommandPermissions *api.GuildCommandPermissions, err error) { + return rCommandPermissions, r.Request(endpoints.SetGuildCommandPermissions.Compile(applicationID, guildID, commandID), commandPermissions, &rCommandPermissions) +} + // SendInteractionResponse used to send the initial response on an interaction -func (r RestClientImpl) SendInteractionResponse(interactionID api.Snowflake, interactionToken string, interactionResponse api.InteractionResponse) error { +func (r RestClientImpl) SendInteractionResponse(interactionID api.Snowflake, interactionToken endpoints.Token, interactionResponse api.InteractionResponse) error { return r.Request(endpoints.CreateInteractionResponse.Compile(interactionID, interactionToken), interactionResponse, nil) } // EditInteractionResponse used to edit the initial response on an interaction -func (r RestClientImpl) EditInteractionResponse(applicationID api.Snowflake, interactionToken string, followupMessage api.FollowupMessage) (message *api.Message, err error) { +func (r RestClientImpl) EditInteractionResponse(applicationID api.Snowflake, interactionToken endpoints.Token, followupMessage api.FollowupMessage) (message *api.Message, err error) { return message, r.Request(endpoints.EditInteractionResponse.Compile(applicationID, interactionToken), followupMessage, &message) } // DeleteInteractionResponse used to delete the initial response on an interaction -func (r RestClientImpl) DeleteInteractionResponse(applicationID api.Snowflake, interactionToken string) error { +func (r RestClientImpl) DeleteInteractionResponse(applicationID api.Snowflake, interactionToken endpoints.Token) error { return r.Request(endpoints.DeleteInteractionResponse.Compile(applicationID, interactionToken), nil, nil) } // SendFollowupMessage used to send a followup message_events to an interaction -func (r RestClientImpl) SendFollowupMessage(applicationID api.Snowflake, interactionToken string, followupMessage api.FollowupMessage) (message *api.Message, err error) { +func (r RestClientImpl) SendFollowupMessage(applicationID api.Snowflake, interactionToken endpoints.Token, followupMessage api.FollowupMessage) (message *api.Message, err error) { return message, r.Request(endpoints.CreateFollowupMessage.Compile(applicationID, interactionToken), followupMessage, &message) } // EditFollowupMessage used to edit a api.FollowupMessage from an api.Interaction -func (r RestClientImpl) EditFollowupMessage(applicationID api.Snowflake, interactionToken string, messageID api.Snowflake, followupMessage api.FollowupMessage) (message *api.Message, err error) { +func (r RestClientImpl) EditFollowupMessage(applicationID api.Snowflake, interactionToken endpoints.Token, messageID api.Snowflake, followupMessage api.FollowupMessage) (message *api.Message, err error) { return message, r.Request(endpoints.EditFollowupMessage.Compile(applicationID, interactionToken, messageID), followupMessage, &message) } // DeleteFollowupMessage used to delete a api.FollowupMessage from an api.Interaction -func (r RestClientImpl) DeleteFollowupMessage(applicationID api.Snowflake, interactionToken string, messageID api.Snowflake) error { +func (r RestClientImpl) DeleteFollowupMessage(applicationID api.Snowflake, interactionToken endpoints.Token, messageID api.Snowflake) error { return r.Request(endpoints.DeleteFollowupMessage.Compile(applicationID, interactionToken, messageID), nil, nil) } diff --git a/internal/util.go b/internal/util.go index e460137b..15a5f35c 100644 --- a/internal/util.go +++ b/internal/util.go @@ -6,13 +6,14 @@ import ( "strings" "github.com/DisgoOrg/disgo/api" + "github.com/DisgoOrg/disgo/api/endpoints" ) -// IDFromToken returns the applicationID from the token -func IDFromToken(token string) (*api.Snowflake, error) { - strs := strings.Split(token, ".") +// IDFromToken returns the applicationID from the BotToken +func IDFromToken(token endpoints.Token) (*api.Snowflake, error) { + strs := strings.Split(string(token), ".") if len(strs) == 0 { - return nil, errors.New("token is not in a valid format") + return nil, errors.New("BotToken is not in a valid format") } byteID, err := base64.StdEncoding.DecodeString(strs[0]) if err != nil { diff --git a/testbot/testbot.go b/testbot/testbot.go index 7aedc653..ae0be920 100644 --- a/testbot/testbot.go +++ b/testbot/testbot.go @@ -1,22 +1,34 @@ package main import ( + "fmt" "os" "os/signal" + "strconv" "syscall" "time" + "github.com/PaesslerAG/gval" log "github.com/sirupsen/logrus" "github.com/DisgoOrg/disgo" "github.com/DisgoOrg/disgo/api" + "github.com/DisgoOrg/disgo/api/endpoints" "github.com/DisgoOrg/disgo/api/events" ) +const red = 16711680 +const orange = 16562691 +const green = 65280 + +const guildID = "817327181659111454" +const adminRoleID = "817327279583264788" +const testRoleID = "825156597935243304" + func main() { - log.Infof("starting testbot...") + log.Info("starting testbot...") - dgo, err := disgo.NewBuilder(os.Getenv("token")). + dgo, err := disgo.NewBuilder(endpoints.Token(os.Getenv("token"))). SetLogLevel(log.InfoLevel). SetIntents(api.IntentsGuilds | api.IntentsGuildMessages | api.IntentsGuildMembers). SetMemberCachePolicy(api.MemberCachePolicyAll). @@ -31,64 +43,108 @@ func main() { return } - _, err = dgo.RestClient().SetGuildCommands(dgo.SelfUserID(), "817327181659111454", - api.SlashCommand{ - Name: "test", - Description: "test test test test test test", + commands := []api.Command{ + { + Name: "eval", + Description: "runs some go code", + DefaultPermission: false, + Options: []*api.CommandOption{ + { + Type: api.CommandOptionTypeString, + Name: "code", + Description: "the code to eval", + Required: true, + }, + }, }, - api.SlashCommand{ - Name: "say", - Description: "says what you say", + { + Name: "test", + Description: "test test test test test test", + DefaultPermission: false, + }, + { + Name: "say", + Description: "says what you say", + DefaultPermission: false, Options: []*api.CommandOption{ { - Type: api.OptionTypeString, + Type: api.CommandOptionTypeString, Name: "message", Description: "What to say", Required: true, }, }, }, - api.SlashCommand{ - Name: "addrole", - Description: "This command adds a role to a member", + { + Name: "addrole", + Description: "This command adds a role to a member", + DefaultPermission: false, Options: []*api.CommandOption{ { - Type: api.OptionTypeUser, + Type: api.CommandOptionTypeUser, Name: "member", Description: "The member to add a role to", Required: true, }, { - Type: api.OptionTypeRole, + Type: api.CommandOptionTypeRole, Name: "role", Description: "The role to add to a member", Required: true, }, }, }, - api.SlashCommand{ - Name: "removerole", - Description: "This command removes a role from a member", + { + Name: "removerole", + Description: "This command removes a role from a member", + DefaultPermission: false, Options: []*api.CommandOption{ { - Type: api.OptionTypeUser, + Type: api.CommandOptionTypeUser, Name: "member", Description: "The member to removes a role from", Required: true, }, { - Type: api.OptionTypeRole, + Type: api.CommandOptionTypeRole, Name: "role", Description: "The role to removes from a member", Required: true, }, }, }, - ) + } + + cmds, err := dgo.RestClient().SetGuildCommands(dgo.SelfUserID(), guildID, commands...) if err != nil { log.Errorf("error while registering guild commands: %s", err) } + var cmdsPermissions []api.SetGuildCommandPermissions + for _, cmd := range cmds { + var perms api.CommandPermission + if cmd.Name == "eval" { + perms = api.CommandPermission{ + ID: adminRoleID, + Type: api.CommandPermissionTypeRole, + Permission: true, + } + } else { + perms = api.CommandPermission{ + ID: testRoleID, + Type: api.CommandPermissionTypeRole, + Permission: true, + } + } + cmdsPermissions = append(cmdsPermissions, api.SetGuildCommandPermissions{ + ID: cmd.ID, + Permissions: []api.CommandPermission{perms}, + }) + } + if _, err = dgo.RestClient().SetGuildCommandsPermissions(dgo.SelfUserID(), guildID, cmdsPermissions...); err != nil { + log.Errorf("error while setting command permissions: %s", err) + } + err = dgo.Connect() if err != nil { log.Fatalf("error while connecting to discord: %s", err) @@ -108,9 +164,55 @@ func guildAvailListener(event *events.GuildAvailableEvent) { func slashCommandListener(event *events.SlashCommandEvent) { switch event.Interaction.Data.Name { + case "eval": + go func() { + start := time.Now() + code := event.Option("code").String() + embed := api.NewEmbedBuilder(). + SetColor(orange). + AddField("Status", "...", true). + AddField("Time", "...", true). + AddField("Code", "```go\n"+code+"\n```", false). + AddField("Output", "```\n...\n```", false) + + _ = event.Reply(api.NewInteractionResponseBuilder().SetEmbeds(embed.Build()).Build()) + + vars := map[string]interface{}{ + "disgo": event.Disgo(), + "dgo": event.Disgo(), + "event": event, + } + output, err := gval.Evaluate(code, vars) + + elapsed := time.Since(start) + embed.SetField(1, "Time", strconv.Itoa(int(elapsed.Milliseconds()))+"ms", true) + + if err != nil { + _, _ = event.EditOriginal(api.NewFollowupMessageBuilder(). + SetEmbeds(embed. + SetColor(red). + SetField(0, "Status", "failed", true). + SetField(3, "Output", "```"+err.Error()+"```", false). + Build(), + ). + Build(), + ) + return + } + _, _ = event.EditOriginal(api.NewFollowupMessageBuilder(). + SetEmbeds(embed. + SetColor(green). + SetField(0, "Status", "success", true). + SetField(3, "Output", "```"+fmt.Sprintf("%+v", output)+"```", false). + Build(), + ). + Build(), + ) + }() + case "say": _ = event.Reply(api.NewInteractionResponseBuilder(). - SetContent(event.OptionByName("message").String()). + SetContent(event.Option("message").String()). SetAllowedMentionsEmpty(). Build(), ) @@ -144,22 +246,22 @@ func slashCommandListener(event *events.SlashCommandEvent) { }() case "addrole": - user := event.OptionByName("member").User() - role := event.OptionByName("role").Role() + user := event.Option("member").User() + role := event.Option("role").Role() err := event.Disgo().RestClient().AddMemberRole(*event.Interaction.GuildID, user.ID, role.ID) if err == nil { _ = event.Reply(api.NewInteractionResponseBuilder().AddEmbeds( - api.NewEmbedBuilder().SetColor(65280).SetDescriptionf("Added %s to %s", role, user).Build(), + api.NewEmbedBuilder().SetColor(green).SetDescriptionf("Added %s to %s", role, user).Build(), ).Build()) } else { _ = event.Reply(api.NewInteractionResponseBuilder().AddEmbeds( - api.NewEmbedBuilder().SetColor(16711680).SetDescriptionf("Failed to add %s to %s", role, user).Build(), + api.NewEmbedBuilder().SetColor(red).SetDescriptionf("Failed to add %s to %s", role, user).Build(), ).Build()) } case "removerole": - user := event.OptionByName("member").User() - role := event.OptionByName("role").Role() + user := event.Option("member").User() + role := event.Option("role").Role() err := event.Disgo().RestClient().RemoveMemberRole(*event.Interaction.GuildID, user.ID, role.ID) if err == nil { _ = event.Reply(api.NewInteractionResponseBuilder().AddEmbeds( From cc8d468f29d2d140aa3b3905313ccaf5a328acd6 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Thu, 8 Apr 2021 01:59:17 +0200 Subject: [PATCH 26/65] added convenient methods for permission & command updating --- api/command.go | 71 ++++++++++-- api/endpoints/cdn_route.go | 1 + api/endpoints/endpoints.go | 1 + api/gateway.go | 3 + api/guild.go | 8 +- api/restclient.go | 12 +-- .../handlers/application_command_create.go | 26 +++++ .../handlers/application_command_delete.go | 26 +++++ .../handlers/application_command_update.go | 26 +++++ internal/restclient_impl.go | 101 ++++++++++++++---- 10 files changed, 236 insertions(+), 39 deletions(-) create mode 100644 internal/handlers/application_command_create.go create mode 100644 internal/handlers/application_command_delete.go create mode 100644 internal/handlers/application_command_update.go diff --git a/api/command.go b/api/command.go index 38c10a27..b426d8db 100644 --- a/api/command.go +++ b/api/command.go @@ -2,12 +2,13 @@ package api import "errors" -var noDisgoInstance = errors.New("no disgo instance injected") +var errNoDisgoInstance = errors.New("no disgo instance injected") // Command is the base "command" model that belongs to an application. type Command struct { Disgo Disgo - GuildID *Snowflake + GuildPermissions map[Snowflake]*GuildCommandPermissions + GuildID *Snowflake `json:"guild_id"` ID Snowflake `json:"id,omitempty"` ApplicationID Snowflake `json:"application_id,omitempty"` Name string `json:"name"` @@ -16,9 +17,23 @@ type Command struct { Options []*CommandOption `json:"options,omitempty"` } +// Guild returns the Guild the Command is from from the Cache or nil if it is a global Command +func (c Command) Guild() *Guild { + if c.GuildID == nil { + return nil + } + return c.Disgo.Cache().Guild(*c.GuildID) +} + +// FromGuild returns true if this is a guild Command else false +func (c Command) FromGuild() bool { + return c.GuildID == nil +} + +// Create creates the Command either as global or guild Command depending on if GuildID is set func (c *Command) Create() error { if c.Disgo == nil { - return noDisgoInstance + return errNoDisgoInstance } var rC *Command var err error @@ -35,9 +50,10 @@ func (c *Command) Create() error { return nil } -func (c *Command) Get() error { +// Fetch updates/fetches the current Command from discord +func (c *Command) Fetch() error { if c.Disgo == nil { - return noDisgoInstance + return errNoDisgoInstance } var rC *Command var err error @@ -54,17 +70,18 @@ func (c *Command) Get() error { return nil } -func (c *Command) Update() error { +// Update updates the current Command with the given fields +func (c *Command) Update(command UpdateCommand) error { if c.Disgo == nil { - return noDisgoInstance + return errNoDisgoInstance } var rC *Command var err error if c.GuildID == nil { - rC, err = c.Disgo.RestClient().EditGlobalCommand(c.Disgo.SelfUserID(), c.ID, *c) + rC, err = c.Disgo.RestClient().EditGlobalCommand(c.Disgo.SelfUserID(), c.ID, command) } else { - rC, err = c.Disgo.RestClient().EditGuildCommand(c.Disgo.SelfUserID(), *c.GuildID, c.ID, *c) + rC, err = c.Disgo.RestClient().EditGuildCommand(c.Disgo.SelfUserID(), *c.GuildID, c.ID, command) } if err != nil { return err @@ -73,9 +90,35 @@ func (c *Command) Update() error { return nil } +// SetPermissions sets the GuildCommandPermissions for a specific Guild. this overrides all existing CommandPermission(s). thx discord for that +func (c Command) SetPermissions(guildID Snowflake, permissions ...CommandPermission) (*GuildCommandPermissions, error) { + perms, err := c.Disgo.RestClient().SetGuildCommandPermissions(c.Disgo.SelfUserID(), guildID, c.ID, SetGuildCommandPermissions{Permissions: permissions}) + if err != nil { + return nil, err + } + c.GuildPermissions[guildID] = perms + return perms, nil +} + +// GetPermissions returns the GuildCommandPermissions for the specific Guild from the Cache +func (c Command) GetPermissions(guildID Snowflake) *GuildCommandPermissions { + return c.GuildPermissions[guildID] +} + +// FetchPermissions fetched the GuildCommandPermissions for a specific Guild from discord +func (c Command) FetchPermissions(guildID Snowflake) (*GuildCommandPermissions, error) { + perms, err := c.Disgo.RestClient().GetGuildCommandPermissions(c.Disgo.SelfUserID(), guildID, c.ID) + if err != nil { + return nil, err + } + c.GuildPermissions[guildID] = perms + return perms, nil +} + +// Delete deletes the Command from discord func (c Command) Delete() error { if c.Disgo == nil { - return noDisgoInstance + return errNoDisgoInstance } if c.GuildID == nil { return c.Disgo.RestClient().DeleteGlobalCommand(c.Disgo.SelfUserID(), c.ID) @@ -146,3 +189,11 @@ type SetGuildCommandPermissions struct { ID Snowflake `json:"id,omitempty"` Permissions []CommandPermission `json:"permissions"` } + +// UpdateCommand is used to update an existing Command. all fields are optional +type UpdateCommand struct { + Name *string `json:"name,omitempty"` + Description *string `json:"description,omitempty"` + DefaultPermission *bool `json:"default_permission,omitempty"` + Options []*CommandOption `json:"options,omitempty"` +} diff --git a/api/endpoints/cdn_route.go b/api/endpoints/cdn_route.go index ba78eaca..5dc87015 100644 --- a/api/endpoints/cdn_route.go +++ b/api/endpoints/cdn_route.go @@ -11,6 +11,7 @@ const ( JPEG FileExtension = "jpg" WEBP FileExtension = "webp" GIF FileExtension = "gif" + BLANK FileExtension = "" ) func (f FileExtension) String() string { diff --git a/api/endpoints/endpoints.go b/api/endpoints/endpoints.go index c3be81db..6f8624fc 100644 --- a/api/endpoints/endpoints.go +++ b/api/endpoints/endpoints.go @@ -201,4 +201,5 @@ var ( ApplicationAsset = NewCDNRoute("/app-assets/{application.id}/{asset.id}.", PNG, JPEG, WEBP) AchievementIcon = NewCDNRoute("/app-assets/{application.id}/achievements/{achievement.id}/icons/{icon.hash}.", PNG, JPEG, WEBP) TeamIcon = NewCDNRoute("/team-icons/{team.id}/team.icon.", PNG, JPEG, WEBP) + Attachments = NewCDNRoute("/attachments/{channel.id}/{attachment.id}/{file.name}", BLANK) ) diff --git a/api/gateway.go b/api/gateway.go index bd95cb8e..734922b0 100644 --- a/api/gateway.go +++ b/api/gateway.go @@ -52,6 +52,9 @@ type GatewayEventName string // Constants for the gateway events const ( + GatewayEventApplicationCommandCreate GatewayEventName = "APPLICATION_COMMAND_CREATE" + GatewayEventApplicationCommandUpdate GatewayEventName = "APPLICATION_COMMAND_UPDATE" + GatewayEventApplicationCommandDelete GatewayEventName = "APPLICATION_COMMAND_DELETE" GatewayEventChannelCreate GatewayEventName = "CHANNEL_CREATE" GatewayEventChannelDelete GatewayEventName = "CHANNEL_DELETE" GatewayEventChannelPinsUpdate GatewayEventName = "CHANNEL_PINS_UPDATE" diff --git a/api/guild.go b/api/guild.go index d2b8f234..5bfb7c3b 100644 --- a/api/guild.go +++ b/api/guild.go @@ -225,13 +225,13 @@ func (g Guild) SetCommands(commands ...Command) ([]*Command, error) { return g.Disgo.RestClient().SetGuildCommands(g.Disgo.SelfUserID(), g.ID, commands...) } -// GetCommandsPermissions returns the CommandPermission for a all Command(s) in a guild -func (g Guild) GetCommandsPermissions() ([]*CommandPermission, error) { +// GetCommandsPermissions returns the GuildCommandPermissions for a all Command(s) in a guild +func (g Guild) GetCommandsPermissions() ([]*GuildCommandPermissions, error) { return g.Disgo.RestClient().GetGuildCommandsPermissions(g.Disgo.SelfUserID(), g.ID) } -// GetCommandPermissions returns the CommandPermission for a specific Command in a guild -func (g Guild) GetCommandPermissions(commandID Snowflake) (*CommandPermission, error) { +// GetCommandPermissions returns the GuildCommandPermissions for a specific Command in a guild +func (g Guild) GetCommandPermissions(commandID Snowflake) (*GuildCommandPermissions, error) { return g.Disgo.RestClient().GetGuildCommandPermissions(g.Disgo.SelfUserID(), g.ID, commandID) } diff --git a/api/restclient.go b/api/restclient.go index ac820869..4eb40110 100644 --- a/api/restclient.go +++ b/api/restclient.go @@ -57,20 +57,20 @@ type RestClient interface { GetGlobalCommand(applicationID Snowflake, commandID Snowflake) (*Command, error) CreateGlobalCommand(applicationID Snowflake, command Command) (*Command, error) SetGlobalCommands(applicationID Snowflake, commands ...Command) ([]*Command, error) - EditGlobalCommand(applicationID Snowflake, commandID Snowflake, command Command) (*Command, error) + EditGlobalCommand(applicationID Snowflake, commandID Snowflake, command UpdateCommand) (*Command, error) DeleteGlobalCommand(applicationID Snowflake, commandID Snowflake) error GetGuildCommands(applicationID Snowflake, guildID Snowflake) ([]*Command, error) + GetGuildCommand(applicationID Snowflake, guildID Snowflake, commandID Snowflake) (*Command, error) CreateGuildCommand(applicationID Snowflake, guildID Snowflake, command Command) (*Command, error) SetGuildCommands(applicationID Snowflake, guildID Snowflake, commands ...Command) ([]*Command, error) - GetGuildCommand(applicationID Snowflake, guildID Snowflake, commandID Snowflake) (*Command, error) - EditGuildCommand(applicationID Snowflake, guildID Snowflake, commandID Snowflake, command Command) (*Command, error) + EditGuildCommand(applicationID Snowflake, guildID Snowflake, commandID Snowflake, command UpdateCommand) (*Command, error) DeleteGuildCommand(applicationID Snowflake, guildID Snowflake, commandID Snowflake) error - GetGuildCommandsPermissions(applicationID Snowflake, guildID Snowflake) ([]*CommandPermission, error) - GetGuildCommandPermissions(applicationID Snowflake, guildID Snowflake, commandID Snowflake) (*CommandPermission, error) + GetGuildCommandsPermissions(applicationID Snowflake, guildID Snowflake) ([]*GuildCommandPermissions, error) + GetGuildCommandPermissions(applicationID Snowflake, guildID Snowflake, commandID Snowflake) (*GuildCommandPermissions, error) SetGuildCommandsPermissions(applicationID Snowflake, guildID Snowflake, commandPermissions ...SetGuildCommandPermissions) ([]*GuildCommandPermissions, error) - SetGuildCommandPermissions(applicationID Snowflake, guildID Snowflake, commandID Snowflake, permissions SetGuildCommandPermissions) (*GuildCommandPermissions, error) + SetGuildCommandPermissions(applicationID Snowflake, guildID Snowflake, commandID Snowflake, commandPermissions SetGuildCommandPermissions) (*GuildCommandPermissions, error) SendInteractionResponse(interactionID Snowflake, interactionToken endpoints.Token, interactionResponse InteractionResponse) error EditInteractionResponse(applicationID Snowflake, interactionToken endpoints.Token, followupMessage FollowupMessage) (*Message, error) diff --git a/internal/handlers/application_command_create.go b/internal/handlers/application_command_create.go new file mode 100644 index 00000000..2e1e78a3 --- /dev/null +++ b/internal/handlers/application_command_create.go @@ -0,0 +1,26 @@ +package handlers + +import ( + "github.com/DisgoOrg/disgo/api" +) + +// GuildCreateHandler handles api.ApplicationCommandCreateEvent +type ApplicationCommandCreateHandler struct{} + +// Event returns the raw gateway event Event +func (h ApplicationCommandCreateHandler) Event() api.GatewayEventName { + return api.GatewayEventApplicationCommandCreate +} + +// New constructs a new payload receiver for the raw gateway event +func (h ApplicationCommandCreateHandler) New() interface{} { + return &api.Command{} +} + +// Handle handles the specific raw gateway event +func (h ApplicationCommandCreateHandler) Handle(disgo api.Disgo, eventManager api.EventManager, i interface{}) { + /*command, ok := i.(*api.Command) + if !ok { + return + }*/ +} diff --git a/internal/handlers/application_command_delete.go b/internal/handlers/application_command_delete.go new file mode 100644 index 00000000..cc4f7c2d --- /dev/null +++ b/internal/handlers/application_command_delete.go @@ -0,0 +1,26 @@ +package handlers + +import ( + "github.com/DisgoOrg/disgo/api" +) + +// GuildCreateHandler handles api.ApplicationCommandCreateEvent +type ApplicationCommandDeleteHandler struct{} + +// Event returns the raw gateway event Event +func (h ApplicationCommandDeleteHandler) Event() api.GatewayEventName { + return api.GatewayEventApplicationCommandDelete +} + +// New constructs a new payload receiver for the raw gateway event +func (h ApplicationCommandDeleteHandler) New() interface{} { + return &api.Command{} +} + +// Handle handles the specific raw gateway event +func (h ApplicationCommandDeleteHandler) Handle(disgo api.Disgo, eventManager api.EventManager, i interface{}) { + /*command, ok := i.(*api.Command) + if !ok { + return + }*/ +} diff --git a/internal/handlers/application_command_update.go b/internal/handlers/application_command_update.go new file mode 100644 index 00000000..f7335ad2 --- /dev/null +++ b/internal/handlers/application_command_update.go @@ -0,0 +1,26 @@ +package handlers + +import ( + "github.com/DisgoOrg/disgo/api" +) + +// GuildCreateHandler handles api.ApplicationCommandCreateEvent +type ApplicationCommandUpdateHandler struct{} + +// Event returns the raw gateway event Event +func (h ApplicationCommandUpdateHandler) Event() api.GatewayEventName { + return api.GatewayEventApplicationCommandUpdate +} + +// New constructs a new payload receiver for the raw gateway event +func (h ApplicationCommandUpdateHandler) New() interface{} { + return &api.Command{} +} + +// Handle handles the specific raw gateway event +func (h ApplicationCommandUpdateHandler) Handle(disgo api.Disgo, eventManager api.EventManager, i interface{}) { + /*command, ok := i.(*api.Command) + if !ok { + return + }*/ +} diff --git a/internal/restclient_impl.go b/internal/restclient_impl.go index bd91bdf2..a6680901 100644 --- a/internal/restclient_impl.go +++ b/internal/restclient_impl.go @@ -366,12 +366,34 @@ func (r RestClientImpl) RemoveUserReaction(channelID api.Snowflake, messageID ap // GetGlobalCommands gets you all global commands func (r RestClientImpl) GetGlobalCommands(applicationID api.Snowflake) (commands []*api.Command, err error) { - return commands, r.Request(endpoints.GetGlobalCommands.Compile(applicationID), nil, &commands) + err = r.Request(endpoints.GetGlobalCommands.Compile(applicationID), nil, &commands) + if err != nil { + return + } + for _, cmd := range commands { + cmd.Disgo = r.disgo + } + return +} + +// GetGlobalCommand gets you a specific global global command +func (r RestClientImpl) GetGlobalCommand(applicationID api.Snowflake, commandID api.Snowflake) (rCommand *api.Command, err error) { + err = r.Request(endpoints.GetGlobalCommand.Compile(applicationID, commandID), nil, &rCommand) + if err != nil { + return + } + rCommand.Disgo = r.disgo + return } // CreateGlobalCommand lets you create a new global command func (r RestClientImpl) CreateGlobalCommand(applicationID api.Snowflake, command api.Command) (rCommand *api.Command, err error) { - return rCommand, r.Request(endpoints.CreateGlobalCommand.Compile(applicationID), command, &rCommand) + err = r.Request(endpoints.CreateGlobalCommand.Compile(applicationID), command, &rCommand) + if err != nil { + return + } + rCommand.Disgo = r.disgo + return } // SetGlobalCommands lets you override all global commands @@ -380,17 +402,24 @@ func (r RestClientImpl) SetGlobalCommands(applicationID api.Snowflake, commands err = api.ErrTooMuchApplicationCommands return } - return rCommands, r.Request(endpoints.SetGlobalCommands.Compile(applicationID), commands, &rCommands) -} - -// GetGlobalCommand gets you a specific global global command -func (r RestClientImpl) GetGlobalCommand(applicationID api.Snowflake, commandID api.Snowflake) (rCommand *api.Command, err error) { - return rCommand, r.Request(endpoints.GetGlobalCommand.Compile(applicationID, commandID), nil, &rCommand) + err = r.Request(endpoints.SetGlobalCommands.Compile(applicationID), commands, &rCommands) + if err != nil { + return + } + for _, cmd := range rCommands { + cmd.Disgo = r.disgo + } + return } // EditGlobalCommand lets you edit a specific global command -func (r RestClientImpl) EditGlobalCommand(applicationID api.Snowflake, commandID api.Snowflake, command api.Command) (rCommand *api.Command, err error) { - return rCommand, r.Request(endpoints.EditGlobalCommand.Compile(applicationID, commandID), command, &rCommand) +func (r RestClientImpl) EditGlobalCommand(applicationID api.Snowflake, commandID api.Snowflake, command api.UpdateCommand) (rCommand *api.Command, err error) { + err = r.Request(endpoints.EditGlobalCommand.Compile(applicationID, commandID), command, &rCommand) + if err != nil { + return + } + rCommand.Disgo = r.disgo + return } // DeleteGlobalCommand lets you delete a specific global command @@ -400,12 +429,26 @@ func (r RestClientImpl) DeleteGlobalCommand(applicationID api.Snowflake, command // GetGuildCommands gets you all guild_events commands func (r RestClientImpl) GetGuildCommands(applicationID api.Snowflake, guildID api.Snowflake) (commands []*api.Command, err error) { - return commands, r.Request(endpoints.GetGuildCommands.Compile(applicationID, guildID), nil, &commands) + err = r.Request(endpoints.GetGuildCommands.Compile(applicationID, guildID), nil, &commands) + if err != nil { + return + } + for _, cmd := range commands { + cmd.Disgo = r.disgo + cmd.GuildID = &guildID + } + return } -// CreateGuildGuildCommand lets you create a new guild_events command +// CreateGuildCommand lets you create a new guild_events command func (r RestClientImpl) CreateGuildCommand(applicationID api.Snowflake, guildID api.Snowflake, command api.Command) (rCommand *api.Command, err error) { - return rCommand, r.Request(endpoints.CreateGuildCommand.Compile(applicationID, guildID), command, &rCommand) + err = r.Request(endpoints.CreateGuildCommand.Compile(applicationID, guildID), command, &rCommand) + if err != nil { + return + } + rCommand.Disgo = r.disgo + rCommand.GuildID = &guildID + return } // SetGuildCommands lets you override all guild_events commands @@ -414,17 +457,37 @@ func (r RestClientImpl) SetGuildCommands(applicationID api.Snowflake, guildID ap err = api.ErrTooMuchApplicationCommands return } - return rCommands, r.Request(endpoints.SetGuildCommands.Compile(applicationID, guildID), commands, &rCommands) + err = r.Request(endpoints.SetGuildCommands.Compile(applicationID, guildID), commands, &rCommands) + if err != nil { + return + } + for _, cmd := range rCommands { + cmd.Disgo = r.disgo + cmd.GuildID = &guildID + } + return } // GetGuildCommand gets you a specific guild_events command func (r RestClientImpl) GetGuildCommand(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake) (rCommand *api.Command, err error) { - return rCommand, r.Request(endpoints.GetGuildCommand.Compile(applicationID, guildID, commandID), nil, &rCommand) + err = r.Request(endpoints.GetGuildCommand.Compile(applicationID, guildID, commandID), nil, &rCommand) + if err != nil { + return + } + rCommand.Disgo = r.disgo + rCommand.GuildID = &guildID + return } // EditGuildCommand lets you edit a specific guild_events command -func (r RestClientImpl) EditGuildCommand(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake, command api.Command) (rCommand *api.Command, err error) { - return rCommand, r.Request(endpoints.EditGuildCommand.Compile(applicationID, guildID, commandID), command, &rCommand) +func (r RestClientImpl) EditGuildCommand(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake, command api.UpdateCommand) (rCommand *api.Command, err error) { + err = r.Request(endpoints.EditGuildCommand.Compile(applicationID, guildID, commandID), command, &rCommand) + if err != nil { + return + } + rCommand.Disgo = r.disgo + rCommand.GuildID = &guildID + return } // DeleteGuildCommand lets you delete a specific guild_events command @@ -433,12 +496,12 @@ func (r RestClientImpl) DeleteGuildCommand(applicationID api.Snowflake, guildID } // GetGuildCommandsPermissions returns the api.CommandPermission for a all api.Command(s) in a guild -func (r RestClientImpl) GetGuildCommandsPermissions(applicationID api.Snowflake, guildID api.Snowflake) (rCommandsPermissions []*api.CommandPermission, err error) { +func (r RestClientImpl) GetGuildCommandsPermissions(applicationID api.Snowflake, guildID api.Snowflake) (rCommandsPermissions []*api.GuildCommandPermissions, err error) { return rCommandsPermissions, r.Request(endpoints.GetGuildCommandPermissions.Compile(applicationID, guildID), nil, &rCommandsPermissions) } // GetGuildCommandPermissions returns the api.CommandPermission for a specific api.Command in a guild -func (r RestClientImpl) GetGuildCommandPermissions(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake) (rCommandPermissions *api.CommandPermission, err error) { +func (r RestClientImpl) GetGuildCommandPermissions(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake) (rCommandPermissions *api.GuildCommandPermissions, err error) { return rCommandPermissions, r.Request(endpoints.GetGuildCommandPermission.Compile(applicationID, guildID, commandID), nil, &rCommandPermissions) } From 05bffe223f3a2d53c25f653c10ce89dbe0de2853 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Thu, 8 Apr 2021 02:21:33 +0200 Subject: [PATCH 27/65] fixed stuff --- api/command.go | 8 ++++---- api/disgo.go | 2 +- api/guild.go | 2 +- internal/disgo_impl.go | 2 +- internal/gateway_impl.go | 2 ++ testbot/testbot.go | 5 +++-- 6 files changed, 12 insertions(+), 9 deletions(-) diff --git a/api/command.go b/api/command.go index b426d8db..f9fd8b49 100644 --- a/api/command.go +++ b/api/command.go @@ -91,13 +91,13 @@ func (c *Command) Update(command UpdateCommand) error { } // SetPermissions sets the GuildCommandPermissions for a specific Guild. this overrides all existing CommandPermission(s). thx discord for that -func (c Command) SetPermissions(guildID Snowflake, permissions ...CommandPermission) (*GuildCommandPermissions, error) { +func (c *Command) SetPermissions(guildID Snowflake, permissions ...CommandPermission) error { perms, err := c.Disgo.RestClient().SetGuildCommandPermissions(c.Disgo.SelfUserID(), guildID, c.ID, SetGuildCommandPermissions{Permissions: permissions}) if err != nil { - return nil, err + return err } c.GuildPermissions[guildID] = perms - return perms, nil + return nil } // GetPermissions returns the GuildCommandPermissions for the specific Guild from the Cache @@ -106,7 +106,7 @@ func (c Command) GetPermissions(guildID Snowflake) *GuildCommandPermissions { } // FetchPermissions fetched the GuildCommandPermissions for a specific Guild from discord -func (c Command) FetchPermissions(guildID Snowflake) (*GuildCommandPermissions, error) { +func (c *Command) FetchPermissions(guildID Snowflake) (*GuildCommandPermissions, error) { perms, err := c.Disgo.RestClient().GetGuildCommandPermissions(c.Disgo.SelfUserID(), guildID, c.ID) if err != nil { return nil, err diff --git a/api/disgo.go b/api/disgo.go index 4caf5072..2912142b 100644 --- a/api/disgo.go +++ b/api/disgo.go @@ -31,7 +31,7 @@ type Disgo interface { GetCommand(commandID Snowflake) (*Command, error) GetCommands() ([]*Command, error) CreateCommand(command Command) (*Command, error) - EditCommand(commandID Snowflake, command Command) (*Command, error) + EditCommand(commandID Snowflake, command UpdateCommand) (*Command, error) DeleteCommand(command Command) (*Command, error) SetCommands(commands ...Command) ([]*Command, error) } diff --git a/api/guild.go b/api/guild.go index 5bfb7c3b..e00dabb0 100644 --- a/api/guild.go +++ b/api/guild.go @@ -211,7 +211,7 @@ func (g Guild) CreateCommand(command Command) (*Command, error) { } // EditCommand edits a specific guild command -func (g Guild) EditCommand(commandID Snowflake, command Command) (*Command, error) { +func (g Guild) EditCommand(commandID Snowflake, command UpdateCommand) (*Command, error) { return g.Disgo.RestClient().EditGuildCommand(g.Disgo.SelfUserID(), g.ID, commandID, command) } diff --git a/internal/disgo_impl.go b/internal/disgo_impl.go index f9ac1720..5e2f6494 100644 --- a/internal/disgo_impl.go +++ b/internal/disgo_impl.go @@ -175,7 +175,7 @@ func (d DisgoImpl) CreateCommand(command api.Command) (*api.Command, error) { } // EditCommand edits a specific guild command -func (d DisgoImpl) EditCommand(commandID api.Snowflake, command api.Command) (*api.Command, error) { +func (d DisgoImpl) EditCommand(commandID api.Snowflake, command api.UpdateCommand) (*api.Command, error) { return d.RestClient().EditGlobalCommand(d.SelfUserID(), commandID, command) } diff --git a/internal/gateway_impl.go b/internal/gateway_impl.go index f1944dab..daa7ddbd 100644 --- a/internal/gateway_impl.go +++ b/internal/gateway_impl.go @@ -183,11 +183,13 @@ func (g *GatewayImpl) Close() { if g.quit != nil { log.Info("closing gateway goroutines...") close(g.quit) + g.quit = nil log.Info("closed gateway goroutines") } if g.conn != nil { if err := g.conn.Close(); err != nil { log.Errorf("error while closing wsconn: %s", err) + g.conn = nil } } } diff --git a/testbot/testbot.go b/testbot/testbot.go index ae0be920..2e693c66 100644 --- a/testbot/testbot.go +++ b/testbot/testbot.go @@ -43,7 +43,7 @@ func main() { return } - commands := []api.Command{ + rawCmds := []api.Command{ { Name: "eval", Description: "runs some go code", @@ -115,7 +115,8 @@ func main() { }, } - cmds, err := dgo.RestClient().SetGuildCommands(dgo.SelfUserID(), guildID, commands...) + // using the api.RestClient directly to avoid the guild needing to be cached + cmds, err := dgo.RestClient().SetGuildCommands(dgo.SelfUserID(), guildID, rawCmds...) if err != nil { log.Errorf("error while registering guild commands: %s", err) } From 68378a738154ec4d3a74c12d91ad30e31e293cf6 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Thu, 8 Apr 2021 02:28:10 +0200 Subject: [PATCH 28/65] fixed docs --- api/command.go | 1 + api/endpoints/token.go | 5 +++++ internal/handlers/application_command_create.go | 2 +- internal/handlers/application_command_delete.go | 2 +- internal/handlers/application_command_update.go | 2 +- 5 files changed, 9 insertions(+), 3 deletions(-) diff --git a/api/command.go b/api/command.go index f9fd8b49..924b6a10 100644 --- a/api/command.go +++ b/api/command.go @@ -169,6 +169,7 @@ type GuildCommandPermissions struct { // CommandPermissionType is the type of the CommandPermission type CommandPermissionType int +// types of CommandPermissionType const ( CommandPermissionTypeRole = iota + 1 CommandPermissionTypeUser diff --git a/api/endpoints/token.go b/api/endpoints/token.go index 8fa9f5a8..887a321c 100644 --- a/api/endpoints/token.go +++ b/api/endpoints/token.go @@ -4,21 +4,26 @@ import ( "strings" ) +// Token holds a discord token and is used to keep your logs clean from critical information type Token string +// MarshalJSON makes sure we don#t send ********* to discords as tokens func (t Token) MarshalJSON() ([]byte, error) { return []byte("\""+t+"\""), nil } +// UnmarshalJSON makes sure we parse tokens from discord correctly func (t *Token) UnmarshalJSON(raw []byte) error { *t = Token(strings.ReplaceAll(string(raw), "\"", "")) return nil } +// String masks the token func (t Token) String() string { return strings.Repeat("*", len(t)) } +// GoString masks the token func (t Token) GoString() string { return t.String() } diff --git a/internal/handlers/application_command_create.go b/internal/handlers/application_command_create.go index 2e1e78a3..2824c9ae 100644 --- a/internal/handlers/application_command_create.go +++ b/internal/handlers/application_command_create.go @@ -4,7 +4,7 @@ import ( "github.com/DisgoOrg/disgo/api" ) -// GuildCreateHandler handles api.ApplicationCommandCreateEvent +// ApplicationCommandCreateHandler handles api.ApplicationCommandCreateEvent type ApplicationCommandCreateHandler struct{} // Event returns the raw gateway event Event diff --git a/internal/handlers/application_command_delete.go b/internal/handlers/application_command_delete.go index cc4f7c2d..fa472868 100644 --- a/internal/handlers/application_command_delete.go +++ b/internal/handlers/application_command_delete.go @@ -4,7 +4,7 @@ import ( "github.com/DisgoOrg/disgo/api" ) -// GuildCreateHandler handles api.ApplicationCommandCreateEvent +// ApplicationCommandDeleteHandler handles api.ApplicationCommandCreateEvent type ApplicationCommandDeleteHandler struct{} // Event returns the raw gateway event Event diff --git a/internal/handlers/application_command_update.go b/internal/handlers/application_command_update.go index f7335ad2..4f8dbb0d 100644 --- a/internal/handlers/application_command_update.go +++ b/internal/handlers/application_command_update.go @@ -4,7 +4,7 @@ import ( "github.com/DisgoOrg/disgo/api" ) -// GuildCreateHandler handles api.ApplicationCommandCreateEvent +// ApplicationCommandUpdateHandler handles api.ApplicationCommandCreateEvent type ApplicationCommandUpdateHandler struct{} // Event returns the raw gateway event Event From 3e14b463e965d6ba85002b649274d42dab397554 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Thu, 8 Apr 2021 18:37:19 +0200 Subject: [PATCH 29/65] added most events for now and changed some stuff for clearity --- api/cache.go | 2 +- api/disgo.go | 15 +-- api/endpoints/request.go | 5 + api/endpoints/response.go | 5 + api/events/application_command_events.go | 28 +++++ api/events/category_events.go | 29 +++++ api/events/channel_events.go | 65 +---------- api/events/dm_event.go | 20 ---- api/events/dm_events.go | 29 +++++ api/events/dm_message_event.go | 9 +- api/events/dm_message_reaction_events.go | 27 +++++ api/events/emote_events.go | 30 +++++ api/events/exception_event.go | 5 + api/events/gateway_status_event.go | 32 +++++ api/events/generic_event.go | 12 +- api/events/guild_events.go | 19 ++- api/events/guild_member_events.go | 9 +- api/events/guild_message_events.go | 18 +-- api/events/guild_message_reaction_events.go | 27 +++++ api/events/guild_role_events.go | 26 ----- api/events/guild_voice_events.go | 26 +++++ api/events/heartbeat_event.go | 7 ++ api/events/http_request_events.go | 16 +++ api/events/interaction_events.go | 110 ++---------------- api/events/listener_adapter.go | 32 ++--- .../{message_event.go => message_events.go} | 17 +-- api/events/message_reaction_events.go | 27 +++++ api/events/raw_gateway_event.go | 14 +++ .../{ready_events.go => ready_event.go} | 3 +- api/events/role_events.go | 34 ++++++ api/events/self_update_events.go | 11 ++ api/events/store_events.go | 29 +++++ api/events/text_events.go | 29 +++++ api/events/user_activity_events.go | 26 +++++ api/events/user_events.go | 44 +++++++ api/events/voice_events.go | 29 +++++ api/gateway.go | 98 ++++++++-------- api/gateway_events.go | 2 +- api/interaction.go | 97 +++++++++++++++ api/message.go | 30 ++--- internal/cache_impl.go | 8 +- internal/event_manager_impl.go | 10 +- internal/gateway_impl.go | 6 +- .../handlers/application_command_create.go | 4 +- .../handlers/application_command_delete.go | 4 +- .../handlers/application_command_update.go | 4 +- internal/handlers/guild_create_handler.go | 6 +- internal/handlers/guild_delete_handler.go | 8 +- internal/handlers/guild_member_add_handler.go | 6 +- .../handlers/guild_member_remove_handler.go | 6 +- .../handlers/guild_member_update_handler.go | 6 +- .../handlers/guild_role_create_handler.go | 12 +- .../handlers/guild_role_delete_handler.go | 14 +-- .../handlers/guild_role_update_handler.go | 14 +-- internal/handlers/guild_update_handler.go | 8 +- .../handlers/interaction_create_handler.go | 14 +-- .../interaction_create_webhook_handler.go | 6 +- internal/handlers/message_create_handler.go | 46 ++++---- internal/handlers/ready_handler.go | 4 +- .../handlers/voice_server_update_handler.go | 4 +- .../handlers/voice_state_update_handler.go | 4 +- internal/webhook_server_impl.go | 2 +- 62 files changed, 873 insertions(+), 416 deletions(-) create mode 100644 api/endpoints/request.go create mode 100644 api/endpoints/response.go create mode 100644 api/events/application_command_events.go create mode 100644 api/events/category_events.go delete mode 100644 api/events/dm_event.go create mode 100644 api/events/dm_events.go create mode 100644 api/events/dm_message_reaction_events.go create mode 100644 api/events/emote_events.go create mode 100644 api/events/exception_event.go create mode 100644 api/events/gateway_status_event.go create mode 100644 api/events/guild_message_reaction_events.go delete mode 100644 api/events/guild_role_events.go create mode 100644 api/events/guild_voice_events.go create mode 100644 api/events/heartbeat_event.go create mode 100644 api/events/http_request_events.go rename api/events/{message_event.go => message_events.go} (71%) create mode 100644 api/events/message_reaction_events.go create mode 100644 api/events/raw_gateway_event.go rename api/events/{ready_events.go => ready_event.go} (82%) create mode 100644 api/events/role_events.go create mode 100644 api/events/self_update_events.go create mode 100644 api/events/store_events.go create mode 100644 api/events/text_events.go create mode 100644 api/events/user_activity_events.go create mode 100644 api/events/user_events.go create mode 100644 api/events/voice_events.go diff --git a/api/cache.go b/api/cache.go index c8da9a36..e1cdc192 100644 --- a/api/cache.go +++ b/api/cache.go @@ -50,7 +50,7 @@ type Cache interface { CacheVoiceState(voiceState *VoiceState) UncacheVoiceState(guildID Snowflake, userID Snowflake) - Role(Snowflake, Snowflake) *Role + Role(roleID Snowflake) *Role RolesByName(Snowflake, string, bool) []*Role Roles(Snowflake) []*Role AllRoles() []*Role diff --git a/api/disgo.go b/api/disgo.go index 2912142b..02ad1c86 100644 --- a/api/disgo.go +++ b/api/disgo.go @@ -38,38 +38,39 @@ type Disgo interface { // EventHandler provides info about the EventHandler type EventHandler interface { - Event() GatewayEventName + Event() GatewayEventType New() interface{} } // GatewayEventHandler is used to handle raw gateway events type GatewayEventHandler interface { EventHandler - Handle(Disgo, EventManager, interface{}) + HandleGatewayEvent(disgo Disgo, eventManager EventManager, sequenceNumber int, payload interface{}) } // WebhookEventHandler is used to handle raw webhook events type WebhookEventHandler interface { EventHandler - Handle(Disgo, EventManager, chan interface{}, interface{}) + HandleWebhookEvent(disgo Disgo, eventManager EventManager, replyChannel chan interface{}, payload interface{}) } // EventListener is used to create new EventListener to listen to events type EventListener interface { - OnEvent(interface{}) + OnEvent(event interface{}) } // Event the basic interface each event implement type Event interface { Disgo() Disgo + SequenceNumber() int } // EventManager lets you listen for specific events triggered by raw gateway events type EventManager interface { Close() - AddEventListeners(...EventListener) - Handle(GatewayEventName, json.RawMessage, chan interface{}) - Dispatch(Event) + AddEventListeners(eventListeners ...EventListener) + Handle(eventType GatewayEventType, replyChannel chan interface{}, sequenceNumber int, payload json.RawMessage) + Dispatch(event Event) } // GetOS returns the simplified version of the operating system for sending to Discord in the IdentifyCommandDataProperties.OS payload diff --git a/api/endpoints/request.go b/api/endpoints/request.go new file mode 100644 index 00000000..eca1f069 --- /dev/null +++ b/api/endpoints/request.go @@ -0,0 +1,5 @@ +package endpoints + +type Request struct { + +} diff --git a/api/endpoints/response.go b/api/endpoints/response.go new file mode 100644 index 00000000..f7b84633 --- /dev/null +++ b/api/endpoints/response.go @@ -0,0 +1,5 @@ +package endpoints + +type Response struct { + StatusCode int +} diff --git a/api/events/application_command_events.go b/api/events/application_command_events.go new file mode 100644 index 00000000..32260d46 --- /dev/null +++ b/api/events/application_command_events.go @@ -0,0 +1,28 @@ +package events + +import ( + "github.com/DisgoOrg/disgo/api" +) + +type GenericApplicationCommandEvent struct { + GenericEvent + CommandID api.Snowflake + GuildID *api.Snowflake + Guild *api.Guild +} + +type ApplicationCommandCreateEvent struct { + GenericApplicationCommandEvent + Command *api.Command +} + +type ApplicationCommandUpdateEvent struct { + GenericApplicationCommandEvent + NewCommand *api.Command + OldCommand *api.Command +} + +type ApplicationCommandDeleteEvent struct { + GenericApplicationCommandEvent + Command *api.Command +} diff --git a/api/events/category_events.go b/api/events/category_events.go new file mode 100644 index 00000000..83621f54 --- /dev/null +++ b/api/events/category_events.go @@ -0,0 +1,29 @@ +package events + +import ( + "github.com/DisgoOrg/disgo/api" +) + +type GenericCategoryEvent struct { + GenericChannelEvent +} + +func (e GenericCategoryEvent) Category() *api.Category { + return e.Disgo().Cache().Category(e.ChannelID) +} + +type CategoryCreateEvent struct { + GenericCategoryEvent + Category *api.Category +} + +type CategoryUpdateEvent struct { + GenericChannelEvent + NewCategory *api.Category + OldCategory *api.Category +} + +type CategoryDeleteEvent struct { + GenericChannelEvent + Category *api.Category +} diff --git a/api/events/channel_events.go b/api/events/channel_events.go index c75139de..39d28344 100644 --- a/api/events/channel_events.go +++ b/api/events/channel_events.go @@ -1,6 +1,8 @@ package events -import "github.com/DisgoOrg/disgo/api" +import ( + "github.com/DisgoOrg/disgo/api" +) // GenericChannelEvent is called upon receiving an event in a api.Channel type GenericChannelEvent struct { @@ -8,67 +10,6 @@ type GenericChannelEvent struct { ChannelID api.Snowflake } -// Channel returns the api.Channel from the api.Cache func (e GenericChannelEvent) Channel() *api.Channel { return e.Disgo().Cache().Channel(e.ChannelID) } - -// GenericDMChannelEvent is called upon receiving an event in a api.DMChannel -type GenericDMChannelEvent struct { - GenericChannelEvent -} - -// DMChannel returns the api.DMChannel from the api.Cache -func (e GenericDMChannelEvent) DMChannel() *api.DMChannel { - return e.Disgo().Cache().DMChannel(e.ChannelID) -} - -// GenericMessageChannelEvent is called upon receiving an event in a api.MessageChannel -type GenericMessageChannelEvent struct { - GenericChannelEvent -} - -// MessageChannel returns the api.MessageChannel from the api.Cache -func (e GenericMessageChannelEvent) MessageChannel() *api.MessageChannel { - return e.Disgo().Cache().MessageChannel(e.ChannelID) -} - -// GenericTextChannelEvent is called upon receiving an event in a api.TextChannel -type GenericTextChannelEvent struct { - GenericChannelEvent -} - -// TextChannel returns the api.TextChannel from the api.Cache -func (e GenericTextChannelEvent) TextChannel() *api.TextChannel { - return e.Disgo().Cache().TextChannel(e.ChannelID) -} - -// GenericVoiceChannelEvent is called upon receiving an event in a api.VoiceChannel -type GenericVoiceChannelEvent struct { - GenericChannelEvent -} - -// VoiceChannel returns the api.VoiceChannel from the api.Cache -func (e GenericVoiceChannelEvent) VoiceChannel() *api.VoiceChannel { - return e.Disgo().Cache().VoiceChannel(e.ChannelID) -} - -// GenericCategoryEvent is called upon receiving an event in a api.Category -type GenericCategoryEvent struct { - GenericChannelEvent -} - -// Category returns the api.Category from the api.Cache -func (e GenericCategoryEvent) Category() *api.Category { - return e.Disgo().Cache().Category(e.ChannelID) -} - -// GenericStoreChannelEvent is called upon receiving an event in a api.StoreChannel -type GenericStoreChannelEvent struct { - GenericChannelEvent -} - -// StoreChannel returns the api.StoreChannel from the api.Cache -func (e GenericStoreChannelEvent) StoreChannel() *api.StoreChannel { - return e.Disgo().Cache().StoreChannel(e.ChannelID) -} diff --git a/api/events/dm_event.go b/api/events/dm_event.go deleted file mode 100644 index 4233cf76..00000000 --- a/api/events/dm_event.go +++ /dev/null @@ -1,20 +0,0 @@ -package events - -import "github.com/DisgoOrg/disgo/api" - -// GenericDMEvent is a generic dm channel event -type GenericDMEvent struct { - GenericEvent - UserID api.Snowflake - DMChannelID api.Snowflake -} - -// User gets the user from the api.Cache -func (e GenericDMEvent) User() *api.DMChannel { - return e.Disgo().Cache().DMChannel(e.DMChannelID) -} - -// DMChannel returns the api.DMChannel from the api.Cache -func (e GenericDMEvent) DMChannel() *api.DMChannel { - return e.Disgo().Cache().DMChannel(e.DMChannelID) -} diff --git a/api/events/dm_events.go b/api/events/dm_events.go new file mode 100644 index 00000000..99c33568 --- /dev/null +++ b/api/events/dm_events.go @@ -0,0 +1,29 @@ +package events + +import ( + "github.com/DisgoOrg/disgo/api" +) + +type GenericDMChannelEvent struct { + GenericChannelEvent +} + +func (e GenericDMChannelEvent) DMChannel() *api.DMChannel { + return e.Disgo().Cache().DMChannel(e.ChannelID) +} + +type DMChannelCreateEvent struct { + GenericDMChannelEvent + DMChannel *api.DMChannel +} + +type DMChannelUpdateEvent struct { + GenericDMChannelEvent + NewDMChannel *api.DMChannel + OldDMChannel *api.DMChannel +} + +type DMChannelDeleteEvent struct { + GenericDMChannelEvent + DMChannel *api.DMChannel +} diff --git a/api/events/dm_message_event.go b/api/events/dm_message_event.go index 5ca752ba..deb6c3f5 100644 --- a/api/events/dm_message_event.go +++ b/api/events/dm_message_event.go @@ -6,10 +6,13 @@ import ( // GenericDMMessageEvent generic api.DMChannel api.Message api.GenericEvent type GenericDMMessageEvent struct { - GenericDMEvent GenericMessageEvent } +func (e GenericDMMessageEvent) DMChannel() *api.DMChannel { + return e.Disgo().Cache().DMChannel(e.ChannelID) +} + // DMMessageReceivedEvent called upon receiving a api.Message in a api.DMChannel type DMMessageReceivedEvent struct { GenericDMMessageEvent @@ -19,10 +22,12 @@ type DMMessageReceivedEvent struct { // DMMessageUpdateEvent called upon editing a api.Message in a api.DMChannel type DMMessageUpdateEvent struct { GenericDMMessageEvent - Message *api.Message + NewMessage *api.Message + OldMessage *api.Message } // DMMessageDeleteEvent called upon deleting a api.Message in a api.DMChannel type DMMessageDeleteEvent struct { GenericDMMessageEvent + Message *api.Message } diff --git a/api/events/dm_message_reaction_events.go b/api/events/dm_message_reaction_events.go new file mode 100644 index 00000000..85ce504c --- /dev/null +++ b/api/events/dm_message_reaction_events.go @@ -0,0 +1,27 @@ +package events + +import "github.com/DisgoOrg/disgo/api" + +type GenericDMMessageReactionEvent struct { + GenericGuildMessageEvent + UserID api.Snowflake + User *api.User + MessageReaction api.MessageReaction +} + +type DMMessageReactionAddEvent struct { + GenericDMMessageReactionEvent +} + +type DMMessageReactionRemoveEvent struct { + GenericDMMessageReactionEvent +} + +type DMMessageReactionRemoveEmoteEvent struct { + GenericDMMessageEvent + MessageReaction api.MessageReaction +} + +type DMMessageReactionRemoveAllEvent struct { + GenericDMMessageEvent +} diff --git a/api/events/emote_events.go b/api/events/emote_events.go new file mode 100644 index 00000000..74e19ec3 --- /dev/null +++ b/api/events/emote_events.go @@ -0,0 +1,30 @@ +package events + +import ( + "github.com/DisgoOrg/disgo/api" +) + +type GenericEmoteEvent struct { + GenericGuildEvent + EmoteID api.Snowflake +} + +func (e GenericEmoteEvent) Emote() *api.Emote { + return e.Disgo().Cache().Emote(e.EmoteID) +} + +type EmoteCreateEvent struct { + GenericEmoteEvent + Emote *api.Emote +} + +type EmoteUpdateEvent struct { + GenericEmoteEvent + NewEmote *api.Emote + OldEmote *api.Emote +} + +type EmoteDeleteEvent struct { + GenericEmoteEvent + Emote *api.Emote +} diff --git a/api/events/exception_event.go b/api/events/exception_event.go new file mode 100644 index 00000000..f8e4dd01 --- /dev/null +++ b/api/events/exception_event.go @@ -0,0 +1,5 @@ +package events + +type ExceptionEvent struct { + Error error +} diff --git a/api/events/gateway_status_event.go b/api/events/gateway_status_event.go new file mode 100644 index 00000000..6831a0b9 --- /dev/null +++ b/api/events/gateway_status_event.go @@ -0,0 +1,32 @@ +package events + +import ( + "github.com/DisgoOrg/disgo/api" +) + +type GenericGatewayStatusEvent struct { + GenericEvent + Status api.GatewayStatus +} + +type ConnectedEvent struct { + GenericGatewayStatusEvent +} + +type ReconnectedEvent struct { + GenericGatewayStatusEvent +} + +type ResumedEvent struct { + GenericGatewayStatusEvent +} + +type DisconnectedEvent struct { + GenericGatewayStatusEvent +} + +type ShutdownEvent struct { + GenericGatewayStatusEvent +} + + diff --git a/api/events/generic_event.go b/api/events/generic_event.go index c15f80c6..905bdc9f 100644 --- a/api/events/generic_event.go +++ b/api/events/generic_event.go @@ -3,16 +3,22 @@ package events import "github.com/DisgoOrg/disgo/api" // NewEvent constructs a new GenericEvent with the provided Disgo instance -func NewEvent(disgo api.Disgo) GenericEvent { - return GenericEvent{disgo: disgo} +func NewEvent(disgo api.Disgo, sequenceNumber int) GenericEvent { + return GenericEvent{disgo: disgo, sequenceNumber: sequenceNumber} } // GenericEvent the base event structure type GenericEvent struct { - disgo api.Disgo + disgo api.Disgo + sequenceNumber int } // Disgo returns the Disgo instance for this event func (d GenericEvent) Disgo() api.Disgo { return d.disgo } + +// SequenceNumber returns the sequence number of the gateway event +func (d GenericEvent) SequenceNumber() int { + return d.sequenceNumber +} diff --git a/api/events/guild_events.go b/api/events/guild_events.go index 0fb7778d..2e7ff529 100644 --- a/api/events/guild_events.go +++ b/api/events/guild_events.go @@ -18,7 +18,7 @@ func (e GenericGuildEvent) Guild() *api.Guild { // GuildUpdateEvent called upon receiving api.Guild updates type GuildUpdateEvent struct { GenericGuildEvent - Guild *api.Guild + NewGuild *api.Guild OldGuild *api.Guild } @@ -31,6 +31,7 @@ type GuildAvailableEvent struct { // GuildUnavailableEvent called when an available api.Guild becomes unavailable type GuildUnavailableEvent struct { GenericGuildEvent + Guild *api.Guild } // GuildJoinEvent called when the bot joins a api.Guild @@ -44,3 +45,19 @@ type GuildLeaveEvent struct { GenericGuildEvent Guild *api.Guild } + +// GuildReadyEvent called when the loaded the api.Guild in login phase +type GuildReadyEvent struct { + GenericGuildEvent + Guild *api.Guild +} + +type GuildBanEvent struct { + GenericGuildEvent + User *api.User +} + +type GuildUnbanEvent struct { + GenericGuildEvent + User *api.User +} diff --git a/api/events/guild_member_events.go b/api/events/guild_member_events.go index cac2a6ac..645eb613 100644 --- a/api/events/guild_member_events.go +++ b/api/events/guild_member_events.go @@ -1,6 +1,8 @@ package events -import "github.com/DisgoOrg/disgo/api" +import ( + "github.com/DisgoOrg/disgo/api" +) // GenericGuildMemberEvent generic api.Member event type GenericGuildMemberEvent struct { @@ -13,6 +15,11 @@ func (e GenericGuildMemberEvent) User() *api.User { return e.Disgo().Cache().User(e.UserID) } +// Member gets the api.Member form the api.Cache +func (e GenericGuildMemberEvent) Member() *api.Member { + return e.Disgo().Cache().Member(e.GuildID, e.UserID) +} + // GuildMemberJoinEvent indicates that a api.Member joined the api.Guild type GuildMemberJoinEvent struct { GenericGuildMemberEvent diff --git a/api/events/guild_message_events.go b/api/events/guild_message_events.go index 2469c360..740568cf 100644 --- a/api/events/guild_message_events.go +++ b/api/events/guild_message_events.go @@ -4,30 +4,34 @@ import ( "github.com/DisgoOrg/disgo/api" ) -// GenericGuildMessageEvent indicates that we received a api.Message api.GenericEvent in a api.Guild +// GenericDMMessageEvent generic api.DMChannel api.Message api.GenericEvent type GenericGuildMessageEvent struct { GenericMessageEvent GuildID api.Snowflake } -// Guild returns the api.Guild from the api.Cache func (e GenericGuildMessageEvent) Guild() *api.Guild { return e.Disgo().Cache().Guild(e.GuildID) } -// GuildMessageReceivedEvent indicates that we received a api.Message in a api.Guild +func (e GenericGuildMessageEvent) TextChannel() *api.TextChannel { + return e.Disgo().Cache().TextChannel(e.ChannelID) +} + +// DMMessageReceivedEvent called upon receiving a api.Message in a api.DMChannel type GuildMessageReceivedEvent struct { GenericGuildMessageEvent - Message api.Message + Message *api.Message } -// GuildMessageUpdateEvent indicates that a api.Message was updated in a api.Guild +// DMMessageUpdateEvent called upon editing a api.Message in a api.DMChannel type GuildMessageUpdateEvent struct { GenericGuildMessageEvent - Message api.Message + NewMessage *api.Message + OldMessage *api.Message } -// GuildMessageDeleteEvent indicates that a api.Message was deleted in a api.Guild +// DMMessageDeleteEvent called upon deleting a api.Message in a api.DMChannel type GuildMessageDeleteEvent struct { GenericGuildMessageEvent Message *api.Message diff --git a/api/events/guild_message_reaction_events.go b/api/events/guild_message_reaction_events.go new file mode 100644 index 00000000..df2fd2ea --- /dev/null +++ b/api/events/guild_message_reaction_events.go @@ -0,0 +1,27 @@ +package events + +import "github.com/DisgoOrg/disgo/api" + +type GenericGuildMessageReactionEvent struct { + GenericGuildMessageEvent + UserID api.Snowflake + Member *api.Member + MessageReaction api.MessageReaction +} + +type GuildMessageReactionAddEvent struct { + GenericGuildMessageReactionEvent +} + +type GuildMessageReactionRemoveEvent struct { + GenericGuildMessageReactionEvent +} + +type GuildMessageReactionRemoveEmoteEvent struct { + GenericGuildMessageEvent + MessageReaction api.MessageReaction +} + +type GuildMessageReactionRemoveAllEvent struct { + GenericGuildMessageEvent +} diff --git a/api/events/guild_role_events.go b/api/events/guild_role_events.go deleted file mode 100644 index db36893e..00000000 --- a/api/events/guild_role_events.go +++ /dev/null @@ -1,26 +0,0 @@ -package events - -import "github.com/DisgoOrg/disgo/api" - -// GenericGuildRoleEvent generic api.Role event -type GenericGuildRoleEvent struct { - GenericGuildEvent - Role *api.Role - RoleID api.Snowflake -} - -// GuildRoleCreateEvent indicates that a api.Role got created -type GuildRoleCreateEvent struct { - GenericGuildEvent -} - -// GuildRoleDeleteEvent indicates that a api.Role got deleted -type GuildRoleDeleteEvent struct { - GenericGuildEvent -} - -// GuildRoleUpdateEvent indicates that a api.Role got updated -type GuildRoleUpdateEvent struct { - GenericGuildEvent - OldRole *api.Role -} diff --git a/api/events/guild_voice_events.go b/api/events/guild_voice_events.go new file mode 100644 index 00000000..e0fe3f56 --- /dev/null +++ b/api/events/guild_voice_events.go @@ -0,0 +1,26 @@ +package events + +import ( + "github.com/DisgoOrg/disgo/api" +) + +type GenericGuildVoiceEvent struct { + GenericGuildMemberEvent + Member *api.Member +} + +type GuildVoiceUpdateEvent struct { + GenericGuildVoiceEvent + NewVoiceState *api.VoiceState + OldVoiceState *api.VoiceState +} + +type GuildVoiceJoinEvent struct { + GenericGuildVoiceEvent + GenericVoiceChannelEvent +} + +type GuildVoiceLeaveEvent struct { + GenericGuildVoiceEvent + GenericVoiceChannelEvent +} diff --git a/api/events/heartbeat_event.go b/api/events/heartbeat_event.go new file mode 100644 index 00000000..93d4da68 --- /dev/null +++ b/api/events/heartbeat_event.go @@ -0,0 +1,7 @@ +package events + +type HeartbeatEvent struct { + GenericEvent + NewPing int + OldPing int +} diff --git a/api/events/http_request_events.go b/api/events/http_request_events.go new file mode 100644 index 00000000..602f2a3c --- /dev/null +++ b/api/events/http_request_events.go @@ -0,0 +1,16 @@ +package events + +import ( + "net/http" + + "github.com/DisgoOrg/disgo/api/endpoints" +) + +type GenericHttpEvent struct { + Request endpoints.Request + Response endpoints.Response +} + +func (e GenericHttpEvent) RateLimited() bool { + return e.Response.StatusCode == http.StatusTooManyRequests +} diff --git a/api/events/interaction_events.go b/api/events/interaction_events.go index fd50cf75..b8d01728 100644 --- a/api/events/interaction_events.go +++ b/api/events/interaction_events.go @@ -61,107 +61,10 @@ type SlashCommandEvent struct { CommandName string SubCommandName *string SubCommandGroupName *string - Options []*Option + Options []*api.Option Replied bool } -// Option holds info about an Option.Value -type Option struct { - Resolved *api.Resolved - Name string - Type api.CommandOptionType - Value interface{} -} - -// String returns the Option.Value as string -func (o Option) String() string { - return o.Value.(string) -} - -// Bool returns the Option.Value as bool -func (o Option) Bool() bool { - return o.Value.(bool) -} - -// Snowflake returns the Option.Value as api.Snowflake -func (o Option) Snowflake() api.Snowflake { - return api.Snowflake(o.String()) -} - -// User returns the Option.Value as api.User -func (o Option) User() *api.User { - return o.Resolved.Users[o.Snowflake()] -} - -// Member returns the Option.Value as api.Member -func (o Option) Member() *api.Member { - return o.Resolved.Members[o.Snowflake()] -} - -// Role returns the Option.Value as api.Role -func (o Option) Role() *api.Role { - return o.Resolved.Roles[o.Snowflake()] -} - -// Channel returns the Option.Value as api.Channel -func (o Option) Channel() *api.Channel { - return o.Resolved.Channels[o.Snowflake()] -} - -// MessageChannel returns the Option.Value as api.MessageChannel -func (o Option) MessageChannel() *api.MessageChannel { - channel := o.Channel() - if channel == nil || (channel.Type != api.ChannelTypeText && channel.Type != api.ChannelTypeNews) { - return nil - } - return &api.MessageChannel{Channel: *channel} -} - -// GuildChannel returns the Option.Value as api.GuildChannel -func (o Option) GuildChannel() *api.GuildChannel { - channel := o.Channel() - if channel == nil || (channel.Type != api.ChannelTypeText && channel.Type != api.ChannelTypeNews && channel.Type != api.ChannelTypeCategory && channel.Type != api.ChannelTypeStore && channel.Type != api.ChannelTypeVoice) { - return nil - } - return &api.GuildChannel{Channel: *channel} -} - -// VoiceChannel returns the Option.Value as api.VoiceChannel -func (o Option) VoiceChannel() *api.VoiceChannel { - channel := o.Channel() - if channel == nil || channel.Type != api.ChannelTypeVoice { - return nil - } - return &api.VoiceChannel{GuildChannel: api.GuildChannel{Channel: *channel}} -} - -// TextChannel returns the Option.Value as api.TextChannel -func (o Option) TextChannel() *api.TextChannel { - channel := o.Channel() - if channel == nil || (channel.Type != api.ChannelTypeText && channel.Type != api.ChannelTypeNews) { - return nil - } - return &api.TextChannel{GuildChannel: api.GuildChannel{Channel: *channel}, MessageChannel: api.MessageChannel{Channel: *channel}} -} - -// Category returns the Option.Value as api.Category -func (o Option) Category() *api.Category { - channel := o.Channel() - if channel == nil || channel.Type != api.ChannelTypeCategory { - return nil - } - return &api.Category{GuildChannel: api.GuildChannel{Channel: *channel}} -} - -// StoreChannel returns the Option.Value as api.StoreChannel -func (o Option) StoreChannel() *api.StoreChannel { - channel := o.Channel() - if channel == nil || channel.Type != api.ChannelTypeStore { - return nil - } - return &api.StoreChannel{GuildChannel: api.GuildChannel{Channel: *channel}} -} - // CommandPath returns the api.Command path func (e SlashCommandEvent) CommandPath() string { path := e.CommandName @@ -175,7 +78,7 @@ func (e SlashCommandEvent) CommandPath() string { } // Option returns an Option by name -func (e SlashCommandEvent) Option(name string) *Option { +func (e SlashCommandEvent) Option(name string) *api.Option { options := e.OptionN(name) if len(options) == 0 { return nil @@ -184,8 +87,8 @@ func (e SlashCommandEvent) Option(name string) *Option { } // OptionN returns Option(s) by name -func (e SlashCommandEvent) OptionN(name string) []*Option { - options := make([]*Option, 0) +func (e SlashCommandEvent) OptionN(name string) []*api.Option { + options := make([]*api.Option, 0) for _, option := range e.Options { if option.Name == name { options = append(options, option) @@ -195,8 +98,8 @@ func (e SlashCommandEvent) OptionN(name string) []*Option { } // OptionsT returns Option(s) by api.CommandOptionType -func (e SlashCommandEvent) OptionsT(optionType api.CommandOptionType) []*Option { - options := make([]*Option, 0) +func (e SlashCommandEvent) OptionsT(optionType api.CommandOptionType) []*api.Option { + options := make([]*api.Option, 0) for _, option := range e.Options { if option.Type == optionType { options = append(options, option) @@ -249,3 +152,4 @@ func (e *SlashCommandEvent) EditFollowup(messageID api.Snowflake, followupMessag func (e *SlashCommandEvent) DeleteFollowup(messageID api.Snowflake) error { return e.Disgo().RestClient().DeleteFollowupMessage(e.Disgo().SelfUserID(), e.Interaction.Token, messageID) } + diff --git a/api/events/listener_adapter.go b/api/events/listener_adapter.go index a193eeb6..24e12d25 100644 --- a/api/events/listener_adapter.go +++ b/api/events/listener_adapter.go @@ -17,10 +17,10 @@ type ListenerAdapter struct { OnGuildUnavailable func(event *GuildUnavailableEvent) // Guild Role Events - OnGenericGuildRole func(event *GenericGuildRoleEvent) - OnGuildRoleCreate func(event *GuildRoleCreateEvent) - OnGuildRoleUpdate func(event *GuildRoleUpdateEvent) - OnGuildRoleDelete func(event *GuildRoleDeleteEvent) + OnGenericRole func(event *GenericRoleEvent) + OnRoleCreate func(event *RoleCreateEvent) + OnRoleUpdate func(event *RoleUpdateEvent) + OnRoleDelete func(event *RoleDeleteEvent) // Message Events OnMessageReceived func(event *MessageReceivedEvent) @@ -66,21 +66,21 @@ func (l ListenerAdapter) OnEvent(event interface{}) { } // Guild Role Events - case GenericGuildRoleEvent: - if l.OnGenericGuildRole != nil { - l.OnGenericGuildRole(&e) + case GenericRoleEvent: + if l.OnGenericRole != nil { + l.OnGenericRole(&e) } - case GuildRoleCreateEvent: - if l.OnGuildRoleCreate != nil { - l.OnGuildRoleCreate(&e) + case RoleCreateEvent: + if l.OnRoleCreate != nil { + l.OnRoleCreate(&e) } - case GuildRoleUpdateEvent: - if l.OnGuildRoleUpdate != nil { - l.OnGuildRoleUpdate(&e) + case RoleUpdateEvent: + if l.OnRoleUpdate != nil { + l.OnRoleUpdate(&e) } - case GuildRoleDeleteEvent: - if l.OnGuildRoleDelete != nil { - l.OnGuildRoleDelete(&e) + case RoleDeleteEvent: + if l.OnRoleDelete != nil { + l.OnRoleDelete(&e) } // Message Events diff --git a/api/events/message_event.go b/api/events/message_events.go similarity index 71% rename from api/events/message_event.go rename to api/events/message_events.go index 71db6fc4..7426ca09 100644 --- a/api/events/message_event.go +++ b/api/events/message_events.go @@ -1,33 +1,36 @@ package events -import "github.com/DisgoOrg/disgo/api" +import ( + "github.com/DisgoOrg/disgo/api" +) // GenericMessageEvent generic api.Message event type GenericMessageEvent struct { GenericEvent - MessageID api.Snowflake - MessageChannelID api.Snowflake + MessageID api.Snowflake + ChannelID api.Snowflake } // MessageChannel returns the api.MessageChannel where this api.message got received func (e *GenericMessageEvent) MessageChannel() *api.MessageChannel { - return e.Disgo().Cache().MessageChannel(e.MessageChannelID) + return e.Disgo().Cache().MessageChannel(e.ChannelID) } // MessageDeleteEvent indicates a api.Message got deleted type MessageDeleteEvent struct { GenericMessageEvent - Message api.Message + Message *api.Message } // MessageReceivedEvent indicates a api.Message got received type MessageReceivedEvent struct { GenericMessageEvent - Message api.Message + Message *api.Message } // MessageUpdateEvent indicates a api.Message got update type MessageUpdateEvent struct { GenericMessageEvent - Message api.Message + NewMessage *api.Message + OldMessage *api.Message } diff --git a/api/events/message_reaction_events.go b/api/events/message_reaction_events.go new file mode 100644 index 00000000..8333b8d8 --- /dev/null +++ b/api/events/message_reaction_events.go @@ -0,0 +1,27 @@ +package events + +import "github.com/DisgoOrg/disgo/api" + +type GenericReactionEvents struct { + GenericMessageEvent + UserID api.Snowflake + User *api.User + MessageReaction api.MessageReaction +} + +type MessageReactionAddEvent struct { + GenericReactionEvents +} + +type MessageReactionRemoveEvent struct { + GenericReactionEvents +} + +type MessageReactionRemoveEmoteEvent struct { + GenericMessageEvent + MessageReaction api.MessageReaction +} + +type MessageReactionRemoveAllEvent struct { + GenericMessageEvent +} diff --git a/api/events/raw_gateway_event.go b/api/events/raw_gateway_event.go new file mode 100644 index 00000000..ac136681 --- /dev/null +++ b/api/events/raw_gateway_event.go @@ -0,0 +1,14 @@ +package events + +import ( + "encoding/json" + + "github.com/DisgoOrg/disgo/api" +) + +type RawGatewayEvent struct { + GenericEvent + Type api.GatewayEventType + RawPayload json.RawMessage + Payload map[string]interface{} +} diff --git a/api/events/ready_events.go b/api/events/ready_event.go similarity index 82% rename from api/events/ready_events.go rename to api/events/ready_event.go index 77bcb301..dbcae5ab 100644 --- a/api/events/ready_events.go +++ b/api/events/ready_event.go @@ -5,5 +5,6 @@ import "github.com/DisgoOrg/disgo/api" // ReadyEvent indicates we received the ReadyEvent from the api.Gateway type ReadyEvent struct { GenericEvent - api.ReadyGatewayEvent + ReadyEvent api.ReadyGatewayEvent } + diff --git a/api/events/role_events.go b/api/events/role_events.go new file mode 100644 index 00000000..a3f9ae85 --- /dev/null +++ b/api/events/role_events.go @@ -0,0 +1,34 @@ +package events + +import ( + "github.com/DisgoOrg/disgo/api" +) + +// GenericRoleEvent generic api.Role event +type GenericRoleEvent struct { + GenericGuildEvent + RoleID api.Snowflake +} + +func (e GenericRoleEvent) Role() *api.Role { + return e.Disgo().Cache().Role(e.RoleID) +} + +// RoleCreateEvent indicates that a api.Role got created +type RoleCreateEvent struct { + GenericGuildEvent + Role *api.Role +} + +// RoleUpdateEvent indicates that a api.Role got updated +type RoleUpdateEvent struct { + GenericGuildEvent + NewRole *api.Role + OldRole *api.Role +} + +// GuildRRoleDeleteEventoleDeleteEvent indicates that a api.Role got deleted +type RoleDeleteEvent struct { + GenericGuildEvent + Role *api.Role +} diff --git a/api/events/self_update_events.go b/api/events/self_update_events.go new file mode 100644 index 00000000..907c2d2e --- /dev/null +++ b/api/events/self_update_events.go @@ -0,0 +1,11 @@ +package events + +import ( + "github.com/DisgoOrg/disgo/api" +) + +type SelfUpdateEvent struct { + GenericEvent + NewSelf *api.User + OldSelf *api.User +} diff --git a/api/events/store_events.go b/api/events/store_events.go new file mode 100644 index 00000000..7cf30065 --- /dev/null +++ b/api/events/store_events.go @@ -0,0 +1,29 @@ +package events + +import ( + "github.com/DisgoOrg/disgo/api" +) + +type GenericStoreChannelEvent struct { + GenericChannelEvent +} + +func (e GenericStoreChannelEvent) Category() *api.StoreChannel { + return e.Disgo().Cache().StoreChannel(e.ChannelID) +} + +type StoreChannelCreateEvent struct { + GenericStoreChannelEvent + StoreChannel *api.Category +} + +type StoreChannelUpdateEvent struct { + GenericStoreChannelEvent + NewStoreChannel *api.StoreChannel + OldStoreChannel *api.StoreChannel +} + +type StoreChannelDeleteEvent struct { + GenericStoreChannelEvent + StoreChannel *api.StoreChannel +} diff --git a/api/events/text_events.go b/api/events/text_events.go new file mode 100644 index 00000000..55edc2c5 --- /dev/null +++ b/api/events/text_events.go @@ -0,0 +1,29 @@ +package events + +import ( + "github.com/DisgoOrg/disgo/api" +) + +type GenericTextChannelEvent struct { + GenericChannelEvent +} + +func (e GenericTextChannelEvent) Category() *api.TextChannel { + return e.Disgo().Cache().TextChannel(e.ChannelID) +} + +type TextChannelCreateEvent struct { + GenericTextChannelEvent + TextChannel *api.TextChannel +} + +type TextChannelUpdateEvent struct { + GenericTextChannelEvent + NewTextChannel *api.TextChannel + OldTextChannel *api.TextChannel +} + +type TextChannelDeleteEvent struct { + GenericTextChannelEvent + TextChannel *api.TextChannel +} diff --git a/api/events/user_activity_events.go b/api/events/user_activity_events.go new file mode 100644 index 00000000..7518e195 --- /dev/null +++ b/api/events/user_activity_events.go @@ -0,0 +1,26 @@ +package events + +import ( + "github.com/DisgoOrg/disgo/api" +) + +type GenericUserActivityEvent struct { + GenericGuildMemberEvent + Member *api.Member +} + +type UserActivityStartEvent struct { + GenericUserActivityEvent + Activity *api.Activity +} + +type UserActivityUpdateEvent struct { + GenericUserActivityEvent + NewActivities *api.Activity + OldActivities *api.Activity +} + +type UserActivityEndEvent struct { + GenericUserActivityEvent + Activity *api.Activity +} diff --git a/api/events/user_events.go b/api/events/user_events.go new file mode 100644 index 00000000..0a263445 --- /dev/null +++ b/api/events/user_events.go @@ -0,0 +1,44 @@ +package events + +import ( + "github.com/DisgoOrg/disgo/api" +) + +type GenericUserEvent struct { + GenericEvent + UserID api.Snowflake +} + +type UserUpdateEvent struct { + GenericUserEvent + NewUser *api.User + OldUser *api.User +} + +type UserTypingEvent struct { + GenericUserEvent + User *api.User + ChannelID api.Snowflake +} + +func (e UserTypingEvent) Channel() *api.Channel { + return e.Disgo().Cache().Channel(e.ChannelID) +} + +type GuildUserTypingEvent struct { + UserTypingEvent + GenericGuildMemberEvent + Member *api.Member +} + +func (e UserTypingEvent) TextChannel() *api.TextChannel { + return e.Disgo().Cache().TextChannel(e.ChannelID) +} + +type DMUserTypingEvent struct { + UserTypingEvent +} + +func (e UserTypingEvent) DMChannel() *api.DMChannel { + return e.Disgo().Cache().DMChannel(e.ChannelID) +} diff --git a/api/events/voice_events.go b/api/events/voice_events.go new file mode 100644 index 00000000..558b32d4 --- /dev/null +++ b/api/events/voice_events.go @@ -0,0 +1,29 @@ +package events + +import ( + "github.com/DisgoOrg/disgo/api" +) + +type GenericVoiceChannelEvent struct { + GenericChannelEvent +} + +func (e GenericVoiceChannelEvent) VoiceChannel() *api.VoiceChannel { + return e.Disgo().Cache().VoiceChannel(e.ChannelID) +} + +type VoiceChannelCreateEvent struct { + GenericVoiceChannelEvent + VoiceChannel *api.VoiceChannel +} + +type VoiceChannelUpdateEvent struct { + GenericVoiceChannelEvent + NewVoiceChannel *api.VoiceChannel + OldVoiceChannel *api.VoiceChannel +} + +type VoiceChannelDeleteEvent struct { + GenericVoiceChannelEvent + VoiceChannel *api.VoiceChannel +} diff --git a/api/gateway.go b/api/gateway.go index 734922b0..5a39c650 100644 --- a/api/gateway.go +++ b/api/gateway.go @@ -2,12 +2,12 @@ package api import "time" -// ConnectionStatus is the state that the client is currently in -type ConnectionStatus int +// GatewayStatus is the state that the client is currently in +type GatewayStatus int // Indicates how far along the client is to connecting const ( - Ready ConnectionStatus = iota + Ready GatewayStatus = iota Unconnected Connecting Reconnecting @@ -23,7 +23,7 @@ const ( type Gateway interface { Disgo() Disgo Open() error - Status() ConnectionStatus + Status() GatewayStatus Close() Latency() time.Duration } @@ -47,54 +47,54 @@ const ( OpHeartbeatACK ) -// GatewayEventName wraps all GatewayEventName types -type GatewayEventName string +// GatewayEventType wraps all GatewayEventType types +type GatewayEventType string // Constants for the gateway events const ( - GatewayEventApplicationCommandCreate GatewayEventName = "APPLICATION_COMMAND_CREATE" - GatewayEventApplicationCommandUpdate GatewayEventName = "APPLICATION_COMMAND_UPDATE" - GatewayEventApplicationCommandDelete GatewayEventName = "APPLICATION_COMMAND_DELETE" - GatewayEventChannelCreate GatewayEventName = "CHANNEL_CREATE" - GatewayEventChannelDelete GatewayEventName = "CHANNEL_DELETE" - GatewayEventChannelPinsUpdate GatewayEventName = "CHANNEL_PINS_UPDATE" - GatewayEventChannelUpdate GatewayEventName = "CHANNEL_UPDATE" - GatewayEventGuildBanAdd GatewayEventName = "GUILD_BAN_ADD" - GatewayEventGuildBanRemove GatewayEventName = "GUILD_BAN_REMOVE" - GatewayEventGuildCreate GatewayEventName = "GUILD_CREATE" - GatewayEventGuildDelete GatewayEventName = "GUILD_DELETE" - GatewayEventGuildEmojisUpdate GatewayEventName = "GUILD_EMOJIS_UPDATE" - GatewayEventGuildIntegrationsUpdate GatewayEventName = "GUILD_INTEGRATIONS_UPDATE" - GatewayEventGuildMemberAdd GatewayEventName = "GUILD_MEMBER_ADD" - GatewayEventGuildMemberRemove GatewayEventName = "GUILD_MEMBER_REMOVE" - GatewayEventGuildMemberUpdate GatewayEventName = "GUILD_MEMBER_UPDATE" - GatewayEventGuildMembersChunk GatewayEventName = "GUILD_MEMBERS_CHUNK" - GatewayEventGuildRoleCreate GatewayEventName = "GUILD_ROLE_CREATE" - GatewayEventGuildRoleDelete GatewayEventName = "GUILD_ROLE_DELETE" - GatewayEventGuildRoleUpdate GatewayEventName = "GUILD_ROLE_UPDATE" - GatewayEventGuildUpdate GatewayEventName = "GUILD_UPDATE" - GatewayEventInteractionCreate GatewayEventName = "INTERACTION_CREATE" - WebhookEventInteractionCreate GatewayEventName = "INTERACTION_WEBHOOK_CREATE" - GatewayEventMessageAck GatewayEventName = "MESSAGE_ACK" - GatewayEventMessageCreate GatewayEventName = "MESSAGE_CREATE" - GatewayEventMessageDelete GatewayEventName = "MESSAGE_DELETE" - GatewayEventMessageDeleteBulk GatewayEventName = "MESSAGE_DELETE_BULK" - GatewayEventMessageReactionAdd GatewayEventName = "MESSAGE_REACTION_ADD" - GatewayEventMessageReactionRemove GatewayEventName = "MESSAGE_REACTION_REMOVE" - GatewayEventMessageReactionRemoveAll GatewayEventName = "MESSAGE_REACTION_REMOVE_ALL" - GatewayEventMessageUpdate GatewayEventName = "MESSAGE_UPDATE" - GatewayEventPresenceUpdate GatewayEventName = "PRESENCE_UPDATE" - GatewayEventPresencesReplace GatewayEventName = "PRESENCES_REPLACE" - GatewayEventReady GatewayEventName = "READY" - GatewayEventResumed GatewayEventName = "RESUMED" - GatewayEventTypingStart GatewayEventName = "TYPING_START" - GatewayEventUserGuildSettingsUpdate GatewayEventName = "USER_GUILD_SETTINGS_UPDATE" - GatewayEventUserNoteUpdate GatewayEventName = "USER_NOTE_UPDATE" - GatewayEventUserSettingsUpdate GatewayEventName = "USER_SETTINGS_UPDATE" - GatewayEventUserUpdate GatewayEventName = "USER_UPDATE" - GatewayEventVoiceServerUpdate GatewayEventName = "VOICE_SERVER_UPDATE" - GatewayEventVoiceStateUpdate GatewayEventName = "VOICE_STATE_UPDATE" - GatewayEventWebhooksUpdate GatewayEventName = "WEBHOOKS_UPDATE" + GatewayEventApplicationCommandCreate GatewayEventType = "APPLICATION_COMMAND_CREATE" + GatewayEventApplicationCommandUpdate GatewayEventType = "APPLICATION_COMMAND_UPDATE" + GatewayEventApplicationCommandDelete GatewayEventType = "APPLICATION_COMMAND_DELETE" + GatewayEventChannelCreate GatewayEventType = "CHANNEL_CREATE" + GatewayEventChannelDelete GatewayEventType = "CHANNEL_DELETE" + GatewayEventChannelPinsUpdate GatewayEventType = "CHANNEL_PINS_UPDATE" + GatewayEventChannelUpdate GatewayEventType = "CHANNEL_UPDATE" + GatewayEventGuildBanAdd GatewayEventType = "GUILD_BAN_ADD" + GatewayEventGuildBanRemove GatewayEventType = "GUILD_BAN_REMOVE" + GatewayEventGuildCreate GatewayEventType = "GUILD_CREATE" + GatewayEventGuildDelete GatewayEventType = "GUILD_DELETE" + GatewayEventGuildEmojisUpdate GatewayEventType = "GUILD_EMOJIS_UPDATE" + GatewayEventGuildIntegrationsUpdate GatewayEventType = "GUILD_INTEGRATIONS_UPDATE" + GatewayEventGuildMemberAdd GatewayEventType = "GUILD_MEMBER_ADD" + GatewayEventGuildMemberRemove GatewayEventType = "GUILD_MEMBER_REMOVE" + GatewayEventGuildMemberUpdate GatewayEventType = "GUILD_MEMBER_UPDATE" + GatewayEventGuildMembersChunk GatewayEventType = "GUILD_MEMBERS_CHUNK" + GatewayEventGuildRoleCreate GatewayEventType = "GUILD_ROLE_CREATE" + GatewayEventGuildRoleDelete GatewayEventType = "GUILD_ROLE_DELETE" + GatewayEventGuildRoleUpdate GatewayEventType = "GUILD_ROLE_UPDATE" + GatewayEventGuildUpdate GatewayEventType = "GUILD_UPDATE" + GatewayEventInteractionCreate GatewayEventType = "INTERACTION_CREATE" + WebhookEventInteractionCreate GatewayEventType = "INTERACTION_WEBHOOK_CREATE" + GatewayEventMessageAck GatewayEventType = "MESSAGE_ACK" + GatewayEventMessageCreate GatewayEventType = "MESSAGE_CREATE" + GatewayEventMessageDelete GatewayEventType = "MESSAGE_DELETE" + GatewayEventMessageDeleteBulk GatewayEventType = "MESSAGE_DELETE_BULK" + GatewayEventMessageReactionAdd GatewayEventType = "MESSAGE_REACTION_ADD" + GatewayEventMessageReactionRemove GatewayEventType = "MESSAGE_REACTION_REMOVE" + GatewayEventMessageReactionRemoveAll GatewayEventType = "MESSAGE_REACTION_REMOVE_ALL" + GatewayEventMessageUpdate GatewayEventType = "MESSAGE_UPDATE" + GatewayEventPresenceUpdate GatewayEventType = "PRESENCE_UPDATE" + GatewayEventPresencesReplace GatewayEventType = "PRESENCES_REPLACE" + GatewayEventReady GatewayEventType = "READY" + GatewayEventResumed GatewayEventType = "RESUMED" + GatewayEventTypingStart GatewayEventType = "TYPING_START" + GatewayEventUserGuildSettingsUpdate GatewayEventType = "USER_GUILD_SETTINGS_UPDATE" + GatewayEventUserNoteUpdate GatewayEventType = "USER_NOTE_UPDATE" + GatewayEventUserSettingsUpdate GatewayEventType = "USER_SETTINGS_UPDATE" + GatewayEventUserUpdate GatewayEventType = "USER_UPDATE" + GatewayEventVoiceServerUpdate GatewayEventType = "VOICE_SERVER_UPDATE" + GatewayEventVoiceStateUpdate GatewayEventType = "VOICE_STATE_UPDATE" + GatewayEventWebhooksUpdate GatewayEventType = "WEBHOOKS_UPDATE" ) // GatewayRs contains the response for GET /gateway diff --git a/api/gateway_events.go b/api/gateway_events.go index e568118b..8aae2aaf 100644 --- a/api/gateway_events.go +++ b/api/gateway_events.go @@ -9,7 +9,7 @@ import ( type GatewayPacket struct { Op GatewayOp `json:"op"` S *int `json:"s,omitempty"` - T *GatewayEventName `json:"t,omitempty"` + T *GatewayEventType `json:"t,omitempty"` } // RawGatewayEvent specifies the data for the GatewayCommand payload that is being sent diff --git a/api/interaction.go b/api/interaction.go index 96f2bee8..689c17e3 100644 --- a/api/interaction.go +++ b/api/interaction.go @@ -47,3 +47,100 @@ type OptionData struct { Value interface{} `json:"value,omitempty"` Options []*OptionData `json:"options,omitempty"` } + +// Option holds info about an Option.Value +type Option struct { + Resolved *Resolved + Name string + Type CommandOptionType + Value interface{} +} + +// String returns the Option.Value as string +func (o Option) String() string { + return o.Value.(string) +} + +// Bool returns the Option.Value as bool +func (o Option) Bool() bool { + return o.Value.(bool) +} + +// Snowflake returns the Option.Value as Snowflake +func (o Option) Snowflake() Snowflake { + return Snowflake(o.String()) +} + +// User returns the Option.Value as User +func (o Option) User() *User { + return o.Resolved.Users[o.Snowflake()] +} + +// Member returns the Option.Value as Member +func (o Option) Member() *Member { + return o.Resolved.Members[o.Snowflake()] +} + +// Role returns the Option.Value as Role +func (o Option) Role() *Role { + return o.Resolved.Roles[o.Snowflake()] +} + +// Channel returns the Option.Value as Channel +func (o Option) Channel() *Channel { + return o.Resolved.Channels[o.Snowflake()] +} + +// MessageChannel returns the Option.Value as MessageChannel +func (o Option) MessageChannel() *MessageChannel { + channel := o.Channel() + if channel == nil || (channel.Type != ChannelTypeText && channel.Type != ChannelTypeNews) { + return nil + } + return &MessageChannel{Channel: *channel} +} + +// GuildChannel returns the Option.Value as GuildChannel +func (o Option) GuildChannel() *GuildChannel { + channel := o.Channel() + if channel == nil || (channel.Type != ChannelTypeText && channel.Type != ChannelTypeNews && channel.Type != ChannelTypeCategory && channel.Type != ChannelTypeStore && channel.Type != ChannelTypeVoice) { + return nil + } + return &GuildChannel{Channel: *channel} +} + +// VoiceChannel returns the Option.Value as VoiceChannel +func (o Option) VoiceChannel() *VoiceChannel { + channel := o.Channel() + if channel == nil || channel.Type != ChannelTypeVoice { + return nil + } + return &VoiceChannel{GuildChannel: GuildChannel{Channel: *channel}} +} + +// TextChannel returns the Option.Value as TextChannel +func (o Option) TextChannel() *TextChannel { + channel := o.Channel() + if channel == nil || (channel.Type != ChannelTypeText && channel.Type != ChannelTypeNews) { + return nil + } + return &TextChannel{GuildChannel: GuildChannel{Channel: *channel}, MessageChannel: MessageChannel{Channel: *channel}} +} + +// Category returns the Option.Value as Category +func (o Option) Category() *Category { + channel := o.Channel() + if channel == nil || channel.Type != ChannelTypeCategory { + return nil + } + return &Category{GuildChannel: GuildChannel{Channel: *channel}} +} + +// StoreChannel returns the Option.Value as StoreChannel +func (o Option) StoreChannel() *StoreChannel { + channel := o.Channel() + if channel == nil || channel.Type != ChannelTypeStore { + return nil + } + return &StoreChannel{GuildChannel: GuildChannel{Channel: *channel}} +} diff --git a/api/message.go b/api/message.go index ebf5b7cf..43e23907 100644 --- a/api/message.go +++ b/api/message.go @@ -103,19 +103,19 @@ const ( // https://discord.com/developers/docs/resources/channel#message-object type Message struct { Disgo Disgo - ID Snowflake `json:"id"` - GuildID *Snowflake `json:"guild_id"` - Reactions []Reactions `json:"reactions"` - Attachments []interface{} `json:"attachments"` - TTS bool `json:"tts"` - Embeds []*Embed `json:"embeds,omitempty"` - CreatedAt time.Time `json:"timestamp"` - MentionEveryone bool `json:"mention_everyone"` - Pinned bool `json:"pinned"` - EditedTimestamp interface{} `json:"edited_timestamp"` - Author User `json:"author"` - MentionRoles []interface{} `json:"mention_roles"` - Content *string `json:"content,omitempty"` + ID Snowflake `json:"id"` + GuildID *Snowflake `json:"guild_id"` + Reactions []MessageReaction `json:"reactions"` + Attachments []interface{} `json:"attachments"` + TTS bool `json:"tts"` + Embeds []*Embed `json:"embeds,omitempty"` + CreatedAt time.Time `json:"timestamp"` + MentionEveryone bool `json:"mention_everyone"` + Pinned bool `json:"pinned"` + EditedTimestamp interface{} `json:"edited_timestamp"` + Author User `json:"author"` + MentionRoles []interface{} `json:"mention_roles"` + Content *string `json:"content,omitempty"` ChannelID Snowflake `json:"channel_id"` Mentions []interface{} `json:"mentions"` Type MessageType `json:"type"` @@ -191,8 +191,8 @@ func (m Message) Reply(message MessageCreate) (*Message, error) { return m.Disgo.RestClient().SendMessage(m.ChannelID, message) } -// Reactions contains information about the reactions of a message_events -type Reactions struct { +// MessageReaction contains information about the reactions of a message_events +type MessageReaction struct { Count int `json:"count"` Me bool `json:"me"` Emoji Emote `json:"emoji"` diff --git a/internal/cache_impl.go b/internal/cache_impl.go index 1378ec55..746e1bbf 100644 --- a/internal/cache_impl.go +++ b/internal/cache_impl.go @@ -426,9 +426,11 @@ func (c *CacheImpl) UncacheVoiceState(guildID api.Snowflake, userID api.Snowflak } // Role returns a role from cache by guild ID and role ID -func (c *CacheImpl) Role(guildID api.Snowflake, roleID api.Snowflake) *api.Role { - if guildRoles, ok := c.roles[guildID]; ok { - return guildRoles[roleID] +func (c *CacheImpl) Role(roleID api.Snowflake) *api.Role { + for _, guildRoles := range c.roles { + if role, ok := guildRoles[roleID]; ok { + return role + } } return nil } diff --git a/internal/event_manager_impl.go b/internal/event_manager_impl.go index f80ea166..4d5f9a1d 100644 --- a/internal/event_manager_impl.go +++ b/internal/event_manager_impl.go @@ -15,7 +15,7 @@ func newEventManagerImpl(disgo api.Disgo, listeners []api.EventListener) api.Eve disgo: disgo, channel: make(chan api.Event), listeners: listeners, - handlers: map[api.GatewayEventName]api.EventHandler{}, + handlers: map[api.GatewayEventType]api.EventHandler{}, } for _, handler := range handlers.GetAllHandlers() { eventManager.handlers[handler.Event()] = handler @@ -28,7 +28,7 @@ func newEventManagerImpl(disgo api.Disgo, listeners []api.EventListener) api.Eve type EventManagerImpl struct { disgo api.Disgo listeners []api.EventListener - handlers map[api.GatewayEventName]api.EventHandler + handlers map[api.GatewayEventType]api.EventHandler channel chan api.Event } @@ -39,7 +39,7 @@ func (e EventManagerImpl) Close() { } // Handle calls the correct api.EventHandler -func (e EventManagerImpl) Handle(name api.GatewayEventName, payload json.RawMessage, c chan interface{}) { +func (e EventManagerImpl) Handle(name api.GatewayEventType, c chan interface{}, sequenceNumber int, payload json.RawMessage) { if handler, ok := e.handlers[name]; ok { eventPayload := handler.New() if err := json.Unmarshal(payload, &eventPayload); err != nil { @@ -47,9 +47,9 @@ func (e EventManagerImpl) Handle(name api.GatewayEventName, payload json.RawMess } switch h := handler.(type) { case api.GatewayEventHandler: - h.Handle(e.disgo, e, eventPayload) + h.HandleGatewayEvent(e.disgo, e, sequenceNumber, eventPayload) case api.WebhookEventHandler: - h.Handle(e.disgo, e, c, eventPayload) + h.HandleWebhookEvent(e.disgo, e, c, eventPayload) } } } diff --git a/internal/gateway_impl.go b/internal/gateway_impl.go index daa7ddbd..0c2dac1e 100644 --- a/internal/gateway_impl.go +++ b/internal/gateway_impl.go @@ -29,7 +29,7 @@ type GatewayImpl struct { disgo api.Disgo conn *websocket.Conn quit chan interface{} - status api.ConnectionStatus + status api.GatewayStatus heartbeatInterval time.Duration lastHeartbeatSent time.Time lastHeartbeatReceived time.Time @@ -168,7 +168,7 @@ func (g *GatewayImpl) Open() error { } // Status returns the gateway connection status -func (g *GatewayImpl) Status() api.ConnectionStatus { +func (g *GatewayImpl) Status() api.GatewayStatus { return g.status } @@ -287,7 +287,7 @@ func (g *GatewayImpl) listen() { } d := g.Disgo() e := d.EventManager() - e.Handle(*event.T, event.D, nil) + e.Handle(*event.T, nil, *event.S, event.D) case api.OpHeartbeat: log.Debugf("received: OpHeartbeat") diff --git a/internal/handlers/application_command_create.go b/internal/handlers/application_command_create.go index 2824c9ae..b4862b3b 100644 --- a/internal/handlers/application_command_create.go +++ b/internal/handlers/application_command_create.go @@ -8,7 +8,7 @@ import ( type ApplicationCommandCreateHandler struct{} // Event returns the raw gateway event Event -func (h ApplicationCommandCreateHandler) Event() api.GatewayEventName { +func (h ApplicationCommandCreateHandler) Event() api.GatewayEventType { return api.GatewayEventApplicationCommandCreate } @@ -18,7 +18,7 @@ func (h ApplicationCommandCreateHandler) New() interface{} { } // Handle handles the specific raw gateway event -func (h ApplicationCommandCreateHandler) Handle(disgo api.Disgo, eventManager api.EventManager, i interface{}) { +func (h ApplicationCommandCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, i interface{}) { /*command, ok := i.(*api.Command) if !ok { return diff --git a/internal/handlers/application_command_delete.go b/internal/handlers/application_command_delete.go index fa472868..bc794799 100644 --- a/internal/handlers/application_command_delete.go +++ b/internal/handlers/application_command_delete.go @@ -8,7 +8,7 @@ import ( type ApplicationCommandDeleteHandler struct{} // Event returns the raw gateway event Event -func (h ApplicationCommandDeleteHandler) Event() api.GatewayEventName { +func (h ApplicationCommandDeleteHandler) Event() api.GatewayEventType { return api.GatewayEventApplicationCommandDelete } @@ -18,7 +18,7 @@ func (h ApplicationCommandDeleteHandler) New() interface{} { } // Handle handles the specific raw gateway event -func (h ApplicationCommandDeleteHandler) Handle(disgo api.Disgo, eventManager api.EventManager, i interface{}) { +func (h ApplicationCommandDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, i interface{}) { /*command, ok := i.(*api.Command) if !ok { return diff --git a/internal/handlers/application_command_update.go b/internal/handlers/application_command_update.go index 4f8dbb0d..8c0aa7cc 100644 --- a/internal/handlers/application_command_update.go +++ b/internal/handlers/application_command_update.go @@ -8,7 +8,7 @@ import ( type ApplicationCommandUpdateHandler struct{} // Event returns the raw gateway event Event -func (h ApplicationCommandUpdateHandler) Event() api.GatewayEventName { +func (h ApplicationCommandUpdateHandler) Event() api.GatewayEventType { return api.GatewayEventApplicationCommandUpdate } @@ -18,7 +18,7 @@ func (h ApplicationCommandUpdateHandler) New() interface{} { } // Handle handles the specific raw gateway event -func (h ApplicationCommandUpdateHandler) Handle(disgo api.Disgo, eventManager api.EventManager, i interface{}) { +func (h ApplicationCommandUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, i interface{}) { /*command, ok := i.(*api.Command) if !ok { return diff --git a/internal/handlers/guild_create_handler.go b/internal/handlers/guild_create_handler.go index 20e295ec..d5450a7d 100644 --- a/internal/handlers/guild_create_handler.go +++ b/internal/handlers/guild_create_handler.go @@ -9,7 +9,7 @@ import ( type GuildCreateHandler struct{} // Event returns the raw gateway event Event -func (h GuildCreateHandler) Event() api.GatewayEventName { +func (h GuildCreateHandler) Event() api.GatewayEventType { return api.GatewayEventGuildCreate } @@ -19,7 +19,7 @@ func (h GuildCreateHandler) New() interface{} { } // Handle handles the specific raw gateway event -func (h GuildCreateHandler) Handle(disgo api.Disgo, eventManager api.EventManager, i interface{}) { +func (h GuildCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { fullGuild, ok := i.(*api.FullGuild) if !ok { return @@ -98,7 +98,7 @@ func (h GuildCreateHandler) Handle(disgo api.Disgo, eventManager api.EventManage }*/ genericGuildEvent := events.GenericGuildEvent{ - GenericEvent: events.NewEvent(disgo), + GenericEvent: events.NewEvent(disgo, sequenceNumber), GuildID: guild.ID, } diff --git a/internal/handlers/guild_delete_handler.go b/internal/handlers/guild_delete_handler.go index c3188b17..80e4dd7f 100644 --- a/internal/handlers/guild_delete_handler.go +++ b/internal/handlers/guild_delete_handler.go @@ -9,7 +9,7 @@ import ( type GuildDeleteHandler struct{} // Event returns the raw gateway event Event -func (h GuildDeleteHandler) Event() api.GatewayEventName { +func (h GuildDeleteHandler) Event() api.GatewayEventType { return api.GatewayEventGuildDelete } @@ -19,7 +19,7 @@ func (h GuildDeleteHandler) New() interface{} { } // Handle handles the specific raw gateway event -func (h GuildDeleteHandler) Handle(disgo api.Disgo, eventManager api.EventManager, i interface{}) { +func (h GuildDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { guild, ok := i.(*api.Guild) if !ok { return @@ -29,7 +29,7 @@ func (h GuildDeleteHandler) Handle(disgo api.Disgo, eventManager api.EventManage disgo.Cache().Guild(guild.ID).Unavailable = true eventManager.Dispatch(events.GuildUnavailableEvent{ GenericGuildEvent: events.GenericGuildEvent{ - GenericEvent: events.NewEvent(disgo), + GenericEvent: events.NewEvent(disgo, sequenceNumber), GuildID: guild.ID, }, }) @@ -38,7 +38,7 @@ func (h GuildDeleteHandler) Handle(disgo api.Disgo, eventManager api.EventManage disgo.Cache().UncacheGuild(guild.ID) genericGuildEvent := events.GenericGuildEvent{ - GenericEvent: events.NewEvent(disgo), + GenericEvent: events.NewEvent(disgo, sequenceNumber), GuildID: guild.ID, } diff --git a/internal/handlers/guild_member_add_handler.go b/internal/handlers/guild_member_add_handler.go index c21766b7..52b28f2a 100644 --- a/internal/handlers/guild_member_add_handler.go +++ b/internal/handlers/guild_member_add_handler.go @@ -9,7 +9,7 @@ import ( type GuildMemberAddHandler struct{} // Event returns the raw gateway event Event -func (h GuildMemberAddHandler) Event() api.GatewayEventName { +func (h GuildMemberAddHandler) Event() api.GatewayEventType { return api.GatewayEventGuildMemberAdd } @@ -19,7 +19,7 @@ func (h GuildMemberAddHandler) New() interface{} { } // Handle handles the specific raw gateway event -func (h GuildMemberAddHandler) Handle(disgo api.Disgo, eventManager api.EventManager, i interface{}) { +func (h GuildMemberAddHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { member, ok := i.(*api.Member) if !ok { return @@ -28,7 +28,7 @@ func (h GuildMemberAddHandler) Handle(disgo api.Disgo, eventManager api.EventMan disgo.Cache().CacheMember(member) genericGuildEvent := events.GenericGuildEvent{ - GenericEvent: events.NewEvent(disgo), + GenericEvent: events.NewEvent(disgo, sequenceNumber), GuildID: member.GuildID, } eventManager.Dispatch(genericGuildEvent) diff --git a/internal/handlers/guild_member_remove_handler.go b/internal/handlers/guild_member_remove_handler.go index b9837c45..fce32213 100644 --- a/internal/handlers/guild_member_remove_handler.go +++ b/internal/handlers/guild_member_remove_handler.go @@ -14,7 +14,7 @@ type guildMemberRemoveData struct { type GuildMemberRemoveHandler struct{} // Event returns the raw gateway event Event -func (h GuildMemberRemoveHandler) Event() api.GatewayEventName { +func (h GuildMemberRemoveHandler) Event() api.GatewayEventType { return api.GatewayEventGuildMemberRemove } @@ -24,7 +24,7 @@ func (h GuildMemberRemoveHandler) New() interface{} { } // Handle handles the specific raw gateway event -func (h GuildMemberRemoveHandler) Handle(disgo api.Disgo, eventManager api.EventManager, i interface{}) { +func (h GuildMemberRemoveHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { member, ok := i.(*guildMemberRemoveData) if !ok { return @@ -34,7 +34,7 @@ func (h GuildMemberRemoveHandler) Handle(disgo api.Disgo, eventManager api.Event disgo.Cache().UncacheMember(member.GuildID, member.User.ID) genericGuildEvent := events.GenericGuildEvent{ - GenericEvent: events.NewEvent(disgo), + GenericEvent: events.NewEvent(disgo, sequenceNumber), GuildID: member.GuildID, } eventManager.Dispatch(genericGuildEvent) diff --git a/internal/handlers/guild_member_update_handler.go b/internal/handlers/guild_member_update_handler.go index 18f190a5..8616e405 100644 --- a/internal/handlers/guild_member_update_handler.go +++ b/internal/handlers/guild_member_update_handler.go @@ -9,7 +9,7 @@ import ( type GuildMemberUpdateHandler struct{} // Event returns the raw gateway event Event -func (h GuildMemberUpdateHandler) Event() api.GatewayEventName { +func (h GuildMemberUpdateHandler) Event() api.GatewayEventType { return api.GatewayEventGuildMemberUpdate } @@ -19,7 +19,7 @@ func (h GuildMemberUpdateHandler) New() interface{} { } // Handle handles the specific raw gateway event -func (h GuildMemberUpdateHandler) Handle(disgo api.Disgo, eventManager api.EventManager, i interface{}) { +func (h GuildMemberUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { member, ok := i.(*api.Member) if !ok { return @@ -30,7 +30,7 @@ func (h GuildMemberUpdateHandler) Handle(disgo api.Disgo, eventManager api.Event disgo.Cache().CacheMember(member) genericGuildEvent := events.GenericGuildEvent{ - GenericEvent: events.NewEvent(disgo), + GenericEvent: events.NewEvent(disgo, sequenceNumber), GuildID: member.GuildID, } eventManager.Dispatch(genericGuildEvent) diff --git a/internal/handlers/guild_role_create_handler.go b/internal/handlers/guild_role_create_handler.go index b4e141e8..daad3afb 100644 --- a/internal/handlers/guild_role_create_handler.go +++ b/internal/handlers/guild_role_create_handler.go @@ -14,7 +14,7 @@ type roleCreateData struct { type GuildRoleCreateHandler struct{} // Event returns the raw gateway event Event -func (h GuildRoleCreateHandler) Event() api.GatewayEventName { +func (h GuildRoleCreateHandler) Event() api.GatewayEventType { return api.GatewayEventGuildRoleCreate } @@ -24,7 +24,7 @@ func (h GuildRoleCreateHandler) New() interface{} { } // Handle handles the specific raw gateway event -func (h GuildRoleCreateHandler) Handle(disgo api.Disgo, eventManager api.EventManager, i interface{}) { +func (h GuildRoleCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { roleCreateData, ok := i.(*roleCreateData) if !ok { return @@ -34,19 +34,19 @@ func (h GuildRoleCreateHandler) Handle(disgo api.Disgo, eventManager api.EventMa disgo.Cache().CacheRole(roleCreateData.Role) genericGuildEvent := events.GenericGuildEvent{ - GenericEvent: events.NewEvent(disgo), + GenericEvent: events.NewEvent(disgo, sequenceNumber), GuildID: roleCreateData.GuildID, } eventManager.Dispatch(genericGuildEvent) - genericRoleEvent := events.GenericGuildRoleEvent{ + genericRoleEvent := events.GenericRoleEvent{ GenericGuildEvent: genericGuildEvent, - Role: roleCreateData.Role, RoleID: roleCreateData.Role.ID, } eventManager.Dispatch(genericRoleEvent) - eventManager.Dispatch(events.GuildRoleCreateEvent{ + eventManager.Dispatch(events.RoleCreateEvent{ GenericGuildEvent: genericGuildEvent, + Role: roleCreateData.Role, }) } diff --git a/internal/handlers/guild_role_delete_handler.go b/internal/handlers/guild_role_delete_handler.go index 175579c2..febfcce1 100644 --- a/internal/handlers/guild_role_delete_handler.go +++ b/internal/handlers/guild_role_delete_handler.go @@ -14,7 +14,7 @@ type roleDeleteData struct { type GuildRoleDeleteHandler struct{} // Event returns the raw gateway event Event -func (h GuildRoleDeleteHandler) Event() api.GatewayEventName { +func (h GuildRoleDeleteHandler) Event() api.GatewayEventType { return api.GatewayEventGuildRoleDelete } @@ -24,29 +24,29 @@ func (h GuildRoleDeleteHandler) New() interface{} { } // Handle handles the specific raw gateway event -func (h GuildRoleDeleteHandler) Handle(disgo api.Disgo, eventManager api.EventManager, i interface{}) { +func (h GuildRoleDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { roleDeleteData, ok := i.(*roleDeleteData) if !ok { return } - role := *disgo.Cache().Role(roleDeleteData.GuildID, roleDeleteData.RoleID) + role := *disgo.Cache().Role(roleDeleteData.RoleID) disgo.Cache().UncacheRole(roleDeleteData.GuildID, roleDeleteData.RoleID) genericGuildEvent := events.GenericGuildEvent{ - GenericEvent: events.NewEvent(disgo), + GenericEvent: events.NewEvent(disgo, sequenceNumber), GuildID: roleDeleteData.GuildID, } eventManager.Dispatch(genericGuildEvent) - genericRoleEvent := events.GenericGuildRoleEvent{ + genericRoleEvent := events.GenericRoleEvent{ GenericGuildEvent: genericGuildEvent, - Role: &role, RoleID: roleDeleteData.RoleID, } eventManager.Dispatch(genericRoleEvent) - eventManager.Dispatch(events.GuildRoleDeleteEvent{ + eventManager.Dispatch(events.RoleDeleteEvent{ GenericGuildEvent: genericGuildEvent, + Role: &role, }) } diff --git a/internal/handlers/guild_role_update_handler.go b/internal/handlers/guild_role_update_handler.go index 07b32574..e32a6ea8 100644 --- a/internal/handlers/guild_role_update_handler.go +++ b/internal/handlers/guild_role_update_handler.go @@ -14,7 +14,7 @@ type roleUpdateData struct { type GuildRoleUpdateHandler struct{} // Event returns the raw gateway event Event -func (h GuildRoleUpdateHandler) Event() api.GatewayEventName { +func (h GuildRoleUpdateHandler) Event() api.GatewayEventType { return api.GatewayEventGuildRoleUpdate } @@ -24,7 +24,7 @@ func (h GuildRoleUpdateHandler) New() interface{} { } // Handle handles the specific raw gateway event -func (h GuildRoleUpdateHandler) Handle(disgo api.Disgo, eventManager api.EventManager, i interface{}) { +func (h GuildRoleUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { roleUpdateData, ok := i.(*roleUpdateData) if !ok { return @@ -32,24 +32,24 @@ func (h GuildRoleUpdateHandler) Handle(disgo api.Disgo, eventManager api.EventMa roleUpdateData.Role.Disgo = disgo roleUpdateData.Role.GuildID = roleUpdateData.GuildID - oldRole := *disgo.Cache().Role(roleUpdateData.GuildID, roleUpdateData.Role.ID) + oldRole := *disgo.Cache().Role(roleUpdateData.Role.ID) disgo.Cache().CacheRole(roleUpdateData.Role) genericGuildEvent := events.GenericGuildEvent{ - GenericEvent: events.NewEvent(disgo), + GenericEvent: events.NewEvent(disgo, sequenceNumber), GuildID: roleUpdateData.GuildID, } eventManager.Dispatch(genericGuildEvent) - genericRoleEvent := events.GenericGuildRoleEvent{ + genericRoleEvent := events.GenericRoleEvent{ GenericGuildEvent: genericGuildEvent, - Role: roleUpdateData.Role, RoleID: roleUpdateData.Role.ID, } eventManager.Dispatch(genericRoleEvent) - eventManager.Dispatch(events.GuildRoleUpdateEvent{ + eventManager.Dispatch(events.RoleUpdateEvent{ GenericGuildEvent: genericGuildEvent, + NewRole: roleUpdateData.Role, OldRole: &oldRole, }) } diff --git a/internal/handlers/guild_update_handler.go b/internal/handlers/guild_update_handler.go index e1e14f3b..2b24c5bf 100644 --- a/internal/handlers/guild_update_handler.go +++ b/internal/handlers/guild_update_handler.go @@ -9,7 +9,7 @@ import ( type GuildUpdateHandler struct{} // Event returns the raw gateway event Event -func (h GuildUpdateHandler) Event() api.GatewayEventName { +func (h GuildUpdateHandler) Event() api.GatewayEventType { return api.GatewayEventGuildUpdate } @@ -19,7 +19,7 @@ func (h GuildUpdateHandler) New() interface{} { } // Handle handles the specific raw gateway event -func (h GuildUpdateHandler) Handle(disgo api.Disgo, eventManager api.EventManager, i interface{}) { +func (h GuildUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { guild, ok := i.(*api.Guild) if !ok { return @@ -29,14 +29,14 @@ func (h GuildUpdateHandler) Handle(disgo api.Disgo, eventManager api.EventManage disgo.Cache().CacheGuild(guild) genericGuildEvent := events.GenericGuildEvent{ - GenericEvent: events.NewEvent(disgo), + GenericEvent: events.NewEvent(disgo, sequenceNumber), GuildID: guild.ID, } eventManager.Dispatch(genericGuildEvent) eventManager.Dispatch(events.GuildUpdateEvent{ GenericGuildEvent: genericGuildEvent, - Guild: guild, + NewGuild: guild, OldGuild: &oldGuild, }) diff --git a/internal/handlers/interaction_create_handler.go b/internal/handlers/interaction_create_handler.go index c224b6ee..6ded0ea6 100644 --- a/internal/handlers/interaction_create_handler.go +++ b/internal/handlers/interaction_create_handler.go @@ -9,7 +9,7 @@ import ( type InteractionCreateHandler struct{} // Event returns the raw gateway event Event -func (h InteractionCreateHandler) Event() api.GatewayEventName { +func (h InteractionCreateHandler) Event() api.GatewayEventType { return api.GatewayEventInteractionCreate } @@ -19,15 +19,15 @@ func (h InteractionCreateHandler) New() interface{} { } // Handle handles the specific raw gateway event -func (h InteractionCreateHandler) Handle(disgo api.Disgo, eventManager api.EventManager, i interface{}) { +func (h InteractionCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { interaction, ok := i.(*api.Interaction) if !ok { return } - handleInteraction(disgo, eventManager, nil, interaction) + handleInteraction(disgo, eventManager, sequenceNumber, interaction, nil) } -func handleInteraction(disgo api.Disgo, eventManager api.EventManager, c chan interface{}, interaction *api.Interaction) { +func handleInteraction(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, interaction *api.Interaction, c chan interface{}) { if interaction.Member != nil { interaction.Member.Disgo = disgo if interaction.Member.User != nil { @@ -71,7 +71,7 @@ func handleInteraction(disgo api.Disgo, eventManager api.EventManager, c chan in } genericInteractionEvent := events.GenericInteractionEvent{ - GenericEvent: events.NewEvent(disgo), + GenericEvent: events.NewEvent(disgo, sequenceNumber), Interaction: *interaction, } eventManager.Dispatch(genericInteractionEvent) @@ -92,9 +92,9 @@ func handleInteraction(disgo api.Disgo, eventManager api.EventManager, c chan in options = option.Options } } - var newOptions []*events.Option + var newOptions []*api.Option for _, optionData := range options { - newOptions = append(newOptions, &events.Option{ + newOptions = append(newOptions, &api.Option{ Resolved: interaction.Data.Resolved, Name: optionData.Name, Type: optionData.Type, diff --git a/internal/handlers/interaction_create_webhook_handler.go b/internal/handlers/interaction_create_webhook_handler.go index ea436cb1..9c8753bf 100644 --- a/internal/handlers/interaction_create_webhook_handler.go +++ b/internal/handlers/interaction_create_webhook_handler.go @@ -8,7 +8,7 @@ import ( type InteractionCreateWebhookHandler struct{} // Event returns the raw gateway event Event -func (h InteractionCreateWebhookHandler) Event() api.GatewayEventName { +func (h InteractionCreateWebhookHandler) Event() api.GatewayEventType { return api.WebhookEventInteractionCreate } @@ -18,7 +18,7 @@ func (h InteractionCreateWebhookHandler) New() interface{} { } // Handle handles the specific raw gateway event -func (h InteractionCreateWebhookHandler) Handle(disgo api.Disgo, eventManager api.EventManager, c chan interface{}, i interface{}) { +func (h InteractionCreateWebhookHandler) HandleWebhookEvent(disgo api.Disgo, eventManager api.EventManager, c chan interface{}, i interface{}) { interaction, ok := i.(*api.Interaction) if !ok { return @@ -30,5 +30,5 @@ func (h InteractionCreateWebhookHandler) Handle(disgo api.Disgo, eventManager ap } return } - handleInteraction(disgo, eventManager, c, interaction) + handleInteraction(disgo, eventManager, -1, interaction, c) } diff --git a/internal/handlers/message_create_handler.go b/internal/handlers/message_create_handler.go index f2c7fbb3..4475e305 100644 --- a/internal/handlers/message_create_handler.go +++ b/internal/handlers/message_create_handler.go @@ -9,7 +9,7 @@ import ( type MessageCreateHandler struct{} // Event returns the raw gateway event Event -func (h MessageCreateHandler) Event() api.GatewayEventName { +func (h MessageCreateHandler) Event() api.GatewayEventType { return api.GatewayEventMessageCreate } @@ -19,41 +19,47 @@ func (h MessageCreateHandler) New() interface{} { } // Handle handles the specific raw gateway event -func (h MessageCreateHandler) Handle(disgo api.Disgo, eventManager api.EventManager, i interface{}) { +func (h MessageCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { message, ok := i.(*api.Message) if !ok { return } + message.Disgo = disgo + message.Author.Disgo = disgo + genericMessageEvent := events.GenericMessageEvent{ - GenericEvent: events.NewEvent(disgo), - MessageChannelID: message.ChannelID, - MessageID: message.ID, + GenericEvent: events.NewEvent(disgo, sequenceNumber), + ChannelID: message.ChannelID, + MessageID: message.ID, } eventManager.Dispatch(genericMessageEvent) - genericGuildEvent := events.GenericGuildEvent{ - GenericEvent: events.NewEvent(disgo), - GuildID: *message.GuildID, - } - eventManager.Dispatch(genericGuildEvent) - eventManager.Dispatch(events.MessageReceivedEvent{ GenericMessageEvent: genericMessageEvent, - Message: *message, + Message: message, }) if message.GuildID == nil { - // dm channel + genericDMMessageEvent := events.GenericDMMessageEvent{ + GenericMessageEvent: genericMessageEvent, + } + eventManager.Dispatch(genericDMMessageEvent) + + eventManager.Dispatch(events.DMMessageReceivedEvent{ + GenericDMMessageEvent: genericDMMessageEvent, + Message: message, + }) } else { - // text channel - message.Disgo = disgo - message.Author.Disgo = disgo + genericGuildMessageEvent := events.GenericGuildMessageEvent{ + GenericMessageEvent: genericMessageEvent, + GuildID: *message.GuildID, + } + eventManager.Dispatch(genericGuildMessageEvent) + eventManager.Dispatch(events.GuildMessageReceivedEvent{ - Message: *message, - GenericGuildMessageEvent: events.GenericGuildMessageEvent{ - GenericMessageEvent: genericMessageEvent, - }, + GenericGuildMessageEvent: genericGuildMessageEvent, + Message: message, }) } diff --git a/internal/handlers/ready_handler.go b/internal/handlers/ready_handler.go index 8a3d6cca..da6d6fda 100644 --- a/internal/handlers/ready_handler.go +++ b/internal/handlers/ready_handler.go @@ -17,7 +17,7 @@ type readyEventData struct { type ReadyHandler struct{} // Event returns the raw gateway event Event -func (h ReadyHandler) Event() api.GatewayEventName { +func (h ReadyHandler) Event() api.GatewayEventType { return api.GatewayEventReady } @@ -27,7 +27,7 @@ func (h ReadyHandler) New() interface{} { } // Handle handles the specific raw gateway event -func (h ReadyHandler) Handle(disgo api.Disgo, eventManager api.EventManager, i interface{}) { +func (h ReadyHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { readyEvent, ok := i.(*readyEventData) if !ok { return diff --git a/internal/handlers/voice_server_update_handler.go b/internal/handlers/voice_server_update_handler.go index 94162e14..51e31c56 100644 --- a/internal/handlers/voice_server_update_handler.go +++ b/internal/handlers/voice_server_update_handler.go @@ -6,7 +6,7 @@ import "github.com/DisgoOrg/disgo/api" type VoiceServerUpdateHandler struct{} // Event returns the raw gateway event Event -func (h VoiceServerUpdateHandler) Event() api.GatewayEventName { +func (h VoiceServerUpdateHandler) Event() api.GatewayEventType { return api.GatewayEventVoiceServerUpdate } @@ -16,7 +16,7 @@ func (h VoiceServerUpdateHandler) New() interface{} { } // Handle handles the specific raw gateway event -func (h VoiceServerUpdateHandler) Handle(disgo api.Disgo, eventManager api.EventManager, i interface{}) { +func (h VoiceServerUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { voiceServerUpdate, ok := i.(*api.VoiceServerUpdate) if !ok { return diff --git a/internal/handlers/voice_state_update_handler.go b/internal/handlers/voice_state_update_handler.go index 9fcb2aac..41dc7031 100644 --- a/internal/handlers/voice_state_update_handler.go +++ b/internal/handlers/voice_state_update_handler.go @@ -8,7 +8,7 @@ import ( type VoiceStateUpdateHandler struct{} // Event returns the raw gateway event Event -func (h VoiceStateUpdateHandler) Event() api.GatewayEventName { +func (h VoiceStateUpdateHandler) Event() api.GatewayEventType { return api.GatewayEventVoiceStateUpdate } @@ -18,7 +18,7 @@ func (h VoiceStateUpdateHandler) New() interface{} { } // Handle handles the specific raw gateway event -func (h VoiceStateUpdateHandler) Handle(disgo api.Disgo, eventManager api.EventManager, i interface{}) { +func (h VoiceStateUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { voiceStateUpdate, ok := i.(*api.VoiceStateUpdate) if !ok { return diff --git a/internal/webhook_server_impl.go b/internal/webhook_server_impl.go index 54ea1609..6aa3492d 100644 --- a/internal/webhook_server_impl.go +++ b/internal/webhook_server_impl.go @@ -97,7 +97,7 @@ func (h *webhookInteractionHandler) ServeHTTP(w http.ResponseWriter, r *http.Req w.WriteHeader(http.StatusBadRequest) } c := make(chan interface{}) - go h.webhookServer.Disgo().EventManager().Handle(api.WebhookEventInteractionCreate, rawBody, c) + go h.webhookServer.Disgo().EventManager().Handle(api.WebhookEventInteractionCreate, c, -1, rawBody) w.WriteHeader(http.StatusOK) w.Header().Set("Content-Type", "application/json") From f61d2a3162dd447b950c5b1b036caaf3c0987e74 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Fri, 9 Apr 2021 03:20:33 +0200 Subject: [PATCH 30/65] more refactoring, added EntityBuilder and added channe handlers --- api/channels.go | 7 +- api/disgo.go | 1 + api/disgo_builder.go | 3 +- api/endpoints/endpoints.go | 5 + api/endpoints/route.go | 8 ++ api/entity_builder.go | 11 ++ api/events/application_command_events.go | 8 +- api/events/guild_invite_events.go | 45 ++++++++ api/events/store_events.go | 2 +- api/invite.go | 55 +++++++++ internal/disgo_builder_impl.go | 12 ++ internal/disgo_impl.go | 8 ++ internal/entity_builder_impl.go | 75 ++++++++++++ .../handlers/application_command_create.go | 21 +++- .../handlers/application_command_delete.go | 21 +++- .../handlers/application_command_update.go | 22 +++- internal/handlers/channel_create_handler.go | 108 ++++++++++++++++++ internal/handlers/channel_delete_handler.go | 28 +++++ internal/handlers/channel_update_handler.go | 28 +++++ internal/handlers/guild_create_handler.go | 2 +- internal/handlers/guild_delete_handler.go | 2 +- internal/handlers/guild_member_add_handler.go | 2 +- .../handlers/guild_member_remove_handler.go | 2 +- .../handlers/guild_member_update_handler.go | 2 +- .../handlers/guild_role_create_handler.go | 2 +- .../handlers/guild_role_delete_handler.go | 2 +- .../handlers/guild_role_update_handler.go | 2 +- internal/handlers/guild_update_handler.go | 2 +- .../handlers/interaction_create_handler.go | 2 +- .../interaction_create_webhook_handler.go | 2 +- internal/handlers/message_create_handler.go | 2 +- internal/handlers/ready_handler.go | 2 +- .../handlers/voice_server_update_handler.go | 2 +- .../handlers/voice_state_update_handler.go | 2 +- 34 files changed, 465 insertions(+), 33 deletions(-) create mode 100644 api/entity_builder.go create mode 100644 api/events/guild_invite_events.go create mode 100644 api/invite.go create mode 100644 internal/entity_builder_impl.go create mode 100644 internal/handlers/channel_create_handler.go create mode 100644 internal/handlers/channel_delete_handler.go create mode 100644 internal/handlers/channel_update_handler.go diff --git a/api/channels.go b/api/channels.go index 9d80cdb5..ffeb636c 100644 --- a/api/channels.go +++ b/api/channels.go @@ -76,18 +76,19 @@ func (c MessageChannel) CrosspostMessage(messageID Snowflake) (*Message, error) // DMChannel is used for interacting in private Message(s) with users type DMChannel struct { MessageChannel - Users []User `json:"recipients"` } // GuildChannel is a generic type for all server channels type GuildChannel struct { Channel - GuildID Snowflake `json:"guild_id"` } // Guild returns the channel's Guild func (c GuildChannel) Guild() *Guild { - return c.Disgo.Cache().Guild(c.GuildID) + if c.GuildID == nil { + return nil + } + return c.Disgo.Cache().Guild(*c.GuildID) } // Category groups text & voice channels in servers together diff --git a/api/disgo.go b/api/disgo.go index 02ad1c86..7ed4fb16 100644 --- a/api/disgo.go +++ b/api/disgo.go @@ -22,6 +22,7 @@ type Disgo interface { Intents() Intents SelfUserID() Snowflake SelfUser() *User + EntityBuilder() EntityBuilder EventManager() EventManager VoiceDispatchInterceptor() VoiceDispatchInterceptor SetVoiceDispatchInterceptor(voiceInterceptor VoiceDispatchInterceptor) diff --git a/api/disgo_builder.go b/api/disgo_builder.go index 0407c9c4..9ed26a48 100644 --- a/api/disgo_builder.go +++ b/api/disgo_builder.go @@ -11,7 +11,8 @@ type DisgoBuilder interface { SetLogLevel(level log.Level) DisgoBuilder SetToken(token endpoints.Token) DisgoBuilder SetIntents(intents Intents) DisgoBuilder - SetVoiceDispatchInterceptor(VoiceDispatchInterceptor) DisgoBuilder + SetVoiceDispatchInterceptor(voiceDispatchInterceptor VoiceDispatchInterceptor) DisgoBuilder + SetEntityBuilder(entityBuilder EntityBuilder) DisgoBuilder SetEventManager(eventManager EventManager) DisgoBuilder AddEventListeners(eventsListeners ...EventListener) DisgoBuilder SetWebhookServer(webhookServer WebhookServer) DisgoBuilder diff --git a/api/endpoints/endpoints.go b/api/endpoints/endpoints.go index 6f8624fc..1b7b6cf8 100644 --- a/api/endpoints/endpoints.go +++ b/api/endpoints/endpoints.go @@ -203,3 +203,8 @@ var ( TeamIcon = NewCDNRoute("/team-icons/{team.id}/team.icon.", PNG, JPEG, WEBP) Attachments = NewCDNRoute("/attachments/{channel.id}/{attachment.id}/{file.name}", BLANK) ) + +// Other +var ( + InviteURL = NewRoute("https://discord.gg/{code}") +) diff --git a/api/endpoints/route.go b/api/endpoints/route.go index 234ec17c..50cc2157 100644 --- a/api/endpoints/route.go +++ b/api/endpoints/route.go @@ -37,6 +37,14 @@ func (r Route) Compile(args ...interface{}) CompiledRoute { return CompiledRoute{route: r.baseRoute + route} } +func NewRoute(url string) Route { + return Route{ + baseRoute: "", + route: url, + paramCount: countParams(url), + } +} + func countParams(url string) int { paramCount := strings.Count(url, "{") if paramCount != strings.Count(url, "}") { diff --git a/api/entity_builder.go b/api/entity_builder.go new file mode 100644 index 00000000..474b65ec --- /dev/null +++ b/api/entity_builder.go @@ -0,0 +1,11 @@ +package api + +type EntityBuilder interface { + Disgo() Disgo + + CreateTextChannel(channel *Channel) *TextChannel + CreateVoiceChannel(channel *Channel) *VoiceChannel + CreateStoreChannel(channel *Channel) *StoreChannel + CreateCategory(channel *Channel) *Category + CreateDMChannel(channel *Channel) *DMChannel +} diff --git a/api/events/application_command_events.go b/api/events/application_command_events.go index 32260d46..6a44a340 100644 --- a/api/events/application_command_events.go +++ b/api/events/application_command_events.go @@ -8,7 +8,13 @@ type GenericApplicationCommandEvent struct { GenericEvent CommandID api.Snowflake GuildID *api.Snowflake - Guild *api.Guild +} + +func (e GenericApplicationCommandEvent) Guild() *api.Guild { + if e.GuildID == nil { + return nil + } + return e.Disgo().Cache().Guild(*e.GuildID) } type ApplicationCommandCreateEvent struct { diff --git a/api/events/guild_invite_events.go b/api/events/guild_invite_events.go new file mode 100644 index 00000000..c8169796 --- /dev/null +++ b/api/events/guild_invite_events.go @@ -0,0 +1,45 @@ +package events + +import ( + "github.com/DisgoOrg/disgo/api" + "github.com/DisgoOrg/disgo/api/endpoints" +) + +type GenericGuildInviteEvent struct { + GenericGuildEvent + Code string + ChannelID api.Snowflake +} + +func (e GenericGuildInviteEvent) GuildChannel() *api.GuildChannel { + return e.Disgo().Cache().GuildChannel(e.ChannelID) +} + +func (e GenericGuildInviteEvent) TextChannel() *api.TextChannel { + return e.Disgo().Cache().TextChannel(e.ChannelID) +} + +func (e GenericGuildInviteEvent) VoiceChannel() *api.VoiceChannel { + return e.Disgo().Cache().VoiceChannel(e.ChannelID) +} + +func (e GenericGuildInviteEvent) StoreChannel() *api.StoreChannel { + return e.Disgo().Cache().StoreChannel(e.ChannelID) +} + +func (e GenericGuildInviteEvent) Category() *api.Category { + return e.Disgo().Cache().Category(e.ChannelID) +} + +func (e GenericGuildInviteEvent) URL() string { + return endpoints.InviteURL.Compile(e.Code).Route() +} + +type GuildInviteCreateEvent struct { + GenericGuildInviteEvent + Invite *api.Invite +} + +type GuildInviteDeleteEvent struct { + GenericGuildInviteEvent +} diff --git a/api/events/store_events.go b/api/events/store_events.go index 7cf30065..cd58632b 100644 --- a/api/events/store_events.go +++ b/api/events/store_events.go @@ -14,7 +14,7 @@ func (e GenericStoreChannelEvent) Category() *api.StoreChannel { type StoreChannelCreateEvent struct { GenericStoreChannelEvent - StoreChannel *api.Category + StoreChannel *api.StoreChannel } type StoreChannelUpdateEvent struct { diff --git a/api/invite.go b/api/invite.go new file mode 100644 index 00000000..e04a75fa --- /dev/null +++ b/api/invite.go @@ -0,0 +1,55 @@ +package api + +import "time" + +type ExpandedInvite struct { + Invite + Uses int `json:"uses"` + MaxUses int `json:"max_uses"` + MaxAge int `json:"max_age"` + Temporary bool `json:"temporary"` + CreatedAt time.Time `json:"created_at"` +} + +type Invite struct { + Disgo Disgo + Code string `json:"code"` + Guild *InviteGuild `json:"guild"` + Channel InviteChannel `json:"channel"` + Inviter *User `json:"inviter"` + TargetUser *InviteUser `json:"target_user"` + TargetUserType *TargetUserType `json:"target_user_type"` + ApproximatePresenceCount *int `json:"approximate_presence_count"` + ApproximateMemberCount *int `json:"approximate_member_count"` +} + +type TargetUserType int + +const ( + TargetUserTypeStream = iota + 1 +) + +type InviteGuild struct { + Id Snowflake `json:"id"` + Name string `json:"name"` + Splash *string `json:"splash"` + Banner *string `json:"banner"` + Description *string `json:"description"` + Icon *string `json:"icon"` + Features []GuildFeature `json:"features"` + VerificationLevel VerificationLevel `json:"verification_level"` + VanityUrlCode *string `json:"vanity_url_code"` +} + +type InviteChannel struct { + Id string `json:"id"` + Name string `json:"name"` + Type int `json:"type"` +} + +type InviteUser struct { + Id string `json:"id"` + Username string `json:"username"` + Avatar string `json:"avatar"` + Discriminator string `json:"discriminator"` +} diff --git a/internal/disgo_builder_impl.go b/internal/disgo_builder_impl.go index c12c06e5..dbea4d2f 100644 --- a/internal/disgo_builder_impl.go +++ b/internal/disgo_builder_impl.go @@ -30,6 +30,7 @@ type DisgoBuilderImpl struct { messageCachePolicy api.MessageCachePolicy cacheFlags api.CacheFlags intents api.Intents + entityBuilder api.EntityBuilder eventManager api.EventManager voiceDispatchInterceptor api.VoiceDispatchInterceptor webhookServer api.WebhookServer @@ -57,6 +58,12 @@ func (b *DisgoBuilderImpl) SetIntents(intents api.Intents) api.DisgoBuilder { return b } +// SetEntityBuilder lets you inject your own api.EntityBuilder +func (b *DisgoBuilderImpl) SetEntityBuilder(entityBuilder api.EntityBuilder) api.DisgoBuilder { + b.entityBuilder = entityBuilder + return b +} + // SetEventManager lets you inject your own api.EventManager func (b *DisgoBuilderImpl) SetEventManager(eventManager api.EventManager) api.DisgoBuilder { b.eventManager = eventManager @@ -169,6 +176,11 @@ func (b *DisgoBuilderImpl) Build() (api.Disgo, error) { disgo.intents = b.intents + if b.entityBuilder == nil { + b.entityBuilder = newEntityBuilderImpl(disgo) + } + disgo.entityBuilder = b.entityBuilder + if b.eventManager == nil { b.eventManager = newEventManagerImpl(disgo, b.eventListeners) } diff --git a/internal/disgo_impl.go b/internal/disgo_impl.go index 5e2f6494..42589265 100644 --- a/internal/disgo_impl.go +++ b/internal/disgo_impl.go @@ -32,6 +32,8 @@ func New(token endpoints.Token, options api.Options) (api.Disgo, error) { disgo.restClient = newRestClientImpl(disgo) + disgo.entityBuilder = newEntityBuilderImpl(disgo) + disgo.eventManager = newEventManagerImpl(disgo, []api.EventListener{}) if options.EnableWebhookInteractions { @@ -50,6 +52,7 @@ type DisgoImpl struct { gateway api.Gateway restClient api.RestClient intents api.Intents + entityBuilder api.EntityBuilder eventManager api.EventManager voiceDispatchInterceptor api.VoiceDispatchInterceptor webhookServer api.WebhookServer @@ -107,6 +110,11 @@ func (d *DisgoImpl) RestClient() api.RestClient { return d.restClient } +// EntityBuilder returns the api.EntityBuilder +func (d *DisgoImpl) EntityBuilder() api.EntityBuilder { + return d.entityBuilder +} + // EventManager returns the api.EventManager func (d *DisgoImpl) EventManager() api.EventManager { return d.eventManager diff --git a/internal/entity_builder_impl.go b/internal/entity_builder_impl.go new file mode 100644 index 00000000..3edeaf92 --- /dev/null +++ b/internal/entity_builder_impl.go @@ -0,0 +1,75 @@ +package internal + +import ( + "github.com/DisgoOrg/disgo/api" +) + +func newEntityBuilderImpl(disgo api.Disgo) api.EntityBuilder { + return &EntityBuilderImpl{disgo: disgo} +} + +type EntityBuilderImpl struct { + disgo api.Disgo +} + +func (b EntityBuilderImpl) Disgo() api.Disgo { + return b.disgo +} + +func (b EntityBuilderImpl) CreateTextChannel(channel *api.Channel) *api.TextChannel { + channel.Disgo = b.Disgo() + textChannel := &api.TextChannel{ + MessageChannel: api.MessageChannel{ + Channel: *channel, + }, + GuildChannel: api.GuildChannel{ + Channel: *channel, + }, + } + b.Disgo().Cache().CacheTextChannel(textChannel) + return textChannel +} + +func (b EntityBuilderImpl) CreateVoiceChannel(channel *api.Channel) *api.VoiceChannel { + channel.Disgo = b.Disgo() + voiceChannel := &api.VoiceChannel{ + GuildChannel: api.GuildChannel{ + Channel: *channel, + }, + } + b.Disgo().Cache().CacheVoiceChannel(voiceChannel) + return voiceChannel +} + +func (b EntityBuilderImpl) CreateStoreChannel(channel *api.Channel) *api.StoreChannel { + channel.Disgo = b.Disgo() + storeChannel := &api.StoreChannel{ + GuildChannel: api.GuildChannel{ + Channel: *channel, + }, + } + b.Disgo().Cache().CacheStoreChannel(storeChannel) + return storeChannel +} + +func (b EntityBuilderImpl) CreateCategory(channel *api.Channel) *api.Category { + channel.Disgo = b.Disgo() + category := &api.Category{ + GuildChannel: api.GuildChannel{ + Channel: *channel, + }, + } + b.Disgo().Cache().CacheCategory(category) + return category +} + +func (b EntityBuilderImpl) CreateDMChannel(channel *api.Channel) *api.DMChannel { + channel.Disgo = b.Disgo() + dmChannel := &api.DMChannel{ + MessageChannel: api.MessageChannel{ + Channel: *channel, + }, + } + b.Disgo().Cache().CacheDMChannel(dmChannel) + return dmChannel +} diff --git a/internal/handlers/application_command_create.go b/internal/handlers/application_command_create.go index b4862b3b..8caa4395 100644 --- a/internal/handlers/application_command_create.go +++ b/internal/handlers/application_command_create.go @@ -2,6 +2,7 @@ package handlers import ( "github.com/DisgoOrg/disgo/api" + "github.com/DisgoOrg/disgo/api/events" ) // ApplicationCommandCreateHandler handles api.ApplicationCommandCreateEvent @@ -17,10 +18,22 @@ func (h ApplicationCommandCreateHandler) New() interface{} { return &api.Command{} } -// Handle handles the specific raw gateway event -func (h ApplicationCommandCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, i interface{}) { - /*command, ok := i.(*api.Command) +// HandleGatewayEvent handles the specific raw gateway event +func (h ApplicationCommandCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { + command, ok := i.(*api.Command) if !ok { return - }*/ + } + + genericApplicationCommandEvent := events.GenericApplicationCommandEvent{ + GenericEvent: events.NewEvent(disgo, sequenceNumber), + CommandID: command.ID, + GuildID: command.GuildID, + } + eventManager.Dispatch(genericApplicationCommandEvent) + + eventManager.Dispatch(events.ApplicationCommandCreateEvent{ + GenericApplicationCommandEvent: genericApplicationCommandEvent, + Command: command, + }) } diff --git a/internal/handlers/application_command_delete.go b/internal/handlers/application_command_delete.go index bc794799..12c226aa 100644 --- a/internal/handlers/application_command_delete.go +++ b/internal/handlers/application_command_delete.go @@ -2,6 +2,7 @@ package handlers import ( "github.com/DisgoOrg/disgo/api" + "github.com/DisgoOrg/disgo/api/events" ) // ApplicationCommandDeleteHandler handles api.ApplicationCommandCreateEvent @@ -17,10 +18,22 @@ func (h ApplicationCommandDeleteHandler) New() interface{} { return &api.Command{} } -// Handle handles the specific raw gateway event -func (h ApplicationCommandDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, i interface{}) { - /*command, ok := i.(*api.Command) +// HandleGatewayEvent handles the specific raw gateway event +func (h ApplicationCommandDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { + command, ok := i.(*api.Command) if !ok { return - }*/ + } + + genericApplicationCommandEvent := events.GenericApplicationCommandEvent{ + GenericEvent: events.NewEvent(disgo, sequenceNumber), + CommandID: command.ID, + GuildID: command.GuildID, + } + eventManager.Dispatch(genericApplicationCommandEvent) + + eventManager.Dispatch(events.ApplicationCommandDeleteEvent{ + GenericApplicationCommandEvent: genericApplicationCommandEvent, + Command: command, + }) } diff --git a/internal/handlers/application_command_update.go b/internal/handlers/application_command_update.go index 8c0aa7cc..5e5ae23f 100644 --- a/internal/handlers/application_command_update.go +++ b/internal/handlers/application_command_update.go @@ -2,6 +2,7 @@ package handlers import ( "github.com/DisgoOrg/disgo/api" + "github.com/DisgoOrg/disgo/api/events" ) // ApplicationCommandUpdateHandler handles api.ApplicationCommandCreateEvent @@ -17,10 +18,23 @@ func (h ApplicationCommandUpdateHandler) New() interface{} { return &api.Command{} } -// Handle handles the specific raw gateway event -func (h ApplicationCommandUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, i interface{}) { - /*command, ok := i.(*api.Command) +// HandleGatewayEvent handles the specific raw gateway event +func (h ApplicationCommandUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { + command, ok := i.(*api.Command) if !ok { return - }*/ + } + + genericApplicationCommandEvent := events.GenericApplicationCommandEvent{ + GenericEvent: events.NewEvent(disgo, sequenceNumber), + CommandID: command.ID, + GuildID: command.GuildID, + } + eventManager.Dispatch(genericApplicationCommandEvent) + + eventManager.Dispatch(events.ApplicationCommandUpdateEvent{ + GenericApplicationCommandEvent: genericApplicationCommandEvent, + NewCommand: command, + OldCommand: nil, + }) } diff --git a/internal/handlers/channel_create_handler.go b/internal/handlers/channel_create_handler.go new file mode 100644 index 00000000..9d621903 --- /dev/null +++ b/internal/handlers/channel_create_handler.go @@ -0,0 +1,108 @@ +package handlers + +import ( + "github.com/DisgoOrg/disgo/api" + "github.com/DisgoOrg/disgo/api/events" + log "github.com/sirupsen/logrus" +) + +// ChannelCreateHandler handles api.GatewayEventChannelCreate +type ChannelCreateHandler struct{} + +// Event returns the raw gateway event Event +func (h ChannelCreateHandler) Event() api.GatewayEventType { + return api.GatewayEventChannelCreate +} + +// New constructs a new payload receiver for the raw gateway event +func (h ChannelCreateHandler) New() interface{} { + return &api.Channel{} +} + +// HandleGatewayEvent handles the specific raw gateway event +func (h ChannelCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { + channel, ok := i.(*api.Channel) + if !ok { + return + } + + genericChannelEvent := events.GenericChannelEvent{ + GenericEvent: events.NewEvent(disgo, sequenceNumber), + ChannelID: channel.ID, + } + eventManager.Dispatch(genericChannelEvent) + + switch channel.Type { + case api.ChannelTypeDM: + dmChannel := disgo.EntityBuilder().CreateDMChannel(channel) + + genericDMChannelEvent := events.GenericDMChannelEvent{ + GenericChannelEvent: genericChannelEvent, + } + eventManager.Dispatch(genericDMChannelEvent) + + eventManager.Dispatch(events.DMChannelCreateEvent{ + GenericDMChannelEvent: genericDMChannelEvent, + DMChannel: dmChannel, + }) + + case api.ChannelTypeGroupDM: + log.Warnf("ChannelTypeGroupDM received what the hell discord") + + case api.ChannelTypeText, api.ChannelTypeNews: + textChannel := disgo.EntityBuilder().CreateTextChannel(channel) + + genericTextChannelEvent := events.GenericTextChannelEvent{ + GenericChannelEvent: genericChannelEvent, + } + eventManager.Dispatch(genericTextChannelEvent) + + eventManager.Dispatch(events.TextChannelCreateEvent{ + GenericTextChannelEvent: genericTextChannelEvent, + TextChannel: textChannel, + }) + + case api.ChannelTypeStore: + storeChannel := disgo.EntityBuilder().CreateStoreChannel(channel) + + genericStoreChannelEvent := events.GenericStoreChannelEvent{ + GenericChannelEvent: genericChannelEvent, + } + eventManager.Dispatch(genericStoreChannelEvent) + + eventManager.Dispatch(events.StoreChannelCreateEvent{ + GenericStoreChannelEvent: genericStoreChannelEvent, + StoreChannel: storeChannel, + }) + + case api.ChannelTypeCategory: + category := disgo.EntityBuilder().CreateCategory(channel) + + genericCategoryEvent := events.GenericCategoryEvent{ + GenericChannelEvent: genericChannelEvent, + } + eventManager.Dispatch(genericCategoryEvent) + + eventManager.Dispatch(events.CategoryCreateEvent{ + GenericCategoryEvent: genericCategoryEvent, + Category: category, + }) + + case api.ChannelTypeVoice: + voiceChannel := disgo.EntityBuilder().CreateVoiceChannel(channel) + + genericVoiceChannelEvent := events.GenericVoiceChannelEvent{ + GenericChannelEvent: genericChannelEvent, + } + eventManager.Dispatch(genericVoiceChannelEvent) + + eventManager.Dispatch(events.VoiceChannelCreateEvent{ + GenericVoiceChannelEvent: genericVoiceChannelEvent, + VoiceChannel: voiceChannel, + }) + + default: + log.Warnf("unknown channel type received: %d", channel.Type) + } + +} diff --git a/internal/handlers/channel_delete_handler.go b/internal/handlers/channel_delete_handler.go new file mode 100644 index 00000000..1885a54d --- /dev/null +++ b/internal/handlers/channel_delete_handler.go @@ -0,0 +1,28 @@ +package handlers + +import ( + "github.com/DisgoOrg/disgo/api" +) + +// ChannelDeleteHandler handles api.GatewayEventChannelDelete +type ChannelDeleteHandler struct{} + +// Event returns the raw gateway event Event +func (h ChannelDeleteHandler) Event() api.GatewayEventType { + return api.GatewayEventChannelDelete +} + +// New constructs a new payload receiver for the raw gateway event +func (h ChannelDeleteHandler) New() interface{} { + return &api.Channel{} +} + +// HandleGatewayEvent handles the specific raw gateway event +func (h ChannelDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { + channel, ok := i.(*api.Channel) + if !ok { + return + } + + +} diff --git a/internal/handlers/channel_update_handler.go b/internal/handlers/channel_update_handler.go new file mode 100644 index 00000000..025de6ca --- /dev/null +++ b/internal/handlers/channel_update_handler.go @@ -0,0 +1,28 @@ +package handlers + +import ( + "github.com/DisgoOrg/disgo/api" +) + +// ChannelUpdateHandler handles api.GatewayEventChannelUpdate +type ChannelUpdateHandler struct{} + +// Event returns the raw gateway event Event +func (h ChannelUpdateHandler) Event() api.GatewayEventType { + return api.GatewayEventChannelUpdate +} + +// New constructs a new payload receiver for the raw gateway event +func (h ChannelUpdateHandler) New() interface{} { + return &api.Channel{} +} + +// HandleGatewayEvent handles the specific raw gateway event +func (h ChannelUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { + channel, ok := i.(*api.Channel) + if !ok { + return + } + + +} diff --git a/internal/handlers/guild_create_handler.go b/internal/handlers/guild_create_handler.go index d5450a7d..288a80cd 100644 --- a/internal/handlers/guild_create_handler.go +++ b/internal/handlers/guild_create_handler.go @@ -18,7 +18,7 @@ func (h GuildCreateHandler) New() interface{} { return &api.FullGuild{} } -// Handle handles the specific raw gateway event +// HandleGatewayEvent handles the specific raw gateway event func (h GuildCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { fullGuild, ok := i.(*api.FullGuild) if !ok { diff --git a/internal/handlers/guild_delete_handler.go b/internal/handlers/guild_delete_handler.go index 80e4dd7f..be709bc9 100644 --- a/internal/handlers/guild_delete_handler.go +++ b/internal/handlers/guild_delete_handler.go @@ -18,7 +18,7 @@ func (h GuildDeleteHandler) New() interface{} { return &api.Guild{} } -// Handle handles the specific raw gateway event +// HandleGatewayEvent handles the specific raw gateway event func (h GuildDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { guild, ok := i.(*api.Guild) if !ok { diff --git a/internal/handlers/guild_member_add_handler.go b/internal/handlers/guild_member_add_handler.go index 52b28f2a..9655ef83 100644 --- a/internal/handlers/guild_member_add_handler.go +++ b/internal/handlers/guild_member_add_handler.go @@ -18,7 +18,7 @@ func (h GuildMemberAddHandler) New() interface{} { return &api.Member{} } -// Handle handles the specific raw gateway event +// HandleGatewayEvent handles the specific raw gateway event func (h GuildMemberAddHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { member, ok := i.(*api.Member) if !ok { diff --git a/internal/handlers/guild_member_remove_handler.go b/internal/handlers/guild_member_remove_handler.go index fce32213..86afb193 100644 --- a/internal/handlers/guild_member_remove_handler.go +++ b/internal/handlers/guild_member_remove_handler.go @@ -23,7 +23,7 @@ func (h GuildMemberRemoveHandler) New() interface{} { return &guildMemberRemoveData{} } -// Handle handles the specific raw gateway event +// HandleGatewayEvent handles the specific raw gateway event func (h GuildMemberRemoveHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { member, ok := i.(*guildMemberRemoveData) if !ok { diff --git a/internal/handlers/guild_member_update_handler.go b/internal/handlers/guild_member_update_handler.go index 8616e405..88166b78 100644 --- a/internal/handlers/guild_member_update_handler.go +++ b/internal/handlers/guild_member_update_handler.go @@ -18,7 +18,7 @@ func (h GuildMemberUpdateHandler) New() interface{} { return &api.Member{} } -// Handle handles the specific raw gateway event +// HandleGatewayEvent handles the specific raw gateway event func (h GuildMemberUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { member, ok := i.(*api.Member) if !ok { diff --git a/internal/handlers/guild_role_create_handler.go b/internal/handlers/guild_role_create_handler.go index daad3afb..e70cb3f0 100644 --- a/internal/handlers/guild_role_create_handler.go +++ b/internal/handlers/guild_role_create_handler.go @@ -23,7 +23,7 @@ func (h GuildRoleCreateHandler) New() interface{} { return &roleCreateData{} } -// Handle handles the specific raw gateway event +// HandleGatewayEvent handles the specific raw gateway event func (h GuildRoleCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { roleCreateData, ok := i.(*roleCreateData) if !ok { diff --git a/internal/handlers/guild_role_delete_handler.go b/internal/handlers/guild_role_delete_handler.go index febfcce1..328c3357 100644 --- a/internal/handlers/guild_role_delete_handler.go +++ b/internal/handlers/guild_role_delete_handler.go @@ -23,7 +23,7 @@ func (h GuildRoleDeleteHandler) New() interface{} { return &roleCreateData{} } -// Handle handles the specific raw gateway event +// HandleGatewayEvent handles the specific raw gateway event func (h GuildRoleDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { roleDeleteData, ok := i.(*roleDeleteData) if !ok { diff --git a/internal/handlers/guild_role_update_handler.go b/internal/handlers/guild_role_update_handler.go index e32a6ea8..7ce2458d 100644 --- a/internal/handlers/guild_role_update_handler.go +++ b/internal/handlers/guild_role_update_handler.go @@ -23,7 +23,7 @@ func (h GuildRoleUpdateHandler) New() interface{} { return &roleUpdateData{} } -// Handle handles the specific raw gateway event +// HandleGatewayEvent handles the specific raw gateway event func (h GuildRoleUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { roleUpdateData, ok := i.(*roleUpdateData) if !ok { diff --git a/internal/handlers/guild_update_handler.go b/internal/handlers/guild_update_handler.go index 2b24c5bf..2eecf394 100644 --- a/internal/handlers/guild_update_handler.go +++ b/internal/handlers/guild_update_handler.go @@ -18,7 +18,7 @@ func (h GuildUpdateHandler) New() interface{} { return &api.Guild{} } -// Handle handles the specific raw gateway event +// HandleGatewayEvent handles the specific raw gateway event func (h GuildUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { guild, ok := i.(*api.Guild) if !ok { diff --git a/internal/handlers/interaction_create_handler.go b/internal/handlers/interaction_create_handler.go index 6ded0ea6..ecd2af6e 100644 --- a/internal/handlers/interaction_create_handler.go +++ b/internal/handlers/interaction_create_handler.go @@ -18,7 +18,7 @@ func (h InteractionCreateHandler) New() interface{} { return &api.Interaction{} } -// Handle handles the specific raw gateway event +// HandleGatewayEvent handles the specific raw gateway event func (h InteractionCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { interaction, ok := i.(*api.Interaction) if !ok { diff --git a/internal/handlers/interaction_create_webhook_handler.go b/internal/handlers/interaction_create_webhook_handler.go index 9c8753bf..0cf2282a 100644 --- a/internal/handlers/interaction_create_webhook_handler.go +++ b/internal/handlers/interaction_create_webhook_handler.go @@ -17,7 +17,7 @@ func (h InteractionCreateWebhookHandler) New() interface{} { return &api.Interaction{} } -// Handle handles the specific raw gateway event +// HandleWebhookEvent handles the specific raw gateway event func (h InteractionCreateWebhookHandler) HandleWebhookEvent(disgo api.Disgo, eventManager api.EventManager, c chan interface{}, i interface{}) { interaction, ok := i.(*api.Interaction) if !ok { diff --git a/internal/handlers/message_create_handler.go b/internal/handlers/message_create_handler.go index 4475e305..ed560e6b 100644 --- a/internal/handlers/message_create_handler.go +++ b/internal/handlers/message_create_handler.go @@ -18,7 +18,7 @@ func (h MessageCreateHandler) New() interface{} { return &api.Message{} } -// Handle handles the specific raw gateway event +// HandleGatewayEvent handles the specific raw gateway event func (h MessageCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { message, ok := i.(*api.Message) if !ok { diff --git a/internal/handlers/ready_handler.go b/internal/handlers/ready_handler.go index da6d6fda..05f4559c 100644 --- a/internal/handlers/ready_handler.go +++ b/internal/handlers/ready_handler.go @@ -26,7 +26,7 @@ func (h ReadyHandler) New() interface{} { return &readyEventData{} } -// Handle handles the specific raw gateway event +// HandleGatewayEvent handles the specific raw gateway event func (h ReadyHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { readyEvent, ok := i.(*readyEventData) if !ok { diff --git a/internal/handlers/voice_server_update_handler.go b/internal/handlers/voice_server_update_handler.go index 51e31c56..d5e808e9 100644 --- a/internal/handlers/voice_server_update_handler.go +++ b/internal/handlers/voice_server_update_handler.go @@ -15,7 +15,7 @@ func (h VoiceServerUpdateHandler) New() interface{} { return &api.VoiceServerUpdate{} } -// Handle handles the specific raw gateway event +// HandleGatewayEvent handles the specific raw gateway event func (h VoiceServerUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { voiceServerUpdate, ok := i.(*api.VoiceServerUpdate) if !ok { diff --git a/internal/handlers/voice_state_update_handler.go b/internal/handlers/voice_state_update_handler.go index 41dc7031..59f8124b 100644 --- a/internal/handlers/voice_state_update_handler.go +++ b/internal/handlers/voice_state_update_handler.go @@ -17,7 +17,7 @@ func (h VoiceStateUpdateHandler) New() interface{} { return &api.VoiceStateUpdate{} } -// Handle handles the specific raw gateway event +// HandleGatewayEvent handles the specific raw gateway event func (h VoiceStateUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { voiceStateUpdate, ok := i.(*api.VoiceStateUpdate) if !ok { From d8d6645fee72b4517ac54c83151654f1c5c39bca Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Fri, 9 Apr 2021 12:13:03 +0200 Subject: [PATCH 31/65] entity builder stuff wuhu --- api/cache.go | 50 ++--- api/cache_flags.go | 1 + api/entity_builder.go | 20 +- internal/cache_impl.go | 173 +++++++++++++----- internal/entity_builder_impl.go | 80 +++++++- .../handlers/application_command_create.go | 6 + .../handlers/application_command_delete.go | 10 +- .../handlers/application_command_update.go | 13 +- internal/handlers/channel_create_handler.go | 10 +- internal/handlers/channel_delete_handler.go | 86 ++++++++- internal/handlers/channel_update_handler.go | 90 ++++++++- 11 files changed, 446 insertions(+), 93 deletions(-) diff --git a/api/cache.go b/api/cache.go index e1cdc192..4a70af50 100644 --- a/api/cache.go +++ b/api/cache.go @@ -7,11 +7,29 @@ type Cache interface { DoCleanup() CacheFlags() CacheFlags + Command(commandID Snowflake) *Command + GuildCommandCache(guildID Snowflake) map[Snowflake]*Command + AllGuildCommandCache() map[Snowflake]map[Snowflake]*Command + GlobalCommandCache() map[Snowflake]*Command + CacheGlobalCommand(command *Command) *Command + CacheGuildCommand(command *Command) *Command + UncacheCommand(commandID Snowflake) + + User(Snowflake) *User + UserByTag(string) *User + UsersByName(string, bool) []*User + Users() []*User + UserCache() map[Snowflake]*User + CacheUser(*User) *User + UncacheUser(Snowflake) + FindUser(func(*User) bool) *User + FindUsers(func(*User) bool) []*User + Guild(Snowflake) *Guild GuildsByName(string, bool) []*Guild Guilds() []*Guild GuildCache() map[Snowflake]*Guild - CacheGuild(*Guild) + CacheGuild(*Guild) *Guild UncacheGuild(Snowflake) /*Message(Snowflake) *Message @@ -19,19 +37,9 @@ type Cache interface { AllMessages() []*Message MessageCache(Snowflake) map[Snowflake]*Message AllMessageCache() map[Snowflake]map[Snowflake]*Message - CacheMessage(*Message) + CacheMessage(*Message) *Message UncacheMessage(Snowflake)*/ - User(Snowflake) *User - UserByTag(string) *User - UsersByName(string, bool) []*User - Users() []*User - UserCache() map[Snowflake]*User - CacheUser(*User) - UncacheUser(Snowflake) - FindUser(func(*User) bool) *User - FindUsers(func(*User) bool) []*User - Member(Snowflake, Snowflake) *Member MemberByTag(Snowflake, string) *Member MembersByName(Snowflake, string, bool) []*Member @@ -39,7 +47,7 @@ type Cache interface { AllMembers() []*Member MemberCache(Snowflake) map[Snowflake]*Member AllMemberCache() map[Snowflake]map[Snowflake]*Member - CacheMember(*Member) + CacheMember(member *Member) *Member UncacheMember(Snowflake, Snowflake) FindMember(Snowflake, func(*Member) bool) *Member FindMembers(Snowflake, func(*Member) bool) []*Member @@ -47,7 +55,7 @@ type Cache interface { VoiceState(guildID Snowflake, userID Snowflake) *VoiceState VoiceStates(guildID Snowflake) []*VoiceState VoiceStateCache(guildID Snowflake) map[Snowflake]*VoiceState - CacheVoiceState(voiceState *VoiceState) + CacheVoiceState(voiceState *VoiceState) *VoiceState UncacheVoiceState(guildID Snowflake, userID Snowflake) Role(roleID Snowflake) *Role @@ -56,7 +64,7 @@ type Cache interface { AllRoles() []*Role RoleCache(Snowflake) map[Snowflake]*Role AllRoleCache() map[Snowflake]map[Snowflake]*Role - CacheRole(*Role) + CacheRole(*Role) *Role UncacheRole(Snowflake, Snowflake) FindRole(Snowflake, func(*Role) bool) *Role FindRoles(Snowflake, func(*Role) bool) []*Role @@ -64,7 +72,7 @@ type Cache interface { DMChannel(Snowflake) *DMChannel DMChannels() []*DMChannel DMChannelCache() map[Snowflake]*DMChannel - CacheDMChannel(*DMChannel) + CacheDMChannel(*DMChannel) *DMChannel UncacheDMChannel(Snowflake) FindDMChannel(func(*DMChannel) bool) *DMChannel FindDMChannels(func(*DMChannel) bool) []*DMChannel @@ -77,7 +85,7 @@ type Cache interface { TextChannelsByName(Snowflake, string, bool) []*TextChannel TextChannels(Snowflake) []*TextChannel TextChannelCache(Snowflake) map[Snowflake]*TextChannel - CacheTextChannel(*TextChannel) + CacheTextChannel(*TextChannel) *TextChannel UncacheTextChannel(Snowflake, Snowflake) FindTextChannel(Snowflake, func(*TextChannel) bool) *TextChannel FindTextChannels(Snowflake, func(*TextChannel) bool) []*TextChannel @@ -86,7 +94,7 @@ type Cache interface { StoreChannelsByName(Snowflake, string, bool) []*StoreChannel StoreChannels(Snowflake) []*StoreChannel StoreChannelCache(Snowflake) map[Snowflake]*StoreChannel - CacheStoreChannel(*StoreChannel) + CacheStoreChannel(*StoreChannel) *StoreChannel UncacheStoreChannel(Snowflake, Snowflake) FindStoreChannel(Snowflake, func(*StoreChannel) bool) *StoreChannel FindStoreChannels(Snowflake, func(*StoreChannel) bool) []*StoreChannel @@ -95,7 +103,7 @@ type Cache interface { VoiceChannelsByName(Snowflake, string, bool) []*VoiceChannel VoiceChannels(Snowflake) []*VoiceChannel VoiceChannelCache(Snowflake) map[Snowflake]*VoiceChannel - CacheVoiceChannel(*VoiceChannel) + CacheVoiceChannel(*VoiceChannel) *VoiceChannel UncacheVoiceChannel(Snowflake, Snowflake) FindVoiceChannel(Snowflake, func(*VoiceChannel) bool) *VoiceChannel FindVoiceChannels(Snowflake, func(*VoiceChannel) bool) []*VoiceChannel @@ -106,7 +114,7 @@ type Cache interface { AllCategories() []*Category CategoryCache(Snowflake) map[Snowflake]*Category AllCategoryCache() map[Snowflake]map[Snowflake]*Category - CacheCategory(*Category) + CacheCategory(*Category) *Category UncacheCategory(Snowflake, Snowflake) FindCategory(Snowflake, func(*Category) bool) *Category FindCategories(Snowflake, func(*Category) bool) []*Category @@ -116,6 +124,6 @@ type Cache interface { Emotes(guildID Snowflake) []*Emote EmoteCache(guildID Snowflake) map[Snowflake]*Emote AllEmoteCache() map[Snowflake]map[Snowflake]*Emote - CacheEmote(*Emote) + CacheEmote(*Emote) *Emote UncacheEmote(guildID Snowflake, emoteID Snowflake) } diff --git a/api/cache_flags.go b/api/cache_flags.go index 01a2a783..f655d2d2 100644 --- a/api/cache_flags.go +++ b/api/cache_flags.go @@ -14,6 +14,7 @@ const ( CacheFlagRoles CacheFlagEmotes CacheFlagVoiceState + CacheFlagCommands CacheFlagsDefault = CacheFlagDMChannels | CacheFlagCategories | diff --git a/api/entity_builder.go b/api/entity_builder.go index 474b65ec..07f18ee6 100644 --- a/api/entity_builder.go +++ b/api/entity_builder.go @@ -3,9 +3,19 @@ package api type EntityBuilder interface { Disgo() Disgo - CreateTextChannel(channel *Channel) *TextChannel - CreateVoiceChannel(channel *Channel) *VoiceChannel - CreateStoreChannel(channel *Channel) *StoreChannel - CreateCategory(channel *Channel) *Category - CreateDMChannel(channel *Channel) *DMChannel + CreateGlobalCommand(command *Command, updateCache bool) *Command + + CreateUser(user *User, updateCache bool) *User + + CreateGuild(guild *Guild, updateCache bool) *Guild + CreateMember(member *Member, updateCache bool) *Member + CreateGuildCommand(guildID Snowflake, command *Command, updateCache bool) *Command + + CreateTextChannel(channel *Channel, updateCache bool) *TextChannel + CreateVoiceChannel(channel *Channel, updateCache bool) *VoiceChannel + CreateStoreChannel(channel *Channel, updateCache bool) *StoreChannel + CreateCategory(channel *Channel, updateCache bool) *Category + CreateDMChannel(channel *Channel, updateCache bool) *DMChannel + + CreateEmote(emote *Emote, updateCache bool) *Emote } diff --git a/internal/cache_impl.go b/internal/cache_impl.go index 746e1bbf..e156b3a8 100644 --- a/internal/cache_impl.go +++ b/internal/cache_impl.go @@ -17,6 +17,8 @@ func newCacheImpl(disgo api.Disgo, memberCachePolicy api.MemberCachePolicy, mess memberCachePolicy: memberCachePolicy, messageCachePolicy: messageCachePolicy, cacheFlags: cacheFlags, + globalCommands: map[api.Snowflake]*api.Command{}, + guildCommands: map[api.Snowflake]map[api.Snowflake]*api.Command{}, users: map[api.Snowflake]*api.User{}, guilds: map[api.Snowflake]*api.Guild{}, members: map[api.Snowflake]map[api.Snowflake]*api.Member{}, @@ -40,6 +42,8 @@ type CacheImpl struct { memberCachePolicy api.MemberCachePolicy messageCachePolicy api.MessageCachePolicy cacheFlags api.CacheFlags + globalCommands map[api.Snowflake]*api.Command + guildCommands map[api.Snowflake]map[api.Snowflake]*api.Command users map[api.Snowflake]*api.User guilds map[api.Snowflake]*api.Guild members map[api.Snowflake]map[api.Snowflake]*api.Member @@ -98,6 +102,67 @@ func (c CacheImpl) CacheFlags() api.CacheFlags { return c.cacheFlags } +func (c *CacheImpl) Command(commandID api.Snowflake) *api.Command { + if command, ok := c.globalCommands[commandID]; ok { + return command + } + for _, guildCommands := range c.guildCommands { + if command, ok := guildCommands[commandID]; ok { + return command + } + } + return nil +} + +func (c *CacheImpl) GuildCommandCache(guildID api.Snowflake) map[api.Snowflake]*api.Command { + return c.guildCommands[guildID] +} + +func (c *CacheImpl) AllGuildCommandCache() map[api.Snowflake]map[api.Snowflake]*api.Command { + return c.guildCommands +} + +func (c *CacheImpl) GlobalCommandCache() map[api.Snowflake]*api.Command { + return c.globalCommands +} + +func (c *CacheImpl) CacheGlobalCommand(command *api.Command) *api.Command { + if !c.CacheFlags().Has(api.CacheFlagCommands) { + return command + } + if _, ok := c.globalCommands[command.ID]; ok { + *c.globalCommands[command.ID] = *command + return c.globalCommands[command.ID] + } + c.globalCommands[command.ID] = command + return command +} +func (c *CacheImpl) CacheGuildCommand(command *api.Command) *api.Command { + if !c.CacheFlags().Has(api.CacheFlagCommands) { + return command + } + if guildCommands, ok := c.guildCommands[command.ID]; ok { + if _, ok = guildCommands[command.ID]; ok { + *guildCommands[command.ID] = *command + return guildCommands[command.ID] + } + guildCommands[command.ID] = command + } + return command +} +func (c *CacheImpl) UncacheCommand(commandID api.Snowflake) { + if _, ok := c.globalCommands[commandID]; ok { + delete(c.globalCommands, commandID) + return + } + for _, guildCommands := range c.guildCommands { + if _, ok := guildCommands[commandID]; ok { + delete(c.guildCommands, commandID) + return + } + } +} + // User allows you to get a user from the cache by ID func (c *CacheImpl) User(id api.Snowflake) *api.User { return c.users[id] @@ -144,13 +209,14 @@ func (c *CacheImpl) UserCache() map[api.Snowflake]*api.User { } // CacheUser adds a user to the cache -func (c *CacheImpl) CacheUser(user *api.User) { +func (c *CacheImpl) CacheUser(user *api.User) *api.User { // TODO: only cache user if we have a mutal guild & always cache self user - if _, ok := c.guilds[user.ID]; ok { - // update old user - return + if globalUser, ok := c.users[user.ID]; ok { + *globalUser = *user + return globalUser } c.users[user.ID] = user + return user } // UncacheUser removes a user from the cache @@ -215,26 +281,28 @@ func (c *CacheImpl) GuildCache() map[api.Snowflake]*api.Guild { } // CacheGuild adds a guild to the cache -func (c *CacheImpl) CacheGuild(guild *api.Guild) { - // TODO: guilds are always cached? +func (c *CacheImpl) CacheGuild(guild *api.Guild) *api.Guild { if _, ok := c.guilds[guild.ID]; ok { - // update old guild_events + // update old guild *c.guilds[guild.ID] = *guild - return + return c.guilds[guild.ID] } - // guild_events was not yet cached so cache it directly + // guild was not yet cached so cache it directly c.guilds[guild.ID] = guild + c.guildCommands[guild.ID] = map[api.Snowflake]*api.Command{} c.members[guild.ID] = map[api.Snowflake]*api.Member{} c.roles[guild.ID] = map[api.Snowflake]*api.Role{} c.categories[guild.ID] = map[api.Snowflake]*api.Category{} c.textChannels[guild.ID] = map[api.Snowflake]*api.TextChannel{} c.voiceChannels[guild.ID] = map[api.Snowflake]*api.VoiceChannel{} c.storeChannels[guild.ID] = map[api.Snowflake]*api.StoreChannel{} + return guild } //UncacheGuild removes a guild and all of it's children from the cache func (c *CacheImpl) UncacheGuild(guildID api.Snowflake) { delete(c.guilds, guildID) + delete(c.guildCommands, guildID) delete(c.members, guildID) delete(c.voiceStates, guildID) delete(c.roles, guildID) @@ -338,18 +406,19 @@ func (c *CacheImpl) AllMemberCache() map[api.Snowflake]map[api.Snowflake]*api.Me } // CacheMember adds a member to the cache -func (c *CacheImpl) CacheMember(member *api.Member) { +func (c *CacheImpl) CacheMember(member *api.Member) *api.Member { // only cache member if we want to & always cache self member! if member.User.ID != member.Disgo.SelfUserID() && !c.memberCachePolicy(member) { - return + return member } if guildMembers, ok := c.members[member.GuildID]; ok { - if _, ok := guildMembers[member.User.ID]; ok { - // update old guild_events - return + if guildMember, ok := guildMembers[member.User.ID]; ok { + *guildMember = *member + return guildMember } guildMembers[member.User.ID] = member } + return member } // UncacheMember removes a guild member from the cache @@ -406,18 +475,19 @@ func (c *CacheImpl) VoiceStateCache(guildID api.Snowflake) map[api.Snowflake]*ap } // CacheVoiceState adds a api.VoiceState from the api.Cache -func (c *CacheImpl) CacheVoiceState(voiceState *api.VoiceState) { +func (c *CacheImpl) CacheVoiceState(voiceState *api.VoiceState) *api.VoiceState { // only cache voice states for ourself or member is cached & cache flag activated if voiceState.UserID != c.disgo.SelfUserID() && (!c.cacheFlags.Has(api.CacheFlagVoiceState) || c.Member(voiceState.GuildID, voiceState.UserID) == nil) { - return + return voiceState } - if voiceStates, ok := c.voiceStates[voiceState.GuildID]; ok { - if _, ok = voiceStates[voiceState.UserID]; ok { - *voiceStates[voiceState.UserID] = *voiceState - return + if guildVoiceStates, ok := c.voiceStates[voiceState.GuildID]; ok { + if guildVoiceState, ok := guildVoiceStates[voiceState.UserID]; ok { + *guildVoiceState = *voiceState + return guildVoiceState } - voiceStates[voiceState.UserID] = voiceState + guildVoiceStates[voiceState.UserID] = voiceState } + return voiceState } // UncacheVoiceState removes a api.VoiceState from the api.Cache @@ -488,17 +558,18 @@ func (c *CacheImpl) AllRoleCache() map[api.Snowflake]map[api.Snowflake]*api.Role } // CacheRole adds a role to the cache -func (c *CacheImpl) CacheRole(role *api.Role) { +func (c *CacheImpl) CacheRole(role *api.Role) *api.Role { if !c.cacheFlags.Has(api.CacheFlagRoles) { - return + return role } if guildRoles, ok := c.roles[role.GuildID]; ok { - if _, ok := guildRoles[role.ID]; ok { - // update old role - return + if guildRole, ok := guildRoles[role.ID]; ok { + *guildRole = *role + return guildRole } guildRoles[role.ID] = role } + return role } // UncacheRole removes a role from cache @@ -608,15 +679,16 @@ func (c *CacheImpl) DMChannelCache() map[api.Snowflake]*api.DMChannel { } // CacheDMChannel adds a DM channel to the cache -func (c *CacheImpl) CacheDMChannel(dmChannel *api.DMChannel) { +func (c *CacheImpl) CacheDMChannel(dmChannel *api.DMChannel) *api.DMChannel{ if !c.cacheFlags.Has(api.CacheFlagDMChannels) { - return + return dmChannel } if oldChannel, ok := c.dmChannels[dmChannel.ID]; ok { *oldChannel = *dmChannel - return + return oldChannel } c.dmChannels[dmChannel.ID] = dmChannel + return dmChannel } // UncacheDMChannel removes a DM channel from cache @@ -708,17 +780,18 @@ func (c *CacheImpl) AllTextChannelCache() map[api.Snowflake]map[api.Snowflake]*a } // CacheTextChannel adds a channel to the cache -func (c *CacheImpl) CacheTextChannel(textChannel *api.TextChannel) { +func (c *CacheImpl) CacheTextChannel(textChannel *api.TextChannel) *api.TextChannel { if !c.cacheFlags.Has(api.CacheFlagTextChannels) { - return + return textChannel } - if guildTextChannels, ok := c.textChannels[textChannel.GuildID]; ok { + if guildTextChannels, ok := c.textChannels[*textChannel.GuildID]; ok { if guildTextChannel, ok := guildTextChannels[textChannel.MessageChannel.ID]; ok { *guildTextChannel = *textChannel - return + return guildTextChannel } guildTextChannels[textChannel.MessageChannel.ID] = textChannel } + return textChannel } // UncacheTextChannel removes a text channel from the cache @@ -810,17 +883,18 @@ func (c *CacheImpl) AllStoreChannelCache() map[api.Snowflake]map[api.Snowflake]* } // CacheStoreChannel adds a store channel to the cache -func (c *CacheImpl) CacheStoreChannel(storeChannel *api.StoreChannel) { +func (c *CacheImpl) CacheStoreChannel(storeChannel *api.StoreChannel) *api.StoreChannel { if !c.cacheFlags.Has(api.CacheFlagStoreChannels) { - return + return storeChannel } - if guildStoreChannels, ok := c.storeChannels[storeChannel.GuildID]; ok { + if guildStoreChannels, ok := c.storeChannels[*storeChannel.GuildID]; ok { if guildStoreChannel, ok := guildStoreChannels[storeChannel.ID]; ok { *guildStoreChannel = *storeChannel - return + return guildStoreChannel } guildStoreChannels[storeChannel.ID] = storeChannel } + return storeChannel } // UncacheStoreChannel removes a store channel from cache @@ -912,17 +986,18 @@ func (c *CacheImpl) AllVoiceChannelCache() map[api.Snowflake]map[api.Snowflake]* } // CacheVoiceChannel adds a voice channel to cache -func (c *CacheImpl) CacheVoiceChannel(voiceChannel *api.VoiceChannel) { +func (c *CacheImpl) CacheVoiceChannel(voiceChannel *api.VoiceChannel) *api.VoiceChannel { if !c.cacheFlags.Has(api.CacheFlagVoiceChannels) { - return + return voiceChannel } - if guildVoiceChannels, ok := c.voiceChannels[voiceChannel.GuildID]; ok { + if guildVoiceChannels, ok := c.voiceChannels[*voiceChannel.GuildID]; ok { if guildVoiceChannel, ok := guildVoiceChannels[voiceChannel.ID]; ok { *guildVoiceChannel = *voiceChannel - return + return guildVoiceChannel } guildVoiceChannels[voiceChannel.ID] = voiceChannel } + return voiceChannel } // UncacheVoiceChannel removes a voice channel from cache @@ -1014,17 +1089,18 @@ func (c *CacheImpl) AllCategoryCache() map[api.Snowflake]map[api.Snowflake]*api. } // CacheCategory adds a category to the cache -func (c *CacheImpl) CacheCategory(category *api.Category) { +func (c *CacheImpl) CacheCategory(category *api.Category) *api.Category { if !c.cacheFlags.Has(api.CacheFlagCategories) { - return + return category } - if guildCategories, ok := c.categories[category.GuildID]; ok { + if guildCategories, ok := c.categories[*category.GuildID]; ok { if guildCategory, ok := guildCategories[category.ID]; ok { *guildCategory = *category - return + return guildCategory } guildCategories[category.ID] = category } + return category } // UncacheCategory removes a category from cache @@ -1105,17 +1181,18 @@ func (c *CacheImpl) AllEmoteCache() map[api.Snowflake]map[api.Snowflake]*api.Emo } // CacheEmote adds an Emote to the api.Cache if emoji caches are used -func (c *CacheImpl) CacheEmote(emote *api.Emote) { +func (c *CacheImpl) CacheEmote(emote *api.Emote) *api.Emote { if !c.cacheFlags.Has(api.CacheFlagEmotes) { - return + return emote } if guildEmotes, ok := c.emotes[emote.GuildID]; ok { if guildEmote, ok := guildEmotes[emote.ID]; ok { *guildEmote = *emote - return + return guildEmote } guildEmotes[emote.ID] = emote } + return emote } // UncacheEmote removes an Emote from api.Cache diff --git a/internal/entity_builder_impl.go b/internal/entity_builder_impl.go index 3edeaf92..8a842039 100644 --- a/internal/entity_builder_impl.go +++ b/internal/entity_builder_impl.go @@ -16,7 +16,49 @@ func (b EntityBuilderImpl) Disgo() api.Disgo { return b.disgo } -func (b EntityBuilderImpl) CreateTextChannel(channel *api.Channel) *api.TextChannel { +func (b EntityBuilderImpl) CreateGlobalCommand(command *api.Command, updateCache bool) *api.Command { + command.Disgo = b.Disgo() + if updateCache { + return b.Disgo().Cache().CacheGlobalCommand(command) + } + return command +} + +func (b EntityBuilderImpl) CreateUser(user *api.User, updateCache bool) *api.User { + user.Disgo = b.Disgo() + if updateCache { + return b.Disgo().Cache().CacheUser(user) + } + return user +} + +func (b EntityBuilderImpl) CreateGuild(guild *api.Guild, updateCache bool) *api.Guild { + guild.Disgo = b.Disgo() + if updateCache { + return b.Disgo().Cache().CacheGuild(guild) + } + return guild +} + +func (b EntityBuilderImpl) CreateMember(member *api.Member, updateCache bool) *api.Member { + member.Disgo = b.Disgo() + member.User = b.CreateUser(member.User, updateCache) + if updateCache { + return b.Disgo().Cache().CacheMember(member) + } + return member +} + +func (b EntityBuilderImpl) CreateGuildCommand(guildID api.Snowflake, command *api.Command, updateCache bool) *api.Command { + command.Disgo = b.Disgo() + command.GuildID = &guildID + if updateCache { + return b.Disgo().Cache().CacheGuildCommand(command) + } + return command +} + +func (b EntityBuilderImpl) CreateTextChannel(channel *api.Channel, updateCache bool) *api.TextChannel { channel.Disgo = b.Disgo() textChannel := &api.TextChannel{ MessageChannel: api.MessageChannel{ @@ -26,50 +68,68 @@ func (b EntityBuilderImpl) CreateTextChannel(channel *api.Channel) *api.TextChan Channel: *channel, }, } - b.Disgo().Cache().CacheTextChannel(textChannel) + if updateCache { + return b.Disgo().Cache().CacheTextChannel(textChannel) + } return textChannel } -func (b EntityBuilderImpl) CreateVoiceChannel(channel *api.Channel) *api.VoiceChannel { +func (b EntityBuilderImpl) CreateVoiceChannel(channel *api.Channel, updateCache bool) *api.VoiceChannel { channel.Disgo = b.Disgo() voiceChannel := &api.VoiceChannel{ GuildChannel: api.GuildChannel{ Channel: *channel, }, } - b.Disgo().Cache().CacheVoiceChannel(voiceChannel) + if updateCache { + return b.Disgo().Cache().CacheVoiceChannel(voiceChannel) + } return voiceChannel } -func (b EntityBuilderImpl) CreateStoreChannel(channel *api.Channel) *api.StoreChannel { +func (b EntityBuilderImpl) CreateStoreChannel(channel *api.Channel, updateCache bool) *api.StoreChannel { channel.Disgo = b.Disgo() storeChannel := &api.StoreChannel{ GuildChannel: api.GuildChannel{ Channel: *channel, }, } - b.Disgo().Cache().CacheStoreChannel(storeChannel) + if updateCache { + return b.Disgo().Cache().CacheStoreChannel(storeChannel) + } return storeChannel } -func (b EntityBuilderImpl) CreateCategory(channel *api.Channel) *api.Category { +func (b EntityBuilderImpl) CreateCategory(channel *api.Channel, updateCache bool) *api.Category { channel.Disgo = b.Disgo() category := &api.Category{ GuildChannel: api.GuildChannel{ Channel: *channel, }, } - b.Disgo().Cache().CacheCategory(category) + if updateCache { + return b.Disgo().Cache().CacheCategory(category) + } return category } -func (b EntityBuilderImpl) CreateDMChannel(channel *api.Channel) *api.DMChannel { +func (b EntityBuilderImpl) CreateDMChannel(channel *api.Channel, updateCache bool) *api.DMChannel { channel.Disgo = b.Disgo() dmChannel := &api.DMChannel{ MessageChannel: api.MessageChannel{ Channel: *channel, }, } - b.Disgo().Cache().CacheDMChannel(dmChannel) + if updateCache { + return b.Disgo().Cache().CacheDMChannel(dmChannel) + } return dmChannel } + +func (b EntityBuilderImpl) CreateEmote(emote *api.Emote, updateCache bool) *api.Emote { + emote.Disgo = b.Disgo() + if updateCache { + return b.Disgo().Cache().CacheEmote(emote) + } + return emote +} diff --git a/internal/handlers/application_command_create.go b/internal/handlers/application_command_create.go index 8caa4395..eb86cddd 100644 --- a/internal/handlers/application_command_create.go +++ b/internal/handlers/application_command_create.go @@ -25,6 +25,12 @@ func (h ApplicationCommandCreateHandler) HandleGatewayEvent(disgo api.Disgo, eve return } + if command.FromGuild() { + command = disgo.EntityBuilder().CreateGuildCommand(*command.GuildID, command, true) + } else { + command = disgo.EntityBuilder().CreateGlobalCommand(command, true) + } + genericApplicationCommandEvent := events.GenericApplicationCommandEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), CommandID: command.ID, diff --git a/internal/handlers/application_command_delete.go b/internal/handlers/application_command_delete.go index 12c226aa..e50d46b4 100644 --- a/internal/handlers/application_command_delete.go +++ b/internal/handlers/application_command_delete.go @@ -25,6 +25,14 @@ func (h ApplicationCommandDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eve return } + disgo.Cache().UncacheCommand(command.ID) + + if command.FromGuild() { + command = disgo.EntityBuilder().CreateGuildCommand(*command.GuildID, command, false) + } else { + command = disgo.EntityBuilder().CreateGlobalCommand(command, false) + } + genericApplicationCommandEvent := events.GenericApplicationCommandEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), CommandID: command.ID, @@ -34,6 +42,6 @@ func (h ApplicationCommandDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eve eventManager.Dispatch(events.ApplicationCommandDeleteEvent{ GenericApplicationCommandEvent: genericApplicationCommandEvent, - Command: command, + Command: command, }) } diff --git a/internal/handlers/application_command_update.go b/internal/handlers/application_command_update.go index 5e5ae23f..c8a278ca 100644 --- a/internal/handlers/application_command_update.go +++ b/internal/handlers/application_command_update.go @@ -25,6 +25,17 @@ func (h ApplicationCommandUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eve return } + oldCommand := disgo.Cache().Command(command.ID) + if oldCommand != nil { + oldCommand = &*oldCommand + } + + if command.FromGuild() { + command = disgo.EntityBuilder().CreateGuildCommand(*command.GuildID, command, true) + } else { + command = disgo.EntityBuilder().CreateGlobalCommand(command, true) + } + genericApplicationCommandEvent := events.GenericApplicationCommandEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), CommandID: command.ID, @@ -35,6 +46,6 @@ func (h ApplicationCommandUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eve eventManager.Dispatch(events.ApplicationCommandUpdateEvent{ GenericApplicationCommandEvent: genericApplicationCommandEvent, NewCommand: command, - OldCommand: nil, + OldCommand: oldCommand, }) } diff --git a/internal/handlers/channel_create_handler.go b/internal/handlers/channel_create_handler.go index 9d621903..592f59d0 100644 --- a/internal/handlers/channel_create_handler.go +++ b/internal/handlers/channel_create_handler.go @@ -34,7 +34,7 @@ func (h ChannelCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a switch channel.Type { case api.ChannelTypeDM: - dmChannel := disgo.EntityBuilder().CreateDMChannel(channel) + dmChannel := disgo.EntityBuilder().CreateDMChannel(channel, true) genericDMChannelEvent := events.GenericDMChannelEvent{ GenericChannelEvent: genericChannelEvent, @@ -50,7 +50,7 @@ func (h ChannelCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a log.Warnf("ChannelTypeGroupDM received what the hell discord") case api.ChannelTypeText, api.ChannelTypeNews: - textChannel := disgo.EntityBuilder().CreateTextChannel(channel) + textChannel := disgo.EntityBuilder().CreateTextChannel(channel, true) genericTextChannelEvent := events.GenericTextChannelEvent{ GenericChannelEvent: genericChannelEvent, @@ -63,7 +63,7 @@ func (h ChannelCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a }) case api.ChannelTypeStore: - storeChannel := disgo.EntityBuilder().CreateStoreChannel(channel) + storeChannel := disgo.EntityBuilder().CreateStoreChannel(channel, true) genericStoreChannelEvent := events.GenericStoreChannelEvent{ GenericChannelEvent: genericChannelEvent, @@ -76,7 +76,7 @@ func (h ChannelCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a }) case api.ChannelTypeCategory: - category := disgo.EntityBuilder().CreateCategory(channel) + category := disgo.EntityBuilder().CreateCategory(channel, true) genericCategoryEvent := events.GenericCategoryEvent{ GenericChannelEvent: genericChannelEvent, @@ -89,7 +89,7 @@ func (h ChannelCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a }) case api.ChannelTypeVoice: - voiceChannel := disgo.EntityBuilder().CreateVoiceChannel(channel) + voiceChannel := disgo.EntityBuilder().CreateVoiceChannel(channel, true) genericVoiceChannelEvent := events.GenericVoiceChannelEvent{ GenericChannelEvent: genericChannelEvent, diff --git a/internal/handlers/channel_delete_handler.go b/internal/handlers/channel_delete_handler.go index 1885a54d..69c3e98c 100644 --- a/internal/handlers/channel_delete_handler.go +++ b/internal/handlers/channel_delete_handler.go @@ -2,6 +2,8 @@ package handlers import ( "github.com/DisgoOrg/disgo/api" + "github.com/DisgoOrg/disgo/api/events" + log "github.com/sirupsen/logrus" ) // ChannelDeleteHandler handles api.GatewayEventChannelDelete @@ -24,5 +26,87 @@ func (h ChannelDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a return } - + genericChannelEvent := events.GenericChannelEvent{ + GenericEvent: events.NewEvent(disgo, sequenceNumber), + ChannelID: channel.ID, + } + eventManager.Dispatch(genericChannelEvent) + + switch channel.Type { + case api.ChannelTypeDM: + disgo.Cache().UncacheDMChannel(channel.ID) + dmChannel := disgo.EntityBuilder().CreateDMChannel(channel, false) + + genericDMChannelEvent := events.GenericDMChannelEvent{ + GenericChannelEvent: genericChannelEvent, + } + eventManager.Dispatch(genericDMChannelEvent) + + eventManager.Dispatch(events.DMChannelCreateEvent{ + GenericDMChannelEvent: genericDMChannelEvent, + DMChannel: dmChannel, + }) + + case api.ChannelTypeGroupDM: + log.Warnf("ChannelTypeGroupDM received what the hell discord") + + case api.ChannelTypeText, api.ChannelTypeNews: + disgo.Cache().UncacheTextChannel(*channel.GuildID, channel.ID) + textChannel := disgo.EntityBuilder().CreateTextChannel(channel, false) + + genericTextChannelEvent := events.GenericTextChannelEvent{ + GenericChannelEvent: genericChannelEvent, + } + eventManager.Dispatch(genericTextChannelEvent) + + eventManager.Dispatch(events.TextChannelCreateEvent{ + GenericTextChannelEvent: genericTextChannelEvent, + TextChannel: textChannel, + }) + + case api.ChannelTypeStore: + disgo.Cache().UncacheStoreChannel(*channel.GuildID, channel.ID) + storeChannel := disgo.EntityBuilder().CreateStoreChannel(channel, false) + + genericStoreChannelEvent := events.GenericStoreChannelEvent{ + GenericChannelEvent: genericChannelEvent, + } + eventManager.Dispatch(genericStoreChannelEvent) + + eventManager.Dispatch(events.StoreChannelCreateEvent{ + GenericStoreChannelEvent: genericStoreChannelEvent, + StoreChannel: storeChannel, + }) + + case api.ChannelTypeCategory: + disgo.Cache().UncacheCategory(*channel.GuildID, channel.ID) + category := disgo.EntityBuilder().CreateCategory(channel, false) + + genericCategoryEvent := events.GenericCategoryEvent{ + GenericChannelEvent: genericChannelEvent, + } + eventManager.Dispatch(genericCategoryEvent) + + eventManager.Dispatch(events.CategoryCreateEvent{ + GenericCategoryEvent: genericCategoryEvent, + Category: category, + }) + + case api.ChannelTypeVoice: + disgo.Cache().UncacheVoiceChannel(*channel.GuildID, channel.ID) + voiceChannel := disgo.EntityBuilder().CreateVoiceChannel(channel, false) + + genericVoiceChannelEvent := events.GenericVoiceChannelEvent{ + GenericChannelEvent: genericChannelEvent, + } + eventManager.Dispatch(genericVoiceChannelEvent) + + eventManager.Dispatch(events.VoiceChannelCreateEvent{ + GenericVoiceChannelEvent: genericVoiceChannelEvent, + VoiceChannel: voiceChannel, + }) + + default: + log.Warnf("unknown channel type received: %d", channel.Type) + } } diff --git a/internal/handlers/channel_update_handler.go b/internal/handlers/channel_update_handler.go index 025de6ca..c832de17 100644 --- a/internal/handlers/channel_update_handler.go +++ b/internal/handlers/channel_update_handler.go @@ -2,6 +2,8 @@ package handlers import ( "github.com/DisgoOrg/disgo/api" + "github.com/DisgoOrg/disgo/api/events" + log "github.com/sirupsen/logrus" ) // ChannelUpdateHandler handles api.GatewayEventChannelUpdate @@ -24,5 +26,91 @@ func (h ChannelUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a return } - + genericChannelEvent := events.GenericChannelEvent{ + GenericEvent: events.NewEvent(disgo, sequenceNumber), + ChannelID: channel.ID, + } + eventManager.Dispatch(genericChannelEvent) + + switch channel.Type { + case api.ChannelTypeDM: + oldDMChannel := disgo.Cache().DMChannel(channel.ID) + if oldDMChannel != nil { + oldDMChannel = &*oldDMChannel + } + newDMChannel := disgo.EntityBuilder().CreateDMChannel(channel, false) + + genericDMChannelEvent := events.GenericDMChannelEvent{ + GenericChannelEvent: genericChannelEvent, + } + eventManager.Dispatch(genericDMChannelEvent) + + eventManager.Dispatch(events.DMChannelUpdateEvent{ + GenericDMChannelEvent: genericDMChannelEvent, + NewDMChannel: newDMChannel, + OldDMChannel: oldDMChannel, + }) + + case api.ChannelTypeGroupDM: + log.Warnf("ChannelTypeGroupDM received what the hell discord") + + case api.ChannelTypeText, api.ChannelTypeNews: + disgo.Cache().UncacheTextChannel(*channel.GuildID, channel.ID) + textChannel := disgo.EntityBuilder().CreateTextChannel(channel, false) + + genericTextChannelEvent := events.GenericTextChannelEvent{ + GenericChannelEvent: genericChannelEvent, + } + eventManager.Dispatch(genericTextChannelEvent) + + eventManager.Dispatch(events.TextChannelUpdateEvent{ + GenericTextChannelEvent: genericTextChannelEvent, + TextChannel: textChannel, + }) + + case api.ChannelTypeStore: + disgo.Cache().UncacheStoreChannel(*channel.GuildID, channel.ID) + storeChannel := disgo.EntityBuilder().CreateStoreChannel(channel, false) + + genericStoreChannelEvent := events.GenericStoreChannelEvent{ + GenericChannelEvent: genericChannelEvent, + } + eventManager.Dispatch(genericStoreChannelEvent) + + eventManager.Dispatch(events.StoreChannelUpdateEvent{ + GenericStoreChannelEvent: genericStoreChannelEvent, + StoreChannel: storeChannel, + }) + + case api.ChannelTypeCategory: + disgo.Cache().UncacheCategory(*channel.GuildID, channel.ID) + category := disgo.EntityBuilder().CreateCategory(channel, false) + + genericCategoryEvent := events.GenericCategoryEvent{ + GenericChannelEvent: genericChannelEvent, + } + eventManager.Dispatch(genericCategoryEvent) + + eventManager.Dispatch(events.CategoryUpdateEvent{ + GenericCategoryEvent: genericCategoryEvent, + Category: category, + }) + + case api.ChannelTypeVoice: + disgo.Cache().UncacheVoiceChannel(*channel.GuildID, channel.ID) + voiceChannel := disgo.EntityBuilder().CreateVoiceChannel(channel, false) + + genericVoiceChannelEvent := events.GenericVoiceChannelEvent{ + GenericChannelEvent: genericChannelEvent, + } + eventManager.Dispatch(genericVoiceChannelEvent) + + eventManager.Dispatch(events.VoiceChannelUpdateEvent{ + GenericVoiceChannelEvent: genericVoiceChannelEvent, + VoiceChannel: voiceChannel, + }) + + default: + log.Warnf("unknown channel type received: %d", channel.Type) + } } From 139a8aafb07961e7e055cba8c19c423cfefabdc8 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Fri, 9 Apr 2021 13:10:29 +0200 Subject: [PATCH 32/65] message & cachetuff --- api/entity_builder.go | 6 ++- api/events/category_events.go | 4 +- api/guild.go | 2 +- api/message.go | 54 ++++++++++++------- internal/cache_impl.go | 2 +- internal/entity_builder_impl.go | 23 +++++++- internal/handlers/channel_update_handler.go | 42 ++++++++++----- internal/handlers/guild_create_handler.go | 47 +++++----------- internal/handlers/guild_delete_handler.go | 6 +-- internal/handlers/guild_member_add_handler.go | 2 +- .../handlers/guild_member_update_handler.go | 16 +++--- .../handlers/guild_role_create_handler.go | 11 ++-- .../handlers/guild_role_delete_handler.go | 8 +-- .../handlers/guild_role_update_handler.go | 17 +++--- internal/handlers/guild_update_handler.go | 15 +++--- 15 files changed, 144 insertions(+), 111 deletions(-) diff --git a/api/entity_builder.go b/api/entity_builder.go index 07f18ee6..ec7c0356 100644 --- a/api/entity_builder.go +++ b/api/entity_builder.go @@ -8,8 +8,10 @@ type EntityBuilder interface { CreateUser(user *User, updateCache bool) *User CreateGuild(guild *Guild, updateCache bool) *Guild - CreateMember(member *Member, updateCache bool) *Member + CreateMember(guildID Snowflake, member *Member, updateCache bool) *Member CreateGuildCommand(guildID Snowflake, command *Command, updateCache bool) *Command + CreateRole(guildID Snowflake, role *Role, updateCache bool) *Role + CreateVoiceState(role *VoiceState, updateCache bool) *VoiceState CreateTextChannel(channel *Channel, updateCache bool) *TextChannel CreateVoiceChannel(channel *Channel, updateCache bool) *VoiceChannel @@ -17,5 +19,5 @@ type EntityBuilder interface { CreateCategory(channel *Channel, updateCache bool) *Category CreateDMChannel(channel *Channel, updateCache bool) *DMChannel - CreateEmote(emote *Emote, updateCache bool) *Emote + CreateEmote(guildID Snowflake, emote *Emote, updateCache bool) *Emote } diff --git a/api/events/category_events.go b/api/events/category_events.go index 83621f54..124ab633 100644 --- a/api/events/category_events.go +++ b/api/events/category_events.go @@ -18,12 +18,12 @@ type CategoryCreateEvent struct { } type CategoryUpdateEvent struct { - GenericChannelEvent + GenericCategoryEvent NewCategory *api.Category OldCategory *api.Category } type CategoryDeleteEvent struct { - GenericChannelEvent + GenericCategoryEvent Category *api.Category } diff --git a/api/guild.go b/api/guild.go index e00dabb0..01f577e9 100644 --- a/api/guild.go +++ b/api/guild.go @@ -124,7 +124,7 @@ type FullGuild struct { Roles []*Role `json:"roles"` Emotes []*Emote `json:"emojis"` Members []*Member `json:"members"` - Channels []*GuildChannel `json:"channels"` + Channels []*Channel `json:"channels"` VoiceStates []*VoiceState `json:"voice_states"` //Presences []*Presence `json:"presences"` } diff --git a/api/message.go b/api/message.go index 43e23907..896ee45c 100644 --- a/api/message.go +++ b/api/message.go @@ -98,30 +98,44 @@ const ( MessageFlagLoading // Message is an interaction of type 5, awaiting further response ) +//MessageAttachment is used for files sent in a Message +type MessageAttachment struct { + ID Snowflake `json:"id,omitempty"` + Filename string `json:"filename"` + Size int `json:"size"` + URL string `json:"url"` + ProxyURL string `json:"proxy_url"` + Height *int `json:"height"` + Width *int `json:"width"` +} + // Message is a struct for messages sent in discord text-based channels -// todo: missing Member, mention channels, webhook id, activity, application, stickers, referenced_message +// todo: missing activity, application, stickers, referenced_message // https://discord.com/developers/docs/resources/channel#message-object type Message struct { Disgo Disgo - ID Snowflake `json:"id"` - GuildID *Snowflake `json:"guild_id"` - Reactions []MessageReaction `json:"reactions"` - Attachments []interface{} `json:"attachments"` - TTS bool `json:"tts"` - Embeds []*Embed `json:"embeds,omitempty"` - CreatedAt time.Time `json:"timestamp"` - MentionEveryone bool `json:"mention_everyone"` - Pinned bool `json:"pinned"` - EditedTimestamp interface{} `json:"edited_timestamp"` - Author User `json:"author"` - MentionRoles []interface{} `json:"mention_roles"` - Content *string `json:"content,omitempty"` - ChannelID Snowflake `json:"channel_id"` - Mentions []interface{} `json:"mentions"` - Type MessageType `json:"type"` - Flags *MessageFlags `json:"flags"` - MessageReference *MessageReference `json:"message_reference,omitempty"` - Interaction *MessageInteraction `json:"message_interaction,omitempty"` + ID Snowflake `json:"id"` + GuildID *Snowflake `json:"guild_id"` + Reactions []*MessageReaction `json:"reactions"` + Attachments []*MessageAttachment `json:"attachments"` + TTS bool `json:"tts"` + Embeds []*Embed `json:"embeds,omitempty"` + CreatedAt time.Time `json:"timestamp"` + Mentions []interface{} `json:"mentions"` + MentionEveryone bool `json:"mention_everyone"` + MentionRoles []*Role `json:"mention_roles"` + MentionChannels []*Channel `json:"mention_channels"` + Pinned bool `json:"pinned"` + EditedTimestamp *time.Time `json:"edited_timestamp"` + Author *User `json:"author"` + Member *Member `json:"member"` + Content *string `json:"content,omitempty"` + ChannelID Snowflake `json:"channel_id"` + Type MessageType `json:"type"` + Flags *MessageFlags `json:"flags"` + MessageReference *MessageReference `json:"message_reference,omitempty"` + Interaction *MessageInteraction `json:"message_interaction,omitempty"` + WebhookID *Snowflake `json:"webhook_id,omitempty"` LastUpdated *time.Time } diff --git a/internal/cache_impl.go b/internal/cache_impl.go index e156b3a8..c3f95ed3 100644 --- a/internal/cache_impl.go +++ b/internal/cache_impl.go @@ -784,7 +784,7 @@ func (c *CacheImpl) CacheTextChannel(textChannel *api.TextChannel) *api.TextChan if !c.cacheFlags.Has(api.CacheFlagTextChannels) { return textChannel } - if guildTextChannels, ok := c.textChannels[*textChannel.GuildID]; ok { + if guildTextChannels, ok := c.textChannels[*textChannel.GuildChannel.GuildID]; ok { if guildTextChannel, ok := guildTextChannels[textChannel.MessageChannel.ID]; ok { *guildTextChannel = *textChannel return guildTextChannel diff --git a/internal/entity_builder_impl.go b/internal/entity_builder_impl.go index 8a842039..96c9de76 100644 --- a/internal/entity_builder_impl.go +++ b/internal/entity_builder_impl.go @@ -40,8 +40,9 @@ func (b EntityBuilderImpl) CreateGuild(guild *api.Guild, updateCache bool) *api. return guild } -func (b EntityBuilderImpl) CreateMember(member *api.Member, updateCache bool) *api.Member { +func (b EntityBuilderImpl) CreateMember(guildID api.Snowflake, member *api.Member, updateCache bool) *api.Member { member.Disgo = b.Disgo() + member.GuildID = guildID member.User = b.CreateUser(member.User, updateCache) if updateCache { return b.Disgo().Cache().CacheMember(member) @@ -49,6 +50,14 @@ func (b EntityBuilderImpl) CreateMember(member *api.Member, updateCache bool) *a return member } +func (b EntityBuilderImpl) CreateVoiceState(voiceState *api.VoiceState, updateCache bool) *api.VoiceState { + voiceState.Disgo = b.Disgo() + if updateCache { + return b.Disgo().Cache().CacheVoiceState(voiceState) + } + return voiceState +} + func (b EntityBuilderImpl) CreateGuildCommand(guildID api.Snowflake, command *api.Command, updateCache bool) *api.Command { command.Disgo = b.Disgo() command.GuildID = &guildID @@ -58,6 +67,15 @@ func (b EntityBuilderImpl) CreateGuildCommand(guildID api.Snowflake, command *ap return command } +func (b EntityBuilderImpl) CreateRole(guildID api.Snowflake, role *api.Role, updateCache bool) *api.Role { + role.Disgo = b.Disgo() + role.GuildID = guildID + if updateCache { + return b.Disgo().Cache().CacheRole(role) + } + return role +} + func (b EntityBuilderImpl) CreateTextChannel(channel *api.Channel, updateCache bool) *api.TextChannel { channel.Disgo = b.Disgo() textChannel := &api.TextChannel{ @@ -126,8 +144,9 @@ func (b EntityBuilderImpl) CreateDMChannel(channel *api.Channel, updateCache boo return dmChannel } -func (b EntityBuilderImpl) CreateEmote(emote *api.Emote, updateCache bool) *api.Emote { +func (b EntityBuilderImpl) CreateEmote(guildId api.Snowflake, emote *api.Emote, updateCache bool) *api.Emote { emote.Disgo = b.Disgo() + emote.GuildID = guildId if updateCache { return b.Disgo().Cache().CacheEmote(emote) } diff --git a/internal/handlers/channel_update_handler.go b/internal/handlers/channel_update_handler.go index c832de17..d0e0b8f5 100644 --- a/internal/handlers/channel_update_handler.go +++ b/internal/handlers/channel_update_handler.go @@ -38,7 +38,7 @@ func (h ChannelUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a if oldDMChannel != nil { oldDMChannel = &*oldDMChannel } - newDMChannel := disgo.EntityBuilder().CreateDMChannel(channel, false) + newDMChannel := disgo.EntityBuilder().CreateDMChannel(channel, true) genericDMChannelEvent := events.GenericDMChannelEvent{ GenericChannelEvent: genericChannelEvent, @@ -55,8 +55,11 @@ func (h ChannelUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a log.Warnf("ChannelTypeGroupDM received what the hell discord") case api.ChannelTypeText, api.ChannelTypeNews: - disgo.Cache().UncacheTextChannel(*channel.GuildID, channel.ID) - textChannel := disgo.EntityBuilder().CreateTextChannel(channel, false) + oldTextChannel := disgo.Cache().TextChannel(channel.ID) + if oldTextChannel != nil { + oldTextChannel = &*oldTextChannel + } + newTextChannel := disgo.EntityBuilder().CreateTextChannel(channel, true) genericTextChannelEvent := events.GenericTextChannelEvent{ GenericChannelEvent: genericChannelEvent, @@ -65,12 +68,16 @@ func (h ChannelUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a eventManager.Dispatch(events.TextChannelUpdateEvent{ GenericTextChannelEvent: genericTextChannelEvent, - TextChannel: textChannel, + NewTextChannel: newTextChannel, + OldTextChannel: oldTextChannel, }) case api.ChannelTypeStore: - disgo.Cache().UncacheStoreChannel(*channel.GuildID, channel.ID) - storeChannel := disgo.EntityBuilder().CreateStoreChannel(channel, false) + oldStoreChannel := disgo.Cache().StoreChannel(channel.ID) + if oldStoreChannel != nil { + oldStoreChannel = &*oldStoreChannel + } + newStoreChannel := disgo.EntityBuilder().CreateStoreChannel(channel, true) genericStoreChannelEvent := events.GenericStoreChannelEvent{ GenericChannelEvent: genericChannelEvent, @@ -79,12 +86,16 @@ func (h ChannelUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a eventManager.Dispatch(events.StoreChannelUpdateEvent{ GenericStoreChannelEvent: genericStoreChannelEvent, - StoreChannel: storeChannel, + NewStoreChannel: newStoreChannel, + OldStoreChannel: oldStoreChannel, }) case api.ChannelTypeCategory: - disgo.Cache().UncacheCategory(*channel.GuildID, channel.ID) - category := disgo.EntityBuilder().CreateCategory(channel, false) + oldCategory := disgo.Cache().Category(channel.ID) + if oldCategory != nil { + oldCategory = &*oldCategory + } + newCategory := disgo.EntityBuilder().CreateCategory(channel, true) genericCategoryEvent := events.GenericCategoryEvent{ GenericChannelEvent: genericChannelEvent, @@ -93,12 +104,16 @@ func (h ChannelUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a eventManager.Dispatch(events.CategoryUpdateEvent{ GenericCategoryEvent: genericCategoryEvent, - Category: category, + NewCategory: newCategory, + OldCategory: oldCategory, }) case api.ChannelTypeVoice: - disgo.Cache().UncacheVoiceChannel(*channel.GuildID, channel.ID) - voiceChannel := disgo.EntityBuilder().CreateVoiceChannel(channel, false) + oldVoiceChannel := disgo.Cache().VoiceChannel(channel.ID) + if oldVoiceChannel != nil { + oldVoiceChannel = &*oldVoiceChannel + } + newVoiceChannel := disgo.EntityBuilder().CreateVoiceChannel(channel, true) genericVoiceChannelEvent := events.GenericVoiceChannelEvent{ GenericChannelEvent: genericChannelEvent, @@ -107,7 +122,8 @@ func (h ChannelUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a eventManager.Dispatch(events.VoiceChannelUpdateEvent{ GenericVoiceChannelEvent: genericVoiceChannelEvent, - VoiceChannel: voiceChannel, + NewVoiceChannel: newVoiceChannel, + OldVoiceChannel: oldVoiceChannel, }) default: diff --git a/internal/handlers/guild_create_handler.go b/internal/handlers/guild_create_handler.go index 288a80cd..ca32b11f 100644 --- a/internal/handlers/guild_create_handler.go +++ b/internal/handlers/guild_create_handler.go @@ -39,58 +39,36 @@ func (h GuildCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api disgo.Cache().CacheGuild(guild) for i := range fullGuild.Channels { channel := fullGuild.Channels[i] - channel.Disgo = disgo - channel.GuildID = guild.ID + channel.GuildID = &guild.ID switch channel.Type { case api.ChannelTypeText, api.ChannelTypeNews: - disgo.Cache().CacheTextChannel(&api.TextChannel{ - GuildChannel: *channel, - MessageChannel: api.MessageChannel{ - Channel: channel.Channel, - }, - }) + disgo.EntityBuilder().CreateTextChannel(channel, true) case api.ChannelTypeVoice: - disgo.Cache().CacheVoiceChannel(&api.VoiceChannel{ - GuildChannel: *channel, - }) + disgo.EntityBuilder().CreateVoiceChannel(channel, true) case api.ChannelTypeCategory: - disgo.Cache().CacheCategory(&api.Category{ - GuildChannel: *channel, - }) + disgo.EntityBuilder().CreateCategory(channel, true) case api.ChannelTypeStore: - disgo.Cache().CacheStoreChannel(&api.StoreChannel{ - GuildChannel: *channel, - }) + disgo.EntityBuilder().CreateStoreChannel(channel, true) } } for i := range fullGuild.Roles { - role := fullGuild.Roles[i] - role.Disgo = disgo - role.GuildID = guild.ID - disgo.Cache().CacheRole(role) + disgo.EntityBuilder().CreateRole(guild.ID, fullGuild.Roles[i], true) } for i := range fullGuild.Members { - member := fullGuild.Members[i] - member.Disgo = disgo - member.GuildID = guild.ID - disgo.Cache().CacheMember(member) + disgo.EntityBuilder().CreateMember(guild.ID, fullGuild.Members[i], true) } for i := range fullGuild.VoiceStates { - voiceState := fullGuild.VoiceStates[i] - voiceState.Disgo = disgo - disgo.Cache().CacheVoiceState(voiceState) + disgo.EntityBuilder().CreateVoiceState(fullGuild.VoiceStates[i], true) } - /*for i := range fullGuild.Emotes { - emote := fullGuild.Emotes[i] - emote.Disgo = disgo - emote.GuildID = guild.ID - disgo.Cache().CacheEmote(emote) - }*/ + for i := range fullGuild.Emotes { + disgo.EntityBuilder().CreateEmote(guild.ID, fullGuild.Emotes[i], true) + } + // TODO: presence /*for i := range fullGuild.Presences { presence := fullGuild.Presences[i] presence.Disgo = disgo @@ -110,7 +88,6 @@ func (h GuildCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api Guild: guild, }) } else { - // guild join eventManager.Dispatch(events.GuildJoinEvent{ GenericGuildEvent: genericGuildEvent, Guild: guild, diff --git a/internal/handlers/guild_delete_handler.go b/internal/handlers/guild_delete_handler.go index be709bc9..d59954d7 100644 --- a/internal/handlers/guild_delete_handler.go +++ b/internal/handlers/guild_delete_handler.go @@ -26,6 +26,7 @@ func (h GuildDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api } if guild.Unavailable { + // set guild to unavail for now disgo.Cache().Guild(guild.ID).Unavailable = true eventManager.Dispatch(events.GuildUnavailableEvent{ GenericGuildEvent: events.GenericGuildEvent{ @@ -34,19 +35,18 @@ func (h GuildDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api }, }) } else { - cachedGuild := disgo.Cache().Guild(guild.ID) + guild = disgo.Cache().Guild(guild.ID) disgo.Cache().UncacheGuild(guild.ID) genericGuildEvent := events.GenericGuildEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), GuildID: guild.ID, } - eventManager.Dispatch(genericGuildEvent) eventManager.Dispatch(events.GuildLeaveEvent{ GenericGuildEvent: genericGuildEvent, - Guild: cachedGuild, + Guild: guild, }) } } diff --git a/internal/handlers/guild_member_add_handler.go b/internal/handlers/guild_member_add_handler.go index 9655ef83..f5cc4e43 100644 --- a/internal/handlers/guild_member_add_handler.go +++ b/internal/handlers/guild_member_add_handler.go @@ -25,7 +25,7 @@ func (h GuildMemberAddHandler) HandleGatewayEvent(disgo api.Disgo, eventManager return } - disgo.Cache().CacheMember(member) + member = disgo.EntityBuilder().CreateMember(member.GuildID, member, true) genericGuildEvent := events.GenericGuildEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), diff --git a/internal/handlers/guild_member_update_handler.go b/internal/handlers/guild_member_update_handler.go index 88166b78..7a287c09 100644 --- a/internal/handlers/guild_member_update_handler.go +++ b/internal/handlers/guild_member_update_handler.go @@ -20,30 +20,32 @@ func (h GuildMemberUpdateHandler) New() interface{} { // HandleGatewayEvent handles the specific raw gateway event func (h GuildMemberUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { - member, ok := i.(*api.Member) + newMember, ok := i.(*api.Member) if !ok { return } - oldMember := disgo.Cache().Member(member.GuildID, member.User.ID) - member.Disgo = disgo - disgo.Cache().CacheMember(member) + oldMember := disgo.Cache().Member(newMember.GuildID, newMember.User.ID) + if oldMember != nil { + oldMember = &*oldMember + } + newMember = disgo.EntityBuilder().CreateMember(newMember.GuildID, newMember, true) genericGuildEvent := events.GenericGuildEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), - GuildID: member.GuildID, + GuildID: newMember.GuildID, } eventManager.Dispatch(genericGuildEvent) genericGuildMemberEvent := events.GenericGuildMemberEvent{ GenericGuildEvent: genericGuildEvent, - UserID: member.User.ID, + UserID: newMember.User.ID, } eventManager.Dispatch(genericGuildMemberEvent) eventManager.Dispatch(events.GuildMemberUpdateEvent{ GenericGuildMemberEvent: genericGuildMemberEvent, - NewMember: member, + NewMember: newMember, OldMember: oldMember, }) } diff --git a/internal/handlers/guild_role_create_handler.go b/internal/handlers/guild_role_create_handler.go index e70cb3f0..507779aa 100644 --- a/internal/handlers/guild_role_create_handler.go +++ b/internal/handlers/guild_role_create_handler.go @@ -29,24 +29,23 @@ func (h GuildRoleCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager if !ok { return } - roleCreateData.Role.Disgo = disgo - roleCreateData.Role.GuildID = roleCreateData.GuildID - disgo.Cache().CacheRole(roleCreateData.Role) + + role := disgo.EntityBuilder().CreateRole(roleCreateData.GuildID, roleCreateData.Role, true) genericGuildEvent := events.GenericGuildEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), - GuildID: roleCreateData.GuildID, + GuildID: role.GuildID, } eventManager.Dispatch(genericGuildEvent) genericRoleEvent := events.GenericRoleEvent{ GenericGuildEvent: genericGuildEvent, - RoleID: roleCreateData.Role.ID, + RoleID: role.ID, } eventManager.Dispatch(genericRoleEvent) eventManager.Dispatch(events.RoleCreateEvent{ GenericGuildEvent: genericGuildEvent, - Role: roleCreateData.Role, + Role: role, }) } diff --git a/internal/handlers/guild_role_delete_handler.go b/internal/handlers/guild_role_delete_handler.go index 328c3357..97c230b8 100644 --- a/internal/handlers/guild_role_delete_handler.go +++ b/internal/handlers/guild_role_delete_handler.go @@ -30,23 +30,23 @@ func (h GuildRoleDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eventManager return } - role := *disgo.Cache().Role(roleDeleteData.RoleID) + role := disgo.Cache().Role(roleDeleteData.RoleID) disgo.Cache().UncacheRole(roleDeleteData.GuildID, roleDeleteData.RoleID) genericGuildEvent := events.GenericGuildEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), - GuildID: roleDeleteData.GuildID, + GuildID: role.GuildID, } eventManager.Dispatch(genericGuildEvent) genericRoleEvent := events.GenericRoleEvent{ GenericGuildEvent: genericGuildEvent, - RoleID: roleDeleteData.RoleID, + RoleID: role.ID, } eventManager.Dispatch(genericRoleEvent) eventManager.Dispatch(events.RoleDeleteEvent{ GenericGuildEvent: genericGuildEvent, - Role: &role, + Role: role, }) } diff --git a/internal/handlers/guild_role_update_handler.go b/internal/handlers/guild_role_update_handler.go index 7ce2458d..538ca1c3 100644 --- a/internal/handlers/guild_role_update_handler.go +++ b/internal/handlers/guild_role_update_handler.go @@ -29,27 +29,28 @@ func (h GuildRoleUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager if !ok { return } - roleUpdateData.Role.Disgo = disgo - roleUpdateData.Role.GuildID = roleUpdateData.GuildID - oldRole := *disgo.Cache().Role(roleUpdateData.Role.ID) - disgo.Cache().CacheRole(roleUpdateData.Role) + oldRole := disgo.Cache().Role(roleUpdateData.Role.ID) + if oldRole != nil { + oldRole = &*oldRole + } + newRole := disgo.EntityBuilder().CreateRole(roleUpdateData.GuildID, roleUpdateData.Role, true) genericGuildEvent := events.GenericGuildEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), - GuildID: roleUpdateData.GuildID, + GuildID: newRole.GuildID, } eventManager.Dispatch(genericGuildEvent) genericRoleEvent := events.GenericRoleEvent{ GenericGuildEvent: genericGuildEvent, - RoleID: roleUpdateData.Role.ID, + RoleID: newRole.ID, } eventManager.Dispatch(genericRoleEvent) eventManager.Dispatch(events.RoleUpdateEvent{ GenericGuildEvent: genericGuildEvent, - NewRole: roleUpdateData.Role, - OldRole: &oldRole, + NewRole: newRole, + OldRole: oldRole, }) } diff --git a/internal/handlers/guild_update_handler.go b/internal/handlers/guild_update_handler.go index 2eecf394..79409052 100644 --- a/internal/handlers/guild_update_handler.go +++ b/internal/handlers/guild_update_handler.go @@ -20,24 +20,27 @@ func (h GuildUpdateHandler) New() interface{} { // HandleGatewayEvent handles the specific raw gateway event func (h GuildUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { - guild, ok := i.(*api.Guild) + newGuild, ok := i.(*api.Guild) if !ok { return } - oldGuild := *disgo.Cache().Guild(guild.ID) - disgo.Cache().CacheGuild(guild) + oldGuild := disgo.Cache().Guild(newGuild.ID) + if oldGuild != nil { + oldGuild = &*oldGuild + } + newGuild = disgo.EntityBuilder().CreateGuild(newGuild, true) genericGuildEvent := events.GenericGuildEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), - GuildID: guild.ID, + GuildID: newGuild.ID, } eventManager.Dispatch(genericGuildEvent) eventManager.Dispatch(events.GuildUpdateEvent{ GenericGuildEvent: genericGuildEvent, - NewGuild: guild, - OldGuild: &oldGuild, + NewGuild: newGuild, + OldGuild: oldGuild, }) } From 9a3b193d602beb62062614760787aef9e617f4f9 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Fri, 9 Apr 2021 13:13:50 +0200 Subject: [PATCH 33/65] more message stuff --- api/message.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/api/message.go b/api/message.go index 896ee45c..ab4ff69a 100644 --- a/api/message.go +++ b/api/message.go @@ -109,6 +109,17 @@ type MessageAttachment struct { Width *int `json:"width"` } +// MessageActivityType is the type of a MessageActivity +type MessageActivityType int + +const ( + MessageActivityTypeJoin MessageActivityType = iota + 1 + MessageActivityTypeSpectate + MessageActivityTypeListen + _ + MessageAcitivtyTypeJoinReqi +) + // Message is a struct for messages sent in discord text-based channels // todo: missing activity, application, stickers, referenced_message // https://discord.com/developers/docs/resources/channel#message-object From 2585ed27b155c0c385a55fbcdd3154dd60696f0d Mon Sep 17 00:00:00 2001 From: BennyDiscord <46286597+BennyDiscord@users.noreply.github.com> Date: Fri, 9 Apr 2021 12:35:39 +0100 Subject: [PATCH 34/65] Finish message object --- api/message.go | 104 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 77 insertions(+), 27 deletions(-) diff --git a/api/message.go b/api/message.go index 896ee45c..22bb05de 100644 --- a/api/message.go +++ b/api/message.go @@ -89,11 +89,12 @@ func (f MessageFlags) Missing(bit MessageFlags) bool { // Constants for MessageFlags const ( MessageFlagNone MessageFlags = 0 - MessageFlagCrossposted MessageFlags = 1 << iota + MessageFlagCrossposted MessageFlags = 1 << (iota - 1) MessageFlagIsCrosspost MessageFlagSuppressEmbeds MessageFlagSourceMessageDeleted MessageFlagUrgent + _ MessageFlagEphemeral MessageFlagLoading // Message is an interaction of type 5, awaiting further response ) @@ -109,34 +110,83 @@ type MessageAttachment struct { Width *int `json:"width"` } +// MessageActivityType is the type of MessageActivity +type MessageActivityType int + +//Constants for MessageActivityType +const ( + MessageActivityTypeJoin MessageActivityType = iota + 1 + MessageActivityTypeSpectate + MessageActivityTypeListen + _ + MessageActivityTypeJoinRequest +) + +//MessageActivity is used for rich presence-related chat embeds in a Message +type MessageActivity struct { + Type MessageActivityType `json:"type"` + PartyID *string `json:"party_id,omitempty"` +} + +//MessageApplication is used for rich presence-related chat embeds in a Message +type MessageApplication struct { + ID Snowflake `json:"id"` + CoverImage *string `json:"cover_image,omitempty"` + Description string `json:"description"` + Icon *string `json:"icon,omitempty"` + Name string `json:"name"` +} + +// MessageStickerFormatType is the Format Type of a MessageSticker +type MessageStickerFormatType int + +// Constants for MessageStickerFormatType +const ( + MessageStickerFormatPNG MessageStickerFormatType = iota + 1 + MessageStickerFormatAPNG + MessageStickerFormatLottie +) + +// MessageSticker is a sticker sent with a Message +type MessageSticker struct { + ID Snowflake `json:"id"` + PackID Snowflake `json:"pack_id"` + Name string `json:"name"` + Description string `json:"description"` + Tags *string `json:"tags"` + FormatType MessageStickerFormatType `json:"format_type"` +} + // Message is a struct for messages sent in discord text-based channels -// todo: missing activity, application, stickers, referenced_message -// https://discord.com/developers/docs/resources/channel#message-object type Message struct { - Disgo Disgo - ID Snowflake `json:"id"` - GuildID *Snowflake `json:"guild_id"` - Reactions []*MessageReaction `json:"reactions"` - Attachments []*MessageAttachment `json:"attachments"` - TTS bool `json:"tts"` - Embeds []*Embed `json:"embeds,omitempty"` - CreatedAt time.Time `json:"timestamp"` - Mentions []interface{} `json:"mentions"` - MentionEveryone bool `json:"mention_everyone"` - MentionRoles []*Role `json:"mention_roles"` - MentionChannels []*Channel `json:"mention_channels"` - Pinned bool `json:"pinned"` - EditedTimestamp *time.Time `json:"edited_timestamp"` - Author *User `json:"author"` - Member *Member `json:"member"` - Content *string `json:"content,omitempty"` - ChannelID Snowflake `json:"channel_id"` - Type MessageType `json:"type"` - Flags *MessageFlags `json:"flags"` - MessageReference *MessageReference `json:"message_reference,omitempty"` - Interaction *MessageInteraction `json:"message_interaction,omitempty"` - WebhookID *Snowflake `json:"webhook_id,omitempty"` - LastUpdated *time.Time + Disgo Disgo + ID Snowflake `json:"id"` + GuildID *Snowflake `json:"guild_id"` + Reactions []*MessageReaction `json:"reactions"` + Attachments []*MessageAttachment `json:"attachments"` + TTS bool `json:"tts"` + Embeds []*Embed `json:"embeds,omitempty"` + CreatedAt time.Time `json:"timestamp"` + Mentions []interface{} `json:"mentions"` + MentionEveryone bool `json:"mention_everyone"` + MentionRoles []*Role `json:"mention_roles"` + MentionChannels []*Channel `json:"mention_channels"` + Pinned bool `json:"pinned"` + EditedTimestamp *time.Time `json:"edited_timestamp"` + Author *User `json:"author"` + Member *Member `json:"member"` + Content *string `json:"content,omitempty"` + ChannelID Snowflake `json:"channel_id"` + Type MessageType `json:"type"` + Flags *MessageFlags `json:"flags"` + MessageReference *MessageReference `json:"message_reference,omitempty"` + Interaction *MessageInteraction `json:"message_interaction,omitempty"` + WebhookID *Snowflake `json:"webhook_id,omitempty"` + Activity *MessageActivity `json:"activity,omitempty"` + Application *MessageApplication `json:"application,omitempty"` + Stickers []*MessageSticker `json:"stickers,omitempty"` + ReferencedMessage *Message `json:"referenced_message,omitempty"` + LastUpdated *time.Time } // MessageReference is a reference to another message From 97936e89eac06c0dcaaa3d4d84f5d79b7cbe959b Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Fri, 9 Apr 2021 18:07:27 +0200 Subject: [PATCH 35/65] added files for missing handlers & removed private channels in ready handler --- api/permissions.go | 14 ++++++++++++++ internal/handlers/channel_pins_update_handler.go | 1 + internal/handlers/guild_ban_add_handler.go | 1 + internal/handlers/guild_ban_remove_handler.go | 1 + internal/handlers/guild_emojis_update_handler.go | 1 + internal/handlers/guild_integrations_update.go | 1 + internal/handlers/guild_member_chunk.go | 1 + internal/handlers/invite_create_handler.go | 1 + internal/handlers/invite_delete_handler.go | 1 + internal/handlers/message_delete_bulk_handler.go | 1 + internal/handlers/message_delete_handler.go | 1 + internal/handlers/message_reaction_add_handler.go | 1 + .../message_reaction_remove_all_handler.go | 1 + .../message_reaction_remove_emoji_handler.go | 1 + .../handlers/message_reaction_remove_handler.go | 1 + internal/handlers/message_update_handler.go | 1 + internal/handlers/presence_update_handler.go | 1 + internal/handlers/ready_handler.go | 1 - internal/handlers/typing_start_handler.go | 1 + internal/handlers/user_update_handler.go | 1 + internal/handlers/webhooks_update_handler.go | 1 + 21 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 internal/handlers/channel_pins_update_handler.go create mode 100644 internal/handlers/guild_ban_add_handler.go create mode 100644 internal/handlers/guild_ban_remove_handler.go create mode 100644 internal/handlers/guild_emojis_update_handler.go create mode 100644 internal/handlers/guild_integrations_update.go create mode 100644 internal/handlers/guild_member_chunk.go create mode 100644 internal/handlers/invite_create_handler.go create mode 100644 internal/handlers/invite_delete_handler.go create mode 100644 internal/handlers/message_delete_bulk_handler.go create mode 100644 internal/handlers/message_delete_handler.go create mode 100644 internal/handlers/message_reaction_add_handler.go create mode 100644 internal/handlers/message_reaction_remove_all_handler.go create mode 100644 internal/handlers/message_reaction_remove_emoji_handler.go create mode 100644 internal/handlers/message_reaction_remove_handler.go create mode 100644 internal/handlers/message_update_handler.go create mode 100644 internal/handlers/presence_update_handler.go create mode 100644 internal/handlers/typing_start_handler.go create mode 100644 internal/handlers/user_update_handler.go create mode 100644 internal/handlers/webhooks_update_handler.go diff --git a/api/permissions.go b/api/permissions.go index 9873e1ec..1ede25f7 100644 --- a/api/permissions.go +++ b/api/permissions.go @@ -5,6 +5,20 @@ import ( "strconv" ) +type PermissionOverwriteType int + +const ( + PermissionOverwriteTypeRole PermissionOverwriteType = iota + PermissionOverwriteTypeMember +) + +type PermissionOverwrite struct { + ID Snowflake `json:"id"` + Type PermissionOverwriteType `json:"type"` + Allow Permissions `json:"allow"` + Deny Permissions `json:"deny"` +} + // Permissions extends the Bit structure, and is used within roles and channels type Permissions int64 diff --git a/internal/handlers/channel_pins_update_handler.go b/internal/handlers/channel_pins_update_handler.go new file mode 100644 index 00000000..5ac8282f --- /dev/null +++ b/internal/handlers/channel_pins_update_handler.go @@ -0,0 +1 @@ +package handlers diff --git a/internal/handlers/guild_ban_add_handler.go b/internal/handlers/guild_ban_add_handler.go new file mode 100644 index 00000000..5ac8282f --- /dev/null +++ b/internal/handlers/guild_ban_add_handler.go @@ -0,0 +1 @@ +package handlers diff --git a/internal/handlers/guild_ban_remove_handler.go b/internal/handlers/guild_ban_remove_handler.go new file mode 100644 index 00000000..5ac8282f --- /dev/null +++ b/internal/handlers/guild_ban_remove_handler.go @@ -0,0 +1 @@ +package handlers diff --git a/internal/handlers/guild_emojis_update_handler.go b/internal/handlers/guild_emojis_update_handler.go new file mode 100644 index 00000000..5ac8282f --- /dev/null +++ b/internal/handlers/guild_emojis_update_handler.go @@ -0,0 +1 @@ +package handlers diff --git a/internal/handlers/guild_integrations_update.go b/internal/handlers/guild_integrations_update.go new file mode 100644 index 00000000..5ac8282f --- /dev/null +++ b/internal/handlers/guild_integrations_update.go @@ -0,0 +1 @@ +package handlers diff --git a/internal/handlers/guild_member_chunk.go b/internal/handlers/guild_member_chunk.go new file mode 100644 index 00000000..5ac8282f --- /dev/null +++ b/internal/handlers/guild_member_chunk.go @@ -0,0 +1 @@ +package handlers diff --git a/internal/handlers/invite_create_handler.go b/internal/handlers/invite_create_handler.go new file mode 100644 index 00000000..5ac8282f --- /dev/null +++ b/internal/handlers/invite_create_handler.go @@ -0,0 +1 @@ +package handlers diff --git a/internal/handlers/invite_delete_handler.go b/internal/handlers/invite_delete_handler.go new file mode 100644 index 00000000..5ac8282f --- /dev/null +++ b/internal/handlers/invite_delete_handler.go @@ -0,0 +1 @@ +package handlers diff --git a/internal/handlers/message_delete_bulk_handler.go b/internal/handlers/message_delete_bulk_handler.go new file mode 100644 index 00000000..5ac8282f --- /dev/null +++ b/internal/handlers/message_delete_bulk_handler.go @@ -0,0 +1 @@ +package handlers diff --git a/internal/handlers/message_delete_handler.go b/internal/handlers/message_delete_handler.go new file mode 100644 index 00000000..5ac8282f --- /dev/null +++ b/internal/handlers/message_delete_handler.go @@ -0,0 +1 @@ +package handlers diff --git a/internal/handlers/message_reaction_add_handler.go b/internal/handlers/message_reaction_add_handler.go new file mode 100644 index 00000000..5ac8282f --- /dev/null +++ b/internal/handlers/message_reaction_add_handler.go @@ -0,0 +1 @@ +package handlers diff --git a/internal/handlers/message_reaction_remove_all_handler.go b/internal/handlers/message_reaction_remove_all_handler.go new file mode 100644 index 00000000..5ac8282f --- /dev/null +++ b/internal/handlers/message_reaction_remove_all_handler.go @@ -0,0 +1 @@ +package handlers diff --git a/internal/handlers/message_reaction_remove_emoji_handler.go b/internal/handlers/message_reaction_remove_emoji_handler.go new file mode 100644 index 00000000..5ac8282f --- /dev/null +++ b/internal/handlers/message_reaction_remove_emoji_handler.go @@ -0,0 +1 @@ +package handlers diff --git a/internal/handlers/message_reaction_remove_handler.go b/internal/handlers/message_reaction_remove_handler.go new file mode 100644 index 00000000..5ac8282f --- /dev/null +++ b/internal/handlers/message_reaction_remove_handler.go @@ -0,0 +1 @@ +package handlers diff --git a/internal/handlers/message_update_handler.go b/internal/handlers/message_update_handler.go new file mode 100644 index 00000000..5ac8282f --- /dev/null +++ b/internal/handlers/message_update_handler.go @@ -0,0 +1 @@ +package handlers diff --git a/internal/handlers/presence_update_handler.go b/internal/handlers/presence_update_handler.go new file mode 100644 index 00000000..5ac8282f --- /dev/null +++ b/internal/handlers/presence_update_handler.go @@ -0,0 +1 @@ +package handlers diff --git a/internal/handlers/ready_handler.go b/internal/handlers/ready_handler.go index 05f4559c..4a0d9fe1 100644 --- a/internal/handlers/ready_handler.go +++ b/internal/handlers/ready_handler.go @@ -7,7 +7,6 @@ import ( type readyEventData struct { Version int `json:"v"` SelfUser api.User `json:"user"` - PrivateChannels []*api.DMChannel `json:"private_channels"` Guilds []*api.Guild `json:"guilds"` SessionID string `json:"session_id"` Shard *[2]int `json:"shard,omitempty"` diff --git a/internal/handlers/typing_start_handler.go b/internal/handlers/typing_start_handler.go new file mode 100644 index 00000000..5ac8282f --- /dev/null +++ b/internal/handlers/typing_start_handler.go @@ -0,0 +1 @@ +package handlers diff --git a/internal/handlers/user_update_handler.go b/internal/handlers/user_update_handler.go new file mode 100644 index 00000000..5ac8282f --- /dev/null +++ b/internal/handlers/user_update_handler.go @@ -0,0 +1 @@ +package handlers diff --git a/internal/handlers/webhooks_update_handler.go b/internal/handlers/webhooks_update_handler.go new file mode 100644 index 00000000..5ac8282f --- /dev/null +++ b/internal/handlers/webhooks_update_handler.go @@ -0,0 +1 @@ +package handlers From dc54f2de52fafa7f55dd5857b2831673a1b6ec95 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Sat, 10 Apr 2021 00:51:45 +0200 Subject: [PATCH 36/65] added all events to listeneradapter --- api/events/guild_message_events.go | 9 +- api/events/http_request_events.go | 6 +- api/events/listener_adapter.go | 145 +++++++++++++++--- api/events/role_events.go | 2 +- ...tore_events.go => store_channel_events.go} | 0 ...{text_events.go => text_channel_events.go} | 0 ...oice_events.go => voice_channel_events.go} | 0 7 files changed, 136 insertions(+), 26 deletions(-) rename api/events/{store_events.go => store_channel_events.go} (100%) rename api/events/{text_events.go => text_channel_events.go} (100%) rename api/events/{voice_events.go => voice_channel_events.go} (100%) diff --git a/api/events/guild_message_events.go b/api/events/guild_message_events.go index 740568cf..13eb3d7e 100644 --- a/api/events/guild_message_events.go +++ b/api/events/guild_message_events.go @@ -4,7 +4,7 @@ import ( "github.com/DisgoOrg/disgo/api" ) -// GenericDMMessageEvent generic api.DMChannel api.Message api.GenericEvent +// GenericGuildMessageEvent generic api.DMChannel api.Message api.GenericEvent type GenericGuildMessageEvent struct { GenericMessageEvent GuildID api.Snowflake @@ -14,24 +14,25 @@ func (e GenericGuildMessageEvent) Guild() *api.Guild { return e.Disgo().Cache().Guild(e.GuildID) } +// TextChannel returns the api.TextChannel from the api.Cache func (e GenericGuildMessageEvent) TextChannel() *api.TextChannel { return e.Disgo().Cache().TextChannel(e.ChannelID) } -// DMMessageReceivedEvent called upon receiving a api.Message in a api.DMChannel +// GuildMessageReceivedEvent called upon receiving a api.Message in a api.DMChannel type GuildMessageReceivedEvent struct { GenericGuildMessageEvent Message *api.Message } -// DMMessageUpdateEvent called upon editing a api.Message in a api.DMChannel +// GuildMessageUpdateEvent called upon editing a api.Message in a api.DMChannel type GuildMessageUpdateEvent struct { GenericGuildMessageEvent NewMessage *api.Message OldMessage *api.Message } -// DMMessageDeleteEvent called upon deleting a api.Message in a api.DMChannel +// GuildMessageDeleteEvent called upon deleting a api.Message in a api.DMChannel type GuildMessageDeleteEvent struct { GenericGuildMessageEvent Message *api.Message diff --git a/api/events/http_request_events.go b/api/events/http_request_events.go index 602f2a3c..fe250dd2 100644 --- a/api/events/http_request_events.go +++ b/api/events/http_request_events.go @@ -6,11 +6,11 @@ import ( "github.com/DisgoOrg/disgo/api/endpoints" ) -type GenericHttpEvent struct { - Request endpoints.Request +type HttpRequestEvent struct { + Request endpoints.Request Response endpoints.Response } -func (e GenericHttpEvent) RateLimited() bool { +func (e HttpRequestEvent) RateLimited() bool { return e.Response.StatusCode == http.StatusTooManyRequests } diff --git a/api/events/listener_adapter.go b/api/events/listener_adapter.go index 24e12d25..d73eb29b 100644 --- a/api/events/listener_adapter.go +++ b/api/events/listener_adapter.go @@ -6,36 +6,145 @@ import ( // ListenerAdapter lets you override the handles for receiving events type ListenerAdapter struct { - OnGenericEvent func(*api.Event) + OnGenericApplicationCommandEvent func(event *GenericApplicationCommandEvent) + OnApplicationCommandCreate func(event *ApplicationCommandCreateEvent) + OnApplicationCommandUpdate func(event *ApplicationCommandUpdateEvent) + OnApplicationCommandDelete func(event *ApplicationCommandDeleteEvent) + + OnGenericCategoryEvent func(event *GenericCategoryEvent) + OnCategoryCreate func(event *CategoryCreateEvent) + OnCategoryUpdate func(event *CategoryUpdateEvent) + OnCategoryDelete func(event *CategoryDeleteEvent) + + OnGenericChannelEvent func(event *GenericChannelEvent) + + OnGenericDMChannelEvent func(event *GenericDMChannelEvent) + OnDMChannelCreate func(event *DMChannelCreateEvent) + OnDMChannelUpdate func(event *DMChannelUpdateEvent) + OnDMChannelDelete func(event *DMChannelDeleteEvent) + + OnGenericDMMessageReactionEventEvent func(event *GenericDMMessageReactionEvent) + OnDMMessageReactionAddEvent func(event *DMMessageReactionAddEvent) + OnDMMessageReactionRemove func(event *DMMessageReactionRemoveEvent) + OnDMMessageReactionRemoveEmote func(event *DMMessageReactionRemoveEmoteEvent) + OnDMMessageReactionRemoveAll func(event *DMMessageReactionRemoveAllEvent) + + OnGenericEmoteEvent func(event *GenericEmoteEvent) + OnEmoteCreate func(event *EmoteCreateEvent) + OnEmoteUpdate func(event *EmoteUpdateEvent) + OnEmoteDelete func(event *EmoteDeleteEvent) + + OnException func(event *ExceptionEvent) + + OnGenericGatewayStatusEvent func(event *GenericGatewayStatusEvent) + OnConnected func(event *ConnectedEvent) + OnReconnected func(event *ReconnectedEvent) + OnResumed func(event *ResumedEvent) + OnDisconnected func(event *DisconnectedEvent) + OnShutdown func(event *ShutdownEvent) + + OnGenericEvent func(event api.Event) // Guild Events OnGenericGuildEvent func(event *GenericGuildEvent) - OnGuildJoin func(event *GuildJoinEvent) OnGuildUpdate func(event *GuildUpdateEvent) - OnGuildLeave func(event *GuildLeaveEvent) OnGuildAvailable func(event *GuildAvailableEvent) OnGuildUnavailable func(event *GuildUnavailableEvent) + OnGuildJoin func(event *GuildJoinEvent) + OnGuildLeave func(event *GuildLeaveEvent) + OnGuildReady func(event *GuildReadyEvent) + OnGuildBan func(event *GuildBanEvent) + OnGuildUnban func(event *GuildUnbanEvent) - // Guild Role Events - OnGenericRole func(event *GenericRoleEvent) - OnRoleCreate func(event *RoleCreateEvent) - OnRoleUpdate func(event *RoleUpdateEvent) - OnRoleDelete func(event *RoleDeleteEvent) + OnGenericGuildInviteEvent func(event *GenericGuildInviteEvent) + OnGuildInviteCreate func(event *GuildInviteCreateEvent) + OnGuildInviteDelete func(event *GuildInviteDeleteEvent) - // Message Events - OnMessageReceived func(event *MessageReceivedEvent) - OnGuildMessageReceived func(event *GuildMessageReceivedEvent) + // Member Events + OnGenericGuildMemberEvent func(event *GenericGuildMemberEvent) + OnGuildMemberJoin func(event *GuildMemberJoinEvent) + OnGuildMemberUpdate func(event *GuildMemberUpdateEvent) + OnGuildMemberLeave func(event *GuildMemberLeaveEvent) + + OnGenericGuildMessageEvent func(event *GenericGuildMessageEvent) + OnGuildMessageReceived func(event *GuildMessageReceivedEvent) + OnGuildMessageUpdate func(event *GuildMessageUpdateEvent) + OnGuildMessageDelete func(event *GuildMessageDeleteEvent) + + OnGenericGuildMessageReactionEvent func(event *GenericGuildMessageReactionEvent) + OnGuildMessageReactionAdd func(event *GuildMessageReactionAddEvent) + OnGuildMessageReactionRemove func(event *GuildMessageReactionRemoveEvent) + OnGuildMessageReactionRemoveEmote func(event *GuildMessageReactionRemoveEmoteEvent) + OnGuildMessageReactionRemoveAll func(event *GuildMessageReactionRemoveAllEvent) + + OnGenericGuildVoiceEvent func(event *GenericGuildVoiceEvent) + OnGuildVoiceUpdate func(event *GuildVoiceUpdateEvent) + OnGuildVoiceJoin func(event *GuildVoiceJoinEvent) + OnGuildVoiceLeave func(event *GuildVoiceLeaveEvent) + + OnHeartbeat func(event *HeartbeatEvent) + + OnHttpRequest func(event *HttpRequestEvent) // Interaction Events - OnGenericInteraction func(event *GenericInteractionEvent) - OnSlashCommand func(event *SlashCommandEvent) + OnGenericInteractionEvent func(event *GenericInteractionEvent) + OnSlashCommand func(event *SlashCommandEvent) + + OnGenericMessageEvent func(event *GenericMessageEvent) + OnMessageDelete func(event *MessageDeleteEvent) + OnMessageReceived func(event *MessageReceivedEvent) + OnMessageUpdate func(event *MessageUpdateEvent) + + OnGenericReactionEvent func(event *GenericReactionEvents) + OnMessageReactionAdd func(event *MessageReactionAddEvent) + OnMessageReactionRemove func(event *MessageReactionRemoveEvent) + OnMessageReactionRemoveEmote func(event *MessageReactionRemoveEmoteEvent) + OnMessageReactionRemoveAll func(event *MessageReactionRemoveAllEvent) + + OnRawGateway func(event *RawGatewayEvent) + + OnReadyEvent func(event *ReadyEvent) + + // Guild Role Events + OnGenericRoleEvent func(event *GenericRoleEvent) + OnRoleCreate func(event *RoleCreateEvent) + OnRoleUpdate func(event *RoleUpdateEvent) + OnRoleDelete func(event *RoleDeleteEvent) + + OnSelfUpdate func(event *SelfUpdateEvent) + + OnGenericStoreChannelEvent func(event *StoreChannelCreateEvent) + OnStoreChannelCreate func(event *StoreChannelCreateEvent) + OnStoreChannelUpdate func(event *StoreChannelUpdateEvent) + OnStoreChannelDelete func(event *StoreChannelDeleteEvent) + + OnGenericTextChannelEvent func(event *GenericTextChannelEvent) + OnTextChannelCreate func(event *TextChannelCreateEvent) + OnTextChannelUpdate func(event *TextChannelUpdateEvent) + OnTextChannelDelete func(event *TextChannelDeleteEvent) + + OnGenericUserActivityEvent func(event *GenericUserActivityEvent) + OnUserActivityStart func(event *UserActivityStartEvent) + OnUserActivityUpdate func(event *UserActivityUpdateEvent) + OnUserActivityEnd func(event *UserActivityEndEvent) + + OnGenericUserEvent func(event *GenericUserEvent) + OnUserUpdate func(event *UserUpdateEvent) + OnUserTyping func(event *UserTypingEvent) + OnGuildUserTyping func(event *GuildUserTypingEvent) + OnDMUserTyping func(event *DMUserTypingEvent) + + OnGenericVoiceChannelEvent func(event *GenericVoiceChannelEvent) + OnVoiceChannelCreate func(event *VoiceChannelCreateEvent) + OnVoiceChannelUpdate func(event *VoiceChannelUpdateEvent) + OnVoiceChannelDelete func(event *VoiceChannelDeleteEvent) } // OnEvent is getting called everytime we receive an event func (l ListenerAdapter) OnEvent(event interface{}) { if e, ok := event.(api.Event); ok { if l.OnGenericEvent != nil { - l.OnGenericEvent(&e) + l.OnGenericEvent(e) } } switch e := event.(type) { @@ -67,8 +176,8 @@ func (l ListenerAdapter) OnEvent(event interface{}) { // Guild Role Events case GenericRoleEvent: - if l.OnGenericRole != nil { - l.OnGenericRole(&e) + if l.OnGenericRoleEvent != nil { + l.OnGenericRoleEvent(&e) } case RoleCreateEvent: if l.OnRoleCreate != nil { @@ -95,8 +204,8 @@ func (l ListenerAdapter) OnEvent(event interface{}) { // Interaction Events case GenericInteractionEvent: - if l.OnGenericInteraction != nil { - l.OnGenericInteraction(&e) + if l.OnGenericInteractionEvent != nil { + l.OnGenericInteractionEvent(&e) } case SlashCommandEvent: if l.OnSlashCommand != nil { diff --git a/api/events/role_events.go b/api/events/role_events.go index a3f9ae85..e0d58457 100644 --- a/api/events/role_events.go +++ b/api/events/role_events.go @@ -27,7 +27,7 @@ type RoleUpdateEvent struct { OldRole *api.Role } -// GuildRRoleDeleteEventoleDeleteEvent indicates that a api.Role got deleted +// RoleDeleteEvent indicates that a api.Role got deleted type RoleDeleteEvent struct { GenericGuildEvent Role *api.Role diff --git a/api/events/store_events.go b/api/events/store_channel_events.go similarity index 100% rename from api/events/store_events.go rename to api/events/store_channel_events.go diff --git a/api/events/text_events.go b/api/events/text_channel_events.go similarity index 100% rename from api/events/text_events.go rename to api/events/text_channel_events.go diff --git a/api/events/voice_events.go b/api/events/voice_channel_events.go similarity index 100% rename from api/events/voice_events.go rename to api/events/voice_channel_events.go From 93f61bb02e83df9b1de60decbc8934d8e442ab05 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Sat, 10 Apr 2021 03:59:45 +0200 Subject: [PATCH 37/65] added rest events --- api/events/generic_event.go | 4 +- api/events/listener_adapter.go | 568 ++++++++++++++++++++++++++++----- 2 files changed, 486 insertions(+), 86 deletions(-) diff --git a/api/events/generic_event.go b/api/events/generic_event.go index 905bdc9f..0561e8e8 100644 --- a/api/events/generic_event.go +++ b/api/events/generic_event.go @@ -4,7 +4,9 @@ import "github.com/DisgoOrg/disgo/api" // NewEvent constructs a new GenericEvent with the provided Disgo instance func NewEvent(disgo api.Disgo, sequenceNumber int) GenericEvent { - return GenericEvent{disgo: disgo, sequenceNumber: sequenceNumber} + event := GenericEvent{disgo: disgo, sequenceNumber: sequenceNumber} + disgo.EventManager().Dispatch(event) + return event } // GenericEvent the base event structure diff --git a/api/events/listener_adapter.go b/api/events/listener_adapter.go index d73eb29b..f5681ea6 100644 --- a/api/events/listener_adapter.go +++ b/api/events/listener_adapter.go @@ -1,34 +1,67 @@ package events import ( - "github.com/DisgoOrg/disgo/api" + "reflect" + + log "github.com/sirupsen/logrus" ) // ListenerAdapter lets you override the handles for receiving events type ListenerAdapter struct { + // Other events + OnGenericEvent func(event *GenericEvent) + OnHeartbeat func(event *HeartbeatEvent) + OnHttpRequest func(event *HttpRequestEvent) + OnRawGateway func(event *RawGatewayEvent) + OnReadyEvent func(event *ReadyEvent) + + // api.Command Events OnGenericApplicationCommandEvent func(event *GenericApplicationCommandEvent) OnApplicationCommandCreate func(event *ApplicationCommandCreateEvent) OnApplicationCommandUpdate func(event *ApplicationCommandUpdateEvent) OnApplicationCommandDelete func(event *ApplicationCommandDeleteEvent) + // api.Channel Events + OnGenericChannelEvent func(event *GenericChannelEvent) + + // api.Category Events OnGenericCategoryEvent func(event *GenericCategoryEvent) OnCategoryCreate func(event *CategoryCreateEvent) OnCategoryUpdate func(event *CategoryUpdateEvent) OnCategoryDelete func(event *CategoryDeleteEvent) - OnGenericChannelEvent func(event *GenericChannelEvent) - + // api.DMChannel Events OnGenericDMChannelEvent func(event *GenericDMChannelEvent) OnDMChannelCreate func(event *DMChannelCreateEvent) OnDMChannelUpdate func(event *DMChannelUpdateEvent) OnDMChannelDelete func(event *DMChannelDeleteEvent) + // api.DMChannel Reaction Events OnGenericDMMessageReactionEventEvent func(event *GenericDMMessageReactionEvent) - OnDMMessageReactionAddEvent func(event *DMMessageReactionAddEvent) + OnDMMessageReactionAdd func(event *DMMessageReactionAddEvent) OnDMMessageReactionRemove func(event *DMMessageReactionRemoveEvent) OnDMMessageReactionRemoveEmote func(event *DMMessageReactionRemoveEmoteEvent) OnDMMessageReactionRemoveAll func(event *DMMessageReactionRemoveAllEvent) + // api.StoreChannel Events + OnGenericStoreChannelEvent func(event *GenericStoreChannelEvent) + OnStoreChannelCreate func(event *StoreChannelCreateEvent) + OnStoreChannelUpdate func(event *StoreChannelUpdateEvent) + OnStoreChannelDelete func(event *StoreChannelDeleteEvent) + + // api.TextChannel Events + OnGenericTextChannelEvent func(event *GenericTextChannelEvent) + OnTextChannelCreate func(event *TextChannelCreateEvent) + OnTextChannelUpdate func(event *TextChannelUpdateEvent) + OnTextChannelDelete func(event *TextChannelDeleteEvent) + + // api.VoiceChannel Events + OnGenericVoiceChannelEvent func(event *GenericVoiceChannelEvent) + OnVoiceChannelCreate func(event *VoiceChannelCreateEvent) + OnVoiceChannelUpdate func(event *VoiceChannelUpdateEvent) + OnVoiceChannelDelete func(event *VoiceChannelDeleteEvent) + + // api.Emote Events OnGenericEmoteEvent func(event *GenericEmoteEvent) OnEmoteCreate func(event *EmoteCreateEvent) OnEmoteUpdate func(event *EmoteUpdateEvent) @@ -36,6 +69,7 @@ type ListenerAdapter struct { OnException func(event *ExceptionEvent) + // api.GatewayStatus Events OnGenericGatewayStatusEvent func(event *GenericGatewayStatusEvent) OnConnected func(event *ConnectedEvent) OnReconnected func(event *ReconnectedEvent) @@ -43,175 +77,539 @@ type ListenerAdapter struct { OnDisconnected func(event *DisconnectedEvent) OnShutdown func(event *ShutdownEvent) - OnGenericEvent func(event api.Event) - - // Guild Events + // api.Guild Events OnGenericGuildEvent func(event *GenericGuildEvent) + OnGuildJoin func(event *GuildJoinEvent) OnGuildUpdate func(event *GuildUpdateEvent) + OnGuildLeave func(event *GuildLeaveEvent) OnGuildAvailable func(event *GuildAvailableEvent) OnGuildUnavailable func(event *GuildUnavailableEvent) - OnGuildJoin func(event *GuildJoinEvent) - OnGuildLeave func(event *GuildLeaveEvent) OnGuildReady func(event *GuildReadyEvent) OnGuildBan func(event *GuildBanEvent) OnGuildUnban func(event *GuildUnbanEvent) + // api.Guild api.Invite Events OnGenericGuildInviteEvent func(event *GenericGuildInviteEvent) OnGuildInviteCreate func(event *GuildInviteCreateEvent) OnGuildInviteDelete func(event *GuildInviteDeleteEvent) - // Member Events + // api.Guild api.Member Events OnGenericGuildMemberEvent func(event *GenericGuildMemberEvent) OnGuildMemberJoin func(event *GuildMemberJoinEvent) OnGuildMemberUpdate func(event *GuildMemberUpdateEvent) OnGuildMemberLeave func(event *GuildMemberLeaveEvent) + // api.Guild api.Message Events OnGenericGuildMessageEvent func(event *GenericGuildMessageEvent) OnGuildMessageReceived func(event *GuildMessageReceivedEvent) OnGuildMessageUpdate func(event *GuildMessageUpdateEvent) OnGuildMessageDelete func(event *GuildMessageDeleteEvent) + // api.Guild api.Message Reaction Events OnGenericGuildMessageReactionEvent func(event *GenericGuildMessageReactionEvent) OnGuildMessageReactionAdd func(event *GuildMessageReactionAddEvent) OnGuildMessageReactionRemove func(event *GuildMessageReactionRemoveEvent) OnGuildMessageReactionRemoveEmote func(event *GuildMessageReactionRemoveEmoteEvent) OnGuildMessageReactionRemoveAll func(event *GuildMessageReactionRemoveAllEvent) + // api.Guild Voice Events OnGenericGuildVoiceEvent func(event *GenericGuildVoiceEvent) OnGuildVoiceUpdate func(event *GuildVoiceUpdateEvent) OnGuildVoiceJoin func(event *GuildVoiceJoinEvent) OnGuildVoiceLeave func(event *GuildVoiceLeaveEvent) - OnHeartbeat func(event *HeartbeatEvent) - - OnHttpRequest func(event *HttpRequestEvent) + // api.Guild api.Role Events + OnGenericRoleEvent func(event *GenericRoleEvent) + OnRoleCreate func(event *RoleCreateEvent) + OnRoleUpdate func(event *RoleUpdateEvent) + OnRoleDelete func(event *RoleDeleteEvent) - // Interaction Events + // api.Interaction Events OnGenericInteractionEvent func(event *GenericInteractionEvent) OnSlashCommand func(event *SlashCommandEvent) + // api.Message Events OnGenericMessageEvent func(event *GenericMessageEvent) - OnMessageDelete func(event *MessageDeleteEvent) OnMessageReceived func(event *MessageReceivedEvent) OnMessageUpdate func(event *MessageUpdateEvent) + OnMessageDelete func(event *MessageDeleteEvent) + // api.Message Reaction Events OnGenericReactionEvent func(event *GenericReactionEvents) OnMessageReactionAdd func(event *MessageReactionAddEvent) OnMessageReactionRemove func(event *MessageReactionRemoveEvent) OnMessageReactionRemoveEmote func(event *MessageReactionRemoveEmoteEvent) OnMessageReactionRemoveAll func(event *MessageReactionRemoveAllEvent) - OnRawGateway func(event *RawGatewayEvent) - - OnReadyEvent func(event *ReadyEvent) - - // Guild Role Events - OnGenericRoleEvent func(event *GenericRoleEvent) - OnRoleCreate func(event *RoleCreateEvent) - OnRoleUpdate func(event *RoleUpdateEvent) - OnRoleDelete func(event *RoleDeleteEvent) - + // Self Events OnSelfUpdate func(event *SelfUpdateEvent) - OnGenericStoreChannelEvent func(event *StoreChannelCreateEvent) - OnStoreChannelCreate func(event *StoreChannelCreateEvent) - OnStoreChannelUpdate func(event *StoreChannelUpdateEvent) - OnStoreChannelDelete func(event *StoreChannelDeleteEvent) - - OnGenericTextChannelEvent func(event *GenericTextChannelEvent) - OnTextChannelCreate func(event *TextChannelCreateEvent) - OnTextChannelUpdate func(event *TextChannelUpdateEvent) - OnTextChannelDelete func(event *TextChannelDeleteEvent) - - OnGenericUserActivityEvent func(event *GenericUserActivityEvent) - OnUserActivityStart func(event *UserActivityStartEvent) - OnUserActivityUpdate func(event *UserActivityUpdateEvent) - OnUserActivityEnd func(event *UserActivityEndEvent) - + // api.User Events OnGenericUserEvent func(event *GenericUserEvent) OnUserUpdate func(event *UserUpdateEvent) OnUserTyping func(event *UserTypingEvent) OnGuildUserTyping func(event *GuildUserTypingEvent) OnDMUserTyping func(event *DMUserTypingEvent) - OnGenericVoiceChannelEvent func(event *GenericVoiceChannelEvent) - OnVoiceChannelCreate func(event *VoiceChannelCreateEvent) - OnVoiceChannelUpdate func(event *VoiceChannelUpdateEvent) - OnVoiceChannelDelete func(event *VoiceChannelDeleteEvent) + // api.User api.Activity Events + OnGenericUserActivityEvent func(event *GenericUserActivityEvent) + OnUserActivityStart func(event *UserActivityStartEvent) + OnUserActivityUpdate func(event *UserActivityUpdateEvent) + OnUserActivityEnd func(event *UserActivityEndEvent) } // OnEvent is getting called everytime we receive an event func (l ListenerAdapter) OnEvent(event interface{}) { - if e, ok := event.(api.Event); ok { - if l.OnGenericEvent != nil { - l.OnGenericEvent(e) - } - } switch e := event.(type) { - // Guild Events + case GenericEvent: + if listener := l.OnGenericEvent; listener != nil { + listener(&e) + } + case HeartbeatEvent: + if listener := l.OnHeartbeat; listener != nil { + listener(&e) + } + case HttpRequestEvent: + if listener := l.OnHttpRequest; listener != nil { + listener(&e) + } + case RawGatewayEvent: + if listener := l.OnRawGateway; listener != nil { + listener(&e) + } + case ReadyEvent: + if listener := l.OnReadyEvent; listener != nil { + listener(&e) + } + + // api.Command Events + case GenericApplicationCommandEvent: + if listener := l.OnGenericApplicationCommandEvent; listener != nil { + listener(&e) + } + case ApplicationCommandCreateEvent: + if listener := l.OnApplicationCommandCreate; listener != nil { + listener(&e) + } + case ApplicationCommandUpdateEvent: + if listener := l.OnApplicationCommandUpdate; listener != nil { + listener(&e) + } + case ApplicationCommandDeleteEvent: + if listener := l.OnApplicationCommandDelete; listener != nil { + listener(&e) + } + + // api.Channel Events + case GenericChannelEvent: + if listener := l.OnGenericChannelEvent; listener != nil { + listener(&e) + } + + // api.Category Events + case GenericCategoryEvent: + if listener := l.OnGenericCategoryEvent; listener != nil { + listener(&e) + } + case CategoryCreateEvent: + if listener := l.OnCategoryCreate; listener != nil { + listener(&e) + } + case CategoryUpdateEvent: + if listener := l.OnCategoryUpdate; listener != nil { + listener(&e) + } + case CategoryDeleteEvent: + if listener := l.OnCategoryDelete; listener != nil { + listener(&e) + } + + // api.DMChannel Events// api.Category Events + case GenericDMChannelEvent: + if listener := l.OnGenericDMChannelEvent; listener != nil { + listener(&e) + } + case DMChannelCreateEvent: + if listener := l.OnDMChannelCreate; listener != nil { + listener(&e) + } + case DMChannelUpdateEvent: + if listener := l.OnDMChannelUpdate; listener != nil { + listener(&e) + } + case DMChannelDeleteEvent: + if listener := l.OnDMChannelDelete; listener != nil { + listener(&e) + } + + // api.DMChannel Events// api.Category Events + case GenericDMMessageReactionEvent: + if listener := l.OnGenericDMMessageReactionEventEvent; listener != nil { + listener(&e) + } + case DMMessageReactionAddEvent: + if listener := l.OnDMMessageReactionAdd; listener != nil { + listener(&e) + } + case DMMessageReactionRemoveEvent: + if listener := l.OnDMMessageReactionRemove; listener != nil { + listener(&e) + } + case DMMessageReactionRemoveEmoteEvent: + if listener := l.OnDMMessageReactionRemoveEmote; listener != nil { + listener(&e) + } + case DMMessageReactionRemoveAllEvent: + if listener := l.OnDMMessageReactionRemoveAll; listener != nil { + listener(&e) + } + + // api.StoreChannel Events + case GenericStoreChannelEvent: + if listener := l.OnGenericStoreChannelEvent; listener != nil { + listener(&e) + } + case StoreChannelCreateEvent: + if listener := l.OnStoreChannelCreate; listener != nil { + listener(&e) + } + case StoreChannelUpdateEvent: + if listener := l.OnStoreChannelUpdate; listener != nil { + listener(&e) + } + case StoreChannelDeleteEvent: + if listener := l.OnStoreChannelDelete; listener != nil { + listener(&e) + } + + // api.TextChannel Events + case GenericTextChannelEvent: + if listener := l.OnGenericTextChannelEvent; listener != nil { + listener(&e) + } + case TextChannelCreateEvent: + if listener := l.OnTextChannelCreate; listener != nil { + listener(&e) + } + case TextChannelUpdateEvent: + if listener := l.OnTextChannelUpdate; listener != nil { + listener(&e) + } + case TextChannelDeleteEvent: + if listener := l.OnTextChannelDelete; listener != nil { + listener(&e) + } + + // api.VoiceChannel Events + case GenericVoiceChannelEvent: + if listener := l.OnGenericVoiceChannelEvent; listener != nil { + listener(&e) + } + case VoiceChannelCreateEvent: + if listener := l.OnVoiceChannelCreate; listener != nil { + listener(&e) + } + case VoiceChannelUpdateEvent: + if listener := l.OnVoiceChannelUpdate; listener != nil { + listener(&e) + } + case VoiceChannelDeleteEvent: + if listener := l.OnVoiceChannelDelete; listener != nil { + listener(&e) + } + + // api.emote Events + case GenericEmoteEvent: + if listener := l.OnGenericEmoteEvent; listener != nil { + listener(&e) + } + case EmoteCreateEvent: + if listener := l.OnEmoteCreate; listener != nil { + listener(&e) + } + case EmoteUpdateEvent: + if listener := l.OnEmoteUpdate; listener != nil { + listener(&e) + } + case EmoteDeleteEvent: + if listener := l.OnEmoteDelete; listener != nil { + listener(&e) + } + + case ExceptionEvent: + if listener := l.OnException; listener != nil { + listener(&e) + } + + // api.GatewayStatus Events + case GenericGatewayStatusEvent: + if listener := l.OnGenericGatewayStatusEvent; listener != nil { + listener(&e) + } + case ConnectedEvent: + if listener := l.OnConnected; listener != nil { + listener(&e) + } + case ReconnectedEvent: + if listener := l.OnReconnected; listener != nil { + listener(&e) + } + case ResumedEvent: + if listener := l.OnResumed; listener != nil { + listener(&e) + } + case DisconnectedEvent: + if listener := l.OnDisconnected; listener != nil { + listener(&e) + } + case ShutdownEvent: + if listener := l.OnShutdown; listener != nil { + listener(&e) + } + + // api.Guild Events case GenericGuildEvent: - if l.OnGenericGuildEvent != nil { - l.OnGenericGuildEvent(&e) + if listener := l.OnGenericGuildEvent; listener != nil { + listener(&e) } case GuildJoinEvent: - if l.OnGuildJoin != nil { - l.OnGuildJoin(&e) + if listener := l.OnGuildJoin; listener != nil { + listener(&e) } case GuildUpdateEvent: - if l.OnGuildUpdate != nil { - l.OnGuildUpdate(&e) + if listener := l.OnGuildUpdate; listener != nil { + listener(&e) } case GuildLeaveEvent: - if l.OnGuildLeave != nil { - l.OnGuildLeave(&e) + if listener := l.OnGuildLeave; listener != nil { + listener(&e) } case GuildAvailableEvent: - if l.OnGuildAvailable != nil { - l.OnGuildAvailable(&e) + if listener := l.OnGuildAvailable; listener != nil { + listener(&e) } case GuildUnavailableEvent: - if l.OnGuildUnavailable != nil { - l.OnGuildUnavailable(&e) + if listener := l.OnGuildUnavailable; listener != nil { + listener(&e) + } + case GuildReadyEvent: + if listener := l.OnGuildReady; listener != nil { + listener(&e) + } + case GuildBanEvent: + if listener := l.OnGuildBan; listener != nil { + listener(&e) + } + case GuildUnbanEvent: + if listener := l.OnGuildUnban; listener != nil { + listener(&e) } - // Guild Role Events + // api.Guild api.Invite Events + case GenericGuildInviteEvent: + if listener := l.OnGenericGuildInviteEvent; listener != nil { + listener(&e) + } + case GuildInviteCreateEvent: + if listener := l.OnGuildInviteCreate; listener != nil { + listener(&e) + } + case GuildInviteDeleteEvent: + if listener := l.OnGuildInviteDelete; listener != nil { + listener(&e) + } + + // api.Member Events + case GenericGuildMemberEvent: + if listener := l.OnGenericGuildMemberEvent; listener != nil { + listener(&e) + } + case GuildMemberJoinEvent: + if listener := l.OnGuildMemberJoin; listener != nil { + listener(&e) + } + case GuildMemberUpdateEvent: + if listener := l.OnGuildMemberUpdate; listener != nil { + listener(&e) + } + case GuildMemberLeaveEvent: + if listener := l.OnGuildMemberLeave; listener != nil { + listener(&e) + } + + // api.Guild api.Message Events + case GenericGuildMessageEvent: + if listener := l.OnGenericGuildMessageEvent; listener != nil { + listener(&e) + } + case GuildMessageReceivedEvent: + if listener := l.OnGuildMessageReceived; listener != nil { + listener(&e) + } + case GuildMessageUpdateEvent: + if listener := l.OnGuildMessageUpdate; listener != nil { + listener(&e) + } + case GuildMessageDeleteEvent: + if listener := l.OnGuildMessageDelete; listener != nil { + listener(&e) + } + + // api.Guild api.Message Reaction Events + case GenericGuildMessageReactionEvent: + if listener := l.OnGenericGuildMessageReactionEvent; listener != nil { + listener(&e) + } + case GuildMessageReactionAddEvent: + if listener := l.OnGuildMessageReactionAdd; listener != nil { + listener(&e) + } + case GuildMessageReactionRemoveEvent: + if listener := l.OnGuildMessageReactionRemove; listener != nil { + listener(&e) + } + case GuildMessageReactionRemoveEmoteEvent: + if listener := l.OnGuildMessageReactionRemoveEmote; listener != nil { + listener(&e) + } + case GuildMessageReactionRemoveAllEvent: + if listener := l.OnGuildMessageReactionRemoveAll; listener != nil { + listener(&e) + } + + // api.Guild Voice Events + case GenericGuildVoiceEvent: + if listener := l.OnGenericGuildVoiceEvent; listener != nil { + listener(&e) + } + case GuildVoiceUpdateEvent: + if listener := l.OnGuildVoiceUpdate; listener != nil { + listener(&e) + } + case GuildVoiceJoinEvent: + if listener := l.OnGuildVoiceJoin; listener != nil { + listener(&e) + } + case GuildVoiceLeaveEvent: + if listener := l.OnGuildVoiceLeave; listener != nil { + listener(&e) + } + + // api.Guild api.Role Events case GenericRoleEvent: - if l.OnGenericRoleEvent != nil { - l.OnGenericRoleEvent(&e) + if listener := l.OnGenericRoleEvent; listener != nil { + listener(&e) } case RoleCreateEvent: - if l.OnRoleCreate != nil { - l.OnRoleCreate(&e) + if listener := l.OnRoleCreate; listener != nil { + listener(&e) } case RoleUpdateEvent: - if l.OnRoleUpdate != nil { - l.OnRoleUpdate(&e) + if listener := l.OnRoleUpdate; listener != nil { + listener(&e) } case RoleDeleteEvent: - if l.OnRoleDelete != nil { - l.OnRoleDelete(&e) + if listener := l.OnRoleDelete; listener != nil { + listener(&e) } - // Message Events + // Interaction Events + case GenericInteractionEvent: + if listener := l.OnGenericInteractionEvent; listener != nil { + listener(&e) + } + case SlashCommandEvent: + if listener := l.OnSlashCommand; listener != nil { + listener(&e) + } + + // api.Message Events + case GenericMessageEvent: + if listener := l.OnGenericMessageEvent; listener != nil { + listener(&e) + } case MessageReceivedEvent: - if l.OnMessageReceived != nil { - l.OnMessageReceived(&e) + if listener := l.OnMessageReceived; listener != nil { + listener(&e) } - case GuildMessageReceivedEvent: - if l.OnGuildMessageReceived != nil { - l.OnGuildMessageReceived(&e) + case MessageUpdateEvent: + if listener := l.OnMessageUpdate; listener != nil { + listener(&e) + } + case MessageDeleteEvent: + if listener := l.OnMessageDelete; listener != nil { + listener(&e) } - // Interaction Events - case GenericInteractionEvent: - if l.OnGenericInteractionEvent != nil { - l.OnGenericInteractionEvent(&e) + // api.Message Reaction Events + case GenericReactionEvents: + if listener := l.OnGenericReactionEvent; listener != nil { + listener(&e) } - case SlashCommandEvent: - if l.OnSlashCommand != nil { - l.OnSlashCommand(&e) + case MessageReactionAddEvent: + if listener := l.OnMessageReactionAdd; listener != nil { + listener(&e) + } + case MessageReactionRemoveEvent: + if listener := l.OnMessageReactionRemove; listener != nil { + listener(&e) + } + case MessageReactionRemoveEmoteEvent: + if listener := l.OnMessageReactionRemoveEmote; listener != nil { + listener(&e) + } + case MessageReactionRemoveAllEvent: + if listener := l.OnMessageReactionRemoveAll; listener != nil { + listener(&e) + } + + // Self Events + case SelfUpdateEvent: + if listener := l.OnSelfUpdate; listener != nil { + listener(&e) + } + + // api.User Events + case GenericUserEvent: + if listener := l.OnGenericUserEvent; listener != nil { + listener(&e) + } + case UserUpdateEvent: + if listener := l.OnUserUpdate; listener != nil { + listener(&e) + } + case UserTypingEvent: + if listener := l.OnUserTyping; listener != nil { + listener(&e) } + case GuildUserTypingEvent: + if listener := l.OnGuildUserTyping; listener != nil { + listener(&e) + } + case DMUserTypingEvent: + if listener := l.OnDMUserTyping; listener != nil { + listener(&e) + } + + // api.User api.Activity Events + case GenericUserActivityEvent: + if listener := l.OnGenericUserActivityEvent; listener != nil { + listener(&e) + } + case UserActivityStartEvent: + if listener := l.OnUserActivityStart; listener != nil { + listener(&e) + } + case UserActivityUpdateEvent: + if listener := l.OnUserActivityUpdate; listener != nil { + listener(&e) + } + case UserActivityEndEvent: + if listener := l.OnUserActivityEnd; listener != nil { + listener(&e) + } + default: - //log.Errorf("unexpected event received: %#e", event) + log.Errorf("unexpected event received: \"%s\", event: \"%#e\"", reflect.TypeOf(event).Name(), event) } } From e8fb25f405f95bc1296e82c63f218c18d31ea625 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Sat, 10 Apr 2021 14:20:34 +0200 Subject: [PATCH 38/65] renamed event --- api/events/exception_event.go | 2 +- api/events/listener_adapter.go | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/api/events/exception_event.go b/api/events/exception_event.go index f8e4dd01..0938e2ac 100644 --- a/api/events/exception_event.go +++ b/api/events/exception_event.go @@ -1,5 +1,5 @@ package events -type ExceptionEvent struct { +type ErrorEvent struct { Error error } diff --git a/api/events/listener_adapter.go b/api/events/listener_adapter.go index f5681ea6..0154f230 100644 --- a/api/events/listener_adapter.go +++ b/api/events/listener_adapter.go @@ -11,6 +11,7 @@ type ListenerAdapter struct { // Other events OnGenericEvent func(event *GenericEvent) OnHeartbeat func(event *HeartbeatEvent) + OnError func(event *ErrorEvent) OnHttpRequest func(event *HttpRequestEvent) OnRawGateway func(event *RawGatewayEvent) OnReadyEvent func(event *ReadyEvent) @@ -67,8 +68,6 @@ type ListenerAdapter struct { OnEmoteUpdate func(event *EmoteUpdateEvent) OnEmoteDelete func(event *EmoteDeleteEvent) - OnException func(event *ExceptionEvent) - // api.GatewayStatus Events OnGenericGatewayStatusEvent func(event *GenericGatewayStatusEvent) OnConnected func(event *ConnectedEvent) @@ -173,6 +172,10 @@ func (l ListenerAdapter) OnEvent(event interface{}) { if listener := l.OnHttpRequest; listener != nil { listener(&e) } + case ErrorEvent: + if listener := l.OnError; listener != nil { + listener(&e) + } case RawGatewayEvent: if listener := l.OnRawGateway; listener != nil { listener(&e) @@ -336,11 +339,6 @@ func (l ListenerAdapter) OnEvent(event interface{}) { listener(&e) } - case ExceptionEvent: - if listener := l.OnException; listener != nil { - listener(&e) - } - // api.GatewayStatus Events case GenericGatewayStatusEvent: if listener := l.OnGenericGatewayStatusEvent; listener != nil { From ecec63f172d9c04db1ab0eb7a6c1163321155a9f Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Sat, 10 Apr 2021 16:39:57 +0200 Subject: [PATCH 39/65] added message cache & cleanup task --- api/cache.go | 11 +++---- api/endpoints/request.go | 5 --- api/endpoints/response.go | 5 --- api/events/heartbeat_event.go | 6 ++-- api/events/http_request_events.go | 7 ++-- internal/cache_impl.go | 53 +++++++++++++++++++++++++++++-- internal/gateway_impl.go | 28 ++++++++++++++-- internal/restclient_impl.go | 7 ++++ 8 files changed, 95 insertions(+), 27 deletions(-) delete mode 100644 api/endpoints/request.go delete mode 100644 api/endpoints/response.go diff --git a/api/cache.go b/api/cache.go index 4a70af50..430a5091 100644 --- a/api/cache.go +++ b/api/cache.go @@ -32,13 +32,12 @@ type Cache interface { CacheGuild(*Guild) *Guild UncacheGuild(Snowflake) - /*Message(Snowflake) *Message - Messages(Snowflake) []*Message - AllMessages() []*Message - MessageCache(Snowflake) map[Snowflake]*Message + Message(channelID Snowflake, messageID Snowflake) *Message + Messages(channelID Snowflake) []*Message + MessageCache(channelID Snowflake) map[Snowflake]*Message AllMessageCache() map[Snowflake]map[Snowflake]*Message - CacheMessage(*Message) *Message - UncacheMessage(Snowflake)*/ + CacheMessage(message *Message) *Message + UncacheMessage(channelID Snowflake, messageID Snowflake) Member(Snowflake, Snowflake) *Member MemberByTag(Snowflake, string) *Member diff --git a/api/endpoints/request.go b/api/endpoints/request.go deleted file mode 100644 index eca1f069..00000000 --- a/api/endpoints/request.go +++ /dev/null @@ -1,5 +0,0 @@ -package endpoints - -type Request struct { - -} diff --git a/api/endpoints/response.go b/api/endpoints/response.go deleted file mode 100644 index f7b84633..00000000 --- a/api/endpoints/response.go +++ /dev/null @@ -1,5 +0,0 @@ -package endpoints - -type Response struct { - StatusCode int -} diff --git a/api/events/heartbeat_event.go b/api/events/heartbeat_event.go index 93d4da68..5767363b 100644 --- a/api/events/heartbeat_event.go +++ b/api/events/heartbeat_event.go @@ -1,7 +1,9 @@ package events +import "time" + type HeartbeatEvent struct { GenericEvent - NewPing int - OldPing int + NewPing time.Duration + OldPing time.Duration } diff --git a/api/events/http_request_events.go b/api/events/http_request_events.go index fe250dd2..ec21d74c 100644 --- a/api/events/http_request_events.go +++ b/api/events/http_request_events.go @@ -2,13 +2,12 @@ package events import ( "net/http" - - "github.com/DisgoOrg/disgo/api/endpoints" ) type HttpRequestEvent struct { - Request endpoints.Request - Response endpoints.Response + GenericEvent + Request *http.Request + Response *http.Response } func (e HttpRequestEvent) RateLimited() bool { diff --git a/internal/cache_impl.go b/internal/cache_impl.go index c3f95ed3..15b3c6eb 100644 --- a/internal/cache_impl.go +++ b/internal/cache_impl.go @@ -46,6 +46,7 @@ type CacheImpl struct { guildCommands map[api.Snowflake]map[api.Snowflake]*api.Command users map[api.Snowflake]*api.User guilds map[api.Snowflake]*api.Guild + messages map[api.Snowflake]map[api.Snowflake]*api.Message members map[api.Snowflake]map[api.Snowflake]*api.Member voiceStates map[api.Snowflake]map[api.Snowflake]*api.VoiceState roles map[api.Snowflake]map[api.Snowflake]*api.Role @@ -94,7 +95,13 @@ func (c CacheImpl) startCleanup(cleanupInterval time.Duration) { // DoCleanup removes items from the cache that no longer meet their policy func (c *CacheImpl) DoCleanup() { - // TODO cleanup cache + for channelID, channelMessages := range c.messages { + for _, message := range channelMessages { + if !c.messageCachePolicy(message) { + c.UncacheMessage(channelID, message.ID) + } + } + } } // CacheFlags returns the current active api.CacheFlags @@ -333,6 +340,48 @@ func (c *CacheImpl) FindGuilds(check func(g *api.Guild) bool) []*api.Guild { return guilds } +func (c *CacheImpl) Message(channelID api.Snowflake, messageID api.Snowflake) *api.Message { + if channelMessages, ok := c.messages[channelID]; ok { + return channelMessages[channelID] + } + return nil +} +func (c *CacheImpl) Messages(channelID api.Snowflake) []*api.Message { + if channelMessages, ok := c.messages[channelID]; ok { + messages := make([]*api.Message, len(channelMessages)) + i := 0 + for _, message := range channelMessages { + messages[i] = message + i++ + } + return messages + } + return nil +} +func (c *CacheImpl) MessageCache(channelID api.Snowflake) map[api.Snowflake]*api.Message { + return c.messages[channelID] +} +func (c *CacheImpl) AllMessageCache() map[api.Snowflake]map[api.Snowflake]*api.Message { + return c.messages +} +func (c *CacheImpl) CacheMessage(message *api.Message) *api.Message { + // only cache message if we want to + if !c.messageCachePolicy(message) { + return message + } + if channelMessages, ok := c.messages[message.ChannelID]; ok { + if channelMessage, ok := channelMessages[message.ID]; ok { + *channelMessage = *message + return channelMessage + } + channelMessages[message.ID] = message + } + return message +} +func (c *CacheImpl) UncacheMessage(channelID api.Snowflake, messageID api.Snowflake) { + delete(c.messages[channelID], messageID) +} + // Member returns a member from cache by guild ID and user ID func (c *CacheImpl) Member(guildID api.Snowflake, userID api.Snowflake) *api.Member { if guildMembers, ok := c.members[guildID]; ok { @@ -679,7 +728,7 @@ func (c *CacheImpl) DMChannelCache() map[api.Snowflake]*api.DMChannel { } // CacheDMChannel adds a DM channel to the cache -func (c *CacheImpl) CacheDMChannel(dmChannel *api.DMChannel) *api.DMChannel{ +func (c *CacheImpl) CacheDMChannel(dmChannel *api.DMChannel) *api.DMChannel { if !c.cacheFlags.Has(api.CacheFlagDMChannels) { return dmChannel } diff --git a/internal/gateway_impl.go b/internal/gateway_impl.go index 0c2dac1e..438c58b7 100644 --- a/internal/gateway_impl.go +++ b/internal/gateway_impl.go @@ -10,6 +10,7 @@ import ( "runtime/debug" "time" + "github.com/DisgoOrg/disgo/api/events" "github.com/gorilla/websocket" log "github.com/sirupsen/logrus" @@ -222,12 +223,20 @@ func (g *GatewayImpl) heartbeat() { func (g *GatewayImpl) sendHeartbeat() { log.Debug("sending heartbeat...") + heartbeatEvent := events.HeartbeatEvent{ + GenericEvent: events.NewEvent(g.Disgo(), 0), + OldPing: g.Latency(), + } + if err := g.conn.WriteJSON(api.NewGatewayCommand(api.OpHeartbeat, g.lastSequenceReceived)); err != nil { log.Errorf("failed to send heartbeat with error: %s", err) g.Close() g.reconnect(1 * time.Second) } g.lastHeartbeatSent = time.Now().UTC() + + heartbeatEvent.NewPing = g.Latency() + g.Disgo().EventManager().Dispatch(heartbeatEvent) } func (g *GatewayImpl) listen() { @@ -267,10 +276,14 @@ func (g *GatewayImpl) listen() { if event.S != nil { g.lastSequenceReceived = event.S } + if event.T == nil { + log.Errorf("received event without T. playload: %s", string(data)) + continue + } log.Debugf("received: %s", *event.T) - if event.T != nil && *event.T == api.GatewayEventReady { + if *event.T == api.GatewayEventReady { var readyEvent api.ReadyGatewayEvent if err := parseEventToStruct(event, &readyEvent); err != nil { log.Errorf("Error parsing ready event: %s", err) @@ -281,10 +294,19 @@ func (g *GatewayImpl) listen() { log.Info("ready event received") } - if event.T == nil { - log.Errorf("received event without T. playload: %s", string(data)) + // TODO: add setting to enable raw gateway events? + var payload map[string]interface{} + if err = parseEventToStruct(event, &payload); err != nil { + log.Errorf("Error parsing event: %s", err) continue } + g.Disgo().EventManager().Dispatch(events.RawGatewayEvent{ + GenericEvent: events.NewEvent(g.Disgo(), *event.S), + Type: *event.T, + RawPayload: event.D, + Payload: payload, + }) + d := g.Disgo() e := d.EventManager() e.Handle(*event.T, nil, *event.S, event.D) diff --git a/internal/restclient_impl.go b/internal/restclient_impl.go index a6680901..f4adbc64 100644 --- a/internal/restclient_impl.go +++ b/internal/restclient_impl.go @@ -9,6 +9,7 @@ import ( "net/http" "strings" + "github.com/DisgoOrg/disgo/api/events" log "github.com/sirupsen/logrus" "github.com/DisgoOrg/disgo/api" @@ -88,6 +89,12 @@ func (r RestClientImpl) Request(route endpoints.CompiledAPIRoute, rqBody interfa log.Debugf("code: %d, response: %s", rs.StatusCode, string(rawRsBody)) + r.Disgo().EventManager().Dispatch(events.HttpRequestEvent{ + GenericEvent: events.NewEvent(r.Disgo(), 0), + Request: rq, + Response: rs, + }) + switch rs.StatusCode { case http.StatusOK, http.StatusCreated, http.StatusNoContent: if rsBody != nil { From 4a53bac1a4dab529a2403719e0a3022f2f43c334 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Sat, 10 Apr 2021 16:50:04 +0200 Subject: [PATCH 40/65] added createMesasge to entity builder --- api/entity_builder.go | 2 ++ internal/entity_builder_impl.go | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/api/entity_builder.go b/api/entity_builder.go index ec7c0356..4f90d854 100644 --- a/api/entity_builder.go +++ b/api/entity_builder.go @@ -7,6 +7,8 @@ type EntityBuilder interface { CreateUser(user *User, updateCache bool) *User + CreateMessage(message *Message, updateCache bool) *Message + CreateGuild(guild *Guild, updateCache bool) *Guild CreateMember(guildID Snowflake, member *Member, updateCache bool) *Member CreateGuildCommand(guildID Snowflake, command *Command, updateCache bool) *Command diff --git a/internal/entity_builder_impl.go b/internal/entity_builder_impl.go index 96c9de76..51b512a4 100644 --- a/internal/entity_builder_impl.go +++ b/internal/entity_builder_impl.go @@ -32,6 +32,20 @@ func (b EntityBuilderImpl) CreateUser(user *api.User, updateCache bool) *api.Use return user } +func (b EntityBuilderImpl) CreateMessage(message *api.Message, updateCache bool) *api.Message { + message.Disgo = b.Disgo() + if message.Member != nil { + message.Member = b.CreateMember(*message.GuildID, message.Member, true) + } + if message.Author != nil { + + } + if updateCache { + return b.Disgo().Cache().CacheMessage(message) + } + return message +} + func (b EntityBuilderImpl) CreateGuild(guild *api.Guild, updateCache bool) *api.Guild { guild.Disgo = b.Disgo() if updateCache { From a3355a8a6426bce60242eb65a7b9470058d619c1 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Sun, 11 Apr 2021 04:16:05 +0200 Subject: [PATCH 41/65] a lot of stuff I forgot bruh --- api/cache.go | 2 +- api/cache_flags.go | 1 + api/command.go | 3 + api/disgo.go | 1 + api/entity_builder.go | 37 ++- api/voice_dispatch_interceptor.go | 24 +- api/voice_state.go | 7 + internal/cache_impl.go | 36 ++- internal/disgo_impl.go | 5 + internal/entity_builder_impl.go | 71 +++-- internal/event_manager_impl.go | 4 +- internal/gateway_impl.go | 45 ++- internal/handlers/all_handlers.go | 24 +- .../handlers/application_command_create.go | 4 +- .../handlers/application_command_delete.go | 4 +- .../handlers/application_command_update.go | 4 +- internal/handlers/channel_create_handler.go | 10 +- internal/handlers/channel_delete_handler.go | 10 +- internal/handlers/guild_create_handler.go | 16 +- internal/handlers/guild_delete_handler.go | 2 + internal/handlers/guild_member_add_handler.go | 2 +- .../handlers/guild_member_remove_handler.go | 4 +- .../handlers/guild_member_update_handler.go | 2 +- .../handlers/guild_role_create_handler.go | 2 +- .../handlers/guild_role_update_handler.go | 2 +- internal/handlers/guild_update_handler.go | 2 +- .../handlers/voice_server_update_handler.go | 11 +- .../handlers/voice_state_update_handler.go | 4 +- internal/restclient_impl.go | 265 +++++++++--------- testbot/testbot.go | 2 +- 30 files changed, 356 insertions(+), 250 deletions(-) diff --git a/api/cache.go b/api/cache.go index 430a5091..16241425 100644 --- a/api/cache.go +++ b/api/cache.go @@ -72,7 +72,7 @@ type Cache interface { DMChannels() []*DMChannel DMChannelCache() map[Snowflake]*DMChannel CacheDMChannel(*DMChannel) *DMChannel - UncacheDMChannel(Snowflake) + UncacheDMChannel(dmChannelID Snowflake) FindDMChannel(func(*DMChannel) bool) *DMChannel FindDMChannels(func(*DMChannel) bool) []*DMChannel diff --git a/api/cache_flags.go b/api/cache_flags.go index f655d2d2..324967b6 100644 --- a/api/cache_flags.go +++ b/api/cache_flags.go @@ -15,6 +15,7 @@ const ( CacheFlagEmotes CacheFlagVoiceState CacheFlagCommands + CacheFlagCommandPermissions CacheFlagsDefault = CacheFlagDMChannels | CacheFlagCategories | diff --git a/api/command.go b/api/command.go index 924b6a10..139f74e5 100644 --- a/api/command.go +++ b/api/command.go @@ -160,12 +160,15 @@ type OptionChoice struct { // GuildCommandPermissions holds all permissions for a Command type GuildCommandPermissions struct { + Disgo Disgo ID Snowflake `json:"id"` ApplicationID Snowflake `json:"application_id"` GuildID Snowflake `json:"guild_id"` Permissions []CommandPermission `json:"permissions"` } +// TODO: add methods to update those + // CommandPermissionType is the type of the CommandPermission type CommandPermissionType int diff --git a/api/disgo.go b/api/disgo.go index 7ed4fb16..a551f687 100644 --- a/api/disgo.go +++ b/api/disgo.go @@ -28,6 +28,7 @@ type Disgo interface { SetVoiceDispatchInterceptor(voiceInterceptor VoiceDispatchInterceptor) HeartbeatLatency() time.Duration LargeThreshold() int + HasGateway() bool GetCommand(commandID Snowflake) (*Command, error) GetCommands() ([]*Command, error) diff --git a/api/entity_builder.go b/api/entity_builder.go index 4f90d854..a532a5f6 100644 --- a/api/entity_builder.go +++ b/api/entity_builder.go @@ -1,25 +1,34 @@ package api +type CacheStrategy func(disgo Disgo) bool + +var ( + CacheStrategyYes CacheStrategy = func(disgo Disgo) bool { return true } + CacheStrategyNo CacheStrategy = func(disgo Disgo) bool { return true } + CacheStrategyNoWs CacheStrategy = func(disgo Disgo) bool { return disgo.HasGateway() } +) + type EntityBuilder interface { Disgo() Disgo - CreateGlobalCommand(command *Command, updateCache bool) *Command + CreateGlobalCommand(command *Command, updateCache CacheStrategy) *Command - CreateUser(user *User, updateCache bool) *User + CreateUser(user *User, updateCache CacheStrategy) *User - CreateMessage(message *Message, updateCache bool) *Message + CreateMessage(message *Message, updateCache CacheStrategy) *Message - CreateGuild(guild *Guild, updateCache bool) *Guild - CreateMember(guildID Snowflake, member *Member, updateCache bool) *Member - CreateGuildCommand(guildID Snowflake, command *Command, updateCache bool) *Command - CreateRole(guildID Snowflake, role *Role, updateCache bool) *Role - CreateVoiceState(role *VoiceState, updateCache bool) *VoiceState + CreateGuild(guild *Guild, updateCache CacheStrategy) *Guild + CreateMember(guildID Snowflake, member *Member, updateCache CacheStrategy) *Member + CreateGuildCommand(guildID Snowflake, command *Command, updateCache CacheStrategy) *Command + CreateGuildCommandPermissions(guildCommandPermissions *GuildCommandPermissions, updateCache CacheStrategy) *GuildCommandPermissions + CreateRole(guildID Snowflake, role *Role, updateCache CacheStrategy) *Role + CreateVoiceState(role *VoiceState, updateCache CacheStrategy) *VoiceState - CreateTextChannel(channel *Channel, updateCache bool) *TextChannel - CreateVoiceChannel(channel *Channel, updateCache bool) *VoiceChannel - CreateStoreChannel(channel *Channel, updateCache bool) *StoreChannel - CreateCategory(channel *Channel, updateCache bool) *Category - CreateDMChannel(channel *Channel, updateCache bool) *DMChannel + CreateTextChannel(channel *Channel, updateCache CacheStrategy) *TextChannel + CreateVoiceChannel(channel *Channel, updateCache CacheStrategy) *VoiceChannel + CreateStoreChannel(channel *Channel, updateCache CacheStrategy) *StoreChannel + CreateCategory(channel *Channel, updateCache CacheStrategy) *Category + CreateDMChannel(channel *Channel, updateCache CacheStrategy) *DMChannel - CreateEmote(guildID Snowflake, emote *Emote, updateCache bool) *Emote + CreateEmote(guildID Snowflake, emote *Emote, updateCache CacheStrategy) *Emote } diff --git a/api/voice_dispatch_interceptor.go b/api/voice_dispatch_interceptor.go index 06a6f3c6..3429fe77 100644 --- a/api/voice_dispatch_interceptor.go +++ b/api/voice_dispatch_interceptor.go @@ -1,31 +1,29 @@ package api -// VoiceServerUpdate sent when a guilds voice server is updated -type VoiceServerUpdate struct { - Disgo Disgo - Token string `json:"token"` - GuildID Snowflake `json:"guild_id"` - Endpoint *string `json:"endpoint"` +// VoiceServerUpdateEvent sent when a guilds voice server is updated +type VoiceServerUpdateEvent struct { + VoiceServerUpdate + Disgo Disgo } // Guild returns the Guild for this VoiceServerUpdate from the Cache -func (u VoiceServerUpdate) Guild() *Guild { +func (u VoiceServerUpdateEvent) Guild() *Guild { return u.Disgo.Cache().Guild(u.GuildID) } -// VoiceStateUpdate sent when someone joins/leaves/moves voice channels -type VoiceStateUpdate struct { +// VoiceStateUpdateEvent sent when someone joins/leaves/moves voice channels +type VoiceStateUpdateEvent struct { VoiceState Member *Member `json:"member"` } // Guild returns the Guild for this VoiceStateUpdate from the Cache -func (u VoiceStateUpdate) Guild() *Guild { +func (u VoiceStateUpdateEvent) Guild() *Guild { return u.Disgo.Cache().Guild(u.GuildID) } // VoiceChannel returns the VoiceChannel for this VoiceStateUpdate from the Cache -func (u VoiceStateUpdate) VoiceChannel() *VoiceChannel { +func (u VoiceStateUpdateEvent) VoiceChannel() *VoiceChannel { if u.ChannelID == nil { return nil } @@ -34,6 +32,6 @@ func (u VoiceStateUpdate) VoiceChannel() *VoiceChannel { // VoiceDispatchInterceptor lets you listen to VoiceServerUpdate & VoiceStateUpdate type VoiceDispatchInterceptor interface { - OnVoiceServerUpdate(voiceServerUpdateEvent VoiceServerUpdate) - OnVoiceStateUpdate(voiceStateUpdateEvent VoiceStateUpdate) + OnVoiceServerUpdate(voiceServerUpdateEvent VoiceServerUpdateEvent) + OnVoiceStateUpdate(voiceStateUpdateEvent VoiceStateUpdateEvent) } diff --git a/api/voice_state.go b/api/voice_state.go index 07d43c65..8b71099d 100644 --- a/api/voice_state.go +++ b/api/voice_state.go @@ -1,5 +1,12 @@ package api +// VoiceServerUpdate from Discord +type VoiceServerUpdate struct { + Token string `json:"token"` + GuildID Snowflake `json:"guild_id"` + Endpoint *string `json:"endpoint"` +} + // VoiceState from Discord type VoiceState struct { Disgo Disgo diff --git a/internal/cache_impl.go b/internal/cache_impl.go index 15b3c6eb..da29cb58 100644 --- a/internal/cache_impl.go +++ b/internal/cache_impl.go @@ -342,7 +342,7 @@ func (c *CacheImpl) FindGuilds(check func(g *api.Guild) bool) []*api.Guild { func (c *CacheImpl) Message(channelID api.Snowflake, messageID api.Snowflake) *api.Message { if channelMessages, ok := c.messages[channelID]; ok { - return channelMessages[channelID] + return channelMessages[messageID] } return nil } @@ -379,7 +379,14 @@ func (c *CacheImpl) CacheMessage(message *api.Message) *api.Message { return message } func (c *CacheImpl) UncacheMessage(channelID api.Snowflake, messageID api.Snowflake) { - delete(c.messages[channelID], messageID) + if channelMessages, ok := c.messages[channelID]; ok { + if message, ok := channelMessages[messageID]; ok { + // check if we really want to uncache that message according to our policy + if !c.messageCachePolicy(message) { + delete(channelMessages, messageID) + } + } + } } // Member returns a member from cache by guild ID and user ID @@ -472,7 +479,16 @@ func (c *CacheImpl) CacheMember(member *api.Member) *api.Member { // UncacheMember removes a guild member from the cache func (c *CacheImpl) UncacheMember(guildID api.Snowflake, userID api.Snowflake) { - delete(c.members[guildID], userID) + // TODO: add UncacheUser call! + if guildMembers, ok := c.members[guildID]; ok { + if member, ok := guildMembers[userID]; ok { + // check if we really want to uncache that member according to our policy + if !c.memberCachePolicy(member) { + delete(guildMembers, userID) + } + } + } + } // FindMember allows you to find a member in a guild by custom method @@ -741,8 +757,13 @@ func (c *CacheImpl) CacheDMChannel(dmChannel *api.DMChannel) *api.DMChannel { } // UncacheDMChannel removes a DM channel from cache -func (c *CacheImpl) UncacheDMChannel(channelID api.Snowflake) { - delete(c.dmChannels, channelID) +func (c *CacheImpl) UncacheDMChannel(dmChannelID api.Snowflake) { + // TODO: check this + // should be okay to just uncache all messages if the channel gets uncached as that should mean it got deleted + if _, ok := c.messages[dmChannelID]; ok { + delete(c.messages, dmChannelID) + } + delete(c.dmChannels, dmChannelID) } // FindDMChannel finds a DM channel in cache with a custom method @@ -845,6 +866,11 @@ func (c *CacheImpl) CacheTextChannel(textChannel *api.TextChannel) *api.TextChan // UncacheTextChannel removes a text channel from the cache func (c *CacheImpl) UncacheTextChannel(guildID api.Snowflake, textChannelID api.Snowflake) { + // TODO: check this + // should be okay to just uncache all messages if the channel gets uncached as that should mean it got deleted + if _, ok := c.messages[textChannelID]; ok { + delete(c.messages, textChannelID) + } delete(c.textChannels[guildID], textChannelID) } diff --git a/internal/disgo_impl.go b/internal/disgo_impl.go index 42589265..146518b8 100644 --- a/internal/disgo_impl.go +++ b/internal/disgo_impl.go @@ -167,6 +167,11 @@ func (d *DisgoImpl) LargeThreshold() int { return d.largeThreshold } +// HasGateway returns weather api.Disgo has an active api.Gateway connection or not +func (d DisgoImpl) HasGateway() bool { + return d.gateway != nil +} + // GetCommand fetches a specific guild command func (d DisgoImpl) GetCommand(commandID api.Snowflake) (*api.Command, error) { return d.RestClient().GetGlobalCommand(d.SelfUserID(), commandID) diff --git a/internal/entity_builder_impl.go b/internal/entity_builder_impl.go index 51b512a4..2a65fa44 100644 --- a/internal/entity_builder_impl.go +++ b/internal/entity_builder_impl.go @@ -16,81 +16,92 @@ func (b EntityBuilderImpl) Disgo() api.Disgo { return b.disgo } -func (b EntityBuilderImpl) CreateGlobalCommand(command *api.Command, updateCache bool) *api.Command { +func (b EntityBuilderImpl) CreateGlobalCommand(command *api.Command, updateCache api.CacheStrategy) *api.Command { command.Disgo = b.Disgo() - if updateCache { + if updateCache(b.Disgo()) { return b.Disgo().Cache().CacheGlobalCommand(command) } return command } -func (b EntityBuilderImpl) CreateUser(user *api.User, updateCache bool) *api.User { +func (b EntityBuilderImpl) CreateUser(user *api.User, updateCache api.CacheStrategy) *api.User { user.Disgo = b.Disgo() - if updateCache { + if updateCache(b.Disgo()) { return b.Disgo().Cache().CacheUser(user) } return user } -func (b EntityBuilderImpl) CreateMessage(message *api.Message, updateCache bool) *api.Message { +func (b EntityBuilderImpl) CreateMessage(message *api.Message, updateCache api.CacheStrategy) *api.Message { message.Disgo = b.Disgo() if message.Member != nil { - message.Member = b.CreateMember(*message.GuildID, message.Member, true) + message.Member = b.CreateMember(*message.GuildID, message.Member, updateCache) } if message.Author != nil { - + message.Author = b.CreateUser(message.Author, updateCache) } - if updateCache { + // TODO: should we cache mentioned users, members, etc? + if updateCache(b.Disgo()) { return b.Disgo().Cache().CacheMessage(message) } return message } -func (b EntityBuilderImpl) CreateGuild(guild *api.Guild, updateCache bool) *api.Guild { +func (b EntityBuilderImpl) CreateGuild(guild *api.Guild, updateCache api.CacheStrategy) *api.Guild { guild.Disgo = b.Disgo() - if updateCache { + if updateCache(b.Disgo()) { return b.Disgo().Cache().CacheGuild(guild) } return guild } -func (b EntityBuilderImpl) CreateMember(guildID api.Snowflake, member *api.Member, updateCache bool) *api.Member { +func (b EntityBuilderImpl) CreateMember(guildID api.Snowflake, member *api.Member, updateCache api.CacheStrategy) *api.Member { member.Disgo = b.Disgo() member.GuildID = guildID member.User = b.CreateUser(member.User, updateCache) - if updateCache { + if updateCache(b.Disgo()) { return b.Disgo().Cache().CacheMember(member) } return member } -func (b EntityBuilderImpl) CreateVoiceState(voiceState *api.VoiceState, updateCache bool) *api.VoiceState { +func (b EntityBuilderImpl) CreateVoiceState(voiceState *api.VoiceState, updateCache api.CacheStrategy) *api.VoiceState { voiceState.Disgo = b.Disgo() - if updateCache { + if updateCache(b.Disgo()) { return b.Disgo().Cache().CacheVoiceState(voiceState) } return voiceState } -func (b EntityBuilderImpl) CreateGuildCommand(guildID api.Snowflake, command *api.Command, updateCache bool) *api.Command { +func (b EntityBuilderImpl) CreateGuildCommand(guildID api.Snowflake, command *api.Command, updateCache api.CacheStrategy) *api.Command { command.Disgo = b.Disgo() command.GuildID = &guildID - if updateCache { + if updateCache(b.Disgo()) { return b.Disgo().Cache().CacheGuildCommand(command) } return command } -func (b EntityBuilderImpl) CreateRole(guildID api.Snowflake, role *api.Role, updateCache bool) *api.Role { +func (b EntityBuilderImpl) CreateGuildCommandPermissions(guildCommandPermissions *api.GuildCommandPermissions, updateCache api.CacheStrategy) *api.GuildCommandPermissions { + guildCommandPermissions.Disgo = b.Disgo() + if updateCache(b.Disgo()) && b.Disgo().Cache().CacheFlags().Has(api.CacheFlagCommandPermissions) { + if cmd := b.Disgo().Cache().Command(guildCommandPermissions.ID); cmd != nil { + cmd.GuildPermissions[guildCommandPermissions.GuildID] = guildCommandPermissions + } + } + return guildCommandPermissions +} + +func (b EntityBuilderImpl) CreateRole(guildID api.Snowflake, role *api.Role, updateCache api.CacheStrategy) *api.Role { role.Disgo = b.Disgo() role.GuildID = guildID - if updateCache { + if updateCache(b.Disgo()) { return b.Disgo().Cache().CacheRole(role) } return role } -func (b EntityBuilderImpl) CreateTextChannel(channel *api.Channel, updateCache bool) *api.TextChannel { +func (b EntityBuilderImpl) CreateTextChannel(channel *api.Channel, updateCache api.CacheStrategy) *api.TextChannel { channel.Disgo = b.Disgo() textChannel := &api.TextChannel{ MessageChannel: api.MessageChannel{ @@ -100,68 +111,68 @@ func (b EntityBuilderImpl) CreateTextChannel(channel *api.Channel, updateCache b Channel: *channel, }, } - if updateCache { + if updateCache(b.Disgo()) { return b.Disgo().Cache().CacheTextChannel(textChannel) } return textChannel } -func (b EntityBuilderImpl) CreateVoiceChannel(channel *api.Channel, updateCache bool) *api.VoiceChannel { +func (b EntityBuilderImpl) CreateVoiceChannel(channel *api.Channel, updateCache api.CacheStrategy) *api.VoiceChannel { channel.Disgo = b.Disgo() voiceChannel := &api.VoiceChannel{ GuildChannel: api.GuildChannel{ Channel: *channel, }, } - if updateCache { + if updateCache(b.Disgo()) { return b.Disgo().Cache().CacheVoiceChannel(voiceChannel) } return voiceChannel } -func (b EntityBuilderImpl) CreateStoreChannel(channel *api.Channel, updateCache bool) *api.StoreChannel { +func (b EntityBuilderImpl) CreateStoreChannel(channel *api.Channel, updateCache api.CacheStrategy) *api.StoreChannel { channel.Disgo = b.Disgo() storeChannel := &api.StoreChannel{ GuildChannel: api.GuildChannel{ Channel: *channel, }, } - if updateCache { + if updateCache(b.Disgo()) { return b.Disgo().Cache().CacheStoreChannel(storeChannel) } return storeChannel } -func (b EntityBuilderImpl) CreateCategory(channel *api.Channel, updateCache bool) *api.Category { +func (b EntityBuilderImpl) CreateCategory(channel *api.Channel, updateCache api.CacheStrategy) *api.Category { channel.Disgo = b.Disgo() category := &api.Category{ GuildChannel: api.GuildChannel{ Channel: *channel, }, } - if updateCache { + if updateCache(b.Disgo()) { return b.Disgo().Cache().CacheCategory(category) } return category } -func (b EntityBuilderImpl) CreateDMChannel(channel *api.Channel, updateCache bool) *api.DMChannel { +func (b EntityBuilderImpl) CreateDMChannel(channel *api.Channel, updateCache api.CacheStrategy) *api.DMChannel { channel.Disgo = b.Disgo() dmChannel := &api.DMChannel{ MessageChannel: api.MessageChannel{ Channel: *channel, }, } - if updateCache { + if updateCache(b.Disgo()) { return b.Disgo().Cache().CacheDMChannel(dmChannel) } return dmChannel } -func (b EntityBuilderImpl) CreateEmote(guildId api.Snowflake, emote *api.Emote, updateCache bool) *api.Emote { +func (b EntityBuilderImpl) CreateEmote(guildId api.Snowflake, emote *api.Emote, updateCache api.CacheStrategy) *api.Emote { emote.Disgo = b.Disgo() emote.GuildID = guildId - if updateCache { + if updateCache(b.Disgo()) { return b.Disgo().Cache().CacheEmote(emote) } return emote diff --git a/internal/event_manager_impl.go b/internal/event_manager_impl.go index 4d5f9a1d..daa3fdd8 100644 --- a/internal/event_manager_impl.go +++ b/internal/event_manager_impl.go @@ -56,7 +56,9 @@ func (e EventManagerImpl) Handle(name api.GatewayEventType, c chan interface{}, // Dispatch dispatches a new event to the client func (e EventManagerImpl) Dispatch(event api.Event) { - e.channel <- event + go func() { + e.channel <- event + }() } // AddEventListeners adds one or more api.EventListener(s) to the api.EventManager diff --git a/internal/gateway_impl.go b/internal/gateway_impl.go index 438c58b7..e143b9cc 100644 --- a/internal/gateway_impl.go +++ b/internal/gateway_impl.go @@ -101,7 +101,7 @@ func (g *GatewayImpl) Open() error { return err } wsConn.SetCloseHandler(func(code int, error string) error { - log.Errorf("connection to websocket closed with code: %d, error: %s", code, error) + log.Infof("connection to websocket closed with code: %d, error: %s", code, error) return nil }) @@ -131,6 +131,7 @@ func (g *GatewayImpl) Open() error { if g.lastSequenceReceived == nil || g.sessionID == nil { g.status = api.Identifying + log.Infof("sending Identifying command...") if err = wsConn.WriteJSON( api.NewGatewayCommand(api.OpIdentify, api.IdentifyCommand{ Token: g.Disgo().Token(), @@ -147,9 +148,10 @@ func (g *GatewayImpl) Open() error { return err } } else { + log.Infof("sending Resuming command...") g.status = api.Resuming if err = wsConn.WriteJSON( - api.NewGatewayCommand(api.OpIdentify, api.ResumeCommand{ + api.NewGatewayCommand(api.OpResume, api.ResumeCommand{ Token: g.Disgo().Token(), SessionID: *g.sessionID, Seq: *g.lastSequenceReceived, @@ -188,13 +190,33 @@ func (g *GatewayImpl) Close() { log.Info("closed gateway goroutines") } if g.conn != nil { - if err := g.conn.Close(); err != nil { + if err := g.closeWithCode(websocket.CloseNormalClosure); err != nil { log.Errorf("error while closing wsconn: %s", err) - g.conn = nil } } } +func (g *GatewayImpl) closeWithCode(code int) error { + if g.conn != nil { + + err := g.conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(code, "")) + if err != nil { + return err + } + + // TODO: Wait for Discord to actually close the connection. + time.Sleep(1 * time.Second) + + err = g.conn.Close() + g.conn = nil + if err != nil { + return err + } + + } + return nil +} + func (g *GatewayImpl) heartbeat() { defer func() { if r := recover(); r != nil { @@ -211,11 +233,9 @@ func (g *GatewayImpl) heartbeat() { select { case <-ticker.C: g.sendHeartbeat() - case _, ok := <-g.quit: - if !ok { - ticker.Stop() - return - } + case <-g.quit: + ticker.Stop() + return } } } @@ -251,10 +271,9 @@ func (g *GatewayImpl) listen() { }() for { select { - case _, ok := <-g.quit: - if !ok { - return - } + case <-g.quit: + log.Infof("existed listen routine") + return default: mt, data, err := g.conn.ReadMessage() if err != nil { diff --git a/internal/handlers/all_handlers.go b/internal/handlers/all_handlers.go index cd62ee26..e3f12a41 100644 --- a/internal/handlers/all_handlers.go +++ b/internal/handlers/all_handlers.go @@ -7,26 +7,34 @@ import ( // GetAllHandlers returns all api.GatewayEventHandler(s) func GetAllHandlers() []api.EventHandler { return []api.EventHandler{ - ReadyHandler{}, + ApplicationCommandCreateHandler{}, + ApplicationCommandDeleteHandler{}, + ApplicationCommandUpdateHandler{}, - VoiceServerUpdateHandler{}, - VoiceStateUpdateHandler{}, + ChannelCreateHandler{}, + ChannelDeleteHandler{}, + ChannelUpdateHandler{}, GuildCreateHandler{}, - GuildUpdateHandler{}, GuildDeleteHandler{}, + GuildUpdateHandler{}, GuildMemberAddHandler{}, - GuildMemberUpdateHandler{}, GuildMemberRemoveHandler{}, + GuildMemberUpdateHandler{}, GuildRoleCreateHandler{}, - GuildRoleUpdateHandler{}, GuildRoleDeleteHandler{}, - - MessageCreateHandler{}, + GuildRoleUpdateHandler{}, InteractionCreateHandler{}, InteractionCreateWebhookHandler{}, + + MessageCreateHandler{}, + + ReadyHandler{}, + + VoiceServerUpdateHandler{}, + VoiceStateUpdateHandler{}, } } diff --git a/internal/handlers/application_command_create.go b/internal/handlers/application_command_create.go index eb86cddd..3bcb4e49 100644 --- a/internal/handlers/application_command_create.go +++ b/internal/handlers/application_command_create.go @@ -26,9 +26,9 @@ func (h ApplicationCommandCreateHandler) HandleGatewayEvent(disgo api.Disgo, eve } if command.FromGuild() { - command = disgo.EntityBuilder().CreateGuildCommand(*command.GuildID, command, true) + command = disgo.EntityBuilder().CreateGuildCommand(*command.GuildID, command, api.CacheStrategyYes) } else { - command = disgo.EntityBuilder().CreateGlobalCommand(command, true) + command = disgo.EntityBuilder().CreateGlobalCommand(command, api.CacheStrategyYes) } genericApplicationCommandEvent := events.GenericApplicationCommandEvent{ diff --git a/internal/handlers/application_command_delete.go b/internal/handlers/application_command_delete.go index e50d46b4..34ba42fd 100644 --- a/internal/handlers/application_command_delete.go +++ b/internal/handlers/application_command_delete.go @@ -28,9 +28,9 @@ func (h ApplicationCommandDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eve disgo.Cache().UncacheCommand(command.ID) if command.FromGuild() { - command = disgo.EntityBuilder().CreateGuildCommand(*command.GuildID, command, false) + command = disgo.EntityBuilder().CreateGuildCommand(*command.GuildID, command, api.CacheStrategyNo) } else { - command = disgo.EntityBuilder().CreateGlobalCommand(command, false) + command = disgo.EntityBuilder().CreateGlobalCommand(command, api.CacheStrategyNo) } genericApplicationCommandEvent := events.GenericApplicationCommandEvent{ diff --git a/internal/handlers/application_command_update.go b/internal/handlers/application_command_update.go index c8a278ca..53cfb498 100644 --- a/internal/handlers/application_command_update.go +++ b/internal/handlers/application_command_update.go @@ -31,9 +31,9 @@ func (h ApplicationCommandUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eve } if command.FromGuild() { - command = disgo.EntityBuilder().CreateGuildCommand(*command.GuildID, command, true) + command = disgo.EntityBuilder().CreateGuildCommand(*command.GuildID, command, api.CacheStrategyYes) } else { - command = disgo.EntityBuilder().CreateGlobalCommand(command, true) + command = disgo.EntityBuilder().CreateGlobalCommand(command, api.CacheStrategyYes) } genericApplicationCommandEvent := events.GenericApplicationCommandEvent{ diff --git a/internal/handlers/channel_create_handler.go b/internal/handlers/channel_create_handler.go index 592f59d0..56731cc9 100644 --- a/internal/handlers/channel_create_handler.go +++ b/internal/handlers/channel_create_handler.go @@ -34,7 +34,7 @@ func (h ChannelCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a switch channel.Type { case api.ChannelTypeDM: - dmChannel := disgo.EntityBuilder().CreateDMChannel(channel, true) + dmChannel := disgo.EntityBuilder().CreateDMChannel(channel, api.CacheStrategyYes) genericDMChannelEvent := events.GenericDMChannelEvent{ GenericChannelEvent: genericChannelEvent, @@ -50,7 +50,7 @@ func (h ChannelCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a log.Warnf("ChannelTypeGroupDM received what the hell discord") case api.ChannelTypeText, api.ChannelTypeNews: - textChannel := disgo.EntityBuilder().CreateTextChannel(channel, true) + textChannel := disgo.EntityBuilder().CreateTextChannel(channel, api.CacheStrategyYes) genericTextChannelEvent := events.GenericTextChannelEvent{ GenericChannelEvent: genericChannelEvent, @@ -63,7 +63,7 @@ func (h ChannelCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a }) case api.ChannelTypeStore: - storeChannel := disgo.EntityBuilder().CreateStoreChannel(channel, true) + storeChannel := disgo.EntityBuilder().CreateStoreChannel(channel, api.CacheStrategyYes) genericStoreChannelEvent := events.GenericStoreChannelEvent{ GenericChannelEvent: genericChannelEvent, @@ -76,7 +76,7 @@ func (h ChannelCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a }) case api.ChannelTypeCategory: - category := disgo.EntityBuilder().CreateCategory(channel, true) + category := disgo.EntityBuilder().CreateCategory(channel, api.CacheStrategyYes) genericCategoryEvent := events.GenericCategoryEvent{ GenericChannelEvent: genericChannelEvent, @@ -89,7 +89,7 @@ func (h ChannelCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a }) case api.ChannelTypeVoice: - voiceChannel := disgo.EntityBuilder().CreateVoiceChannel(channel, true) + voiceChannel := disgo.EntityBuilder().CreateVoiceChannel(channel, api.CacheStrategyYes) genericVoiceChannelEvent := events.GenericVoiceChannelEvent{ GenericChannelEvent: genericChannelEvent, diff --git a/internal/handlers/channel_delete_handler.go b/internal/handlers/channel_delete_handler.go index 69c3e98c..48b2400e 100644 --- a/internal/handlers/channel_delete_handler.go +++ b/internal/handlers/channel_delete_handler.go @@ -35,7 +35,7 @@ func (h ChannelDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a switch channel.Type { case api.ChannelTypeDM: disgo.Cache().UncacheDMChannel(channel.ID) - dmChannel := disgo.EntityBuilder().CreateDMChannel(channel, false) + dmChannel := disgo.EntityBuilder().CreateDMChannel(channel, api.CacheStrategyNo) genericDMChannelEvent := events.GenericDMChannelEvent{ GenericChannelEvent: genericChannelEvent, @@ -52,7 +52,7 @@ func (h ChannelDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a case api.ChannelTypeText, api.ChannelTypeNews: disgo.Cache().UncacheTextChannel(*channel.GuildID, channel.ID) - textChannel := disgo.EntityBuilder().CreateTextChannel(channel, false) + textChannel := disgo.EntityBuilder().CreateTextChannel(channel, api.CacheStrategyNo) genericTextChannelEvent := events.GenericTextChannelEvent{ GenericChannelEvent: genericChannelEvent, @@ -66,7 +66,7 @@ func (h ChannelDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a case api.ChannelTypeStore: disgo.Cache().UncacheStoreChannel(*channel.GuildID, channel.ID) - storeChannel := disgo.EntityBuilder().CreateStoreChannel(channel, false) + storeChannel := disgo.EntityBuilder().CreateStoreChannel(channel, api.CacheStrategyNo) genericStoreChannelEvent := events.GenericStoreChannelEvent{ GenericChannelEvent: genericChannelEvent, @@ -80,7 +80,7 @@ func (h ChannelDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a case api.ChannelTypeCategory: disgo.Cache().UncacheCategory(*channel.GuildID, channel.ID) - category := disgo.EntityBuilder().CreateCategory(channel, false) + category := disgo.EntityBuilder().CreateCategory(channel, api.CacheStrategyNo) genericCategoryEvent := events.GenericCategoryEvent{ GenericChannelEvent: genericChannelEvent, @@ -94,7 +94,7 @@ func (h ChannelDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a case api.ChannelTypeVoice: disgo.Cache().UncacheVoiceChannel(*channel.GuildID, channel.ID) - voiceChannel := disgo.EntityBuilder().CreateVoiceChannel(channel, false) + voiceChannel := disgo.EntityBuilder().CreateVoiceChannel(channel, api.CacheStrategyNo) genericVoiceChannelEvent := events.GenericVoiceChannelEvent{ GenericChannelEvent: genericChannelEvent, diff --git a/internal/handlers/guild_create_handler.go b/internal/handlers/guild_create_handler.go index ca32b11f..34218032 100644 --- a/internal/handlers/guild_create_handler.go +++ b/internal/handlers/guild_create_handler.go @@ -42,30 +42,30 @@ func (h GuildCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api channel.GuildID = &guild.ID switch channel.Type { case api.ChannelTypeText, api.ChannelTypeNews: - disgo.EntityBuilder().CreateTextChannel(channel, true) + disgo.EntityBuilder().CreateTextChannel(channel, api.CacheStrategyYes) case api.ChannelTypeVoice: - disgo.EntityBuilder().CreateVoiceChannel(channel, true) + disgo.EntityBuilder().CreateVoiceChannel(channel, api.CacheStrategyYes) case api.ChannelTypeCategory: - disgo.EntityBuilder().CreateCategory(channel, true) + disgo.EntityBuilder().CreateCategory(channel, api.CacheStrategyYes) case api.ChannelTypeStore: - disgo.EntityBuilder().CreateStoreChannel(channel, true) + disgo.EntityBuilder().CreateStoreChannel(channel, api.CacheStrategyYes) } } for i := range fullGuild.Roles { - disgo.EntityBuilder().CreateRole(guild.ID, fullGuild.Roles[i], true) + disgo.EntityBuilder().CreateRole(guild.ID, fullGuild.Roles[i], api.CacheStrategyYes) } for i := range fullGuild.Members { - disgo.EntityBuilder().CreateMember(guild.ID, fullGuild.Members[i], true) + disgo.EntityBuilder().CreateMember(guild.ID, fullGuild.Members[i], api.CacheStrategyYes) } for i := range fullGuild.VoiceStates { - disgo.EntityBuilder().CreateVoiceState(fullGuild.VoiceStates[i], true) + disgo.EntityBuilder().CreateVoiceState(fullGuild.VoiceStates[i], api.CacheStrategyYes) } for i := range fullGuild.Emotes { - disgo.EntityBuilder().CreateEmote(guild.ID, fullGuild.Emotes[i], true) + disgo.EntityBuilder().CreateEmote(guild.ID, fullGuild.Emotes[i], api.CacheStrategyYes) } // TODO: presence diff --git a/internal/handlers/guild_delete_handler.go b/internal/handlers/guild_delete_handler.go index d59954d7..0ec12c69 100644 --- a/internal/handlers/guild_delete_handler.go +++ b/internal/handlers/guild_delete_handler.go @@ -25,6 +25,8 @@ func (h GuildDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api return } + guild = disgo.EntityBuilder().CreateGuild(guild, api.CacheStrategyNo) + if guild.Unavailable { // set guild to unavail for now disgo.Cache().Guild(guild.ID).Unavailable = true diff --git a/internal/handlers/guild_member_add_handler.go b/internal/handlers/guild_member_add_handler.go index f5cc4e43..2d5246ca 100644 --- a/internal/handlers/guild_member_add_handler.go +++ b/internal/handlers/guild_member_add_handler.go @@ -25,7 +25,7 @@ func (h GuildMemberAddHandler) HandleGatewayEvent(disgo api.Disgo, eventManager return } - member = disgo.EntityBuilder().CreateMember(member.GuildID, member, true) + member = disgo.EntityBuilder().CreateMember(member.GuildID, member, api.CacheStrategyYes) genericGuildEvent := events.GenericGuildEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), diff --git a/internal/handlers/guild_member_remove_handler.go b/internal/handlers/guild_member_remove_handler.go index 86afb193..572b603e 100644 --- a/internal/handlers/guild_member_remove_handler.go +++ b/internal/handlers/guild_member_remove_handler.go @@ -7,7 +7,7 @@ import ( type guildMemberRemoveData struct { GuildID api.Snowflake `json:"guild_id"` - User api.User `json:"user"` + User *api.User `json:"user"` } // GuildMemberRemoveHandler handles api.GuildMemberRemoveGatewayEvent @@ -30,6 +30,8 @@ func (h GuildMemberRemoveHandler) HandleGatewayEvent(disgo api.Disgo, eventManag return } + member.User = disgo.EntityBuilder().CreateUser(member.User, api.CacheStrategyYes) + oldMember := disgo.Cache().Member(member.GuildID, member.User.ID) disgo.Cache().UncacheMember(member.GuildID, member.User.ID) diff --git a/internal/handlers/guild_member_update_handler.go b/internal/handlers/guild_member_update_handler.go index 7a287c09..f482c749 100644 --- a/internal/handlers/guild_member_update_handler.go +++ b/internal/handlers/guild_member_update_handler.go @@ -29,7 +29,7 @@ func (h GuildMemberUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManag if oldMember != nil { oldMember = &*oldMember } - newMember = disgo.EntityBuilder().CreateMember(newMember.GuildID, newMember, true) + newMember = disgo.EntityBuilder().CreateMember(newMember.GuildID, newMember, api.CacheStrategyYes) genericGuildEvent := events.GenericGuildEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), diff --git a/internal/handlers/guild_role_create_handler.go b/internal/handlers/guild_role_create_handler.go index 507779aa..429ce03d 100644 --- a/internal/handlers/guild_role_create_handler.go +++ b/internal/handlers/guild_role_create_handler.go @@ -30,7 +30,7 @@ func (h GuildRoleCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager return } - role := disgo.EntityBuilder().CreateRole(roleCreateData.GuildID, roleCreateData.Role, true) + role := disgo.EntityBuilder().CreateRole(roleCreateData.GuildID, roleCreateData.Role, api.CacheStrategyYes) genericGuildEvent := events.GenericGuildEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), diff --git a/internal/handlers/guild_role_update_handler.go b/internal/handlers/guild_role_update_handler.go index 538ca1c3..4e56a83d 100644 --- a/internal/handlers/guild_role_update_handler.go +++ b/internal/handlers/guild_role_update_handler.go @@ -34,7 +34,7 @@ func (h GuildRoleUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager if oldRole != nil { oldRole = &*oldRole } - newRole := disgo.EntityBuilder().CreateRole(roleUpdateData.GuildID, roleUpdateData.Role, true) + newRole := disgo.EntityBuilder().CreateRole(roleUpdateData.GuildID, roleUpdateData.Role, api.CacheStrategyYes) genericGuildEvent := events.GenericGuildEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), diff --git a/internal/handlers/guild_update_handler.go b/internal/handlers/guild_update_handler.go index 79409052..2a8a5da5 100644 --- a/internal/handlers/guild_update_handler.go +++ b/internal/handlers/guild_update_handler.go @@ -29,7 +29,7 @@ func (h GuildUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api if oldGuild != nil { oldGuild = &*oldGuild } - newGuild = disgo.EntityBuilder().CreateGuild(newGuild, true) + newGuild = disgo.EntityBuilder().CreateGuild(newGuild, api.CacheStrategyYes) genericGuildEvent := events.GenericGuildEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), diff --git a/internal/handlers/voice_server_update_handler.go b/internal/handlers/voice_server_update_handler.go index d5e808e9..4b58ecff 100644 --- a/internal/handlers/voice_server_update_handler.go +++ b/internal/handlers/voice_server_update_handler.go @@ -22,13 +22,10 @@ func (h VoiceServerUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManag return } - if voiceServerUpdate.Endpoint == nil { - return - } - - voiceServerUpdate.Disgo = disgo - if interceptor := disgo.VoiceDispatchInterceptor(); interceptor != nil { - interceptor.OnVoiceServerUpdate(*voiceServerUpdate) + interceptor.OnVoiceServerUpdate(api.VoiceServerUpdateEvent{ + VoiceServerUpdate: *voiceServerUpdate, + Disgo: disgo, + }) } } diff --git a/internal/handlers/voice_state_update_handler.go b/internal/handlers/voice_state_update_handler.go index 59f8124b..43478e0f 100644 --- a/internal/handlers/voice_state_update_handler.go +++ b/internal/handlers/voice_state_update_handler.go @@ -14,12 +14,12 @@ func (h VoiceStateUpdateHandler) Event() api.GatewayEventType { // New constructs a new payload receiver for the raw gateway event func (h VoiceStateUpdateHandler) New() interface{} { - return &api.VoiceStateUpdate{} + return &api.VoiceStateUpdateEvent{} } // HandleGatewayEvent handles the specific raw gateway event func (h VoiceStateUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { - voiceStateUpdate, ok := i.(*api.VoiceStateUpdate) + voiceStateUpdate, ok := i.(*api.VoiceStateUpdateEvent) if !ok { return } diff --git a/internal/restclient_impl.go b/internal/restclient_impl.go index f4adbc64..a272c124 100644 --- a/internal/restclient_impl.go +++ b/internal/restclient_impl.go @@ -91,8 +91,8 @@ func (r RestClientImpl) Request(route endpoints.CompiledAPIRoute, rqBody interfa r.Disgo().EventManager().Dispatch(events.HttpRequestEvent{ GenericEvent: events.NewEvent(r.Disgo(), 0), - Request: rq, - Response: rs, + Request: rq, + Response: rs, }) switch rs.StatusCode { @@ -136,38 +136,49 @@ func (r RestClientImpl) Request(route endpoints.CompiledAPIRoute, rqBody interfa } // SendMessage lets you send a api.Message to a api.MessageChannel -func (r RestClientImpl) SendMessage(channelID api.Snowflake, message api.MessageCreate) (rMessage *api.Message, err error) { - err = r.Request(endpoints.CreateMessage.Compile(channelID), message, &rMessage) - if rMessage != nil { - //r.Disgo().Cache().CacheMessage(rMessage) +func (r RestClientImpl) SendMessage(channelID api.Snowflake, message api.MessageCreate) (msg *api.Message, err error) { + err = r.Request(endpoints.CreateMessage.Compile(channelID), message, &msg) + if err == nil { + msg = r.Disgo().EntityBuilder().CreateMessage(msg, api.CacheStrategyNoWs) } return } // EditMessage lets you edit a api.Message -func (r RestClientImpl) EditMessage(channelID api.Snowflake, messageID api.Snowflake, message api.MessageUpdate) (rMessage *api.Message, err error) { - err = r.Request(endpoints.UpdateMessage.Compile(channelID, messageID), message, &rMessage) - if rMessage != nil { - //r.Disgo().Cache().CacheMessage(rMessage) +func (r RestClientImpl) EditMessage(channelID api.Snowflake, messageID api.Snowflake, message api.MessageUpdate) (msg *api.Message, err error) { + err = r.Request(endpoints.UpdateMessage.Compile(channelID, messageID), message, &msg) + if err == nil { + msg = r.Disgo().EntityBuilder().CreateMessage(msg, api.CacheStrategyNoWs) } return } // DeleteMessage lets you delete a api.Message -func (r RestClientImpl) DeleteMessage(channelID api.Snowflake, messageID api.Snowflake) error { - return r.Request(endpoints.DeleteMessage.Compile(channelID, messageID), nil, nil) +func (r RestClientImpl) DeleteMessage(channelID api.Snowflake, messageID api.Snowflake) (err error) { + err = r.Request(endpoints.DeleteMessage.Compile(channelID, messageID), nil, nil) + if err == nil && api.CacheStrategyNoWs(r.Disgo()) { + r.Disgo().Cache().UncacheMessage(channelID, messageID) + } + return } // BulkDeleteMessages lets you bulk delete api.Message(s) -func (r RestClientImpl) BulkDeleteMessages(channelID api.Snowflake, messageIDs ...api.Snowflake) error { - return r.Request(endpoints.BulkDeleteMessage.Compile(channelID), api.MessageBulkDelete{Messages: messageIDs}, nil) +func (r RestClientImpl) BulkDeleteMessages(channelID api.Snowflake, messageIDs ...api.Snowflake) (err error) { + err = r.Request(endpoints.BulkDeleteMessage.Compile(channelID), api.MessageBulkDelete{Messages: messageIDs}, nil) + if err == nil && api.CacheStrategyNoWs(r.Disgo()) { + // TODO: check here if no err means all messages deleted + for _, messageID := range messageIDs { + r.Disgo().Cache().UncacheMessage(channelID, messageID) + } + } + return } // CrosspostMessage lets you crosspost a api.Message in a channel with type api.ChannelTypeNews -func (r RestClientImpl) CrosspostMessage(channelID api.Snowflake, messageID api.Snowflake) (rMessage *api.Message, err error) { - err = r.Request(endpoints.CrosspostMessage.Compile(channelID, messageID), nil, &rMessage) - if rMessage != nil { - //r.Disgo().Cache().CacheMessage(rMessage) +func (r RestClientImpl) CrosspostMessage(channelID api.Snowflake, messageID api.Snowflake) (msg *api.Message, err error) { + err = r.Request(endpoints.CrosspostMessage.Compile(channelID, messageID), nil, &msg) + if err == nil { + msg = r.Disgo().EntityBuilder().CreateMessage(msg, api.CacheStrategyNoWs) } return } @@ -180,9 +191,8 @@ func (r RestClientImpl) OpenDMChannel(userID api.Snowflake) (channel *api.DMChan RecipientID: userID, } err = r.Request(endpoints.CreateDMChannel.Compile(), body, &channel) - if channel != nil { - channel.Disgo = r.Disgo() - r.Disgo().Cache().CacheDMChannel(channel) + if err == nil { + channel = r.Disgo().EntityBuilder().CreateDMChannel(&channel.MessageChannel.Channel, api.CacheStrategyNoWs) } return } @@ -191,7 +201,7 @@ func (r RestClientImpl) OpenDMChannel(userID api.Snowflake) (channel *api.DMChan func (r RestClientImpl) UpdateSelfNick(guildID api.Snowflake, nick *string) (newNick *string, err error) { var updateNick *api.UpdateSelfNick err = r.Request(endpoints.UpdateSelfNick.Compile(guildID), api.UpdateSelfNick{Nick: nick}, &updateNick) - if updateNick != nil { + if err == nil && api.CacheStrategyNoWs(r.Disgo()) { r.Disgo().Cache().Member(guildID, r.Disgo().SelfUserID()).Nick = updateNick.Nick newNick = updateNick.Nick } @@ -201,8 +211,8 @@ func (r RestClientImpl) UpdateSelfNick(guildID api.Snowflake, nick *string) (new // GetUser fetches the specific user func (r RestClientImpl) GetUser(userID api.Snowflake) (user *api.User, err error) { err = r.Request(endpoints.GetUser.Compile(userID), nil, &user) - if user != nil { - r.Disgo().Cache().CacheUser(user) + if err == nil { + user = r.Disgo().EntityBuilder().CreateUser(user, api.CacheStrategyNoWs) } return } @@ -210,8 +220,8 @@ func (r RestClientImpl) GetUser(userID api.Snowflake) (user *api.User, err error // GetMember fetches the specific member func (r RestClientImpl) GetMember(guildID api.Snowflake, userID api.Snowflake) (member *api.Member, err error) { err = r.Request(endpoints.GetMember.Compile(guildID, userID), nil, &member) - if member != nil { - r.Disgo().Cache().CacheMember(member) + if err == nil { + member = r.Disgo().EntityBuilder().CreateMember(guildID, member, api.CacheStrategyNoWs) } return } @@ -219,9 +229,9 @@ func (r RestClientImpl) GetMember(guildID api.Snowflake, userID api.Snowflake) ( // GetMembers fetches all members for a guild func (r RestClientImpl) GetMembers(guildID api.Snowflake) (members []*api.Member, err error) { err = r.Request(endpoints.GetMembers.Compile(guildID), nil, &members) - if members != nil { + if err == nil { for _, member := range members { - r.Disgo().Cache().CacheMember(member) + member = r.Disgo().EntityBuilder().CreateMember(guildID, member, api.CacheStrategyNoWs) } } return @@ -230,8 +240,8 @@ func (r RestClientImpl) GetMembers(guildID api.Snowflake) (members []*api.Member // AddMember adds a member to the guild with the oauth2 access BotToken. requires api.PermissionCreateInstantInvite func (r RestClientImpl) AddMember(guildID api.Snowflake, userID api.Snowflake, addGuildMemberData api.AddGuildMemberData) (member *api.Member, err error) { err = r.Request(endpoints.AddMember.Compile(guildID, userID), addGuildMemberData, &member) - if member != nil { - r.Disgo().Cache().CacheMember(member) + if err == nil { + member = r.Disgo().EntityBuilder().CreateMember(guildID, member, api.CacheStrategyNoWs) } return } @@ -246,7 +256,7 @@ func (r RestClientImpl) KickMember(guildID api.Snowflake, userID api.Snowflake, } err = r.Request(route, nil, nil) - if err == nil { + if err == nil && api.CacheStrategyNoWs(r.Disgo()) { r.Disgo().Cache().UncacheMember(guildID, userID) } return @@ -255,8 +265,8 @@ func (r RestClientImpl) KickMember(guildID api.Snowflake, userID api.Snowflake, // UpdateMember updates a member func (r RestClientImpl) UpdateMember(guildID api.Snowflake, userID api.Snowflake, updateGuildMemberData api.UpdateGuildMemberData) (member *api.Member, err error) { err = r.Request(endpoints.UpdateMember.Compile(guildID, userID), updateGuildMemberData, &member) - if member != nil { - r.Disgo().Cache().CacheMember(member) + if err == nil { + member = r.Disgo().EntityBuilder().CreateMember(guildID, member, api.CacheStrategyNoWs) } return } @@ -264,8 +274,8 @@ func (r RestClientImpl) UpdateMember(guildID api.Snowflake, userID api.Snowflake // MoveMember moves/kicks the member to/from a voice channel func (r RestClientImpl) MoveMember(guildID api.Snowflake, userID api.Snowflake, channelID *api.Snowflake) (member *api.Member, err error) { err = r.Request(endpoints.UpdateMember.Compile(guildID, userID), api.MoveGuildMemberData{ChannelID: channelID}, &member) - if member != nil { - r.Disgo().Cache().CacheMember(member) + if err == nil { + member = r.Disgo().EntityBuilder().CreateMember(guildID, member, api.CacheStrategyNoWs) } return } @@ -273,7 +283,7 @@ func (r RestClientImpl) MoveMember(guildID api.Snowflake, userID api.Snowflake, // AddMemberRole adds a role to a member func (r RestClientImpl) AddMemberRole(guildID api.Snowflake, userID api.Snowflake, roleID api.Snowflake) (err error) { err = r.Request(endpoints.AddMemberRole.Compile(guildID, userID, roleID), nil, nil) - if err == nil { + if err == nil && api.CacheStrategyNoWs(r.Disgo()) { member := r.Disgo().Cache().Member(guildID, userID) if member != nil { member.Roles = append(member.Roles, roleID) @@ -285,7 +295,7 @@ func (r RestClientImpl) AddMemberRole(guildID api.Snowflake, userID api.Snowflak // RemoveMemberRole removes a role from a member func (r RestClientImpl) RemoveMemberRole(guildID api.Snowflake, userID api.Snowflake, roleID api.Snowflake) (err error) { err = r.Request(endpoints.RemoveMemberRole.Compile(guildID, userID, roleID), nil, nil) - if err == nil { + if err == nil && api.CacheStrategyNoWs(r.Disgo()) { member := r.Disgo().Cache().Member(guildID, userID) if member != nil { for i, id := range member.Roles { @@ -302,11 +312,9 @@ func (r RestClientImpl) RemoveMemberRole(guildID api.Snowflake, userID api.Snowf // GetRoles fetches all roles from a guild func (r RestClientImpl) GetRoles(guildID api.Snowflake) (roles []*api.Role, err error) { err = r.Request(endpoints.GetRoles.Compile(guildID), nil, &roles) - if roles != nil { + if err == nil { for _, role := range roles { - role.Disgo = r.disgo - role.GuildID = guildID - r.disgo.Cache().CacheRole(role) + role = r.Disgo().EntityBuilder().CreateRole(guildID, role, api.CacheStrategyNoWs) } } return @@ -315,10 +323,8 @@ func (r RestClientImpl) GetRoles(guildID api.Snowflake) (roles []*api.Role, err // CreateRole creates a new role for a guild. Requires api.PermissionManageRoles func (r RestClientImpl) CreateRole(guildID api.Snowflake, role api.UpdateRole) (newRole *api.Role, err error) { err = r.Request(endpoints.CreateRole.Compile(guildID), role, &newRole) - if newRole != nil { - newRole.Disgo = r.disgo - newRole.GuildID = guildID - r.disgo.Cache().CacheRole(newRole) + if err == nil { + newRole = r.Disgo().EntityBuilder().CreateRole(guildID, newRole, api.CacheStrategyNoWs) } return } @@ -326,10 +332,8 @@ func (r RestClientImpl) CreateRole(guildID api.Snowflake, role api.UpdateRole) ( // UpdateRole updates a role from a guild. Requires api.PermissionManageRoles func (r RestClientImpl) UpdateRole(guildID api.Snowflake, roleID api.Snowflake, role api.UpdateRole) (newRole *api.Role, err error) { err = r.Request(endpoints.UpdateRole.Compile(guildID, roleID), role, &newRole) - if newRole != nil { - newRole.Disgo = r.disgo - newRole.GuildID = guildID - r.disgo.Cache().CacheRole(newRole) + if err == nil { + newRole = r.Disgo().EntityBuilder().CreateRole(guildID, newRole, api.CacheStrategyNoWs) } return } @@ -337,11 +341,9 @@ func (r RestClientImpl) UpdateRole(guildID api.Snowflake, roleID api.Snowflake, // UpdateRolePositions updates the position of a role from a guild. Requires api.PermissionManageRoles func (r RestClientImpl) UpdateRolePositions(guildID api.Snowflake, roleUpdates ...api.UpdateRolePosition) (roles []*api.Role, err error) { err = r.Request(endpoints.GetRoles.Compile(guildID), roleUpdates, &roles) - if roles != nil { + if err == nil { for _, role := range roles { - role.Disgo = r.disgo - role.GuildID = guildID - r.disgo.Cache().CacheRole(role) + role = r.Disgo().EntityBuilder().CreateRole(guildID, role, api.CacheStrategyNoWs) } } return @@ -350,7 +352,7 @@ func (r RestClientImpl) UpdateRolePositions(guildID api.Snowflake, roleUpdates . // DeleteRole deletes a role from a guild. Requires api.PermissionManageRoles func (r RestClientImpl) DeleteRole(guildID api.Snowflake, roleID api.Snowflake) (err error) { err = r.Request(endpoints.UpdateRole.Compile(guildID, roleID), nil, nil) - if err == nil { + if err == nil && api.CacheStrategyNoWs(r.Disgo()) { r.disgo.Cache().UncacheRole(guildID, roleID) } return @@ -374,152 +376,165 @@ func (r RestClientImpl) RemoveUserReaction(channelID api.Snowflake, messageID ap // GetGlobalCommands gets you all global commands func (r RestClientImpl) GetGlobalCommands(applicationID api.Snowflake) (commands []*api.Command, err error) { err = r.Request(endpoints.GetGlobalCommands.Compile(applicationID), nil, &commands) - if err != nil { - return - } - for _, cmd := range commands { - cmd.Disgo = r.disgo + if err == nil { + for _, cmd := range commands { + cmd = r.Disgo().EntityBuilder().CreateGlobalCommand(cmd, api.CacheStrategyNoWs) + } } return } // GetGlobalCommand gets you a specific global global command -func (r RestClientImpl) GetGlobalCommand(applicationID api.Snowflake, commandID api.Snowflake) (rCommand *api.Command, err error) { - err = r.Request(endpoints.GetGlobalCommand.Compile(applicationID, commandID), nil, &rCommand) - if err != nil { - return +func (r RestClientImpl) GetGlobalCommand(applicationID api.Snowflake, commandID api.Snowflake) (cmd *api.Command, err error) { + err = r.Request(endpoints.GetGlobalCommand.Compile(applicationID, commandID), nil, &cmd) + if err == nil { + cmd = r.Disgo().EntityBuilder().CreateGlobalCommand(cmd, api.CacheStrategyNoWs) } - rCommand.Disgo = r.disgo return } // CreateGlobalCommand lets you create a new global command -func (r RestClientImpl) CreateGlobalCommand(applicationID api.Snowflake, command api.Command) (rCommand *api.Command, err error) { - err = r.Request(endpoints.CreateGlobalCommand.Compile(applicationID), command, &rCommand) - if err != nil { - return +func (r RestClientImpl) CreateGlobalCommand(applicationID api.Snowflake, command api.Command) (cmd *api.Command, err error) { + err = r.Request(endpoints.CreateGlobalCommand.Compile(applicationID), command, &cmd) + if err == nil { + cmd = r.Disgo().EntityBuilder().CreateGlobalCommand(cmd, api.CacheStrategyNoWs) } - rCommand.Disgo = r.disgo return } // SetGlobalCommands lets you override all global commands -func (r RestClientImpl) SetGlobalCommands(applicationID api.Snowflake, commands ...api.Command) (rCommands []*api.Command, err error) { +func (r RestClientImpl) SetGlobalCommands(applicationID api.Snowflake, commands ...api.Command) (cmds []*api.Command, err error) { if len(commands) > 100 { err = api.ErrTooMuchApplicationCommands return } - err = r.Request(endpoints.SetGlobalCommands.Compile(applicationID), commands, &rCommands) - if err != nil { - return - } - for _, cmd := range rCommands { - cmd.Disgo = r.disgo + err = r.Request(endpoints.SetGlobalCommands.Compile(applicationID), commands, &cmds) + if err == nil { + for _, cmd := range cmds { + cmd = r.Disgo().EntityBuilder().CreateGlobalCommand(cmd, api.CacheStrategyNoWs) + } } return } // EditGlobalCommand lets you edit a specific global command -func (r RestClientImpl) EditGlobalCommand(applicationID api.Snowflake, commandID api.Snowflake, command api.UpdateCommand) (rCommand *api.Command, err error) { - err = r.Request(endpoints.EditGlobalCommand.Compile(applicationID, commandID), command, &rCommand) - if err != nil { - return +func (r RestClientImpl) EditGlobalCommand(applicationID api.Snowflake, commandID api.Snowflake, command api.UpdateCommand) (cmd *api.Command, err error) { + err = r.Request(endpoints.EditGlobalCommand.Compile(applicationID, commandID), command, &cmd) + if err == nil { + cmd = r.Disgo().EntityBuilder().CreateGlobalCommand(cmd, api.CacheStrategyNoWs) } - rCommand.Disgo = r.disgo return } // DeleteGlobalCommand lets you delete a specific global command -func (r RestClientImpl) DeleteGlobalCommand(applicationID api.Snowflake, commandID api.Snowflake) error { - return r.Request(endpoints.DeleteGlobalCommand.Compile(applicationID, commandID), nil, nil) +func (r RestClientImpl) DeleteGlobalCommand(applicationID api.Snowflake, commandID api.Snowflake) (err error) { + err = r.Request(endpoints.DeleteGlobalCommand.Compile(applicationID, commandID), nil, nil) + if err == nil && api.CacheStrategyNoWs(r.Disgo()) { + r.Disgo().Cache().UncacheCommand(commandID) + } + return } // GetGuildCommands gets you all guild_events commands func (r RestClientImpl) GetGuildCommands(applicationID api.Snowflake, guildID api.Snowflake) (commands []*api.Command, err error) { err = r.Request(endpoints.GetGuildCommands.Compile(applicationID, guildID), nil, &commands) - if err != nil { - return - } - for _, cmd := range commands { - cmd.Disgo = r.disgo - cmd.GuildID = &guildID + if err == nil { + for _, cmd := range commands { + cmd = r.Disgo().EntityBuilder().CreateGuildCommand(guildID, cmd, api.CacheStrategyNoWs) + } } return } // CreateGuildCommand lets you create a new guild_events command -func (r RestClientImpl) CreateGuildCommand(applicationID api.Snowflake, guildID api.Snowflake, command api.Command) (rCommand *api.Command, err error) { - err = r.Request(endpoints.CreateGuildCommand.Compile(applicationID, guildID), command, &rCommand) - if err != nil { - return +func (r RestClientImpl) CreateGuildCommand(applicationID api.Snowflake, guildID api.Snowflake, command api.Command) (cmd *api.Command, err error) { + err = r.Request(endpoints.CreateGuildCommand.Compile(applicationID, guildID), command, &cmd) + if err == nil { + cmd = r.Disgo().EntityBuilder().CreateGuildCommand(guildID, cmd, api.CacheStrategyNoWs) } - rCommand.Disgo = r.disgo - rCommand.GuildID = &guildID return } // SetGuildCommands lets you override all guild_events commands -func (r RestClientImpl) SetGuildCommands(applicationID api.Snowflake, guildID api.Snowflake, commands ...api.Command) (rCommands []*api.Command, err error) { +func (r RestClientImpl) SetGuildCommands(applicationID api.Snowflake, guildID api.Snowflake, commands ...api.Command) (cmds []*api.Command, err error) { if len(commands) > 100 { err = api.ErrTooMuchApplicationCommands return } - err = r.Request(endpoints.SetGuildCommands.Compile(applicationID, guildID), commands, &rCommands) - if err != nil { - return - } - for _, cmd := range rCommands { - cmd.Disgo = r.disgo - cmd.GuildID = &guildID + err = r.Request(endpoints.SetGuildCommands.Compile(applicationID, guildID), commands, &cmds) + if err == nil { + for _, cmd := range cmds { + cmd = r.Disgo().EntityBuilder().CreateGuildCommand(guildID, cmd, api.CacheStrategyNoWs) + } } return } // GetGuildCommand gets you a specific guild_events command -func (r RestClientImpl) GetGuildCommand(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake) (rCommand *api.Command, err error) { - err = r.Request(endpoints.GetGuildCommand.Compile(applicationID, guildID, commandID), nil, &rCommand) - if err != nil { - return +func (r RestClientImpl) GetGuildCommand(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake) (cmd *api.Command, err error) { + err = r.Request(endpoints.GetGuildCommand.Compile(applicationID, guildID, commandID), nil, &cmd) + if err == nil { + cmd = r.Disgo().EntityBuilder().CreateGuildCommand(guildID, cmd, api.CacheStrategyNoWs) } - rCommand.Disgo = r.disgo - rCommand.GuildID = &guildID return } // EditGuildCommand lets you edit a specific guild_events command -func (r RestClientImpl) EditGuildCommand(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake, command api.UpdateCommand) (rCommand *api.Command, err error) { - err = r.Request(endpoints.EditGuildCommand.Compile(applicationID, guildID, commandID), command, &rCommand) - if err != nil { - return +func (r RestClientImpl) EditGuildCommand(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake, command api.UpdateCommand) (cmd *api.Command, err error) { + err = r.Request(endpoints.EditGuildCommand.Compile(applicationID, guildID, commandID), command, &cmd) + if err == nil { + cmd = r.Disgo().EntityBuilder().CreateGuildCommand(guildID, cmd, api.CacheStrategyNoWs) } - rCommand.Disgo = r.disgo - rCommand.GuildID = &guildID return } // DeleteGuildCommand lets you delete a specific guild_events command -func (r RestClientImpl) DeleteGuildCommand(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake) error { - return r.Request(endpoints.DeleteGuildCommand.Compile(applicationID, guildID, commandID), nil, nil) +func (r RestClientImpl) DeleteGuildCommand(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake) (err error) { + err = r.Request(endpoints.DeleteGuildCommand.Compile(applicationID, guildID, commandID), nil, nil) + if err == nil && api.CacheStrategyNoWs(r.Disgo()) { + r.Disgo().Cache().UncacheCommand(commandID) + } + return } // GetGuildCommandsPermissions returns the api.CommandPermission for a all api.Command(s) in a guild -func (r RestClientImpl) GetGuildCommandsPermissions(applicationID api.Snowflake, guildID api.Snowflake) (rCommandsPermissions []*api.GuildCommandPermissions, err error) { - return rCommandsPermissions, r.Request(endpoints.GetGuildCommandPermissions.Compile(applicationID, guildID), nil, &rCommandsPermissions) +func (r RestClientImpl) GetGuildCommandsPermissions(applicationID api.Snowflake, guildID api.Snowflake) (cmdsPerms []*api.GuildCommandPermissions, err error) { + err = r.Request(endpoints.GetGuildCommandPermissions.Compile(applicationID, guildID), nil, &cmdsPerms) + if err == nil { + for _, cmdPerms := range cmdsPerms { + cmdPerms = r.Disgo().EntityBuilder().CreateGuildCommandPermissions(cmdPerms, api.CacheStrategyNoWs) + } + } + return } // GetGuildCommandPermissions returns the api.CommandPermission for a specific api.Command in a guild -func (r RestClientImpl) GetGuildCommandPermissions(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake) (rCommandPermissions *api.GuildCommandPermissions, err error) { - return rCommandPermissions, r.Request(endpoints.GetGuildCommandPermission.Compile(applicationID, guildID, commandID), nil, &rCommandPermissions) +func (r RestClientImpl) GetGuildCommandPermissions(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake) (cmdPerms *api.GuildCommandPermissions, err error) { + err = r.Request(endpoints.GetGuildCommandPermission.Compile(applicationID, guildID, commandID), nil, &cmdPerms) + if err == nil { + cmdPerms = r.Disgo().EntityBuilder().CreateGuildCommandPermissions(cmdPerms, api.CacheStrategyNoWs) + } + return } // SetGuildCommandsPermissions sets the api.GuildCommandPermissions for a all api.Command(s) -func (r RestClientImpl) SetGuildCommandsPermissions(applicationID api.Snowflake, guildID api.Snowflake, commandsPermissions ...api.SetGuildCommandPermissions) (rCommandsPermissions []*api.GuildCommandPermissions, err error) { - return rCommandsPermissions, r.Request(endpoints.SetGuildCommandsPermissions.Compile(applicationID, guildID), api.SetGuildCommandsPermissions(commandsPermissions), &rCommandsPermissions) +func (r RestClientImpl) SetGuildCommandsPermissions(applicationID api.Snowflake, guildID api.Snowflake, commandsPermissions ...api.SetGuildCommandPermissions) (cmdsPerms []*api.GuildCommandPermissions, err error) { + err = r.Request(endpoints.SetGuildCommandsPermissions.Compile(applicationID, guildID), api.SetGuildCommandsPermissions(commandsPermissions), &cmdsPerms) + if err == nil { + for _, cmdPerms := range cmdsPerms { + cmdPerms = r.Disgo().EntityBuilder().CreateGuildCommandPermissions(cmdPerms, api.CacheStrategyNoWs) + } + } + return } // SetGuildCommandPermissions sets the api.GuildCommandPermissions for a specific api.Command -func (r RestClientImpl) SetGuildCommandPermissions(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake, commandPermissions api.SetGuildCommandPermissions) (rCommandPermissions *api.GuildCommandPermissions, err error) { - return rCommandPermissions, r.Request(endpoints.SetGuildCommandPermissions.Compile(applicationID, guildID, commandID), commandPermissions, &rCommandPermissions) +func (r RestClientImpl) SetGuildCommandPermissions(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake, commandPermissions api.SetGuildCommandPermissions) (cmdPerms *api.GuildCommandPermissions, err error) { + err = r.Request(endpoints.SetGuildCommandPermissions.Compile(applicationID, guildID, commandID), commandPermissions, &cmdPerms) + if err == nil { + cmdPerms = r.Disgo().EntityBuilder().CreateGuildCommandPermissions(cmdPerms, api.CacheStrategyNoWs) + } + return } // SendInteractionResponse used to send the initial response on an interaction diff --git a/testbot/testbot.go b/testbot/testbot.go index 2e693c66..1aa3b42b 100644 --- a/testbot/testbot.go +++ b/testbot/testbot.go @@ -29,7 +29,7 @@ func main() { log.Info("starting testbot...") dgo, err := disgo.NewBuilder(endpoints.Token(os.Getenv("token"))). - SetLogLevel(log.InfoLevel). + SetLogLevel(log.DebugLevel). SetIntents(api.IntentsGuilds | api.IntentsGuildMessages | api.IntentsGuildMembers). SetMemberCachePolicy(api.MemberCachePolicyAll). AddEventListeners(&events.ListenerAdapter{ From 308d669026bd4a2c697557bdc5e79294be6c6148 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Sun, 11 Apr 2021 04:21:55 +0200 Subject: [PATCH 42/65] fixed stuffu --- internal/handlers/channel_update_handler.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/handlers/channel_update_handler.go b/internal/handlers/channel_update_handler.go index d0e0b8f5..c883cae7 100644 --- a/internal/handlers/channel_update_handler.go +++ b/internal/handlers/channel_update_handler.go @@ -38,7 +38,7 @@ func (h ChannelUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a if oldDMChannel != nil { oldDMChannel = &*oldDMChannel } - newDMChannel := disgo.EntityBuilder().CreateDMChannel(channel, true) + newDMChannel := disgo.EntityBuilder().CreateDMChannel(channel, api.CacheStrategyYes) genericDMChannelEvent := events.GenericDMChannelEvent{ GenericChannelEvent: genericChannelEvent, @@ -59,7 +59,7 @@ func (h ChannelUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a if oldTextChannel != nil { oldTextChannel = &*oldTextChannel } - newTextChannel := disgo.EntityBuilder().CreateTextChannel(channel, true) + newTextChannel := disgo.EntityBuilder().CreateTextChannel(channel, api.CacheStrategyYes) genericTextChannelEvent := events.GenericTextChannelEvent{ GenericChannelEvent: genericChannelEvent, @@ -77,7 +77,7 @@ func (h ChannelUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a if oldStoreChannel != nil { oldStoreChannel = &*oldStoreChannel } - newStoreChannel := disgo.EntityBuilder().CreateStoreChannel(channel, true) + newStoreChannel := disgo.EntityBuilder().CreateStoreChannel(channel, api.CacheStrategyYes) genericStoreChannelEvent := events.GenericStoreChannelEvent{ GenericChannelEvent: genericChannelEvent, @@ -95,7 +95,7 @@ func (h ChannelUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a if oldCategory != nil { oldCategory = &*oldCategory } - newCategory := disgo.EntityBuilder().CreateCategory(channel, true) + newCategory := disgo.EntityBuilder().CreateCategory(channel, api.CacheStrategyYes) genericCategoryEvent := events.GenericCategoryEvent{ GenericChannelEvent: genericChannelEvent, @@ -113,7 +113,7 @@ func (h ChannelUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a if oldVoiceChannel != nil { oldVoiceChannel = &*oldVoiceChannel } - newVoiceChannel := disgo.EntityBuilder().CreateVoiceChannel(channel, true) + newVoiceChannel := disgo.EntityBuilder().CreateVoiceChannel(channel, api.CacheStrategyYes) genericVoiceChannelEvent := events.GenericVoiceChannelEvent{ GenericChannelEvent: genericChannelEvent, From 6a3fcad5e1e2933dfc8c43f5990ca221070da71c Mon Sep 17 00:00:00 2001 From: Alex <46286597+Alex-R-31@users.noreply.github.com> Date: Sun, 11 Apr 2021 11:33:36 +0100 Subject: [PATCH 43/65] typo --- internal/disgo_impl.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/disgo_impl.go b/internal/disgo_impl.go index 146518b8..e40fc577 100644 --- a/internal/disgo_impl.go +++ b/internal/disgo_impl.go @@ -167,7 +167,7 @@ func (d *DisgoImpl) LargeThreshold() int { return d.largeThreshold } -// HasGateway returns weather api.Disgo has an active api.Gateway connection or not +// HasGateway returns whether api.Disgo has an active api.Gateway connection or not func (d DisgoImpl) HasGateway() bool { return d.gateway != nil } From b49636ed1879e218ae33a3dcf8e9ebf56812d254 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Sun, 11 Apr 2021 14:30:54 +0200 Subject: [PATCH 44/65] added injectable logger --- api/disgo.go | 3 + api/disgo_builder.go | 4 +- api/endpoints/api_route.go | 14 +- api/endpoints/cdn_route.go | 32 ++- api/endpoints/custom_route.go | 12 +- api/endpoints/route.go | 13 +- api/events/guild_invite_events.go | 6 +- api/events/listener_adapter.go | 6 +- api/guild.go | 16 +- api/options.go | 3 + api/webhook_server.go | 5 +- go.mod | 3 +- internal/cache_impl.go | 10 +- internal/disgo_builder_impl.go | 18 +- internal/disgo_impl.go | 14 +- internal/event_manager_impl.go | 25 +- internal/gateway_impl.go | 87 +++--- internal/handlers/channel_create_handler.go | 5 +- internal/handlers/channel_delete_handler.go | 5 +- internal/handlers/channel_update_handler.go | 5 +- internal/restclient_impl.go | 303 ++++++++++++++++---- internal/webhook_server_impl.go | 17 +- testbot/go.mod | 11 + testbot/go.sum | 27 ++ testbot/testbot.go | 21 +- 25 files changed, 460 insertions(+), 205 deletions(-) create mode 100644 testbot/go.mod create mode 100644 testbot/go.sum diff --git a/api/disgo.go b/api/disgo.go index a551f687..e56cecf2 100644 --- a/api/disgo.go +++ b/api/disgo.go @@ -7,10 +7,12 @@ import ( "time" "github.com/DisgoOrg/disgo/api/endpoints" + "github.com/DisgoOrg/log" ) // Disgo is the main discord interface type Disgo interface { + Logger() log.Logger Connect() error Start() Close() @@ -69,6 +71,7 @@ type Event interface { // EventManager lets you listen for specific events triggered by raw gateway events type EventManager interface { + Disgo() Disgo Close() AddEventListeners(eventListeners ...EventListener) Handle(eventType GatewayEventType, replyChannel chan interface{}, sequenceNumber int, payload json.RawMessage) diff --git a/api/disgo_builder.go b/api/disgo_builder.go index 9ed26a48..3857909b 100644 --- a/api/disgo_builder.go +++ b/api/disgo_builder.go @@ -1,14 +1,14 @@ package api import ( - log "github.com/sirupsen/logrus" + "github.com/DisgoOrg/log" "github.com/DisgoOrg/disgo/api/endpoints" ) // DisgoBuilder allows you to create a Disgo client through a series of methods type DisgoBuilder interface { - SetLogLevel(level log.Level) DisgoBuilder + SetLogger(level log.Logger) DisgoBuilder SetToken(token endpoints.Token) DisgoBuilder SetIntents(intents Intents) DisgoBuilder SetVoiceDispatchInterceptor(voiceDispatchInterceptor VoiceDispatchInterceptor) DisgoBuilder diff --git a/api/endpoints/api_route.go b/api/endpoints/api_route.go index d744c989..887d0d13 100644 --- a/api/endpoints/api_route.go +++ b/api/endpoints/api_route.go @@ -7,11 +7,15 @@ type APIRoute struct { } // Compile returns a CompiledAPIRoute -func (r APIRoute) Compile(args ...interface{}) CompiledAPIRoute { - return CompiledAPIRoute{ - CompiledRoute: r.Route.Compile(args...), - method: r.method, +func (r APIRoute) Compile(args ...interface{}) (*CompiledAPIRoute, error) { + compiledRoute, err := r.Route.Compile(args...) + if err != nil { + return nil, err } + return &CompiledAPIRoute{ + CompiledRoute: compiledRoute, + method: r.method, + }, nil } // Method returns the request method used by the route @@ -33,7 +37,7 @@ func NewAPIRoute(method Method, url string) APIRoute { // CompiledAPIRoute is APIRoute compiled with all URL args type CompiledAPIRoute struct { - CompiledRoute + *CompiledRoute method Method } diff --git a/api/endpoints/cdn_route.go b/api/endpoints/cdn_route.go index 5dc87015..7df913d3 100644 --- a/api/endpoints/cdn_route.go +++ b/api/endpoints/cdn_route.go @@ -1,17 +1,19 @@ package endpoints -import log "github.com/sirupsen/logrus" +import ( + "errors" +) // FileExtension is the type of an image on Discord's CDN type FileExtension string // The available FileExtension(s) const ( - PNG FileExtension = "png" - JPEG FileExtension = "jpg" - WEBP FileExtension = "webp" - GIF FileExtension = "gif" - BLANK FileExtension = "" + PNG FileExtension = "png" + JPEG FileExtension = "jpg" + WEBP FileExtension = "webp" + GIF FileExtension = "gif" + BLANK FileExtension = "" ) func (f FileExtension) String() string { @@ -37,7 +39,7 @@ func NewCDNRoute(url string, supportedFileExtensions ...FileExtension) CDNRoute } // Compile builds a full request URL based on provided arguments -func (r CDNRoute) Compile(fileExtension FileExtension, args ...interface{}) CompiledCDNRoute { +func (r CDNRoute) Compile(fileExtension FileExtension, args ...interface{}) (*CompiledCDNRoute, error) { supported := false for _, supportedFileExtension := range r.supportedFileExtensions { if supportedFileExtension == fileExtension { @@ -45,16 +47,20 @@ func (r CDNRoute) Compile(fileExtension FileExtension, args ...interface{}) Comp } } if !supported { - log.Infof("provided file extension: %s is not supported by discord on this endpoint!", fileExtension) + return nil, errors.New("provided file extension: " + fileExtension.String() + " is not supported by discord on this endpoint!") + } + compiledRoute, err := r.Route.Compile(args...) + if err != nil { + return nil, err } - compiledRoute := CompiledCDNRoute{ - CompiledRoute: r.Route.Compile(args...), + compiledRoute.route += fileExtension.String() + compiledCDNRoute := &CompiledCDNRoute{ + CompiledRoute: compiledRoute, } - compiledRoute.CompiledRoute.route += fileExtension.String() - return compiledRoute + return compiledCDNRoute, nil } // CompiledCDNRoute is CDNRoute compiled with all URL args type CompiledCDNRoute struct { - CompiledRoute + *CompiledRoute } diff --git a/api/endpoints/custom_route.go b/api/endpoints/custom_route.go index 2e0f26ab..64b26672 100644 --- a/api/endpoints/custom_route.go +++ b/api/endpoints/custom_route.go @@ -6,11 +6,15 @@ type CustomRoute struct { } // Compile returns a CompiledAPIRoute -func (r CustomRoute) Compile(args ...interface{}) CompiledAPIRoute { - return CompiledAPIRoute{ - CompiledRoute: r.Route.Compile(args...), - method: r.method, +func (r CustomRoute) Compile(args ...interface{}) (*CompiledAPIRoute, error) { + compiledRoute, err := r.Route.Compile(args...) + if err != nil { + return nil, err } + return &CompiledAPIRoute{ + CompiledRoute: compiledRoute, + method: r.method, + }, nil } // NewCustomRoute generates a new custom route struct diff --git a/api/endpoints/route.go b/api/endpoints/route.go index 50cc2157..79e250fc 100644 --- a/api/endpoints/route.go +++ b/api/endpoints/route.go @@ -1,10 +1,10 @@ package endpoints import ( + "errors" "fmt" + "strconv" "strings" - - log "github.com/sirupsen/logrus" ) // Route the base struct for routes used in disgo @@ -15,9 +15,9 @@ type Route struct { } // Compile builds a full request URL based on provided arguments -func (r Route) Compile(args ...interface{}) CompiledRoute { +func (r Route) Compile(args ...interface{}) (*CompiledRoute, error) { if len(args) != r.paramCount { - log.Errorf("invalid amount of arguments received. expected: %d, received: %d", r.paramCount, len(args)) + return nil, errors.New("invalid amount of arguments received. expected: " + strconv.Itoa(len(args)) + ", received: " + strconv.Itoa(r.paramCount)) } route := r.route if len(args) > 0 { @@ -34,7 +34,7 @@ func (r Route) Compile(args ...interface{}) CompiledRoute { } } - return CompiledRoute{route: r.baseRoute + route} + return &CompiledRoute{route: r.baseRoute + route}, nil } func NewRoute(url string) Route { @@ -47,9 +47,6 @@ func NewRoute(url string) Route { func countParams(url string) int { paramCount := strings.Count(url, "{") - if paramCount != strings.Count(url, "}") { - log.Errorf("invalid format for route provided: %s", url) - } return paramCount } diff --git a/api/events/guild_invite_events.go b/api/events/guild_invite_events.go index c8169796..7cfc047f 100644 --- a/api/events/guild_invite_events.go +++ b/api/events/guild_invite_events.go @@ -32,7 +32,11 @@ func (e GenericGuildInviteEvent) Category() *api.Category { } func (e GenericGuildInviteEvent) URL() string { - return endpoints.InviteURL.Compile(e.Code).Route() + url, err := endpoints.InviteURL.Compile(e.Code) + if err != nil { + return "" + } + return url.Route() } type GuildInviteCreateEvent struct { diff --git a/api/events/listener_adapter.go b/api/events/listener_adapter.go index 0154f230..9fd63f57 100644 --- a/api/events/listener_adapter.go +++ b/api/events/listener_adapter.go @@ -3,7 +3,7 @@ package events import ( "reflect" - log "github.com/sirupsen/logrus" + "github.com/DisgoOrg/disgo/api" ) // ListenerAdapter lets you override the handles for receiving events @@ -608,6 +608,8 @@ func (l ListenerAdapter) OnEvent(event interface{}) { } default: - log.Errorf("unexpected event received: \"%s\", event: \"%#e\"", reflect.TypeOf(event).Name(), event) + if e, ok := e.(api.Event); ok { + e.Disgo().Logger().Errorf("unexpected event received: \"%s\", event: \"%#e\"", reflect.TypeOf(event).Name(), event) + } } } diff --git a/api/guild.go b/api/guild.go index 01f577e9..2823d17e 100644 --- a/api/guild.go +++ b/api/guild.go @@ -121,11 +121,11 @@ type GuildPreview struct { // FullGuild represents a Guild objects sent by discord with the GatewayEventGuildCreate type FullGuild struct { *Guild - Roles []*Role `json:"roles"` - Emotes []*Emote `json:"emojis"` - Members []*Member `json:"members"` - Channels []*Channel `json:"channels"` - VoiceStates []*VoiceState `json:"voice_states"` + Roles []*Role `json:"roles"` + Emotes []*Emote `json:"emojis"` + Members []*Member `json:"members"` + Channels []*Channel `json:"channels"` + VoiceStates []*VoiceState `json:"voice_states"` //Presences []*Presence `json:"presences"` } @@ -191,7 +191,11 @@ func (g Guild) IconURL() *string { if animated { format = endpoints.GIF } - u := endpoints.GuildIcon.Compile(format, g.ID.String(), *g.Icon).Route() + route, err := endpoints.GuildIcon.Compile(format, g.ID.String(), *g.Icon) + if err != nil { + return nil + } + u := route.Route() return &u } diff --git a/api/options.go b/api/options.go index 062e8d80..87398788 100644 --- a/api/options.go +++ b/api/options.go @@ -1,7 +1,10 @@ package api +import "github.com/DisgoOrg/log" + // Options is the configuration used when creating the client type Options struct { + Logger log.Logger Intents Intents RestTimeout int EnableWebhookInteractions bool diff --git a/api/webhook_server.go b/api/webhook_server.go index 34c3d5b2..40312720 100644 --- a/api/webhook_server.go +++ b/api/webhook_server.go @@ -9,7 +9,6 @@ import ( "net/http" "github.com/gorilla/mux" - log "github.com/sirupsen/logrus" ) // WebhookServer is used for receiving an Interaction over http @@ -25,7 +24,7 @@ type WebhookServer interface { // Verify implements the verification side of the discord interactions api signing algorithm, as documented here: // https://discord.com/developers/docs/interactions/slash-commands#security-and-authorization // Credit: https://github.com/bsdlp/discord-interactions-go/blob/main/interactions/verify.go -func Verify(r *http.Request, key ed25519.PublicKey) bool { +func Verify(disgo Disgo, r *http.Request, key ed25519.PublicKey) bool { var msg bytes.Buffer signature := r.Header.Get("X-Signature-Ed25519") @@ -52,7 +51,7 @@ func Verify(r *http.Request, key ed25519.PublicKey) bool { defer func() { err = r.Body.Close() if err != nil { - log.Errorf("error while closing request body: %s", err) + disgo.Logger().Errorf("error while closing request body: %s", err) } }() var body bytes.Buffer diff --git a/go.mod b/go.mod index 64333e50..eeb9dc7c 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,8 @@ module github.com/DisgoOrg/disgo go 1.16 require ( - github.com/PaesslerAG/gval v1.1.0 + github.com/DisgoOrg/log v1.0.1 github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.4.2 - github.com/sirupsen/logrus v1.8.1 github.com/stretchr/testify v1.7.0 ) diff --git a/internal/cache_impl.go b/internal/cache_impl.go index da29cb58..1bdc30ca 100644 --- a/internal/cache_impl.go +++ b/internal/cache_impl.go @@ -5,8 +5,6 @@ import ( "strings" "time" - log "github.com/sirupsen/logrus" - "github.com/DisgoOrg/disgo/api" ) @@ -65,20 +63,20 @@ func (c *CacheImpl) Disgo() api.Disgo { // Close cleans up the cache and it's internal tasks func (c *CacheImpl) Close() { - log.Info("closing cache goroutines...") + c.Disgo().Logger().Info("closing cache goroutines...") c.quit <- true - log.Info("closed cache goroutines") + c.Disgo().Logger().Info("closed cache goroutines") } func (c CacheImpl) startCleanup(cleanupInterval time.Duration) { defer func() { if r := recover(); r != nil { - log.Errorf("recovered cache cleanup goroutine error: %s", r) + c.Disgo().Logger().Errorf("recovered cache cleanup goroutine error: %s", r) debug.PrintStack() c.startCleanup(cleanupInterval) return } - log.Info("shut down cache cleanup goroutine") + c.Disgo().Logger().Info("shut down cache cleanup goroutine") }() ticker := time.NewTicker(cleanupInterval) diff --git a/internal/disgo_builder_impl.go b/internal/disgo_builder_impl.go index dbea4d2f..16475d0d 100644 --- a/internal/disgo_builder_impl.go +++ b/internal/disgo_builder_impl.go @@ -3,7 +3,7 @@ package internal import ( "errors" - log "github.com/sirupsen/logrus" + "github.com/DisgoOrg/log" "github.com/DisgoOrg/disgo/api" "github.com/DisgoOrg/disgo/api/endpoints" @@ -12,7 +12,6 @@ import ( // NewBuilder returns a new api.DisgoBuilder instance func NewBuilder(token endpoints.Token) api.DisgoBuilder { return &DisgoBuilderImpl{ - logLevel: log.InfoLevel, BotToken: token, cacheFlags: api.CacheFlagsDefault, } @@ -20,7 +19,7 @@ func NewBuilder(token endpoints.Token) api.DisgoBuilder { // DisgoBuilderImpl implementation of the api.DisgoBuilder interface type DisgoBuilderImpl struct { - logLevel log.Level + logger log.Logger // make this public so it does not print in fmt.Sprint("%+v, DisgoBuilderImpl{}) BotToken endpoints.Token gateway api.Gateway @@ -40,9 +39,9 @@ type DisgoBuilderImpl struct { eventListeners []api.EventListener } -// SetLogLevel sets logrus.Level of logrus -func (b *DisgoBuilderImpl) SetLogLevel(logLevel log.Level) api.DisgoBuilder { - b.logLevel = logLevel +// SetLogger sets logger implementation disgo should use as an example logrus +func (b *DisgoBuilderImpl) SetLogger(logger log.Logger) api.DisgoBuilder { + b.logger = logger return b } @@ -148,9 +147,10 @@ func (b *DisgoBuilderImpl) SetGateway(gateway api.Gateway) api.DisgoBuilder { // Build builds your api.Disgo instance func (b *DisgoBuilderImpl) Build() (api.Disgo, error) { - log.SetLevel(b.logLevel) - disgo := &DisgoImpl{} + disgo := &DisgoImpl{ + logger: b.logger, + } if b.BotToken == "" { return nil, errors.New("please specify the BotToken") } @@ -158,7 +158,7 @@ func (b *DisgoBuilderImpl) Build() (api.Disgo, error) { id, err := IDFromToken(disgo.BotToken) if err != nil { - log.Errorf("error while getting application id from BotToken: %s", err) + disgo.Logger().Errorf("error while getting application id from BotToken: %s", err) return nil, err } diff --git a/internal/disgo_impl.go b/internal/disgo_impl.go index e40fc577..9c5bf988 100644 --- a/internal/disgo_impl.go +++ b/internal/disgo_impl.go @@ -3,7 +3,7 @@ package internal import ( "time" - log "github.com/sirupsen/logrus" + "github.com/DisgoOrg/log" "github.com/DisgoOrg/disgo/api" "github.com/DisgoOrg/disgo/api/endpoints" @@ -16,15 +16,17 @@ func New(token endpoints.Token, options api.Options) (api.Disgo, error) { } else if options.LargeThreshold > 250 { options.LargeThreshold = 250 } + disgo := &DisgoImpl{ BotToken: token, intents: options.Intents, largeThreshold: options.LargeThreshold, + logger: options.Logger, } id, err := IDFromToken(token) if err != nil { - log.Errorf("error while getting application id from BotToken: %s", err) + disgo.Logger().Errorf("error while getting application id from BotToken: %s", err) return nil, err } @@ -49,6 +51,7 @@ func New(token endpoints.Token, options api.Options) (api.Disgo, error) { type DisgoImpl struct { // make this public so it does not print in fmt.Sprint("%+v, DisgoImpl{}) BotToken endpoints.Token + logger log.Logger gateway api.Gateway restClient api.RestClient intents api.Intents @@ -61,11 +64,16 @@ type DisgoImpl struct { largeThreshold int } +// Logger returns the logger instance disgo uses +func (d *DisgoImpl) Logger() log.Logger { + return d.logger +} + // Connect opens the gateway connection to discord func (d *DisgoImpl) Connect() error { err := d.Gateway().Open() if err != nil { - log.Errorf("Unable to connect to gateway. error: %s", err) + d.logger.Errorf("Unable to connect to gateway. error: %s", err) return err } return nil diff --git a/internal/event_manager_impl.go b/internal/event_manager_impl.go index daa3fdd8..25bae32e 100644 --- a/internal/event_manager_impl.go +++ b/internal/event_manager_impl.go @@ -4,8 +4,6 @@ import ( "encoding/json" "runtime/debug" - log "github.com/sirupsen/logrus" - "github.com/DisgoOrg/disgo/api" "github.com/DisgoOrg/disgo/internal/handlers" ) @@ -32,18 +30,23 @@ type EventManagerImpl struct { channel chan api.Event } +// Disgo returns the api.Disgo instance used by the api.EventManager +func (e *EventManagerImpl) Disgo() api.Disgo { + return e.disgo +} + // Close closes all goroutines created by the api.EventManager -func (e EventManagerImpl) Close() { - log.Info("closing eventManager goroutines...") +func (e *EventManagerImpl) Close() { + e.Disgo().Logger().Info("closing eventManager goroutines...") close(e.channel) } // Handle calls the correct api.EventHandler -func (e EventManagerImpl) Handle(name api.GatewayEventType, c chan interface{}, sequenceNumber int, payload json.RawMessage) { +func (e *EventManagerImpl) Handle(name api.GatewayEventType, c chan interface{}, sequenceNumber int, payload json.RawMessage) { if handler, ok := e.handlers[name]; ok { eventPayload := handler.New() if err := json.Unmarshal(payload, &eventPayload); err != nil { - log.Errorf("error while unmarshaling event. error: %s", err) + e.disgo.Logger().Errorf("error while unmarshaling event. error: %s", err) } switch h := handler.(type) { case api.GatewayEventHandler: @@ -55,29 +58,29 @@ func (e EventManagerImpl) Handle(name api.GatewayEventType, c chan interface{}, } // Dispatch dispatches a new event to the client -func (e EventManagerImpl) Dispatch(event api.Event) { +func (e *EventManagerImpl) Dispatch(event api.Event) { go func() { e.channel <- event }() } // AddEventListeners adds one or more api.EventListener(s) to the api.EventManager -func (e EventManagerImpl) AddEventListeners(listeners ...api.EventListener) { +func (e *EventManagerImpl) AddEventListeners(listeners ...api.EventListener) { for _, listener := range listeners { e.listeners = append(e.listeners, listener) } } // ListenEvents starts the event goroutine -func (e EventManagerImpl) ListenEvents() { +func (e *EventManagerImpl) ListenEvents() { defer func() { if r := recover(); r != nil { - log.Errorf("recovered event listen goroutine error: %s", r) + e.Disgo().Logger().Errorf("recovered event listen goroutine error: %s", r) debug.PrintStack() e.ListenEvents() return } - log.Infof("closed event goroutine") + e.Disgo().Logger().Infof("closed event goroutine") }() for { event, ok := <-e.channel diff --git a/internal/gateway_impl.go b/internal/gateway_impl.go index e143b9cc..6bdb2b01 100644 --- a/internal/gateway_impl.go +++ b/internal/gateway_impl.go @@ -12,7 +12,6 @@ import ( "github.com/DisgoOrg/disgo/api/events" "github.com/gorilla/websocket" - log "github.com/sirupsen/logrus" "github.com/DisgoOrg/disgo/api" "github.com/DisgoOrg/disgo/api/endpoints" @@ -49,12 +48,12 @@ func (g *GatewayImpl) reconnect(delay time.Duration) { time.Sleep(delay) if g.Status() == api.Connecting || g.Status() == api.Reconnecting { - log.Error("tried to reconnect gateway while connecting/reconnecting") + g.Disgo().Logger().Error("tried to reconnect gateway while connecting/reconnecting") return } - log.Info("reconnecting gateway...") + g.Disgo().Logger().Info("reconnecting gateway...") if err := g.Open(); err != nil { - log.Errorf("failed to reconnect gateway: %s", err) + g.Disgo().Logger().Errorf("failed to reconnect gateway: %s", err) g.status = api.Disconnected g.reconnect(delay * 2) } @@ -69,12 +68,16 @@ func (g *GatewayImpl) Open() error { g.status = api.Reconnecting } - log.Info("starting ws...") + g.Disgo().Logger().Info("starting ws...") if g.url == nil { - log.Debug("gateway url empty, fetching...") + g.Disgo().Logger().Debug("gateway url empty, fetching...") gatewayRs := api.GatewayRs{} - if err := g.Disgo().RestClient().Request(endpoints.GetGateway.Compile(), nil, &gatewayRs); err != nil { + compiledRoute, err := endpoints.GetGateway.Compile() + if err != nil { + return err + } + if err = g.Disgo().RestClient().Request(*compiledRoute, nil, &gatewayRs); err != nil { return err } g.url = &gatewayRs.URL @@ -88,7 +91,7 @@ func (g *GatewayImpl) Open() error { if rs != nil && rs.Body != nil { rawBody, err := ioutil.ReadAll(rs.Body) if err != nil { - log.Errorf("error while reading response body: %s", err) + g.Disgo().Logger().Errorf("error while reading response body: %s", err) g.url = nil return err } @@ -97,11 +100,11 @@ func (g *GatewayImpl) Open() error { body = "null" } - log.Errorf("error connecting to gateway. url: %s, error: %s, body: %s", gatewayURL, err.Error(), body) + g.Disgo().Logger().Errorf("error connecting to gateway. url: %s, error: %s, body: %s", gatewayURL, err.Error(), body) return err } wsConn.SetCloseHandler(func(code int, error string) error { - log.Infof("connection to websocket closed with code: %d, error: %s", code, error) + g.Disgo().Logger().Infof("connection to websocket closed with code: %d, error: %s", code, error) return nil }) @@ -112,7 +115,7 @@ func (g *GatewayImpl) Open() error { if err != nil { return err } - event, err := parseGatewayEvent(mt, data) + event, err := g.parseGatewayEvent(mt, data) if err != nil { return err } @@ -131,7 +134,7 @@ func (g *GatewayImpl) Open() error { if g.lastSequenceReceived == nil || g.sessionID == nil { g.status = api.Identifying - log.Infof("sending Identifying command...") + g.Disgo().Logger().Infof("sending Identifying command...") if err = wsConn.WriteJSON( api.NewGatewayCommand(api.OpIdentify, api.IdentifyCommand{ Token: g.Disgo().Token(), @@ -148,7 +151,7 @@ func (g *GatewayImpl) Open() error { return err } } else { - log.Infof("sending Resuming command...") + g.Disgo().Logger().Infof("sending Resuming command...") g.status = api.Resuming if err = wsConn.WriteJSON( api.NewGatewayCommand(api.OpResume, api.ResumeCommand{ @@ -184,14 +187,14 @@ func (g *GatewayImpl) Latency() time.Duration { func (g *GatewayImpl) Close() { g.status = api.Disconnected if g.quit != nil { - log.Info("closing gateway goroutines...") + g.Disgo().Logger().Info("closing gateway goroutines...") close(g.quit) g.quit = nil - log.Info("closed gateway goroutines") + g.Disgo().Logger().Info("closed gateway goroutines") } if g.conn != nil { if err := g.closeWithCode(websocket.CloseNormalClosure); err != nil { - log.Errorf("error while closing wsconn: %s", err) + g.Disgo().Logger().Errorf("error while closing wsconn: %s", err) } } } @@ -220,12 +223,12 @@ func (g *GatewayImpl) closeWithCode(code int) error { func (g *GatewayImpl) heartbeat() { defer func() { if r := recover(); r != nil { - log.Errorf("recovered heartbeat goroutine error: %s", r) + g.Disgo().Logger().Errorf("recovered heartbeat goroutine error: %s", r) debug.PrintStack() g.heartbeat() return } - log.Info("shut down heartbeat goroutine") + g.Disgo().Logger().Info("shut down heartbeat goroutine") }() ticker := time.NewTicker(g.heartbeatInterval) @@ -241,7 +244,7 @@ func (g *GatewayImpl) heartbeat() { } func (g *GatewayImpl) sendHeartbeat() { - log.Debug("sending heartbeat...") + g.Disgo().Logger().Debug("sending heartbeat...") heartbeatEvent := events.HeartbeatEvent{ GenericEvent: events.NewEvent(g.Disgo(), 0), @@ -249,7 +252,7 @@ func (g *GatewayImpl) sendHeartbeat() { } if err := g.conn.WriteJSON(api.NewGatewayCommand(api.OpHeartbeat, g.lastSequenceReceived)); err != nil { - log.Errorf("failed to send heartbeat with error: %s", err) + g.Disgo().Logger().Errorf("failed to send heartbeat with error: %s", err) g.Close() g.reconnect(1 * time.Second) } @@ -262,61 +265,61 @@ func (g *GatewayImpl) sendHeartbeat() { func (g *GatewayImpl) listen() { defer func() { if r := recover(); r != nil { - log.Errorf("recovered listen goroutine error: %s", r) + g.Disgo().Logger().Errorf("recovered listen goroutine error: %s", r) debug.PrintStack() g.listen() return } - log.Info("shut down listen goroutine") + g.Disgo().Logger().Info("shut down listen goroutine") }() for { select { case <-g.quit: - log.Infof("existed listen routine") + g.Disgo().Logger().Infof("existed listen routine") return default: mt, data, err := g.conn.ReadMessage() if err != nil { - log.Errorf("error while reading from ws. error: %s", err) + g.Disgo().Logger().Errorf("error while reading from ws. error: %s", err) g.Close() g.reconnect(1 * time.Second) return } - event, err := parseGatewayEvent(mt, data) + event, err := g.parseGatewayEvent(mt, data) if err != nil { - log.Errorf("error while unpacking gateway event. error: %s", err) + g.Disgo().Logger().Errorf("error while unpacking gateway event. error: %s", err) } switch op := event.Op; op { case api.OpDispatch: - log.Debugf("received: OpDispatch") + g.Disgo().Logger().Debugf("received: OpDispatch") if event.S != nil { g.lastSequenceReceived = event.S } if event.T == nil { - log.Errorf("received event without T. playload: %s", string(data)) + g.Disgo().Logger().Errorf("received event without T. playload: %s", string(data)) continue } - log.Debugf("received: %s", *event.T) + g.Disgo().Logger().Debugf("received: %s", *event.T) if *event.T == api.GatewayEventReady { var readyEvent api.ReadyGatewayEvent - if err := parseEventToStruct(event, &readyEvent); err != nil { - log.Errorf("Error parsing ready event: %s", err) + if err := g.parseEventToStruct(event, &readyEvent); err != nil { + g.Disgo().Logger().Errorf("Error parsing ready event: %s", err) continue } g.sessionID = &readyEvent.D.SessionID - log.Info("ready event received") + g.Disgo().Logger().Info("ready event received") } // TODO: add setting to enable raw gateway events? var payload map[string]interface{} - if err = parseEventToStruct(event, &payload); err != nil { - log.Errorf("Error parsing event: %s", err) + if err = g.parseEventToStruct(event, &payload); err != nil { + g.Disgo().Logger().Errorf("Error parsing event: %s", err) continue } g.Disgo().EventManager().Dispatch(events.RawGatewayEvent{ @@ -331,19 +334,19 @@ func (g *GatewayImpl) listen() { e.Handle(*event.T, nil, *event.S, event.D) case api.OpHeartbeat: - log.Debugf("received: OpHeartbeat") + g.Disgo().Logger().Debugf("received: OpHeartbeat") g.sendHeartbeat() case api.OpReconnect: g.Close() g.reconnect(0) - log.Debugf("received: OpReconnect") + g.Disgo().Logger().Debugf("received: OpReconnect") case api.OpInvalidSession: - log.Debugf("received: OpInvalidSession") + g.Disgo().Logger().Debugf("received: OpInvalidSession") case api.OpHeartbeatACK: - log.Debugf("received: OpHeartbeatACK") + g.Disgo().Logger().Debugf("received: OpHeartbeatACK") g.lastHeartbeatReceived = time.Now().UTC() } @@ -352,15 +355,15 @@ func (g *GatewayImpl) listen() { } } -func parseEventToStruct(event *api.RawGatewayEvent, v interface{}) error { +func (g *GatewayImpl) parseEventToStruct(event *api.RawGatewayEvent, v interface{}) error { if err := json.Unmarshal(event.D, v); err != nil { - log.Errorf("error while unmarshaling event. error: %s", err) + g.Disgo().Logger().Errorf("error while unmarshaling event. error: %s", err) return err } return nil } -func parseGatewayEvent(mt int, data []byte) (*api.RawGatewayEvent, error) { +func (g *GatewayImpl) parseGatewayEvent(mt int, data []byte) (*api.RawGatewayEvent, error) { var reader io.Reader = bytes.NewBuffer(data) @@ -374,7 +377,7 @@ func parseGatewayEvent(mt int, data []byte) (*api.RawGatewayEvent, error) { decoder := json.NewDecoder(reader) if err := decoder.Decode(&event); err != nil { - log.Errorf("error decoding websocket message_events, %s", err) + g.Disgo().Logger().Errorf("error decoding websocket message_events, %s", err) return nil, err } return &event, nil diff --git a/internal/handlers/channel_create_handler.go b/internal/handlers/channel_create_handler.go index 56731cc9..bf167aba 100644 --- a/internal/handlers/channel_create_handler.go +++ b/internal/handlers/channel_create_handler.go @@ -3,7 +3,6 @@ package handlers import ( "github.com/DisgoOrg/disgo/api" "github.com/DisgoOrg/disgo/api/events" - log "github.com/sirupsen/logrus" ) // ChannelCreateHandler handles api.GatewayEventChannelCreate @@ -47,7 +46,7 @@ func (h ChannelCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a }) case api.ChannelTypeGroupDM: - log.Warnf("ChannelTypeGroupDM received what the hell discord") + disgo.Logger().Warnf("ChannelTypeGroupDM received what the hell discord") case api.ChannelTypeText, api.ChannelTypeNews: textChannel := disgo.EntityBuilder().CreateTextChannel(channel, api.CacheStrategyYes) @@ -102,7 +101,7 @@ func (h ChannelCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a }) default: - log.Warnf("unknown channel type received: %d", channel.Type) + disgo.Logger().Warnf("unknown channel type received: %d", channel.Type) } } diff --git a/internal/handlers/channel_delete_handler.go b/internal/handlers/channel_delete_handler.go index 48b2400e..3cd6920d 100644 --- a/internal/handlers/channel_delete_handler.go +++ b/internal/handlers/channel_delete_handler.go @@ -3,7 +3,6 @@ package handlers import ( "github.com/DisgoOrg/disgo/api" "github.com/DisgoOrg/disgo/api/events" - log "github.com/sirupsen/logrus" ) // ChannelDeleteHandler handles api.GatewayEventChannelDelete @@ -48,7 +47,7 @@ func (h ChannelDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a }) case api.ChannelTypeGroupDM: - log.Warnf("ChannelTypeGroupDM received what the hell discord") + disgo.Logger().Warnf("ChannelTypeGroupDM received what the hell discord") case api.ChannelTypeText, api.ChannelTypeNews: disgo.Cache().UncacheTextChannel(*channel.GuildID, channel.ID) @@ -107,6 +106,6 @@ func (h ChannelDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a }) default: - log.Warnf("unknown channel type received: %d", channel.Type) + disgo.Logger().Warnf("unknown channel type received: %d", channel.Type) } } diff --git a/internal/handlers/channel_update_handler.go b/internal/handlers/channel_update_handler.go index c883cae7..40e4e73a 100644 --- a/internal/handlers/channel_update_handler.go +++ b/internal/handlers/channel_update_handler.go @@ -3,7 +3,6 @@ package handlers import ( "github.com/DisgoOrg/disgo/api" "github.com/DisgoOrg/disgo/api/events" - log "github.com/sirupsen/logrus" ) // ChannelUpdateHandler handles api.GatewayEventChannelUpdate @@ -52,7 +51,7 @@ func (h ChannelUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a }) case api.ChannelTypeGroupDM: - log.Warnf("ChannelTypeGroupDM received what the hell discord") + disgo.Logger().Warnf("ChannelTypeGroupDM received what the hell discord") case api.ChannelTypeText, api.ChannelTypeNews: oldTextChannel := disgo.Cache().TextChannel(channel.ID) @@ -127,6 +126,6 @@ func (h ChannelUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a }) default: - log.Warnf("unknown channel type received: %d", channel.Type) + disgo.Logger().Warnf("unknown channel type received: %d", channel.Type) } } diff --git a/internal/restclient_impl.go b/internal/restclient_impl.go index a272c124..8c24cf8d 100644 --- a/internal/restclient_impl.go +++ b/internal/restclient_impl.go @@ -10,7 +10,6 @@ import ( "strings" "github.com/DisgoOrg/disgo/api/events" - log "github.com/sirupsen/logrus" "github.com/DisgoOrg/disgo/api" "github.com/DisgoOrg/disgo/api/endpoints" @@ -54,7 +53,7 @@ func (r RestClientImpl) Request(route endpoints.CompiledAPIRoute, rqBody interfa if err != nil { return err } - log.Debugf("request json: \"%s\"", string(rqJSON)) + r.Disgo().Logger().Debugf("request json: \"%s\"", string(rqJSON)) reader = bytes.NewBuffer(rqJSON) } else { reader = nil @@ -77,17 +76,17 @@ func (r RestClientImpl) Request(route endpoints.CompiledAPIRoute, rqBody interfa defer func() { err = rs.Body.Close() if err != nil { - log.Error("error closing response body", err.Error()) + r.Disgo().Logger().Error("error closing response body", err.Error()) } }() rawRsBody, err := ioutil.ReadAll(rs.Body) if err != nil { - log.Errorf("error reading from response body: %s", err) + r.Disgo().Logger().Errorf("error reading from response body: %s", err) return err } - log.Debugf("code: %d, response: %s", rs.StatusCode, string(rawRsBody)) + r.Disgo().Logger().Debugf("code: %d, response: %s", rs.StatusCode, string(rawRsBody)) r.Disgo().EventManager().Dispatch(events.HttpRequestEvent{ GenericEvent: events.NewEvent(r.Disgo(), 0), @@ -99,7 +98,7 @@ func (r RestClientImpl) Request(route endpoints.CompiledAPIRoute, rqBody interfa case http.StatusOK, http.StatusCreated, http.StatusNoContent: if rsBody != nil { if err = json.Unmarshal(rawRsBody, rsBody); err != nil { - log.Errorf("error unmarshalling response. error: %s", err) + r.Disgo().Logger().Errorf("error unmarshalling response. error: %s", err) return err } } @@ -110,25 +109,25 @@ func (r RestClientImpl) Request(route endpoints.CompiledAPIRoute, rqBody interfa remaining := rs.Header.Get("X-RateLimit-Limit") reset := rs.Header.Get("X-RateLimit-Limit") bucket := rs.Header.Get("X-RateLimit-Limit") - log.Errorf("too many requests. limit: %s, remaining: %s, reset: %s,bucket: %s", limit, remaining, reset, bucket) + r.Disgo().Logger().Errorf("too many requests. limit: %s, remaining: %s, reset: %s,bucket: %s", limit, remaining, reset, bucket) return api.ErrRatelimited case http.StatusBadGateway: - log.Error(api.ErrBadGateway) + r.Disgo().Logger().Error(api.ErrBadGateway) return api.ErrBadGateway case http.StatusBadRequest: - log.Errorf("bad request request: \"%s\", response: \"%s\"", string(rqJSON), string(rawRsBody)) + r.Disgo().Logger().Errorf("bad request request: \"%s\", response: \"%s\"", string(rqJSON), string(rawRsBody)) return api.ErrBadRequest case http.StatusUnauthorized: - log.Error(api.ErrUnauthorized) + r.Disgo().Logger().Error(api.ErrUnauthorized) return api.ErrUnauthorized default: var errorRs api.ErrorResponse if err = json.Unmarshal(rawRsBody, &errorRs); err != nil { - log.Errorf("error unmarshalling error response. code: %d, error: %s", rs.StatusCode, err) + r.Disgo().Logger().Errorf("error unmarshalling error response. code: %d, error: %s", rs.StatusCode, err) return err } return fmt.Errorf("request to %s failed. statuscode: %d, errorcode: %d, message_events: %s", rq.URL, rs.StatusCode, errorRs.Code, errorRs.Message) @@ -137,7 +136,11 @@ func (r RestClientImpl) Request(route endpoints.CompiledAPIRoute, rqBody interfa // SendMessage lets you send a api.Message to a api.MessageChannel func (r RestClientImpl) SendMessage(channelID api.Snowflake, message api.MessageCreate) (msg *api.Message, err error) { - err = r.Request(endpoints.CreateMessage.Compile(channelID), message, &msg) + compiledRoute, err := endpoints.CreateMessage.Compile(channelID) + if err != nil { + return nil, err + } + err = r.Request(*compiledRoute, message, &msg) if err == nil { msg = r.Disgo().EntityBuilder().CreateMessage(msg, api.CacheStrategyNoWs) } @@ -146,7 +149,11 @@ func (r RestClientImpl) SendMessage(channelID api.Snowflake, message api.Message // EditMessage lets you edit a api.Message func (r RestClientImpl) EditMessage(channelID api.Snowflake, messageID api.Snowflake, message api.MessageUpdate) (msg *api.Message, err error) { - err = r.Request(endpoints.UpdateMessage.Compile(channelID, messageID), message, &msg) + compiledRoute, err := endpoints.UpdateMessage.Compile(channelID, messageID) + if err != nil { + return nil, err + } + err = r.Request(*compiledRoute, message, &msg) if err == nil { msg = r.Disgo().EntityBuilder().CreateMessage(msg, api.CacheStrategyNoWs) } @@ -155,7 +162,11 @@ func (r RestClientImpl) EditMessage(channelID api.Snowflake, messageID api.Snowf // DeleteMessage lets you delete a api.Message func (r RestClientImpl) DeleteMessage(channelID api.Snowflake, messageID api.Snowflake) (err error) { - err = r.Request(endpoints.DeleteMessage.Compile(channelID, messageID), nil, nil) + compiledRoute, err := endpoints.DeleteMessage.Compile(channelID, messageID) + if err != nil { + return err + } + err = r.Request(*compiledRoute, nil, nil) if err == nil && api.CacheStrategyNoWs(r.Disgo()) { r.Disgo().Cache().UncacheMessage(channelID, messageID) } @@ -164,7 +175,11 @@ func (r RestClientImpl) DeleteMessage(channelID api.Snowflake, messageID api.Sno // BulkDeleteMessages lets you bulk delete api.Message(s) func (r RestClientImpl) BulkDeleteMessages(channelID api.Snowflake, messageIDs ...api.Snowflake) (err error) { - err = r.Request(endpoints.BulkDeleteMessage.Compile(channelID), api.MessageBulkDelete{Messages: messageIDs}, nil) + compiledRoute, err := endpoints.BulkDeleteMessage.Compile(channelID) + if err != nil { + return err + } + err = r.Request(*compiledRoute, api.MessageBulkDelete{Messages: messageIDs}, nil) if err == nil && api.CacheStrategyNoWs(r.Disgo()) { // TODO: check here if no err means all messages deleted for _, messageID := range messageIDs { @@ -176,7 +191,11 @@ func (r RestClientImpl) BulkDeleteMessages(channelID api.Snowflake, messageIDs . // CrosspostMessage lets you crosspost a api.Message in a channel with type api.ChannelTypeNews func (r RestClientImpl) CrosspostMessage(channelID api.Snowflake, messageID api.Snowflake) (msg *api.Message, err error) { - err = r.Request(endpoints.CrosspostMessage.Compile(channelID, messageID), nil, &msg) + compiledRoute, err := endpoints.CrosspostMessage.Compile(channelID, messageID) + if err != nil { + return nil, err + } + err = r.Request(*compiledRoute, nil, &msg) if err == nil { msg = r.Disgo().EntityBuilder().CreateMessage(msg, api.CacheStrategyNoWs) } @@ -185,12 +204,16 @@ func (r RestClientImpl) CrosspostMessage(channelID api.Snowflake, messageID api. // OpenDMChannel opens a new dm channel a user func (r RestClientImpl) OpenDMChannel(userID api.Snowflake) (channel *api.DMChannel, err error) { + compiledRoute, err := endpoints.CreateDMChannel.Compile() + if err != nil { + return nil, err + } body := struct { RecipientID api.Snowflake `json:"recipient_id"` }{ RecipientID: userID, } - err = r.Request(endpoints.CreateDMChannel.Compile(), body, &channel) + err = r.Request(*compiledRoute, body, &channel) if err == nil { channel = r.Disgo().EntityBuilder().CreateDMChannel(&channel.MessageChannel.Channel, api.CacheStrategyNoWs) } @@ -199,8 +222,12 @@ func (r RestClientImpl) OpenDMChannel(userID api.Snowflake) (channel *api.DMChan // UpdateSelfNick updates the bots nickname in a guild func (r RestClientImpl) UpdateSelfNick(guildID api.Snowflake, nick *string) (newNick *string, err error) { + compiledRoute, err := endpoints.UpdateSelfNick.Compile(guildID) + if err != nil { + return nil, err + } var updateNick *api.UpdateSelfNick - err = r.Request(endpoints.UpdateSelfNick.Compile(guildID), api.UpdateSelfNick{Nick: nick}, &updateNick) + err = r.Request(*compiledRoute, api.UpdateSelfNick{Nick: nick}, &updateNick) if err == nil && api.CacheStrategyNoWs(r.Disgo()) { r.Disgo().Cache().Member(guildID, r.Disgo().SelfUserID()).Nick = updateNick.Nick newNick = updateNick.Nick @@ -210,7 +237,11 @@ func (r RestClientImpl) UpdateSelfNick(guildID api.Snowflake, nick *string) (new // GetUser fetches the specific user func (r RestClientImpl) GetUser(userID api.Snowflake) (user *api.User, err error) { - err = r.Request(endpoints.GetUser.Compile(userID), nil, &user) + compiledRoute, err := endpoints.GetUser.Compile(userID) + if err != nil { + return nil, err + } + err = r.Request(*compiledRoute, nil, &user) if err == nil { user = r.Disgo().EntityBuilder().CreateUser(user, api.CacheStrategyNoWs) } @@ -219,7 +250,11 @@ func (r RestClientImpl) GetUser(userID api.Snowflake) (user *api.User, err error // GetMember fetches the specific member func (r RestClientImpl) GetMember(guildID api.Snowflake, userID api.Snowflake) (member *api.Member, err error) { - err = r.Request(endpoints.GetMember.Compile(guildID, userID), nil, &member) + compiledRoute, err := endpoints.GetMember.Compile(guildID, userID) + if err != nil { + return nil, err + } + err = r.Request(*compiledRoute, nil, &member) if err == nil { member = r.Disgo().EntityBuilder().CreateMember(guildID, member, api.CacheStrategyNoWs) } @@ -228,7 +263,11 @@ func (r RestClientImpl) GetMember(guildID api.Snowflake, userID api.Snowflake) ( // GetMembers fetches all members for a guild func (r RestClientImpl) GetMembers(guildID api.Snowflake) (members []*api.Member, err error) { - err = r.Request(endpoints.GetMembers.Compile(guildID), nil, &members) + compiledRoute, err := endpoints.GetMembers.Compile(guildID) + if err != nil { + return nil, err + } + err = r.Request(*compiledRoute, nil, &members) if err == nil { for _, member := range members { member = r.Disgo().EntityBuilder().CreateMember(guildID, member, api.CacheStrategyNoWs) @@ -239,7 +278,11 @@ func (r RestClientImpl) GetMembers(guildID api.Snowflake) (members []*api.Member // AddMember adds a member to the guild with the oauth2 access BotToken. requires api.PermissionCreateInstantInvite func (r RestClientImpl) AddMember(guildID api.Snowflake, userID api.Snowflake, addGuildMemberData api.AddGuildMemberData) (member *api.Member, err error) { - err = r.Request(endpoints.AddMember.Compile(guildID, userID), addGuildMemberData, &member) + compiledRoute, err := endpoints.AddMember.Compile(guildID, userID) + if err != nil { + return nil, err + } + err = r.Request(*compiledRoute, addGuildMemberData, &member) if err == nil { member = r.Disgo().EntityBuilder().CreateMember(guildID, member, api.CacheStrategyNoWs) } @@ -248,14 +291,16 @@ func (r RestClientImpl) AddMember(guildID api.Snowflake, userID api.Snowflake, a // KickMember kicks a member from the guild. requires api.PermissionKickMembers func (r RestClientImpl) KickMember(guildID api.Snowflake, userID api.Snowflake, reason *string) (err error) { - var route endpoints.CompiledAPIRoute + var compiledRoute *endpoints.CompiledAPIRoute if reason == nil { - route = endpoints.RemoveMember.Compile(guildID, userID) + compiledRoute, err = endpoints.RemoveMember.Compile(guildID, userID) } else { - route = endpoints.RemoveMemberReason.Compile(guildID, userID, *reason) + compiledRoute, err = endpoints.RemoveMemberReason.Compile(guildID, userID, *reason) } - - err = r.Request(route, nil, nil) + if err != nil { + return + } + err = r.Request(*compiledRoute, nil, nil) if err == nil && api.CacheStrategyNoWs(r.Disgo()) { r.Disgo().Cache().UncacheMember(guildID, userID) } @@ -264,7 +309,11 @@ func (r RestClientImpl) KickMember(guildID api.Snowflake, userID api.Snowflake, // UpdateMember updates a member func (r RestClientImpl) UpdateMember(guildID api.Snowflake, userID api.Snowflake, updateGuildMemberData api.UpdateGuildMemberData) (member *api.Member, err error) { - err = r.Request(endpoints.UpdateMember.Compile(guildID, userID), updateGuildMemberData, &member) + compiledRoute, err := endpoints.UpdateMember.Compile(guildID, userID) + if err != nil { + return nil, err + } + err = r.Request(*compiledRoute, updateGuildMemberData, &member) if err == nil { member = r.Disgo().EntityBuilder().CreateMember(guildID, member, api.CacheStrategyNoWs) } @@ -273,7 +322,11 @@ func (r RestClientImpl) UpdateMember(guildID api.Snowflake, userID api.Snowflake // MoveMember moves/kicks the member to/from a voice channel func (r RestClientImpl) MoveMember(guildID api.Snowflake, userID api.Snowflake, channelID *api.Snowflake) (member *api.Member, err error) { - err = r.Request(endpoints.UpdateMember.Compile(guildID, userID), api.MoveGuildMemberData{ChannelID: channelID}, &member) + compiledRoute, err := endpoints.UpdateMember.Compile(guildID, userID) + if err != nil { + return nil, err + } + err = r.Request(*compiledRoute, api.MoveGuildMemberData{ChannelID: channelID}, &member) if err == nil { member = r.Disgo().EntityBuilder().CreateMember(guildID, member, api.CacheStrategyNoWs) } @@ -282,7 +335,11 @@ func (r RestClientImpl) MoveMember(guildID api.Snowflake, userID api.Snowflake, // AddMemberRole adds a role to a member func (r RestClientImpl) AddMemberRole(guildID api.Snowflake, userID api.Snowflake, roleID api.Snowflake) (err error) { - err = r.Request(endpoints.AddMemberRole.Compile(guildID, userID, roleID), nil, nil) + compiledRoute, err := endpoints.AddMemberRole.Compile(guildID, userID, roleID) + if err != nil { + return err + } + err = r.Request(*compiledRoute, nil, nil) if err == nil && api.CacheStrategyNoWs(r.Disgo()) { member := r.Disgo().Cache().Member(guildID, userID) if member != nil { @@ -294,7 +351,11 @@ func (r RestClientImpl) AddMemberRole(guildID api.Snowflake, userID api.Snowflak // RemoveMemberRole removes a role from a member func (r RestClientImpl) RemoveMemberRole(guildID api.Snowflake, userID api.Snowflake, roleID api.Snowflake) (err error) { - err = r.Request(endpoints.RemoveMemberRole.Compile(guildID, userID, roleID), nil, nil) + compiledRoute, err := endpoints.RemoveMemberRole.Compile(guildID, userID, roleID) + if err != nil { + return err + } + err = r.Request(*compiledRoute, nil, nil) if err == nil && api.CacheStrategyNoWs(r.Disgo()) { member := r.Disgo().Cache().Member(guildID, userID) if member != nil { @@ -311,7 +372,11 @@ func (r RestClientImpl) RemoveMemberRole(guildID api.Snowflake, userID api.Snowf // GetRoles fetches all roles from a guild func (r RestClientImpl) GetRoles(guildID api.Snowflake) (roles []*api.Role, err error) { - err = r.Request(endpoints.GetRoles.Compile(guildID), nil, &roles) + compiledRoute, err := endpoints.GetRoles.Compile(guildID) + if err != nil { + return nil, err + } + err = r.Request(*compiledRoute, nil, &roles) if err == nil { for _, role := range roles { role = r.Disgo().EntityBuilder().CreateRole(guildID, role, api.CacheStrategyNoWs) @@ -322,7 +387,11 @@ func (r RestClientImpl) GetRoles(guildID api.Snowflake) (roles []*api.Role, err // CreateRole creates a new role for a guild. Requires api.PermissionManageRoles func (r RestClientImpl) CreateRole(guildID api.Snowflake, role api.UpdateRole) (newRole *api.Role, err error) { - err = r.Request(endpoints.CreateRole.Compile(guildID), role, &newRole) + compiledRoute, err := endpoints.CreateRole.Compile(guildID) + if err != nil { + return nil, err + } + err = r.Request(*compiledRoute, role, &newRole) if err == nil { newRole = r.Disgo().EntityBuilder().CreateRole(guildID, newRole, api.CacheStrategyNoWs) } @@ -331,7 +400,11 @@ func (r RestClientImpl) CreateRole(guildID api.Snowflake, role api.UpdateRole) ( // UpdateRole updates a role from a guild. Requires api.PermissionManageRoles func (r RestClientImpl) UpdateRole(guildID api.Snowflake, roleID api.Snowflake, role api.UpdateRole) (newRole *api.Role, err error) { - err = r.Request(endpoints.UpdateRole.Compile(guildID, roleID), role, &newRole) + compiledRoute, err := endpoints.UpdateRole.Compile(guildID, roleID) + if err != nil { + return nil, err + } + err = r.Request(*compiledRoute, role, &newRole) if err == nil { newRole = r.Disgo().EntityBuilder().CreateRole(guildID, newRole, api.CacheStrategyNoWs) } @@ -340,7 +413,11 @@ func (r RestClientImpl) UpdateRole(guildID api.Snowflake, roleID api.Snowflake, // UpdateRolePositions updates the position of a role from a guild. Requires api.PermissionManageRoles func (r RestClientImpl) UpdateRolePositions(guildID api.Snowflake, roleUpdates ...api.UpdateRolePosition) (roles []*api.Role, err error) { - err = r.Request(endpoints.GetRoles.Compile(guildID), roleUpdates, &roles) + compiledRoute, err := endpoints.GetRoles.Compile(guildID) + if err != nil { + return nil, err + } + err = r.Request(*compiledRoute, roleUpdates, &roles) if err == nil { for _, role := range roles { role = r.Disgo().EntityBuilder().CreateRole(guildID, role, api.CacheStrategyNoWs) @@ -351,7 +428,11 @@ func (r RestClientImpl) UpdateRolePositions(guildID api.Snowflake, roleUpdates . // DeleteRole deletes a role from a guild. Requires api.PermissionManageRoles func (r RestClientImpl) DeleteRole(guildID api.Snowflake, roleID api.Snowflake) (err error) { - err = r.Request(endpoints.UpdateRole.Compile(guildID, roleID), nil, nil) + compiledRoute, err := endpoints.UpdateRole.Compile(guildID, roleID) + if err != nil { + return err + } + err = r.Request(*compiledRoute, nil, nil) if err == nil && api.CacheStrategyNoWs(r.Disgo()) { r.disgo.Cache().UncacheRole(guildID, roleID) } @@ -360,22 +441,38 @@ func (r RestClientImpl) DeleteRole(guildID api.Snowflake, roleID api.Snowflake) // AddReaction lets you add a reaction to a message_events func (r RestClientImpl) AddReaction(channelID api.Snowflake, messageID api.Snowflake, emoji string) error { - return r.Request(endpoints.AddReaction.Compile(channelID, messageID, normalizeEmoji(emoji)), nil, nil) + compiledRoute, err := endpoints.AddReaction.Compile(channelID, messageID, normalizeEmoji(emoji)) + if err != nil { + return err + } + return r.Request(*compiledRoute, nil, nil) } // RemoveOwnReaction lets you remove your own reaction from a message_events func (r RestClientImpl) RemoveOwnReaction(channelID api.Snowflake, messageID api.Snowflake, emoji string) error { - return r.Request(endpoints.RemoveOwnReaction.Compile(channelID, messageID, normalizeEmoji(emoji)), nil, nil) + compiledRoute, err := endpoints.RemoveOwnReaction.Compile(channelID, messageID, normalizeEmoji(emoji)) + if err != nil { + return err + } + return r.Request(*compiledRoute, nil, nil) } // RemoveUserReaction lets you remove a specific reaction from a user from a message_events func (r RestClientImpl) RemoveUserReaction(channelID api.Snowflake, messageID api.Snowflake, emoji string, userID api.Snowflake) error { - return r.Request(endpoints.RemoveUserReaction.Compile(channelID, messageID, normalizeEmoji(emoji), userID), nil, nil) + compiledRoute, err := endpoints.RemoveUserReaction.Compile(channelID, messageID, normalizeEmoji(emoji), userID) + if err != nil { + return err + } + return r.Request(*compiledRoute, nil, nil) } // GetGlobalCommands gets you all global commands func (r RestClientImpl) GetGlobalCommands(applicationID api.Snowflake) (commands []*api.Command, err error) { - err = r.Request(endpoints.GetGlobalCommands.Compile(applicationID), nil, &commands) + compiledRoute, err := endpoints.GetGlobalCommands.Compile(applicationID) + if err != nil { + return nil, err + } + err = r.Request(*compiledRoute, nil, &commands) if err == nil { for _, cmd := range commands { cmd = r.Disgo().EntityBuilder().CreateGlobalCommand(cmd, api.CacheStrategyNoWs) @@ -386,7 +483,11 @@ func (r RestClientImpl) GetGlobalCommands(applicationID api.Snowflake) (commands // GetGlobalCommand gets you a specific global global command func (r RestClientImpl) GetGlobalCommand(applicationID api.Snowflake, commandID api.Snowflake) (cmd *api.Command, err error) { - err = r.Request(endpoints.GetGlobalCommand.Compile(applicationID, commandID), nil, &cmd) + compiledRoute, err := endpoints.GetGlobalCommand.Compile(applicationID, commandID) + if err != nil { + return nil, err + } + err = r.Request(*compiledRoute, nil, &cmd) if err == nil { cmd = r.Disgo().EntityBuilder().CreateGlobalCommand(cmd, api.CacheStrategyNoWs) } @@ -395,7 +496,11 @@ func (r RestClientImpl) GetGlobalCommand(applicationID api.Snowflake, commandID // CreateGlobalCommand lets you create a new global command func (r RestClientImpl) CreateGlobalCommand(applicationID api.Snowflake, command api.Command) (cmd *api.Command, err error) { - err = r.Request(endpoints.CreateGlobalCommand.Compile(applicationID), command, &cmd) + compiledRoute, err := endpoints.CreateGlobalCommand.Compile(applicationID) + if err != nil { + return nil, err + } + err = r.Request(*compiledRoute, command, &cmd) if err == nil { cmd = r.Disgo().EntityBuilder().CreateGlobalCommand(cmd, api.CacheStrategyNoWs) } @@ -404,11 +509,15 @@ func (r RestClientImpl) CreateGlobalCommand(applicationID api.Snowflake, command // SetGlobalCommands lets you override all global commands func (r RestClientImpl) SetGlobalCommands(applicationID api.Snowflake, commands ...api.Command) (cmds []*api.Command, err error) { + compiledRoute, err := endpoints.SetGlobalCommands.Compile(applicationID) + if err != nil { + return nil, err + } if len(commands) > 100 { err = api.ErrTooMuchApplicationCommands return } - err = r.Request(endpoints.SetGlobalCommands.Compile(applicationID), commands, &cmds) + err = r.Request(*compiledRoute, commands, &cmds) if err == nil { for _, cmd := range cmds { cmd = r.Disgo().EntityBuilder().CreateGlobalCommand(cmd, api.CacheStrategyNoWs) @@ -419,7 +528,11 @@ func (r RestClientImpl) SetGlobalCommands(applicationID api.Snowflake, commands // EditGlobalCommand lets you edit a specific global command func (r RestClientImpl) EditGlobalCommand(applicationID api.Snowflake, commandID api.Snowflake, command api.UpdateCommand) (cmd *api.Command, err error) { - err = r.Request(endpoints.EditGlobalCommand.Compile(applicationID, commandID), command, &cmd) + compiledRoute, err := endpoints.EditGlobalCommand.Compile(applicationID, commandID) + if err != nil { + return nil, err + } + err = r.Request(*compiledRoute, command, &cmd) if err == nil { cmd = r.Disgo().EntityBuilder().CreateGlobalCommand(cmd, api.CacheStrategyNoWs) } @@ -428,7 +541,11 @@ func (r RestClientImpl) EditGlobalCommand(applicationID api.Snowflake, commandID // DeleteGlobalCommand lets you delete a specific global command func (r RestClientImpl) DeleteGlobalCommand(applicationID api.Snowflake, commandID api.Snowflake) (err error) { - err = r.Request(endpoints.DeleteGlobalCommand.Compile(applicationID, commandID), nil, nil) + compiledRoute, err := endpoints.DeleteGlobalCommand.Compile(applicationID, commandID) + if err != nil { + return err + } + err = r.Request(*compiledRoute, nil, nil) if err == nil && api.CacheStrategyNoWs(r.Disgo()) { r.Disgo().Cache().UncacheCommand(commandID) } @@ -437,7 +554,11 @@ func (r RestClientImpl) DeleteGlobalCommand(applicationID api.Snowflake, command // GetGuildCommands gets you all guild_events commands func (r RestClientImpl) GetGuildCommands(applicationID api.Snowflake, guildID api.Snowflake) (commands []*api.Command, err error) { - err = r.Request(endpoints.GetGuildCommands.Compile(applicationID, guildID), nil, &commands) + compiledRoute, err := endpoints.GetGuildCommands.Compile(applicationID, guildID) + if err != nil { + return nil, err + } + err = r.Request(*compiledRoute, nil, &commands) if err == nil { for _, cmd := range commands { cmd = r.Disgo().EntityBuilder().CreateGuildCommand(guildID, cmd, api.CacheStrategyNoWs) @@ -448,7 +569,11 @@ func (r RestClientImpl) GetGuildCommands(applicationID api.Snowflake, guildID ap // CreateGuildCommand lets you create a new guild_events command func (r RestClientImpl) CreateGuildCommand(applicationID api.Snowflake, guildID api.Snowflake, command api.Command) (cmd *api.Command, err error) { - err = r.Request(endpoints.CreateGuildCommand.Compile(applicationID, guildID), command, &cmd) + compiledRoute, err := endpoints.CreateGuildCommand.Compile(applicationID, guildID) + if err != nil { + return nil, err + } + err = r.Request(*compiledRoute, command, &cmd) if err == nil { cmd = r.Disgo().EntityBuilder().CreateGuildCommand(guildID, cmd, api.CacheStrategyNoWs) } @@ -457,11 +582,15 @@ func (r RestClientImpl) CreateGuildCommand(applicationID api.Snowflake, guildID // SetGuildCommands lets you override all guild_events commands func (r RestClientImpl) SetGuildCommands(applicationID api.Snowflake, guildID api.Snowflake, commands ...api.Command) (cmds []*api.Command, err error) { + compiledRoute, err := endpoints.SetGuildCommands.Compile(applicationID, guildID) + if err != nil { + return nil, err + } if len(commands) > 100 { err = api.ErrTooMuchApplicationCommands return } - err = r.Request(endpoints.SetGuildCommands.Compile(applicationID, guildID), commands, &cmds) + err = r.Request(*compiledRoute, commands, &cmds) if err == nil { for _, cmd := range cmds { cmd = r.Disgo().EntityBuilder().CreateGuildCommand(guildID, cmd, api.CacheStrategyNoWs) @@ -472,7 +601,11 @@ func (r RestClientImpl) SetGuildCommands(applicationID api.Snowflake, guildID ap // GetGuildCommand gets you a specific guild_events command func (r RestClientImpl) GetGuildCommand(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake) (cmd *api.Command, err error) { - err = r.Request(endpoints.GetGuildCommand.Compile(applicationID, guildID, commandID), nil, &cmd) + compiledRoute, err := endpoints.GetGuildCommand.Compile(applicationID, guildID, commandID) + if err != nil { + return nil, err + } + err = r.Request(*compiledRoute, nil, &cmd) if err == nil { cmd = r.Disgo().EntityBuilder().CreateGuildCommand(guildID, cmd, api.CacheStrategyNoWs) } @@ -481,7 +614,11 @@ func (r RestClientImpl) GetGuildCommand(applicationID api.Snowflake, guildID api // EditGuildCommand lets you edit a specific guild_events command func (r RestClientImpl) EditGuildCommand(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake, command api.UpdateCommand) (cmd *api.Command, err error) { - err = r.Request(endpoints.EditGuildCommand.Compile(applicationID, guildID, commandID), command, &cmd) + compiledRoute, err := endpoints.EditGuildCommand.Compile(applicationID, guildID, commandID) + if err != nil { + return nil, err + } + err = r.Request(*compiledRoute, command, &cmd) if err == nil { cmd = r.Disgo().EntityBuilder().CreateGuildCommand(guildID, cmd, api.CacheStrategyNoWs) } @@ -490,7 +627,11 @@ func (r RestClientImpl) EditGuildCommand(applicationID api.Snowflake, guildID ap // DeleteGuildCommand lets you delete a specific guild_events command func (r RestClientImpl) DeleteGuildCommand(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake) (err error) { - err = r.Request(endpoints.DeleteGuildCommand.Compile(applicationID, guildID, commandID), nil, nil) + compiledRoute, err := endpoints.DeleteGuildCommand.Compile(applicationID, guildID, commandID) + if err != nil { + return err + } + err = r.Request(*compiledRoute, nil, nil) if err == nil && api.CacheStrategyNoWs(r.Disgo()) { r.Disgo().Cache().UncacheCommand(commandID) } @@ -499,7 +640,11 @@ func (r RestClientImpl) DeleteGuildCommand(applicationID api.Snowflake, guildID // GetGuildCommandsPermissions returns the api.CommandPermission for a all api.Command(s) in a guild func (r RestClientImpl) GetGuildCommandsPermissions(applicationID api.Snowflake, guildID api.Snowflake) (cmdsPerms []*api.GuildCommandPermissions, err error) { - err = r.Request(endpoints.GetGuildCommandPermissions.Compile(applicationID, guildID), nil, &cmdsPerms) + compiledRoute, err := endpoints.GetGuildCommandPermissions.Compile(applicationID, guildID) + if err != nil { + return nil, err + } + err = r.Request(*compiledRoute, nil, &cmdsPerms) if err == nil { for _, cmdPerms := range cmdsPerms { cmdPerms = r.Disgo().EntityBuilder().CreateGuildCommandPermissions(cmdPerms, api.CacheStrategyNoWs) @@ -510,7 +655,11 @@ func (r RestClientImpl) GetGuildCommandsPermissions(applicationID api.Snowflake, // GetGuildCommandPermissions returns the api.CommandPermission for a specific api.Command in a guild func (r RestClientImpl) GetGuildCommandPermissions(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake) (cmdPerms *api.GuildCommandPermissions, err error) { - err = r.Request(endpoints.GetGuildCommandPermission.Compile(applicationID, guildID, commandID), nil, &cmdPerms) + compiledRoute, err := endpoints.GetGuildCommandPermission.Compile(applicationID, guildID, commandID) + if err != nil { + return nil, err + } + err = r.Request(*compiledRoute, nil, &cmdPerms) if err == nil { cmdPerms = r.Disgo().EntityBuilder().CreateGuildCommandPermissions(cmdPerms, api.CacheStrategyNoWs) } @@ -519,7 +668,11 @@ func (r RestClientImpl) GetGuildCommandPermissions(applicationID api.Snowflake, // SetGuildCommandsPermissions sets the api.GuildCommandPermissions for a all api.Command(s) func (r RestClientImpl) SetGuildCommandsPermissions(applicationID api.Snowflake, guildID api.Snowflake, commandsPermissions ...api.SetGuildCommandPermissions) (cmdsPerms []*api.GuildCommandPermissions, err error) { - err = r.Request(endpoints.SetGuildCommandsPermissions.Compile(applicationID, guildID), api.SetGuildCommandsPermissions(commandsPermissions), &cmdsPerms) + compiledRoute, err := endpoints.SetGuildCommandsPermissions.Compile(applicationID, guildID) + if err != nil { + return nil, err + } + err = r.Request(*compiledRoute, api.SetGuildCommandsPermissions(commandsPermissions), &cmdsPerms) if err == nil { for _, cmdPerms := range cmdsPerms { cmdPerms = r.Disgo().EntityBuilder().CreateGuildCommandPermissions(cmdPerms, api.CacheStrategyNoWs) @@ -530,7 +683,11 @@ func (r RestClientImpl) SetGuildCommandsPermissions(applicationID api.Snowflake, // SetGuildCommandPermissions sets the api.GuildCommandPermissions for a specific api.Command func (r RestClientImpl) SetGuildCommandPermissions(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake, commandPermissions api.SetGuildCommandPermissions) (cmdPerms *api.GuildCommandPermissions, err error) { - err = r.Request(endpoints.SetGuildCommandPermissions.Compile(applicationID, guildID, commandID), commandPermissions, &cmdPerms) + compiledRoute, err := endpoints.SetGuildCommandPermissions.Compile(applicationID, guildID, commandID) + if err != nil { + return nil, err + } + err = r.Request(*compiledRoute, commandPermissions, &cmdPerms) if err == nil { cmdPerms = r.Disgo().EntityBuilder().CreateGuildCommandPermissions(cmdPerms, api.CacheStrategyNoWs) } @@ -539,32 +696,56 @@ func (r RestClientImpl) SetGuildCommandPermissions(applicationID api.Snowflake, // SendInteractionResponse used to send the initial response on an interaction func (r RestClientImpl) SendInteractionResponse(interactionID api.Snowflake, interactionToken endpoints.Token, interactionResponse api.InteractionResponse) error { - return r.Request(endpoints.CreateInteractionResponse.Compile(interactionID, interactionToken), interactionResponse, nil) + compiledRoute, err := endpoints.CreateInteractionResponse.Compile(interactionID, interactionToken) + if err != nil { + return err + } + return r.Request(*compiledRoute, interactionResponse, nil) } // EditInteractionResponse used to edit the initial response on an interaction func (r RestClientImpl) EditInteractionResponse(applicationID api.Snowflake, interactionToken endpoints.Token, followupMessage api.FollowupMessage) (message *api.Message, err error) { - return message, r.Request(endpoints.EditInteractionResponse.Compile(applicationID, interactionToken), followupMessage, &message) + compiledRoute, err := endpoints.EditInteractionResponse.Compile(applicationID, interactionToken) + if err != nil { + return nil, err + } + return message, r.Request(*compiledRoute, followupMessage, &message) } // DeleteInteractionResponse used to delete the initial response on an interaction func (r RestClientImpl) DeleteInteractionResponse(applicationID api.Snowflake, interactionToken endpoints.Token) error { - return r.Request(endpoints.DeleteInteractionResponse.Compile(applicationID, interactionToken), nil, nil) + compiledRoute, err := endpoints.DeleteInteractionResponse.Compile(applicationID, interactionToken) + if err != nil { + return err + } + return r.Request(*compiledRoute, nil, nil) } // SendFollowupMessage used to send a followup message_events to an interaction func (r RestClientImpl) SendFollowupMessage(applicationID api.Snowflake, interactionToken endpoints.Token, followupMessage api.FollowupMessage) (message *api.Message, err error) { - return message, r.Request(endpoints.CreateFollowupMessage.Compile(applicationID, interactionToken), followupMessage, &message) + compiledRoute, err := endpoints.CreateFollowupMessage.Compile(applicationID, interactionToken) + if err != nil { + return nil, err + } + return message, r.Request(*compiledRoute, followupMessage, &message) } // EditFollowupMessage used to edit a api.FollowupMessage from an api.Interaction func (r RestClientImpl) EditFollowupMessage(applicationID api.Snowflake, interactionToken endpoints.Token, messageID api.Snowflake, followupMessage api.FollowupMessage) (message *api.Message, err error) { - return message, r.Request(endpoints.EditFollowupMessage.Compile(applicationID, interactionToken, messageID), followupMessage, &message) + compiledRoute, err := endpoints.EditFollowupMessage.Compile(applicationID, interactionToken, messageID) + if err != nil { + return nil, err + } + return message, r.Request(*compiledRoute, followupMessage, &message) } // DeleteFollowupMessage used to delete a api.FollowupMessage from an api.Interaction func (r RestClientImpl) DeleteFollowupMessage(applicationID api.Snowflake, interactionToken endpoints.Token, messageID api.Snowflake) error { - return r.Request(endpoints.DeleteFollowupMessage.Compile(applicationID, interactionToken, messageID), nil, nil) + compiledRoute, err := endpoints.DeleteFollowupMessage.Compile(applicationID, interactionToken, messageID) + if err != nil { + return err + } + return r.Request(*compiledRoute, nil, nil) } func normalizeEmoji(emoji string) string { diff --git a/internal/webhook_server_impl.go b/internal/webhook_server_impl.go index 6aa3492d..5a17e66c 100644 --- a/internal/webhook_server_impl.go +++ b/internal/webhook_server_impl.go @@ -8,16 +8,14 @@ import ( "net/http" "strconv" - "github.com/gorilla/mux" - log "github.com/sirupsen/logrus" - "github.com/DisgoOrg/disgo/api" + "github.com/gorilla/mux" ) func newWebhookServerImpl(disgo api.Disgo, listenURL string, listenPort int, publicKey string) api.WebhookServer { hexDecodedKey, err := hex.DecodeString(publicKey) if err != nil { - log.Errorf("error while decoding hex string: %s", err) + disgo.Logger().Errorf("error while decoding hex string: %s", err) } w := &WebhookServerImpl{ disgo: disgo, @@ -26,7 +24,7 @@ func newWebhookServerImpl(disgo api.Disgo, listenURL string, listenPort int, pub listenPort: listenPort, } - w.interactionHandler = &webhookInteractionHandler{w} + w.interactionHandler = &webhookInteractionHandler{disgo: disgo, webhookServer: w} return w } @@ -68,7 +66,7 @@ func (w *WebhookServerImpl) Start() { go func() { if err := http.ListenAndServe(":"+strconv.Itoa(w.listenPort), w.router); err != nil { - log.Errorf("error starting webhook server: %s", err) + w.Disgo().Logger().Errorf("error starting webhook server: %s", err) } }() } @@ -79,17 +77,18 @@ func (w *WebhookServerImpl) Close() { } type webhookInteractionHandler struct { + disgo api.Disgo webhookServer api.WebhookServer } func (h *webhookInteractionHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - if ok := api.Verify(r, h.webhookServer.PublicKey()); !ok { + if ok := api.Verify(h.disgo, r, h.webhookServer.PublicKey()); !ok { w.WriteHeader(http.StatusUnauthorized) return } defer func() { if err := r.Body.Close(); err != nil { - log.Errorf("error closing request body in WebhookServer: %s", err) + h.disgo.Logger().Errorf("error closing request body in WebhookServer: %s", err) } }() rawBody, err := ioutil.ReadAll(r.Body) @@ -104,6 +103,6 @@ func (h *webhookInteractionHandler) ServeHTTP(w http.ResponseWriter, r *http.Req err = json.NewEncoder(w).Encode(<-c) if err != nil { - log.Errorf("error writing body: %s", err) + h.disgo.Logger().Errorf("error writing body: %s", err) } } diff --git a/testbot/go.mod b/testbot/go.mod new file mode 100644 index 00000000..911abcf9 --- /dev/null +++ b/testbot/go.mod @@ -0,0 +1,11 @@ +module github.com/DisgoOrg/disgo/testbot + +go 1.16 + +replace github.com/DisgoOrg/disgo => ../ + +require ( + github.com/DisgoOrg/disgo v0.1.6 + github.com/PaesslerAG/gval v1.1.0 + github.com/sirupsen/logrus v1.8.1 +) diff --git a/testbot/go.sum b/testbot/go.sum new file mode 100644 index 00000000..1549f6cf --- /dev/null +++ b/testbot/go.sum @@ -0,0 +1,27 @@ +github.com/DisgoOrg/log v1.0.0 h1:X8WSKatQUhZ/D8nYerJz75X3yD4/0vQgmAVbQ7XSVCI= +github.com/DisgoOrg/log v1.0.0/go.mod h1:E60iniXaAsm9Iuxlz53nQDTYzJTSf1Kn/oH9KQhaK6w= +github.com/PaesslerAG/gval v1.1.0 h1:k3RuxeZDO3eejD4cMPSt+74tUSvTnbGvLx0df4mdwFc= +github.com/PaesslerAG/gval v1.1.0/go.mod h1:y/nm5yEyTeX6av0OfKJNp9rBNj2XrGhAf5+v24IBN1I= +github.com/PaesslerAG/jsonpath v0.1.0 h1:gADYeifvlqK3R3i2cR5B4DGgxLXIPb3TRTH1mGi0jPI= +github.com/PaesslerAG/jsonpath v0.1.0/go.mod h1:4BzmtoM/PI8fPO4aQGIusjGxGir2BzcV0grWtFzq1Y8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/testbot/testbot.go b/testbot/testbot.go index 1aa3b42b..ec21df8b 100644 --- a/testbot/testbot.go +++ b/testbot/testbot.go @@ -9,7 +9,7 @@ import ( "time" "github.com/PaesslerAG/gval" - log "github.com/sirupsen/logrus" + "github.com/sirupsen/logrus" "github.com/DisgoOrg/disgo" "github.com/DisgoOrg/disgo/api" @@ -25,11 +25,14 @@ const guildID = "817327181659111454" const adminRoleID = "817327279583264788" const testRoleID = "825156597935243304" +var logger = logrus.New() + func main() { - log.Info("starting testbot...") + logger.SetLevel(logrus.DebugLevel) + logger.Info("starting testbot...") dgo, err := disgo.NewBuilder(endpoints.Token(os.Getenv("token"))). - SetLogLevel(log.DebugLevel). + SetLogger(logger). SetIntents(api.IntentsGuilds | api.IntentsGuildMessages | api.IntentsGuildMembers). SetMemberCachePolicy(api.MemberCachePolicyAll). AddEventListeners(&events.ListenerAdapter{ @@ -39,7 +42,7 @@ func main() { }). Build() if err != nil { - log.Fatalf("error while building disgo instance: %s", err) + logger.Fatalf("error while building disgo instance: %s", err) return } @@ -118,7 +121,7 @@ func main() { // using the api.RestClient directly to avoid the guild needing to be cached cmds, err := dgo.RestClient().SetGuildCommands(dgo.SelfUserID(), guildID, rawCmds...) if err != nil { - log.Errorf("error while registering guild commands: %s", err) + logger.Errorf("error while registering guild commands: %s", err) } var cmdsPermissions []api.SetGuildCommandPermissions @@ -143,24 +146,24 @@ func main() { }) } if _, err = dgo.RestClient().SetGuildCommandsPermissions(dgo.SelfUserID(), guildID, cmdsPermissions...); err != nil { - log.Errorf("error while setting command permissions: %s", err) + logger.Errorf("error while setting command permissions: %s", err) } err = dgo.Connect() if err != nil { - log.Fatalf("error while connecting to discord: %s", err) + logger.Fatalf("error while connecting to discord: %s", err) } defer dgo.Close() - log.Infof("Bot is now running. Press CTRL-C to exit.") + logger.Infof("Bot is now running. Press CTRL-C to exit.") s := make(chan os.Signal, 1) signal.Notify(s, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill) <-s } func guildAvailListener(event *events.GuildAvailableEvent) { - log.Printf("guild loaded: %s", event.GuildID) + logger.Printf("guild loaded: %s", event.GuildID) } func slashCommandListener(event *events.SlashCommandEvent) { From 7875aad3f5523339f19702a9bd46ebf8163be916 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Sun, 11 Apr 2021 14:34:49 +0200 Subject: [PATCH 45/65] fixed stuff lol --- go.mod | 2 +- go.sum | 14 +++----------- testbot/go.sum | 2 ++ 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index eeb9dc7c..51547a44 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/DisgoOrg/disgo go 1.16 require ( - github.com/DisgoOrg/log v1.0.1 + github.com/DisgoOrg/log v1.0.2 github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.4.2 github.com/stretchr/testify v1.7.0 diff --git a/go.sum b/go.sum index 45356e1d..a1eda3de 100644 --- a/go.sum +++ b/go.sum @@ -1,24 +1,16 @@ -github.com/PaesslerAG/gval v1.1.0 h1:k3RuxeZDO3eejD4cMPSt+74tUSvTnbGvLx0df4mdwFc= -github.com/PaesslerAG/gval v1.1.0/go.mod h1:y/nm5yEyTeX6av0OfKJNp9rBNj2XrGhAf5+v24IBN1I= -github.com/PaesslerAG/jsonpath v0.1.0 h1:gADYeifvlqK3R3i2cR5B4DGgxLXIPb3TRTH1mGi0jPI= -github.com/PaesslerAG/jsonpath v0.1.0/go.mod h1:4BzmtoM/PI8fPO4aQGIusjGxGir2BzcV0grWtFzq1Y8= +github.com/DisgoOrg/log v1.0.2 h1:qDOmBkB2xnN0sG74dTNKs/qdWekVAJAyVPDASofIWOc= +github.com/DisgoOrg/log v1.0.2/go.mod h1:KFGKhBQr37d6rxZ7p2bmc8BEmDH8DZbtgdlJDSCsE7I= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= diff --git a/testbot/go.sum b/testbot/go.sum index 1549f6cf..1ef1fc3b 100644 --- a/testbot/go.sum +++ b/testbot/go.sum @@ -1,5 +1,7 @@ github.com/DisgoOrg/log v1.0.0 h1:X8WSKatQUhZ/D8nYerJz75X3yD4/0vQgmAVbQ7XSVCI= github.com/DisgoOrg/log v1.0.0/go.mod h1:E60iniXaAsm9Iuxlz53nQDTYzJTSf1Kn/oH9KQhaK6w= +github.com/DisgoOrg/log v1.0.2 h1:qDOmBkB2xnN0sG74dTNKs/qdWekVAJAyVPDASofIWOc= +github.com/DisgoOrg/log v1.0.2/go.mod h1:KFGKhBQr37d6rxZ7p2bmc8BEmDH8DZbtgdlJDSCsE7I= github.com/PaesslerAG/gval v1.1.0 h1:k3RuxeZDO3eejD4cMPSt+74tUSvTnbGvLx0df4mdwFc= github.com/PaesslerAG/gval v1.1.0/go.mod h1:y/nm5yEyTeX6av0OfKJNp9rBNj2XrGhAf5+v24IBN1I= github.com/PaesslerAG/jsonpath v0.1.0 h1:gADYeifvlqK3R3i2cR5B4DGgxLXIPb3TRTH1mGi0jPI= From 4b4be32acf4de12b94444542939a743121f38caf Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Sun, 11 Apr 2021 14:37:53 +0200 Subject: [PATCH 46/65] fixed unit test --- api/endpoints/route_test.go | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/api/endpoints/route_test.go b/api/endpoints/route_test.go index 22a0b965..052238ff 100644 --- a/api/endpoints/route_test.go +++ b/api/endpoints/route_test.go @@ -7,16 +7,25 @@ import ( ) func TestAPIRoute_Compile(t *testing.T) { - assert.Equal(t, API+"/channels/test1/messages/test2/reactions/test3/@me", AddReaction.Compile("test1", "test2", "test3").Route()) + compiledRoute, err := AddReaction.Compile("test1", "test2", "test3") + assert.NoError(t, err) + assert.Equal(t, API+"/channels/test1/messages/test2/reactions/test3/@me", compiledRoute.Route()) } func TestCDNRoute_Compile(t *testing.T) { - assert.Equal(t, CDN+"/emojis/test1.png", Emote.Compile(PNG, "test1").Route()) - assert.Equal(t, CDN+"/emojis/test1.gif", Emote.Compile(GIF, "test1").Route()) + compiledRoute, err := Emote.Compile(PNG, "test1") + assert.NoError(t, err) + assert.Equal(t, CDN+"/emojis/test1.png", compiledRoute.Route()) + + compiledRoute, err = Emote.Compile(GIF, "test1") + assert.NoError(t, err) + assert.Equal(t, CDN+"/emojis/test1.gif", compiledRoute.Route()) } func TestCustomRoute_Compile(t *testing.T) { testAPI := NewCustomRoute(GET, "https://test.de/{test}") - assert.Equal(t, "https://test.de/test", testAPI.Compile("test").Route()) + compiledRoute, err := testAPI.Compile("test") + assert.NoError(t, err) + assert.Equal(t, "https://test.de/test", compiledRoute.Route()) } From f4857814ddb2cc2335474c818894145485f18fad Mon Sep 17 00:00:00 2001 From: Alex <46286597+Alex-R-31@users.noreply.github.com> Date: Sun, 11 Apr 2021 16:36:47 +0100 Subject: [PATCH 47/65] i'm not great with the thoughts --- internal/gateway_impl.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/gateway_impl.go b/internal/gateway_impl.go index 6bdb2b01..69fb982c 100644 --- a/internal/gateway_impl.go +++ b/internal/gateway_impl.go @@ -180,7 +180,7 @@ func (g *GatewayImpl) Status() api.GatewayStatus { // Latency returns the api.Gateway latency func (g *GatewayImpl) Latency() time.Duration { - return g.lastHeartbeatSent.Sub(g.lastHeartbeatReceived) + return g.lastHeartbeatReceived.Sub(g.lastHeartbeatSent) } // Close cleans up the gateway internals From 61b290030505eabc9ae0e39c7737d84ab01f9866 Mon Sep 17 00:00:00 2001 From: Alex <46286597+Alex-R-31@users.noreply.github.com> Date: Sun, 11 Apr 2021 18:00:35 +0100 Subject: [PATCH 48/65] topi can't spell --- api/endpoints/endpoints.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/endpoints/endpoints.go b/api/endpoints/endpoints.go index 1b7b6cf8..9b98eef4 100644 --- a/api/endpoints/endpoints.go +++ b/api/endpoints/endpoints.go @@ -10,7 +10,7 @@ const ( // Misc var ( - GetVoiceReagions = NewAPIRoute(GET, "/voice/regions") + GetVoiceRegions = NewAPIRoute(GET, "/voice/regions") GetGateway = NewAPIRoute(GET, "/gateway") GetGatewayBot = NewAPIRoute(GET, "/gateway/bot") GetBotApplication = NewAPIRoute(GET, "/oauth2/applications/@me") From e3bf207899347cea8a6a14c73cd70e419d6c784d Mon Sep 17 00:00:00 2001 From: Alex <46286597+Alex-R-31@users.noreply.github.com> Date: Sun, 11 Apr 2021 18:02:23 +0100 Subject: [PATCH 49/65] remove duplicate request --- api/endpoints/endpoints.go | 1 - 1 file changed, 1 deletion(-) diff --git a/api/endpoints/endpoints.go b/api/endpoints/endpoints.go index 9b98eef4..98d3ca66 100644 --- a/api/endpoints/endpoints.go +++ b/api/endpoints/endpoints.go @@ -10,7 +10,6 @@ const ( // Misc var ( - GetVoiceRegions = NewAPIRoute(GET, "/voice/regions") GetGateway = NewAPIRoute(GET, "/gateway") GetGatewayBot = NewAPIRoute(GET, "/gateway/bot") GetBotApplication = NewAPIRoute(GET, "/oauth2/applications/@me") From 1a9a5b1d766d3ca82e66961749b04ed670925be3 Mon Sep 17 00:00:00 2001 From: Alex <46286597+Alex-R-31@users.noreply.github.com> Date: Sun, 11 Apr 2021 18:08:21 +0100 Subject: [PATCH 50/65] reduce codeql frequency --- .github/workflows/codeql-analysis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 426058c5..eacd49ce 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -13,12 +13,12 @@ name: "CodeQL" on: push: - branches: [ master ] + branches: [ master, development ] pull_request: # The branches below must be a subset of the branches above - branches: [ master ] + branches: [ master, development ] schedule: - - cron: '00 12 * * *' + - cron: '0 0 1 * *' jobs: analyze: From f30b67b7f053d64b4f39be478259ffe2591451a7 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Sun, 11 Apr 2021 19:47:24 +0200 Subject: [PATCH 51/65] adde new methods to embed builder & maybe reconnect fix --- api/embed.go | 29 +++++++++++++++++++++++------ internal/gateway_impl.go | 3 +++ testbot/testbot.go | 2 +- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/api/embed.go b/api/embed.go index 78626f05..23dd08fa 100644 --- a/api/embed.go +++ b/api/embed.go @@ -82,8 +82,8 @@ type EmbedBuilder struct { } // SetTitle sets the title of the EmbedBuilder -func (b *EmbedBuilder) SetTitle(title *string) *EmbedBuilder { - b.Title = title +func (b *EmbedBuilder) SetTitle(title string) *EmbedBuilder { + b.Title = &title return b } @@ -100,12 +100,29 @@ func (b *EmbedBuilder) SetDescriptionf(description string, a ...interface{}) *Em return b } -// SetAuthor sets the author of the EmbedBuilder -func (b *EmbedBuilder) SetAuthor(author *EmbedAuthor) *EmbedBuilder { +// SetEmbedAuthor sets the author of the EmbedBuilder +func (b *EmbedBuilder) SetEmbedAuthor(author *EmbedAuthor) *EmbedBuilder { b.Author = author return b } +func (b *EmbedBuilder) SetAuthor(name string, url string) *EmbedBuilder { + b.Author = &EmbedAuthor{ + Name: &name, + URL: &url, + } + return b +} + +func (b *EmbedBuilder) SetAuthorI(name string, url string, iconURL string) *EmbedBuilder { + b.Author = &EmbedAuthor{ + Name: &name, + URL: &url, + IconURL: &iconURL, + } + return b +} + // SetColor sets the color of the EmbedBuilder func (b *EmbedBuilder) SetColor(color int) *EmbedBuilder { b.Color = &color @@ -144,8 +161,8 @@ func (b *EmbedBuilder) SetThumbnail(i *string) *EmbedBuilder { } // SetURL sets the URL of the EmbedBuilder -func (b *EmbedBuilder) SetURL(u *string) *EmbedBuilder { - b.URL = u +func (b *EmbedBuilder) SetURL(url string) *EmbedBuilder { + b.URL = &url return b } diff --git a/internal/gateway_impl.go b/internal/gateway_impl.go index 69fb982c..48fee6ec 100644 --- a/internal/gateway_impl.go +++ b/internal/gateway_impl.go @@ -278,6 +278,9 @@ func (g *GatewayImpl) listen() { g.Disgo().Logger().Infof("existed listen routine") return default: + if g.conn == nil { + return + } mt, data, err := g.conn.ReadMessage() if err != nil { g.Disgo().Logger().Errorf("error while reading from ws. error: %s", err) diff --git a/testbot/testbot.go b/testbot/testbot.go index ec21df8b..3c852135 100644 --- a/testbot/testbot.go +++ b/testbot/testbot.go @@ -167,7 +167,7 @@ func guildAvailListener(event *events.GuildAvailableEvent) { } func slashCommandListener(event *events.SlashCommandEvent) { - switch event.Interaction.Data.Name { + switch event.CommandName { case "eval": go func() { start := time.Now() From dbf56c9cd5f16b8178631250cb72953aaba19108 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Sun, 11 Apr 2021 23:50:09 +0200 Subject: [PATCH 52/65] fixed nil pointer --- api/command.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/api/command.go b/api/command.go index 139f74e5..548a5a22 100644 --- a/api/command.go +++ b/api/command.go @@ -92,11 +92,10 @@ func (c *Command) Update(command UpdateCommand) error { // SetPermissions sets the GuildCommandPermissions for a specific Guild. this overrides all existing CommandPermission(s). thx discord for that func (c *Command) SetPermissions(guildID Snowflake, permissions ...CommandPermission) error { - perms, err := c.Disgo.RestClient().SetGuildCommandPermissions(c.Disgo.SelfUserID(), guildID, c.ID, SetGuildCommandPermissions{Permissions: permissions}) + _, err := c.Disgo.RestClient().SetGuildCommandPermissions(c.Disgo.SelfUserID(), guildID, c.ID, SetGuildCommandPermissions{Permissions: permissions}) if err != nil { return err } - c.GuildPermissions[guildID] = perms return nil } @@ -111,7 +110,6 @@ func (c *Command) FetchPermissions(guildID Snowflake) (*GuildCommandPermissions, if err != nil { return nil, err } - c.GuildPermissions[guildID] = perms return perms, nil } From 923781cdb0c197d92f21486f21bcdd7eedcf48be Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Mon, 12 Apr 2021 01:56:51 +0200 Subject: [PATCH 53/65] fixed reconnect logik & made VoiceDispatchInterceptor events pointers like they should be --- api/voice_dispatch_interceptor.go | 4 ++-- internal/gateway_impl.go | 9 +++++++-- internal/handlers/voice_server_update_handler.go | 2 +- internal/handlers/voice_state_update_handler.go | 2 +- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/api/voice_dispatch_interceptor.go b/api/voice_dispatch_interceptor.go index 3429fe77..d113f48b 100644 --- a/api/voice_dispatch_interceptor.go +++ b/api/voice_dispatch_interceptor.go @@ -32,6 +32,6 @@ func (u VoiceStateUpdateEvent) VoiceChannel() *VoiceChannel { // VoiceDispatchInterceptor lets you listen to VoiceServerUpdate & VoiceStateUpdate type VoiceDispatchInterceptor interface { - OnVoiceServerUpdate(voiceServerUpdateEvent VoiceServerUpdateEvent) - OnVoiceStateUpdate(voiceStateUpdateEvent VoiceStateUpdateEvent) + OnVoiceServerUpdate(voiceServerUpdateEvent *VoiceServerUpdateEvent) + OnVoiceStateUpdate(voiceStateUpdateEvent *VoiceStateUpdateEvent) } diff --git a/internal/gateway_impl.go b/internal/gateway_impl.go index 48fee6ec..0c75eb41 100644 --- a/internal/gateway_impl.go +++ b/internal/gateway_impl.go @@ -341,12 +341,17 @@ func (g *GatewayImpl) listen() { g.sendHeartbeat() case api.OpReconnect: - g.Close() - g.reconnect(0) g.Disgo().Logger().Debugf("received: OpReconnect") + g.Close() + g.reconnect(1*time.Second) case api.OpInvalidSession: g.Disgo().Logger().Debugf("received: OpInvalidSession") + g.Close() + // clear reconnect info + g.sessionID = nil + g.lastSequenceReceived = nil + g.reconnect(5*time.Second) case api.OpHeartbeatACK: g.Disgo().Logger().Debugf("received: OpHeartbeatACK") diff --git a/internal/handlers/voice_server_update_handler.go b/internal/handlers/voice_server_update_handler.go index 4b58ecff..33ee9fb1 100644 --- a/internal/handlers/voice_server_update_handler.go +++ b/internal/handlers/voice_server_update_handler.go @@ -23,7 +23,7 @@ func (h VoiceServerUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManag } if interceptor := disgo.VoiceDispatchInterceptor(); interceptor != nil { - interceptor.OnVoiceServerUpdate(api.VoiceServerUpdateEvent{ + interceptor.OnVoiceServerUpdate(&api.VoiceServerUpdateEvent{ VoiceServerUpdate: *voiceServerUpdate, Disgo: disgo, }) diff --git a/internal/handlers/voice_state_update_handler.go b/internal/handlers/voice_state_update_handler.go index 43478e0f..f4884756 100644 --- a/internal/handlers/voice_state_update_handler.go +++ b/internal/handlers/voice_state_update_handler.go @@ -36,7 +36,7 @@ func (h VoiceStateUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManage if disgo.SelfUserID() == voiceStateUpdate.UserID { if interceptor := disgo.VoiceDispatchInterceptor(); interceptor != nil { - interceptor.OnVoiceStateUpdate(*voiceStateUpdate) + interceptor.OnVoiceStateUpdate(voiceStateUpdate) } } From 6f84fc9b1fb371808efcea646bc94766713a7fb5 Mon Sep 17 00:00:00 2001 From: BennyDiscord <46286597+BennyDiscord@users.noreply.github.com> Date: Mon, 12 Apr 2021 14:02:59 +0100 Subject: [PATCH 54/65] add some lint --- api/embed.go | 14 ++++++++------ api/endpoints/route.go | 1 + api/entity_builder.go | 4 ++++ api/invite.go | 40 ++++++++++++++++++++++++---------------- api/permissions.go | 3 +++ internal/cache_impl.go | 20 ++++++++++++++++++++ 6 files changed, 60 insertions(+), 22 deletions(-) diff --git a/api/embed.go b/api/embed.go index 23dd08fa..d1238ff9 100644 --- a/api/embed.go +++ b/api/embed.go @@ -100,25 +100,27 @@ func (b *EmbedBuilder) SetDescriptionf(description string, a ...interface{}) *Em return b } -// SetEmbedAuthor sets the author of the EmbedBuilder +// SetEmbedAuthor sets the author of the EmbedBuilder using an EmbedAuthor struct func (b *EmbedBuilder) SetEmbedAuthor(author *EmbedAuthor) *EmbedBuilder { b.Author = author return b } +// SetAuthor sets the author of the EmbedBuilder without an Icon URL func (b *EmbedBuilder) SetAuthor(name string, url string) *EmbedBuilder { b.Author = &EmbedAuthor{ - Name: &name, - URL: &url, + Name: &name, + URL: &url, } return b } +// SetAuthorI sets the author of the EmbedBuilder with all properties func (b *EmbedBuilder) SetAuthorI(name string, url string, iconURL string) *EmbedBuilder { b.Author = &EmbedAuthor{ - Name: &name, - URL: &url, - IconURL: &iconURL, + Name: &name, + URL: &url, + IconURL: &iconURL, } return b } diff --git a/api/endpoints/route.go b/api/endpoints/route.go index 79e250fc..eb5b661d 100644 --- a/api/endpoints/route.go +++ b/api/endpoints/route.go @@ -37,6 +37,7 @@ func (r Route) Compile(args ...interface{}) (*CompiledRoute, error) { return &CompiledRoute{route: r.baseRoute + route}, nil } +// NewRoute generates a Route when given a URL func NewRoute(url string) Route { return Route{ baseRoute: "", diff --git a/api/entity_builder.go b/api/entity_builder.go index a532a5f6..7cded026 100644 --- a/api/entity_builder.go +++ b/api/entity_builder.go @@ -1,13 +1,17 @@ package api +// CacheStrategy is used to determine whether something should be cached when making an api request. When using the +// gateway, you'll receive the event shortly afterwards if you have the correct intents. type CacheStrategy func(disgo Disgo) bool +// Default cache strategy choices var ( CacheStrategyYes CacheStrategy = func(disgo Disgo) bool { return true } CacheStrategyNo CacheStrategy = func(disgo Disgo) bool { return true } CacheStrategyNoWs CacheStrategy = func(disgo Disgo) bool { return disgo.HasGateway() } ) +// EntityBuilder is used to create structs for disgo's cache type EntityBuilder interface { Disgo() Disgo diff --git a/api/invite.go b/api/invite.go index e04a75fa..525ec7ea 100644 --- a/api/invite.go +++ b/api/invite.go @@ -2,6 +2,7 @@ package api import "time" +// ExpandedInvite is a full Invite struct type ExpandedInvite struct { Invite Uses int `json:"uses"` @@ -11,26 +12,31 @@ type ExpandedInvite struct { CreatedAt time.Time `json:"created_at"` } +// Invite is a partial invite struct type Invite struct { Disgo Disgo - Code string `json:"code"` - Guild *InviteGuild `json:"guild"` - Channel InviteChannel `json:"channel"` - Inviter *User `json:"inviter"` - TargetUser *InviteUser `json:"target_user"` - TargetUserType *TargetUserType `json:"target_user_type"` - ApproximatePresenceCount *int `json:"approximate_presence_count"` - ApproximateMemberCount *int `json:"approximate_member_count"` + Code string `json:"code"` + Guild *InviteGuild `json:"guild"` + Channel InviteChannel `json:"channel"` + Inviter *User `json:"inviter"` + TargetUser *InviteUser `json:"target_user"` + TargetType *TargetType `json:"target_user_type"` + ApproximatePresenceCount *int `json:"approximate_presence_count"` + ApproximateMemberCount *int `json:"approximate_member_count"` } -type TargetUserType int +// TargetType is type of target an Invite uses +type TargetType int +// Constants for TargetType const ( - TargetUserTypeStream = iota + 1 + TargetTypeStream TargetType = iota + 1 + TargetTypeEmbeddedApplication ) +// An InviteGuild is the Guild of an Invite type InviteGuild struct { - Id Snowflake `json:"id"` + ID Snowflake `json:"id"` Name string `json:"name"` Splash *string `json:"splash"` Banner *string `json:"banner"` @@ -38,17 +44,19 @@ type InviteGuild struct { Icon *string `json:"icon"` Features []GuildFeature `json:"features"` VerificationLevel VerificationLevel `json:"verification_level"` - VanityUrlCode *string `json:"vanity_url_code"` + VanityURLCode *string `json:"vanity_url_code"` } +// InviteChannel is the Channel of an invite type InviteChannel struct { - Id string `json:"id"` - Name string `json:"name"` - Type int `json:"type"` + ID string `json:"id"` + Name string `json:"name"` + Type ChannelType `json:"type"` } +// InviteUser is the user who created an invite type InviteUser struct { - Id string `json:"id"` + ID string `json:"id"` Username string `json:"username"` Avatar string `json:"avatar"` Discriminator string `json:"discriminator"` diff --git a/api/permissions.go b/api/permissions.go index 1ede25f7..48b64be6 100644 --- a/api/permissions.go +++ b/api/permissions.go @@ -5,13 +5,16 @@ import ( "strconv" ) +// PermissionOverwriteType is the type of a PermissionOverwrite type PermissionOverwriteType int +// Constants for PermissionOverwriteType const ( PermissionOverwriteTypeRole PermissionOverwriteType = iota PermissionOverwriteTypeMember ) +// PermissionOverwrite is used to determine who can perform particular actions in a GuildChannel type PermissionOverwrite struct { ID Snowflake `json:"id"` Type PermissionOverwriteType `json:"type"` diff --git a/internal/cache_impl.go b/internal/cache_impl.go index 1bdc30ca..06090e1c 100644 --- a/internal/cache_impl.go +++ b/internal/cache_impl.go @@ -107,6 +107,7 @@ func (c CacheImpl) CacheFlags() api.CacheFlags { return c.cacheFlags } +// Command returns an api.Command from cache func (c *CacheImpl) Command(commandID api.Snowflake) *api.Command { if command, ok := c.globalCommands[commandID]; ok { return command @@ -119,18 +120,22 @@ func (c *CacheImpl) Command(commandID api.Snowflake) *api.Command { return nil } +// GuildCommandCache returns the cache of commands in a Guild func (c *CacheImpl) GuildCommandCache(guildID api.Snowflake) map[api.Snowflake]*api.Command { return c.guildCommands[guildID] } +// AllGuildCommandCache returns the cache of all Guild Command(s) func (c *CacheImpl) AllGuildCommandCache() map[api.Snowflake]map[api.Snowflake]*api.Command { return c.guildCommands } +// GlobalCommandCache returns the cache of global Command(s) func (c *CacheImpl) GlobalCommandCache() map[api.Snowflake]*api.Command { return c.globalCommands } +// CacheGlobalCommand adds a global command to the cache func (c *CacheImpl) CacheGlobalCommand(command *api.Command) *api.Command { if !c.CacheFlags().Has(api.CacheFlagCommands) { return command @@ -142,6 +147,8 @@ func (c *CacheImpl) CacheGlobalCommand(command *api.Command) *api.Command { c.globalCommands[command.ID] = command return command } + +// CacheGuildCommand adds a Guild Command to the cache func (c *CacheImpl) CacheGuildCommand(command *api.Command) *api.Command { if !c.CacheFlags().Has(api.CacheFlagCommands) { return command @@ -155,6 +162,8 @@ func (c *CacheImpl) CacheGuildCommand(command *api.Command) *api.Command { } return command } + +// UncacheCommand removes a global Command from the cache func (c *CacheImpl) UncacheCommand(commandID api.Snowflake) { if _, ok := c.globalCommands[commandID]; ok { delete(c.globalCommands, commandID) @@ -338,12 +347,15 @@ func (c *CacheImpl) FindGuilds(check func(g *api.Guild) bool) []*api.Guild { return guilds } +// Message returns a message from cache func (c *CacheImpl) Message(channelID api.Snowflake, messageID api.Snowflake) *api.Message { if channelMessages, ok := c.messages[channelID]; ok { return channelMessages[messageID] } return nil } + +// Messages returns the messages of a channel from cache func (c *CacheImpl) Messages(channelID api.Snowflake) []*api.Message { if channelMessages, ok := c.messages[channelID]; ok { messages := make([]*api.Message, len(channelMessages)) @@ -356,12 +368,18 @@ func (c *CacheImpl) Messages(channelID api.Snowflake) []*api.Message { } return nil } + +// MessageCache returns the entire cache of Message(s) for a Channel func (c *CacheImpl) MessageCache(channelID api.Snowflake) map[api.Snowflake]*api.Message { return c.messages[channelID] } + +// AllMessageCache returns the entire cache of messages func (c *CacheImpl) AllMessageCache() map[api.Snowflake]map[api.Snowflake]*api.Message { return c.messages } + +//CacheMessage adds a message to the cache func (c *CacheImpl) CacheMessage(message *api.Message) *api.Message { // only cache message if we want to if !c.messageCachePolicy(message) { @@ -376,6 +394,8 @@ func (c *CacheImpl) CacheMessage(message *api.Message) *api.Message { } return message } + +// UncacheMessage removes a Message from the cache if the cache policy allows it func (c *CacheImpl) UncacheMessage(channelID api.Snowflake, messageID api.Snowflake) { if channelMessages, ok := c.messages[channelID]; ok { if message, ok := channelMessages[messageID]; ok { From 6fb155d674dfe1c84b247377d4a0cac3f417be69 Mon Sep 17 00:00:00 2001 From: BennyDiscord <46286597+BennyDiscord@users.noreply.github.com> Date: Mon, 12 Apr 2021 15:17:11 +0100 Subject: [PATCH 55/65] finish internal\ cache --- internal/entity_builder_impl.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/internal/entity_builder_impl.go b/internal/entity_builder_impl.go index 2a65fa44..3bd49807 100644 --- a/internal/entity_builder_impl.go +++ b/internal/entity_builder_impl.go @@ -8,14 +8,17 @@ func newEntityBuilderImpl(disgo api.Disgo) api.EntityBuilder { return &EntityBuilderImpl{disgo: disgo} } +// EntityBuilderImpl is used for creating structs used by Disgo type EntityBuilderImpl struct { disgo api.Disgo } +// Disgo returns the api.Disgo client func (b EntityBuilderImpl) Disgo() api.Disgo { return b.disgo } +// CreateGlobalCommand returns a new api.Command entity func (b EntityBuilderImpl) CreateGlobalCommand(command *api.Command, updateCache api.CacheStrategy) *api.Command { command.Disgo = b.Disgo() if updateCache(b.Disgo()) { @@ -24,6 +27,7 @@ func (b EntityBuilderImpl) CreateGlobalCommand(command *api.Command, updateCache return command } +// CreateUser returns a new api.User entity func (b EntityBuilderImpl) CreateUser(user *api.User, updateCache api.CacheStrategy) *api.User { user.Disgo = b.Disgo() if updateCache(b.Disgo()) { @@ -32,6 +36,7 @@ func (b EntityBuilderImpl) CreateUser(user *api.User, updateCache api.CacheStrat return user } +// CreateMessage returns a new api.Message entity func (b EntityBuilderImpl) CreateMessage(message *api.Message, updateCache api.CacheStrategy) *api.Message { message.Disgo = b.Disgo() if message.Member != nil { @@ -47,6 +52,7 @@ func (b EntityBuilderImpl) CreateMessage(message *api.Message, updateCache api.C return message } +// CreateGuild returns a new api.Guild entity func (b EntityBuilderImpl) CreateGuild(guild *api.Guild, updateCache api.CacheStrategy) *api.Guild { guild.Disgo = b.Disgo() if updateCache(b.Disgo()) { @@ -55,6 +61,7 @@ func (b EntityBuilderImpl) CreateGuild(guild *api.Guild, updateCache api.CacheSt return guild } +// CreateMember returns a new api.Member entity func (b EntityBuilderImpl) CreateMember(guildID api.Snowflake, member *api.Member, updateCache api.CacheStrategy) *api.Member { member.Disgo = b.Disgo() member.GuildID = guildID @@ -65,6 +72,7 @@ func (b EntityBuilderImpl) CreateMember(guildID api.Snowflake, member *api.Membe return member } +// CreateVoiceState returns a new api.VoiceState entity func (b EntityBuilderImpl) CreateVoiceState(voiceState *api.VoiceState, updateCache api.CacheStrategy) *api.VoiceState { voiceState.Disgo = b.Disgo() if updateCache(b.Disgo()) { @@ -73,6 +81,7 @@ func (b EntityBuilderImpl) CreateVoiceState(voiceState *api.VoiceState, updateCa return voiceState } +// CreateGuildCommand returns a new api.Command entity func (b EntityBuilderImpl) CreateGuildCommand(guildID api.Snowflake, command *api.Command, updateCache api.CacheStrategy) *api.Command { command.Disgo = b.Disgo() command.GuildID = &guildID @@ -82,6 +91,7 @@ func (b EntityBuilderImpl) CreateGuildCommand(guildID api.Snowflake, command *ap return command } +// CreateGuildCommandPermissions returns a new api.GuildCommandPermissions entity func (b EntityBuilderImpl) CreateGuildCommandPermissions(guildCommandPermissions *api.GuildCommandPermissions, updateCache api.CacheStrategy) *api.GuildCommandPermissions { guildCommandPermissions.Disgo = b.Disgo() if updateCache(b.Disgo()) && b.Disgo().Cache().CacheFlags().Has(api.CacheFlagCommandPermissions) { @@ -92,6 +102,7 @@ func (b EntityBuilderImpl) CreateGuildCommandPermissions(guildCommandPermissions return guildCommandPermissions } +// CreateRole returns a new api.Role entity func (b EntityBuilderImpl) CreateRole(guildID api.Snowflake, role *api.Role, updateCache api.CacheStrategy) *api.Role { role.Disgo = b.Disgo() role.GuildID = guildID @@ -101,6 +112,7 @@ func (b EntityBuilderImpl) CreateRole(guildID api.Snowflake, role *api.Role, upd return role } +// CreateTextChannel returns a new api.TextChannel entity func (b EntityBuilderImpl) CreateTextChannel(channel *api.Channel, updateCache api.CacheStrategy) *api.TextChannel { channel.Disgo = b.Disgo() textChannel := &api.TextChannel{ @@ -117,6 +129,7 @@ func (b EntityBuilderImpl) CreateTextChannel(channel *api.Channel, updateCache a return textChannel } +// CreateVoiceChannel returns a new api.VoiceChannel entity func (b EntityBuilderImpl) CreateVoiceChannel(channel *api.Channel, updateCache api.CacheStrategy) *api.VoiceChannel { channel.Disgo = b.Disgo() voiceChannel := &api.VoiceChannel{ @@ -130,6 +143,7 @@ func (b EntityBuilderImpl) CreateVoiceChannel(channel *api.Channel, updateCache return voiceChannel } +// CreateStoreChannel returns a new api.StoreChannel entity func (b EntityBuilderImpl) CreateStoreChannel(channel *api.Channel, updateCache api.CacheStrategy) *api.StoreChannel { channel.Disgo = b.Disgo() storeChannel := &api.StoreChannel{ @@ -143,6 +157,7 @@ func (b EntityBuilderImpl) CreateStoreChannel(channel *api.Channel, updateCache return storeChannel } +// CreateCategory returns a new api.Category entity func (b EntityBuilderImpl) CreateCategory(channel *api.Channel, updateCache api.CacheStrategy) *api.Category { channel.Disgo = b.Disgo() category := &api.Category{ @@ -156,6 +171,7 @@ func (b EntityBuilderImpl) CreateCategory(channel *api.Channel, updateCache api. return category } +// CreateDMChannel returns a new api.DMChannel entity func (b EntityBuilderImpl) CreateDMChannel(channel *api.Channel, updateCache api.CacheStrategy) *api.DMChannel { channel.Disgo = b.Disgo() dmChannel := &api.DMChannel{ @@ -169,6 +185,7 @@ func (b EntityBuilderImpl) CreateDMChannel(channel *api.Channel, updateCache api return dmChannel } +// CreateEmote returns a new api.Emote entity func (b EntityBuilderImpl) CreateEmote(guildId api.Snowflake, emote *api.Emote, updateCache api.CacheStrategy) *api.Emote { emote.Disgo = b.Disgo() emote.GuildID = guildId From 245378f5fa96dfb390ec22ad57858dcc8a309594 Mon Sep 17 00:00:00 2001 From: BennyDiscord <46286597+BennyDiscord@users.noreply.github.com> Date: Mon, 12 Apr 2021 19:09:58 +0100 Subject: [PATCH 56/65] slightly improve order of gateway statuses --- internal/gateway_impl.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/gateway_impl.go b/internal/gateway_impl.go index 0c75eb41..742ef515 100644 --- a/internal/gateway_impl.go +++ b/internal/gateway_impl.go @@ -150,6 +150,7 @@ func (g *GatewayImpl) Open() error { ); err != nil { return err } + g.status = api.WaitingForReady } else { g.Disgo().Logger().Infof("sending Resuming command...") g.status = api.Resuming @@ -164,7 +165,6 @@ func (g *GatewayImpl) Open() error { } } - g.status = api.WaitingForReady g.quit = make(chan interface{}) go g.heartbeat() From 228eccaa23ec5a7f910f1107dbdceac290982257 Mon Sep 17 00:00:00 2001 From: BennyDiscord <46286597+BennyDiscord@users.noreply.github.com> Date: Mon, 12 Apr 2021 19:15:22 +0100 Subject: [PATCH 57/65] fix reconnects in theory --- api/gateway.go | 2 +- internal/gateway_impl.go | 18 +++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/api/gateway.go b/api/gateway.go index 5a39c650..25c72eaa 100644 --- a/api/gateway.go +++ b/api/gateway.go @@ -24,7 +24,7 @@ type Gateway interface { Disgo() Disgo Open() error Status() GatewayStatus - Close() + Close(bool) Latency() time.Duration } diff --git a/internal/gateway_impl.go b/internal/gateway_impl.go index 742ef515..90ee20b7 100644 --- a/internal/gateway_impl.go +++ b/internal/gateway_impl.go @@ -86,7 +86,7 @@ func (g *GatewayImpl) Open() error { gatewayURL := *g.url + "?v=" + endpoints.APIVersion + "&encoding=json" wsConn, rs, err := websocket.DefaultDialer.Dial(gatewayURL, nil) if err != nil { - g.Close() + g.Close(false) var body string if rs != nil && rs.Body != nil { rawBody, err := ioutil.ReadAll(rs.Body) @@ -184,7 +184,7 @@ func (g *GatewayImpl) Latency() time.Duration { } // Close cleans up the gateway internals -func (g *GatewayImpl) Close() { +func (g *GatewayImpl) Close(toReconnect bool) { g.status = api.Disconnected if g.quit != nil { g.Disgo().Logger().Info("closing gateway goroutines...") @@ -193,7 +193,11 @@ func (g *GatewayImpl) Close() { g.Disgo().Logger().Info("closed gateway goroutines") } if g.conn != nil { - if err := g.closeWithCode(websocket.CloseNormalClosure); err != nil { + closeCode := websocket.CloseNormalClosure + if toReconnect { + closeCode = websocket.CloseServiceRestart + } + if err := g.closeWithCode(closeCode); err != nil { g.Disgo().Logger().Errorf("error while closing wsconn: %s", err) } } @@ -253,7 +257,7 @@ func (g *GatewayImpl) sendHeartbeat() { if err := g.conn.WriteJSON(api.NewGatewayCommand(api.OpHeartbeat, g.lastSequenceReceived)); err != nil { g.Disgo().Logger().Errorf("failed to send heartbeat with error: %s", err) - g.Close() + g.Close(true) g.reconnect(1 * time.Second) } g.lastHeartbeatSent = time.Now().UTC() @@ -284,7 +288,7 @@ func (g *GatewayImpl) listen() { mt, data, err := g.conn.ReadMessage() if err != nil { g.Disgo().Logger().Errorf("error while reading from ws. error: %s", err) - g.Close() + g.Close(true) g.reconnect(1 * time.Second) return } @@ -342,12 +346,12 @@ func (g *GatewayImpl) listen() { case api.OpReconnect: g.Disgo().Logger().Debugf("received: OpReconnect") - g.Close() + g.Close(true) g.reconnect(1*time.Second) case api.OpInvalidSession: g.Disgo().Logger().Debugf("received: OpInvalidSession") - g.Close() + g.Close(false) // clear reconnect info g.sessionID = nil g.lastSequenceReceived = nil From b3378fecb505ba3edf3f4d5cf51ef4585b7c6c21 Mon Sep 17 00:00:00 2001 From: BennyDiscord <46286597+BennyDiscord@users.noreply.github.com> Date: Mon, 12 Apr 2021 19:17:12 +0100 Subject: [PATCH 58/65] Oh I missed that --- internal/disgo_impl.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/disgo_impl.go b/internal/disgo_impl.go index 9c5bf988..54a5ad0b 100644 --- a/internal/disgo_impl.go +++ b/internal/disgo_impl.go @@ -93,7 +93,7 @@ func (d *DisgoImpl) Close() { d.WebhookServer().Close() } if d.Gateway() != nil { - d.Gateway().Close() + d.Gateway().Close(false) } if d.EventManager() != nil { d.EventManager().Close() From 575d1db02b6dab98160b2cd1bb3b88cfa6c0983f Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Mon, 12 Apr 2021 20:41:01 +0200 Subject: [PATCH 59/65] changed log level of recovers & updated log lib --- go.mod | 2 +- go.sum | 4 ++-- internal/cache_impl.go | 2 +- internal/event_manager_impl.go | 2 +- internal/gateway_impl.go | 4 ++-- testbot/go.sum | 2 ++ 6 files changed, 9 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 51547a44..460f2c3c 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/DisgoOrg/disgo go 1.16 require ( - github.com/DisgoOrg/log v1.0.2 + github.com/DisgoOrg/log v1.0.3 github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.4.2 github.com/stretchr/testify v1.7.0 diff --git a/go.sum b/go.sum index a1eda3de..7fd0a7b8 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/DisgoOrg/log v1.0.2 h1:qDOmBkB2xnN0sG74dTNKs/qdWekVAJAyVPDASofIWOc= -github.com/DisgoOrg/log v1.0.2/go.mod h1:KFGKhBQr37d6rxZ7p2bmc8BEmDH8DZbtgdlJDSCsE7I= +github.com/DisgoOrg/log v1.0.3 h1:IjmZQQu/kuBIui22EdXmxzQGYwcPCJEkXa0Fe6W9fJk= +github.com/DisgoOrg/log v1.0.3/go.mod h1:KFGKhBQr37d6rxZ7p2bmc8BEmDH8DZbtgdlJDSCsE7I= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= diff --git a/internal/cache_impl.go b/internal/cache_impl.go index 06090e1c..4cabca02 100644 --- a/internal/cache_impl.go +++ b/internal/cache_impl.go @@ -71,7 +71,7 @@ func (c *CacheImpl) Close() { func (c CacheImpl) startCleanup(cleanupInterval time.Duration) { defer func() { if r := recover(); r != nil { - c.Disgo().Logger().Errorf("recovered cache cleanup goroutine error: %s", r) + c.Disgo().Logger().Panicf("recovered cache cleanup goroutine error: %s", r) debug.PrintStack() c.startCleanup(cleanupInterval) return diff --git a/internal/event_manager_impl.go b/internal/event_manager_impl.go index 25bae32e..a6b112bc 100644 --- a/internal/event_manager_impl.go +++ b/internal/event_manager_impl.go @@ -75,7 +75,7 @@ func (e *EventManagerImpl) AddEventListeners(listeners ...api.EventListener) { func (e *EventManagerImpl) ListenEvents() { defer func() { if r := recover(); r != nil { - e.Disgo().Logger().Errorf("recovered event listen goroutine error: %s", r) + e.Disgo().Logger().Panicf("recovered event listen goroutine error: %s", r) debug.PrintStack() e.ListenEvents() return diff --git a/internal/gateway_impl.go b/internal/gateway_impl.go index 90ee20b7..f5ee86fe 100644 --- a/internal/gateway_impl.go +++ b/internal/gateway_impl.go @@ -227,7 +227,7 @@ func (g *GatewayImpl) closeWithCode(code int) error { func (g *GatewayImpl) heartbeat() { defer func() { if r := recover(); r != nil { - g.Disgo().Logger().Errorf("recovered heartbeat goroutine error: %s", r) + g.Disgo().Logger().Panicf("recovered heartbeat goroutine error: %s", r) debug.PrintStack() g.heartbeat() return @@ -269,7 +269,7 @@ func (g *GatewayImpl) sendHeartbeat() { func (g *GatewayImpl) listen() { defer func() { if r := recover(); r != nil { - g.Disgo().Logger().Errorf("recovered listen goroutine error: %s", r) + g.Disgo().Logger().Panicf("recovered listen goroutine error: %s", r) debug.PrintStack() g.listen() return diff --git a/testbot/go.sum b/testbot/go.sum index 1ef1fc3b..094591a0 100644 --- a/testbot/go.sum +++ b/testbot/go.sum @@ -2,6 +2,8 @@ github.com/DisgoOrg/log v1.0.0 h1:X8WSKatQUhZ/D8nYerJz75X3yD4/0vQgmAVbQ7XSVCI= github.com/DisgoOrg/log v1.0.0/go.mod h1:E60iniXaAsm9Iuxlz53nQDTYzJTSf1Kn/oH9KQhaK6w= github.com/DisgoOrg/log v1.0.2 h1:qDOmBkB2xnN0sG74dTNKs/qdWekVAJAyVPDASofIWOc= github.com/DisgoOrg/log v1.0.2/go.mod h1:KFGKhBQr37d6rxZ7p2bmc8BEmDH8DZbtgdlJDSCsE7I= +github.com/DisgoOrg/log v1.0.3 h1:IjmZQQu/kuBIui22EdXmxzQGYwcPCJEkXa0Fe6W9fJk= +github.com/DisgoOrg/log v1.0.3/go.mod h1:KFGKhBQr37d6rxZ7p2bmc8BEmDH8DZbtgdlJDSCsE7I= github.com/PaesslerAG/gval v1.1.0 h1:k3RuxeZDO3eejD4cMPSt+74tUSvTnbGvLx0df4mdwFc= github.com/PaesslerAG/gval v1.1.0/go.mod h1:y/nm5yEyTeX6av0OfKJNp9rBNj2XrGhAf5+v24IBN1I= github.com/PaesslerAG/jsonpath v0.1.0 h1:gADYeifvlqK3R3i2cR5B4DGgxLXIPb3TRTH1mGi0jPI= From a4d06171fba3337c0fb5a8a76006eb6150d4edbc Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Mon, 12 Apr 2021 22:39:27 +0200 Subject: [PATCH 60/65] maybe fixed resume --- internal/gateway_impl.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/internal/gateway_impl.go b/internal/gateway_impl.go index f5ee86fe..3217dcd9 100644 --- a/internal/gateway_impl.go +++ b/internal/gateway_impl.go @@ -193,11 +193,14 @@ func (g *GatewayImpl) Close(toReconnect bool) { g.Disgo().Logger().Info("closed gateway goroutines") } if g.conn != nil { - closeCode := websocket.CloseNormalClosure + var err error if toReconnect { - closeCode = websocket.CloseServiceRestart + err = g.conn.Close() + g.conn = nil + } else { + err = g.closeWithCode(websocket.CloseNormalClosure) } - if err := g.closeWithCode(closeCode); err != nil { + if err != nil { g.Disgo().Logger().Errorf("error while closing wsconn: %s", err) } } From 8e47aebb5e2296854c37afa57b54c36023d9a8de Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Tue, 13 Apr 2021 02:48:42 +0200 Subject: [PATCH 61/65] smal event reformat & audio connect/disconnect support --- api/audio_controller.go | 7 +++ api/channels.go | 4 ++ api/command.go | 20 ++++---- api/disgo.go | 3 +- api/events/application_command_events.go | 4 +- api/events/category_events.go | 8 +-- api/events/dm_events.go | 16 +++--- api/events/dm_message_event.go | 4 +- api/events/emote_events.go | 9 +--- api/events/guild_events.go | 13 +---- api/events/guild_invite_events.go | 9 ---- api/events/guild_member_events.go | 25 ++++++---- api/events/guild_message_events.go | 4 +- api/events/guild_voice_events.go | 11 ++-- api/events/http_request_events.go | 4 -- api/events/interaction_events.go | 13 +++-- api/events/listener_adapter.go | 4 +- api/events/message_events.go | 4 +- api/events/ready_event.go | 2 +- api/events/role_events.go | 8 +-- api/events/store_channel_events.go | 8 +-- api/events/text_channel_events.go | 8 +-- api/events/user_events.go | 21 +------- api/events/voice_channel_events.go | 8 +-- api/gateway.go | 7 ++- api/gateway_commands.go | 8 +-- api/gateway_events.go | 9 ++-- api/guild.go | 50 ++++++++++--------- api/invite.go | 14 +++++- internal/audio_controller_impl.go | 28 +++++++++++ internal/cache_impl.go | 4 +- internal/disgo_builder_impl.go | 12 +++++ internal/disgo_impl.go | 24 ++++++--- internal/gateway_impl.go | 14 ++++-- .../handlers/application_command_create.go | 12 +++-- .../handlers/application_command_delete.go | 8 ++- .../handlers/application_command_update.go | 12 +++-- internal/handlers/channel_create_handler.go | 10 ++-- internal/handlers/channel_delete_handler.go | 15 ++---- internal/handlers/channel_update_handler.go | 25 ++++------ internal/handlers/guild_create_handler.go | 4 +- internal/handlers/guild_delete_handler.go | 17 +++---- internal/handlers/guild_member_add_handler.go | 10 ++-- .../handlers/guild_member_remove_handler.go | 18 ++++--- .../handlers/guild_member_update_handler.go | 17 ++++--- .../handlers/guild_role_create_handler.go | 10 +++- .../handlers/guild_role_delete_handler.go | 16 ++++-- .../handlers/guild_role_update_handler.go | 14 ++++-- internal/handlers/guild_update_handler.go | 9 ++-- .../handlers/interaction_create_handler.go | 2 +- internal/handlers/message_create_handler.go | 6 +-- .../handlers/voice_state_update_handler.go | 2 +- internal/restclient_impl.go | 2 +- testbot/testbot.go | 6 +-- 54 files changed, 316 insertions(+), 286 deletions(-) create mode 100644 api/audio_controller.go create mode 100644 internal/audio_controller_impl.go diff --git a/api/audio_controller.go b/api/audio_controller.go new file mode 100644 index 00000000..68672230 --- /dev/null +++ b/api/audio_controller.go @@ -0,0 +1,7 @@ +package api + +type AudioController interface { + Disgo() Disgo + Connect(guildID Snowflake, channelID Snowflake) error + Disconnect(guildID Snowflake) error +} diff --git a/api/channels.go b/api/channels.go index ffeb636c..5849817d 100644 --- a/api/channels.go +++ b/api/channels.go @@ -101,6 +101,10 @@ type VoiceChannel struct { GuildChannel } +func (c *VoiceChannel) Connect() error { + return c.Disgo.AudioController().Connect(*c.GuildID, c.ID) +} + // TextChannel allows you to interact with discord's text channels type TextChannel struct { GuildChannel diff --git a/api/command.go b/api/command.go index 548a5a22..7af7885c 100644 --- a/api/command.go +++ b/api/command.go @@ -38,10 +38,10 @@ func (c *Command) Create() error { var rC *Command var err error if c.GuildID == nil { - rC, err = c.Disgo.RestClient().CreateGlobalCommand(c.Disgo.SelfUserID(), *c) + rC, err = c.Disgo.RestClient().CreateGlobalCommand(c.Disgo.ApplicationID(), *c) } else { - rC, err = c.Disgo.RestClient().CreateGuildCommand(c.Disgo.SelfUserID(), *c.GuildID, *c) + rC, err = c.Disgo.RestClient().CreateGuildCommand(c.Disgo.ApplicationID(), *c.GuildID, *c) } if err != nil { return err @@ -58,10 +58,10 @@ func (c *Command) Fetch() error { var rC *Command var err error if c.GuildID == nil { - rC, err = c.Disgo.RestClient().GetGlobalCommand(c.Disgo.SelfUserID(), c.ID) + rC, err = c.Disgo.RestClient().GetGlobalCommand(c.Disgo.ApplicationID(), c.ID) } else { - rC, err = c.Disgo.RestClient().GetGuildCommand(c.Disgo.SelfUserID(), *c.GuildID, c.ID) + rC, err = c.Disgo.RestClient().GetGuildCommand(c.Disgo.ApplicationID(), *c.GuildID, c.ID) } if err != nil { return err @@ -78,10 +78,10 @@ func (c *Command) Update(command UpdateCommand) error { var rC *Command var err error if c.GuildID == nil { - rC, err = c.Disgo.RestClient().EditGlobalCommand(c.Disgo.SelfUserID(), c.ID, command) + rC, err = c.Disgo.RestClient().EditGlobalCommand(c.Disgo.ApplicationID(), c.ID, command) } else { - rC, err = c.Disgo.RestClient().EditGuildCommand(c.Disgo.SelfUserID(), *c.GuildID, c.ID, command) + rC, err = c.Disgo.RestClient().EditGuildCommand(c.Disgo.ApplicationID(), *c.GuildID, c.ID, command) } if err != nil { return err @@ -92,7 +92,7 @@ func (c *Command) Update(command UpdateCommand) error { // SetPermissions sets the GuildCommandPermissions for a specific Guild. this overrides all existing CommandPermission(s). thx discord for that func (c *Command) SetPermissions(guildID Snowflake, permissions ...CommandPermission) error { - _, err := c.Disgo.RestClient().SetGuildCommandPermissions(c.Disgo.SelfUserID(), guildID, c.ID, SetGuildCommandPermissions{Permissions: permissions}) + _, err := c.Disgo.RestClient().SetGuildCommandPermissions(c.Disgo.ApplicationID(), guildID, c.ID, SetGuildCommandPermissions{Permissions: permissions}) if err != nil { return err } @@ -106,7 +106,7 @@ func (c Command) GetPermissions(guildID Snowflake) *GuildCommandPermissions { // FetchPermissions fetched the GuildCommandPermissions for a specific Guild from discord func (c *Command) FetchPermissions(guildID Snowflake) (*GuildCommandPermissions, error) { - perms, err := c.Disgo.RestClient().GetGuildCommandPermissions(c.Disgo.SelfUserID(), guildID, c.ID) + perms, err := c.Disgo.RestClient().GetGuildCommandPermissions(c.Disgo.ApplicationID(), guildID, c.ID) if err != nil { return nil, err } @@ -119,10 +119,10 @@ func (c Command) Delete() error { return errNoDisgoInstance } if c.GuildID == nil { - return c.Disgo.RestClient().DeleteGlobalCommand(c.Disgo.SelfUserID(), c.ID) + return c.Disgo.RestClient().DeleteGlobalCommand(c.Disgo.ApplicationID(), c.ID) } - return c.Disgo.RestClient().DeleteGuildCommand(c.Disgo.SelfUserID(), *c.GuildID, c.ID) + return c.Disgo.RestClient().DeleteGuildCommand(c.Disgo.ApplicationID(), *c.GuildID, c.ID) } // CommandOptionType specifies the type of the arguments used in Command.Options diff --git a/api/disgo.go b/api/disgo.go index e56cecf2..6e078ec5 100644 --- a/api/disgo.go +++ b/api/disgo.go @@ -22,12 +22,13 @@ type Disgo interface { WebhookServer() WebhookServer Cache() Cache Intents() Intents - SelfUserID() Snowflake + ApplicationID() Snowflake SelfUser() *User EntityBuilder() EntityBuilder EventManager() EventManager VoiceDispatchInterceptor() VoiceDispatchInterceptor SetVoiceDispatchInterceptor(voiceInterceptor VoiceDispatchInterceptor) + AudioController() AudioController HeartbeatLatency() time.Duration LargeThreshold() int HasGateway() bool diff --git a/api/events/application_command_events.go b/api/events/application_command_events.go index 6a44a340..e712f3b1 100644 --- a/api/events/application_command_events.go +++ b/api/events/application_command_events.go @@ -7,6 +7,7 @@ import ( type GenericApplicationCommandEvent struct { GenericEvent CommandID api.Snowflake + Command *api.Command GuildID *api.Snowflake } @@ -19,16 +20,13 @@ func (e GenericApplicationCommandEvent) Guild() *api.Guild { type ApplicationCommandCreateEvent struct { GenericApplicationCommandEvent - Command *api.Command } type ApplicationCommandUpdateEvent struct { GenericApplicationCommandEvent - NewCommand *api.Command OldCommand *api.Command } type ApplicationCommandDeleteEvent struct { GenericApplicationCommandEvent - Command *api.Command } diff --git a/api/events/category_events.go b/api/events/category_events.go index 124ab633..84993cd8 100644 --- a/api/events/category_events.go +++ b/api/events/category_events.go @@ -6,24 +6,18 @@ import ( type GenericCategoryEvent struct { GenericChannelEvent -} - -func (e GenericCategoryEvent) Category() *api.Category { - return e.Disgo().Cache().Category(e.ChannelID) + Category *api.Category } type CategoryCreateEvent struct { GenericCategoryEvent - Category *api.Category } type CategoryUpdateEvent struct { GenericCategoryEvent - NewCategory *api.Category OldCategory *api.Category } type CategoryDeleteEvent struct { GenericCategoryEvent - Category *api.Category } diff --git a/api/events/dm_events.go b/api/events/dm_events.go index 99c33568..def543b9 100644 --- a/api/events/dm_events.go +++ b/api/events/dm_events.go @@ -6,24 +6,26 @@ import ( type GenericDMChannelEvent struct { GenericChannelEvent -} - -func (e GenericDMChannelEvent) DMChannel() *api.DMChannel { - return e.Disgo().Cache().DMChannel(e.ChannelID) + DMChannel *api.DMChannel } type DMChannelCreateEvent struct { GenericDMChannelEvent - DMChannel *api.DMChannel } type DMChannelUpdateEvent struct { GenericDMChannelEvent - NewDMChannel *api.DMChannel OldDMChannel *api.DMChannel } type DMChannelDeleteEvent struct { GenericDMChannelEvent - DMChannel *api.DMChannel +} + +type DMUserTypingEvent struct { + GenericDMChannelEvent +} + +func (e DMUserTypingEvent) DMChannel() *api.DMChannel { + return e.Disgo().Cache().DMChannel(e.ChannelID) } diff --git a/api/events/dm_message_event.go b/api/events/dm_message_event.go index deb6c3f5..d34ee358 100644 --- a/api/events/dm_message_event.go +++ b/api/events/dm_message_event.go @@ -7,6 +7,7 @@ import ( // GenericDMMessageEvent generic api.DMChannel api.Message api.GenericEvent type GenericDMMessageEvent struct { GenericMessageEvent + Message *api.Message } func (e GenericDMMessageEvent) DMChannel() *api.DMChannel { @@ -16,18 +17,15 @@ func (e GenericDMMessageEvent) DMChannel() *api.DMChannel { // DMMessageReceivedEvent called upon receiving a api.Message in a api.DMChannel type DMMessageReceivedEvent struct { GenericDMMessageEvent - Message *api.Message } // DMMessageUpdateEvent called upon editing a api.Message in a api.DMChannel type DMMessageUpdateEvent struct { GenericDMMessageEvent - NewMessage *api.Message OldMessage *api.Message } // DMMessageDeleteEvent called upon deleting a api.Message in a api.DMChannel type DMMessageDeleteEvent struct { GenericDMMessageEvent - Message *api.Message } diff --git a/api/events/emote_events.go b/api/events/emote_events.go index 74e19ec3..b5c8a295 100644 --- a/api/events/emote_events.go +++ b/api/events/emote_events.go @@ -6,25 +6,18 @@ import ( type GenericEmoteEvent struct { GenericGuildEvent - EmoteID api.Snowflake -} - -func (e GenericEmoteEvent) Emote() *api.Emote { - return e.Disgo().Cache().Emote(e.EmoteID) + Emote *api.Emote } type EmoteCreateEvent struct { GenericEmoteEvent - Emote *api.Emote } type EmoteUpdateEvent struct { GenericEmoteEvent - NewEmote *api.Emote OldEmote *api.Emote } type EmoteDeleteEvent struct { GenericEmoteEvent - Emote *api.Emote } diff --git a/api/events/guild_events.go b/api/events/guild_events.go index 2e7ff529..b3df8c6d 100644 --- a/api/events/guild_events.go +++ b/api/events/guild_events.go @@ -7,49 +7,38 @@ import ( // GenericGuildEvent generic api.Guild api.GenericEvent type GenericGuildEvent struct { GenericEvent - GuildID api.Snowflake -} - -// Guild returns the api.Guild from the api.Cache -func (e GenericGuildEvent) Guild() *api.Guild { - return e.Disgo().Cache().Guild(e.GuildID) + Guild *api.Guild } // GuildUpdateEvent called upon receiving api.Guild updates type GuildUpdateEvent struct { GenericGuildEvent - NewGuild *api.Guild OldGuild *api.Guild } // GuildAvailableEvent called when an unavailable api.Guild becomes available type GuildAvailableEvent struct { GenericGuildEvent - Guild *api.Guild } // GuildUnavailableEvent called when an available api.Guild becomes unavailable type GuildUnavailableEvent struct { GenericGuildEvent - Guild *api.Guild } // GuildJoinEvent called when the bot joins a api.Guild type GuildJoinEvent struct { GenericGuildEvent - Guild *api.Guild } // GuildLeaveEvent called when the bot leaves a api.Guild type GuildLeaveEvent struct { GenericGuildEvent - Guild *api.Guild } // GuildReadyEvent called when the loaded the api.Guild in login phase type GuildReadyEvent struct { GenericGuildEvent - Guild *api.Guild } type GuildBanEvent struct { diff --git a/api/events/guild_invite_events.go b/api/events/guild_invite_events.go index 7cfc047f..7e257778 100644 --- a/api/events/guild_invite_events.go +++ b/api/events/guild_invite_events.go @@ -2,7 +2,6 @@ package events import ( "github.com/DisgoOrg/disgo/api" - "github.com/DisgoOrg/disgo/api/endpoints" ) type GenericGuildInviteEvent struct { @@ -31,14 +30,6 @@ func (e GenericGuildInviteEvent) Category() *api.Category { return e.Disgo().Cache().Category(e.ChannelID) } -func (e GenericGuildInviteEvent) URL() string { - url, err := endpoints.InviteURL.Compile(e.Code) - if err != nil { - return "" - } - return url.Route() -} - type GuildInviteCreateEvent struct { GenericGuildInviteEvent Invite *api.Invite diff --git a/api/events/guild_member_events.go b/api/events/guild_member_events.go index 645eb613..7736387c 100644 --- a/api/events/guild_member_events.go +++ b/api/events/guild_member_events.go @@ -7,34 +7,39 @@ import ( // GenericGuildMemberEvent generic api.Member event type GenericGuildMemberEvent struct { GenericGuildEvent - UserID api.Snowflake + Member *api.Member } // User gets the api.User form the api.Cache func (e GenericGuildMemberEvent) User() *api.User { - return e.Disgo().Cache().User(e.UserID) -} - -// Member gets the api.Member form the api.Cache -func (e GenericGuildMemberEvent) Member() *api.Member { - return e.Disgo().Cache().Member(e.GuildID, e.UserID) + if e.Member == nil { + return nil + } + return e.Disgo().Cache().User(e.Member.User.ID) } // GuildMemberJoinEvent indicates that a api.Member joined the api.Guild type GuildMemberJoinEvent struct { GenericGuildMemberEvent - Member *api.Member } // GuildMemberUpdateEvent indicates that a api.Member updated type GuildMemberUpdateEvent struct { GenericGuildMemberEvent OldMember *api.Member - NewMember *api.Member } // GuildMemberLeaveEvent indicates that a api.Member left the api.Guild type GuildMemberLeaveEvent struct { GenericGuildMemberEvent - Member *api.Member + User *api.User } + +type GuildMemberTypingEvent struct { + GenericGuildMemberEvent + ChannelID api.Snowflake +} + +func (e GuildMemberTypingEvent) TextChannel() *api.TextChannel { + return e.Disgo().Cache().TextChannel(e.ChannelID) +} \ No newline at end of file diff --git a/api/events/guild_message_events.go b/api/events/guild_message_events.go index 13eb3d7e..8829aecf 100644 --- a/api/events/guild_message_events.go +++ b/api/events/guild_message_events.go @@ -8,6 +8,7 @@ import ( type GenericGuildMessageEvent struct { GenericMessageEvent GuildID api.Snowflake + Message *api.Message } func (e GenericGuildMessageEvent) Guild() *api.Guild { @@ -22,18 +23,15 @@ func (e GenericGuildMessageEvent) TextChannel() *api.TextChannel { // GuildMessageReceivedEvent called upon receiving a api.Message in a api.DMChannel type GuildMessageReceivedEvent struct { GenericGuildMessageEvent - Message *api.Message } // GuildMessageUpdateEvent called upon editing a api.Message in a api.DMChannel type GuildMessageUpdateEvent struct { GenericGuildMessageEvent - NewMessage *api.Message OldMessage *api.Message } // GuildMessageDeleteEvent called upon deleting a api.Message in a api.DMChannel type GuildMessageDeleteEvent struct { GenericGuildMessageEvent - Message *api.Message } diff --git a/api/events/guild_voice_events.go b/api/events/guild_voice_events.go index e0fe3f56..01ddb409 100644 --- a/api/events/guild_voice_events.go +++ b/api/events/guild_voice_events.go @@ -6,18 +6,17 @@ import ( type GenericGuildVoiceEvent struct { GenericGuildMemberEvent - Member *api.Member + VoiceState *api.VoiceState } -type GuildVoiceUpdateEvent struct { +type GuildVoiceJoinEvent struct { GenericGuildVoiceEvent - NewVoiceState *api.VoiceState - OldVoiceState *api.VoiceState + GenericVoiceChannelEvent } -type GuildVoiceJoinEvent struct { +type GuildVoiceUpdateEvent struct { GenericGuildVoiceEvent - GenericVoiceChannelEvent + OldVoiceState *api.VoiceState } type GuildVoiceLeaveEvent struct { diff --git a/api/events/http_request_events.go b/api/events/http_request_events.go index ec21d74c..071debe1 100644 --- a/api/events/http_request_events.go +++ b/api/events/http_request_events.go @@ -9,7 +9,3 @@ type HttpRequestEvent struct { Request *http.Request Response *http.Response } - -func (e HttpRequestEvent) RateLimited() bool { - return e.Response.StatusCode == http.StatusTooManyRequests -} diff --git a/api/events/interaction_events.go b/api/events/interaction_events.go index b8d01728..6b819076 100644 --- a/api/events/interaction_events.go +++ b/api/events/interaction_events.go @@ -9,7 +9,7 @@ import ( // GenericInteractionEvent generic api.Interaction event type GenericInteractionEvent struct { GenericEvent - Interaction api.Interaction + *api.Interaction } // Guild returns the api.Guild from the api.Cache @@ -130,26 +130,25 @@ func (e *SlashCommandEvent) Reply(response api.InteractionResponse) error { // EditOriginal edits the original api.InteractionResponse func (e *SlashCommandEvent) EditOriginal(followupMessage api.FollowupMessage) (*api.Message, error) { - return e.Disgo().RestClient().EditInteractionResponse(e.Disgo().SelfUserID(), e.Interaction.Token, followupMessage) + return e.Disgo().RestClient().EditInteractionResponse(e.Disgo().ApplicationID(), e.Interaction.Token, followupMessage) } // DeleteOriginal deletes the original api.InteractionResponse func (e *SlashCommandEvent) DeleteOriginal() error { - return e.Disgo().RestClient().DeleteInteractionResponse(e.Disgo().SelfUserID(), e.Interaction.Token) + return e.Disgo().RestClient().DeleteInteractionResponse(e.Disgo().ApplicationID(), e.Interaction.Token) } // SendFollowup used to send a api.FollowupMessage to an api.Interaction func (e *SlashCommandEvent) SendFollowup(followupMessage api.FollowupMessage) (*api.Message, error) { - return e.Disgo().RestClient().SendFollowupMessage(e.Disgo().SelfUserID(), e.Interaction.Token, followupMessage) + return e.Disgo().RestClient().SendFollowupMessage(e.Disgo().ApplicationID(), e.Interaction.Token, followupMessage) } // EditFollowup used to edit a api.FollowupMessage from an api.Interaction func (e *SlashCommandEvent) EditFollowup(messageID api.Snowflake, followupMessage api.FollowupMessage) (*api.Message, error) { - return e.Disgo().RestClient().EditFollowupMessage(e.Disgo().SelfUserID(), e.Interaction.Token, messageID, followupMessage) + return e.Disgo().RestClient().EditFollowupMessage(e.Disgo().ApplicationID(), e.Interaction.Token, messageID, followupMessage) } // DeleteFollowup used to delete a api.FollowupMessage from an api.Interaction func (e *SlashCommandEvent) DeleteFollowup(messageID api.Snowflake) error { - return e.Disgo().RestClient().DeleteFollowupMessage(e.Disgo().SelfUserID(), e.Interaction.Token, messageID) + return e.Disgo().RestClient().DeleteFollowupMessage(e.Disgo().ApplicationID(), e.Interaction.Token, messageID) } - diff --git a/api/events/listener_adapter.go b/api/events/listener_adapter.go index 9fd63f57..a4e8c41c 100644 --- a/api/events/listener_adapter.go +++ b/api/events/listener_adapter.go @@ -147,7 +147,7 @@ type ListenerAdapter struct { OnGenericUserEvent func(event *GenericUserEvent) OnUserUpdate func(event *UserUpdateEvent) OnUserTyping func(event *UserTypingEvent) - OnGuildUserTyping func(event *GuildUserTypingEvent) + OnGuildUserTyping func(event *GuildMemberTypingEvent) OnDMUserTyping func(event *DMUserTypingEvent) // api.User api.Activity Events @@ -580,7 +580,7 @@ func (l ListenerAdapter) OnEvent(event interface{}) { if listener := l.OnUserTyping; listener != nil { listener(&e) } - case GuildUserTypingEvent: + case GuildMemberTypingEvent: if listener := l.OnGuildUserTyping; listener != nil { listener(&e) } diff --git a/api/events/message_events.go b/api/events/message_events.go index 7426ca09..7f96b5fd 100644 --- a/api/events/message_events.go +++ b/api/events/message_events.go @@ -8,6 +8,7 @@ import ( type GenericMessageEvent struct { GenericEvent MessageID api.Snowflake + Message *api.Message ChannelID api.Snowflake } @@ -19,18 +20,15 @@ func (e *GenericMessageEvent) MessageChannel() *api.MessageChannel { // MessageDeleteEvent indicates a api.Message got deleted type MessageDeleteEvent struct { GenericMessageEvent - Message *api.Message } // MessageReceivedEvent indicates a api.Message got received type MessageReceivedEvent struct { GenericMessageEvent - Message *api.Message } // MessageUpdateEvent indicates a api.Message got update type MessageUpdateEvent struct { GenericMessageEvent - NewMessage *api.Message OldMessage *api.Message } diff --git a/api/events/ready_event.go b/api/events/ready_event.go index dbcae5ab..c919381b 100644 --- a/api/events/ready_event.go +++ b/api/events/ready_event.go @@ -5,6 +5,6 @@ import "github.com/DisgoOrg/disgo/api" // ReadyEvent indicates we received the ReadyEvent from the api.Gateway type ReadyEvent struct { GenericEvent - ReadyEvent api.ReadyGatewayEvent + api.ReadyGatewayEvent } diff --git a/api/events/role_events.go b/api/events/role_events.go index e0d58457..f245f3ef 100644 --- a/api/events/role_events.go +++ b/api/events/role_events.go @@ -8,27 +8,21 @@ import ( type GenericRoleEvent struct { GenericGuildEvent RoleID api.Snowflake -} - -func (e GenericRoleEvent) Role() *api.Role { - return e.Disgo().Cache().Role(e.RoleID) + Role *api.Role } // RoleCreateEvent indicates that a api.Role got created type RoleCreateEvent struct { GenericGuildEvent - Role *api.Role } // RoleUpdateEvent indicates that a api.Role got updated type RoleUpdateEvent struct { GenericGuildEvent - NewRole *api.Role OldRole *api.Role } // RoleDeleteEvent indicates that a api.Role got deleted type RoleDeleteEvent struct { GenericGuildEvent - Role *api.Role } diff --git a/api/events/store_channel_events.go b/api/events/store_channel_events.go index cd58632b..d3837271 100644 --- a/api/events/store_channel_events.go +++ b/api/events/store_channel_events.go @@ -6,24 +6,18 @@ import ( type GenericStoreChannelEvent struct { GenericChannelEvent -} - -func (e GenericStoreChannelEvent) Category() *api.StoreChannel { - return e.Disgo().Cache().StoreChannel(e.ChannelID) + StoreChannel *api.StoreChannel } type StoreChannelCreateEvent struct { GenericStoreChannelEvent - StoreChannel *api.StoreChannel } type StoreChannelUpdateEvent struct { GenericStoreChannelEvent - NewStoreChannel *api.StoreChannel OldStoreChannel *api.StoreChannel } type StoreChannelDeleteEvent struct { GenericStoreChannelEvent - StoreChannel *api.StoreChannel } diff --git a/api/events/text_channel_events.go b/api/events/text_channel_events.go index 55edc2c5..05c30f87 100644 --- a/api/events/text_channel_events.go +++ b/api/events/text_channel_events.go @@ -6,24 +6,18 @@ import ( type GenericTextChannelEvent struct { GenericChannelEvent -} - -func (e GenericTextChannelEvent) Category() *api.TextChannel { - return e.Disgo().Cache().TextChannel(e.ChannelID) + TextChannel *api.TextChannel } type TextChannelCreateEvent struct { GenericTextChannelEvent - TextChannel *api.TextChannel } type TextChannelUpdateEvent struct { GenericTextChannelEvent - NewTextChannel *api.TextChannel OldTextChannel *api.TextChannel } type TextChannelDeleteEvent struct { GenericTextChannelEvent - TextChannel *api.TextChannel } diff --git a/api/events/user_events.go b/api/events/user_events.go index 0a263445..385e6ee8 100644 --- a/api/events/user_events.go +++ b/api/events/user_events.go @@ -7,38 +7,19 @@ import ( type GenericUserEvent struct { GenericEvent UserID api.Snowflake + User *api.User } type UserUpdateEvent struct { GenericUserEvent - NewUser *api.User OldUser *api.User } type UserTypingEvent struct { GenericUserEvent - User *api.User ChannelID api.Snowflake } func (e UserTypingEvent) Channel() *api.Channel { return e.Disgo().Cache().Channel(e.ChannelID) } - -type GuildUserTypingEvent struct { - UserTypingEvent - GenericGuildMemberEvent - Member *api.Member -} - -func (e UserTypingEvent) TextChannel() *api.TextChannel { - return e.Disgo().Cache().TextChannel(e.ChannelID) -} - -type DMUserTypingEvent struct { - UserTypingEvent -} - -func (e UserTypingEvent) DMChannel() *api.DMChannel { - return e.Disgo().Cache().DMChannel(e.ChannelID) -} diff --git a/api/events/voice_channel_events.go b/api/events/voice_channel_events.go index 558b32d4..56d0fbd1 100644 --- a/api/events/voice_channel_events.go +++ b/api/events/voice_channel_events.go @@ -6,24 +6,18 @@ import ( type GenericVoiceChannelEvent struct { GenericChannelEvent -} - -func (e GenericVoiceChannelEvent) VoiceChannel() *api.VoiceChannel { - return e.Disgo().Cache().VoiceChannel(e.ChannelID) + VoiceChannel *api.VoiceChannel } type VoiceChannelCreateEvent struct { GenericVoiceChannelEvent - VoiceChannel *api.VoiceChannel } type VoiceChannelUpdateEvent struct { GenericVoiceChannelEvent - NewVoiceChannel *api.VoiceChannel OldVoiceChannel *api.VoiceChannel } type VoiceChannelDeleteEvent struct { GenericVoiceChannelEvent - VoiceChannel *api.VoiceChannel } diff --git a/api/gateway.go b/api/gateway.go index 25c72eaa..7c4fb17c 100644 --- a/api/gateway.go +++ b/api/gateway.go @@ -1,6 +1,10 @@ package api -import "time" +import ( + "time" + + "github.com/gorilla/websocket" +) // GatewayStatus is the state that the client is currently in type GatewayStatus int @@ -25,6 +29,7 @@ type Gateway interface { Open() error Status() GatewayStatus Close(bool) + Conn() *websocket.Conn Latency() time.Duration } diff --git a/api/gateway_commands.go b/api/gateway_commands.go index ced112df..792c5486 100644 --- a/api/gateway_commands.go +++ b/api/gateway_commands.go @@ -65,10 +65,10 @@ type RequestGuildMembersCommand struct { // UpdateVoiceStateCommand is used for updating the bots voice state in a guild_events type UpdateVoiceStateCommand struct { - GuildID Snowflake `json:"guild_id"` - ChannelID Snowflake `json:"channel_id"` - SelfMute bool `json:"self_mute"` - SelfDeaf bool `json:"self_deaf"` + GuildID Snowflake `json:"guild_id"` + ChannelID *Snowflake `json:"channel_id"` + SelfMute bool `json:"self_mute"` + SelfDeaf bool `json:"self_deaf"` } // UpdateStatusCommand is used for updating Disgo's presence diff --git a/api/gateway_events.go b/api/gateway_events.go index 8aae2aaf..2b687f13 100644 --- a/api/gateway_events.go +++ b/api/gateway_events.go @@ -22,11 +22,10 @@ type RawGatewayEvent struct { type ReadyGatewayEvent struct { GatewayPacket D struct { - User User `json:"user"` - PrivateChannels []DMChannel `json:"channel"` - Guilds []Guild `json:"guild_events"` - SessionID string `json:"session_id"` - Shard [2]int `json:"shard,omitempty"` + User User `json:"user"` + Guilds []Guild `json:"guild_events"` + SessionID string `json:"session_id"` + Shard [2]int `json:"shard,omitempty"` } `json:"d"` } diff --git a/api/guild.go b/api/guild.go index 2823d17e..1d3514cb 100644 --- a/api/guild.go +++ b/api/guild.go @@ -171,18 +171,22 @@ type Guild struct { WelcomeScreen *GuildWelcomeScreen `json:"welcome_screen"` } +func (g *Guild) Disconnect() error { + return g.Disgo.AudioController().Disconnect(g.ID) +} + // CreateRole allows you to create a new Role -func (g Guild) CreateRole(role UpdateRole) (*Role, error) { +func (g *Guild) CreateRole(role UpdateRole) (*Role, error) { return g.Disgo.RestClient().CreateRole(g.ID, role) } // AddMember adds a member to the guild with the oauth2 access token -func (g Guild) AddMember(userID Snowflake, addGuildMemberData AddGuildMemberData) (*Member, error) { +func (g *Guild) AddMember(userID Snowflake, addGuildMemberData AddGuildMemberData) (*Member, error) { return g.Disgo.RestClient().AddMember(g.ID, userID, addGuildMemberData) } // IconURL returns the Icon of a guild_events -func (g Guild) IconURL() *string { +func (g *Guild) IconURL() *string { if g.Icon == nil { return nil } @@ -200,51 +204,51 @@ func (g Guild) IconURL() *string { } // GetCommand fetches a specific guild command -func (g Guild) GetCommand(commandID Snowflake) (*Command, error) { - return g.Disgo.RestClient().GetGuildCommand(g.Disgo.SelfUserID(), g.ID, commandID) +func (g *Guild) GetCommand(commandID Snowflake) (*Command, error) { + return g.Disgo.RestClient().GetGuildCommand(g.Disgo.ApplicationID(), g.ID, commandID) } // GetCommands fetches all guild commands -func (g Guild) GetCommands() ([]*Command, error) { - return g.Disgo.RestClient().GetGuildCommands(g.Disgo.SelfUserID(), g.ID) +func (g *Guild) GetCommands() ([]*Command, error) { + return g.Disgo.RestClient().GetGuildCommands(g.Disgo.ApplicationID(), g.ID) } // CreateCommand creates a new command for this guild -func (g Guild) CreateCommand(command Command) (*Command, error) { - return g.Disgo.RestClient().CreateGuildCommand(g.Disgo.SelfUserID(), g.ID, command) +func (g *Guild) CreateCommand(command Command) (*Command, error) { + return g.Disgo.RestClient().CreateGuildCommand(g.Disgo.ApplicationID(), g.ID, command) } // EditCommand edits a specific guild command -func (g Guild) EditCommand(commandID Snowflake, command UpdateCommand) (*Command, error) { - return g.Disgo.RestClient().EditGuildCommand(g.Disgo.SelfUserID(), g.ID, commandID, command) +func (g *Guild) EditCommand(commandID Snowflake, command UpdateCommand) (*Command, error) { + return g.Disgo.RestClient().EditGuildCommand(g.Disgo.ApplicationID(), g.ID, commandID, command) } // DeleteCommand creates a new command for this guild -func (g Guild) DeleteCommand(command Command) (*Command, error) { - return g.Disgo.RestClient().CreateGuildCommand(g.Disgo.SelfUserID(), g.ID, command) +func (g *Guild) DeleteCommand(command Command) (*Command, error) { + return g.Disgo.RestClient().CreateGuildCommand(g.Disgo.ApplicationID(), g.ID, command) } // SetCommands overrides all commands for this guild -func (g Guild) SetCommands(commands ...Command) ([]*Command, error) { - return g.Disgo.RestClient().SetGuildCommands(g.Disgo.SelfUserID(), g.ID, commands...) +func (g *Guild) SetCommands(commands ...Command) ([]*Command, error) { + return g.Disgo.RestClient().SetGuildCommands(g.Disgo.ApplicationID(), g.ID, commands...) } // GetCommandsPermissions returns the GuildCommandPermissions for a all Command(s) in a guild -func (g Guild) GetCommandsPermissions() ([]*GuildCommandPermissions, error) { - return g.Disgo.RestClient().GetGuildCommandsPermissions(g.Disgo.SelfUserID(), g.ID) +func (g *Guild) GetCommandsPermissions() ([]*GuildCommandPermissions, error) { + return g.Disgo.RestClient().GetGuildCommandsPermissions(g.Disgo.ApplicationID(), g.ID) } // GetCommandPermissions returns the GuildCommandPermissions for a specific Command in a guild -func (g Guild) GetCommandPermissions(commandID Snowflake) (*GuildCommandPermissions, error) { - return g.Disgo.RestClient().GetGuildCommandPermissions(g.Disgo.SelfUserID(), g.ID, commandID) +func (g *Guild) GetCommandPermissions(commandID Snowflake) (*GuildCommandPermissions, error) { + return g.Disgo.RestClient().GetGuildCommandPermissions(g.Disgo.ApplicationID(), g.ID, commandID) } // SetCommandsPermissions sets the GuildCommandPermissions for a all Command(s) -func (g Guild) SetCommandsPermissions(commandPermissions ...SetGuildCommandPermissions) ([]*GuildCommandPermissions, error) { - return g.Disgo.RestClient().SetGuildCommandsPermissions(g.Disgo.SelfUserID(), g.ID, commandPermissions...) +func (g *Guild) SetCommandsPermissions(commandPermissions ...SetGuildCommandPermissions) ([]*GuildCommandPermissions, error) { + return g.Disgo.RestClient().SetGuildCommandsPermissions(g.Disgo.ApplicationID(), g.ID, commandPermissions...) } // SetCommandPermissions sets the GuildCommandPermissions for a specific Command -func (g Guild) SetCommandPermissions(commandID Snowflake, permissions SetGuildCommandPermissions) (*GuildCommandPermissions, error) { - return g.Disgo.RestClient().SetGuildCommandPermissions(g.Disgo.SelfUserID(), g.ID, commandID, permissions) +func (g *Guild) SetCommandPermissions(commandID Snowflake, permissions SetGuildCommandPermissions) (*GuildCommandPermissions, error) { + return g.Disgo.RestClient().SetGuildCommandPermissions(g.Disgo.ApplicationID(), g.ID, commandID, permissions) } diff --git a/api/invite.go b/api/invite.go index 525ec7ea..10fbead4 100644 --- a/api/invite.go +++ b/api/invite.go @@ -1,6 +1,10 @@ package api -import "time" +import ( + "time" + + "github.com/DisgoOrg/disgo/api/endpoints" +) // ExpandedInvite is a full Invite struct type ExpandedInvite struct { @@ -25,6 +29,14 @@ type Invite struct { ApproximateMemberCount *int `json:"approximate_member_count"` } +func (i Invite) URL() string { + url, err := endpoints.InviteURL.Compile(i.Code) + if err != nil { + return "" + } + return url.Route() +} + // TargetType is type of target an Invite uses type TargetType int diff --git a/internal/audio_controller_impl.go b/internal/audio_controller_impl.go new file mode 100644 index 00000000..52f45327 --- /dev/null +++ b/internal/audio_controller_impl.go @@ -0,0 +1,28 @@ +package internal + +import "github.com/DisgoOrg/disgo/api" + +func newAudioControllerImpl(disgo api.Disgo) api.AudioController { + return &AudioControllerImpl{disgo: disgo} +} + +type AudioControllerImpl struct { + disgo api.Disgo +} + +func (c *AudioControllerImpl) Disgo() api.Disgo { + return c.disgo +} + +func (c *AudioControllerImpl) Connect(guildID api.Snowflake, channelID api.Snowflake) error { + return c.Disgo().Gateway().Conn().WriteJSON(api.NewGatewayCommand(api.OpVoiceStateUpdate, api.UpdateVoiceStateCommand{ + GuildID: guildID, + ChannelID: &channelID, + })) +} +func (c *AudioControllerImpl) Disconnect(guildID api.Snowflake) error { + return c.Disgo().Gateway().Conn().WriteJSON(api.NewGatewayCommand(api.OpVoiceStateUpdate, api.UpdateVoiceStateCommand{ + GuildID: guildID, + ChannelID: nil, + })) +} diff --git a/internal/cache_impl.go b/internal/cache_impl.go index 4cabca02..3c16a37d 100644 --- a/internal/cache_impl.go +++ b/internal/cache_impl.go @@ -482,7 +482,7 @@ func (c *CacheImpl) AllMemberCache() map[api.Snowflake]map[api.Snowflake]*api.Me // CacheMember adds a member to the cache func (c *CacheImpl) CacheMember(member *api.Member) *api.Member { // only cache member if we want to & always cache self member! - if member.User.ID != member.Disgo.SelfUserID() && !c.memberCachePolicy(member) { + if member.User.ID != member.Disgo.ApplicationID() && !c.memberCachePolicy(member) { return member } if guildMembers, ok := c.members[member.GuildID]; ok { @@ -560,7 +560,7 @@ func (c *CacheImpl) VoiceStateCache(guildID api.Snowflake) map[api.Snowflake]*ap // CacheVoiceState adds a api.VoiceState from the api.Cache func (c *CacheImpl) CacheVoiceState(voiceState *api.VoiceState) *api.VoiceState { // only cache voice states for ourself or member is cached & cache flag activated - if voiceState.UserID != c.disgo.SelfUserID() && (!c.cacheFlags.Has(api.CacheFlagVoiceState) || c.Member(voiceState.GuildID, voiceState.UserID) == nil) { + if voiceState.UserID != c.disgo.ApplicationID() && (!c.cacheFlags.Has(api.CacheFlagVoiceState) || c.Member(voiceState.GuildID, voiceState.UserID) == nil) { return voiceState } if guildVoiceStates, ok := c.voiceStates[voiceState.GuildID]; ok { diff --git a/internal/disgo_builder_impl.go b/internal/disgo_builder_impl.go index 16475d0d..caa03814 100644 --- a/internal/disgo_builder_impl.go +++ b/internal/disgo_builder_impl.go @@ -24,6 +24,7 @@ type DisgoBuilderImpl struct { BotToken endpoints.Token gateway api.Gateway restClient api.RestClient + audioController api.AudioController cache api.Cache memberCachePolicy api.MemberCachePolicy messageCachePolicy api.MessageCachePolicy @@ -103,6 +104,12 @@ func (b *DisgoBuilderImpl) SetRestClient(restClient api.RestClient) api.DisgoBui return b } +// SetAudioController lets you inject your own api.AudioController +func (b *DisgoBuilderImpl) SetAudioController(audioController api.AudioController) api.DisgoBuilder { + b.audioController = audioController + return b +} + // SetCache lets you inject your own api.Cache func (b *DisgoBuilderImpl) SetCache(cache api.Cache) api.DisgoBuilder { b.cache = cache @@ -174,6 +181,11 @@ func (b *DisgoBuilderImpl) Build() (api.Disgo, error) { } disgo.restClient = b.restClient + if b.audioController == nil { + b.audioController = newAudioControllerImpl(disgo) + } + disgo.audioController = b.audioController + disgo.intents = b.intents if b.entityBuilder == nil { diff --git a/internal/disgo_impl.go b/internal/disgo_impl.go index 54a5ad0b..00266ca4 100644 --- a/internal/disgo_impl.go +++ b/internal/disgo_impl.go @@ -34,6 +34,8 @@ func New(token endpoints.Token, options api.Options) (api.Disgo, error) { disgo.restClient = newRestClientImpl(disgo) + disgo.audioController = newAudioControllerImpl(disgo) + disgo.entityBuilder = newEntityBuilderImpl(disgo) disgo.eventManager = newEventManagerImpl(disgo, []api.EventListener{}) @@ -58,6 +60,7 @@ type DisgoImpl struct { entityBuilder api.EntityBuilder eventManager api.EventManager voiceDispatchInterceptor api.VoiceDispatchInterceptor + audioController api.AudioController webhookServer api.WebhookServer cache api.Cache selfUserID api.Snowflake @@ -138,6 +141,11 @@ func (d *DisgoImpl) SetVoiceDispatchInterceptor(voiceDispatchInterceptor api.Voi d.voiceDispatchInterceptor = voiceDispatchInterceptor } +// AudioController returns the api.AudioController which can be used to connect/reconnect/disconnect to/fom a api.VoiceChannel +func (d *DisgoImpl) AudioController() api.AudioController { + return d.audioController +} + // WebhookServer returns the api.EventManager func (d *DisgoImpl) WebhookServer() api.WebhookServer { return d.webhookServer @@ -155,8 +163,8 @@ func (d *DisgoImpl) Intents() api.Intents { return c } -// SelfUserID returns the current application id -func (d *DisgoImpl) SelfUserID() api.Snowflake { +// ApplicationID returns the current application id +func (d *DisgoImpl) ApplicationID() api.Snowflake { return d.selfUserID } @@ -182,30 +190,30 @@ func (d DisgoImpl) HasGateway() bool { // GetCommand fetches a specific guild command func (d DisgoImpl) GetCommand(commandID api.Snowflake) (*api.Command, error) { - return d.RestClient().GetGlobalCommand(d.SelfUserID(), commandID) + return d.RestClient().GetGlobalCommand(d.ApplicationID(), commandID) } // GetCommands fetches all guild commands func (d DisgoImpl) GetCommands() ([]*api.Command, error) { - return d.RestClient().GetGlobalCommands(d.SelfUserID()) + return d.RestClient().GetGlobalCommands(d.ApplicationID()) } // CreateCommand creates a new command for this guild func (d DisgoImpl) CreateCommand(command api.Command) (*api.Command, error) { - return d.RestClient().CreateGlobalCommand(d.SelfUserID(), command) + return d.RestClient().CreateGlobalCommand(d.ApplicationID(), command) } // EditCommand edits a specific guild command func (d DisgoImpl) EditCommand(commandID api.Snowflake, command api.UpdateCommand) (*api.Command, error) { - return d.RestClient().EditGlobalCommand(d.SelfUserID(), commandID, command) + return d.RestClient().EditGlobalCommand(d.ApplicationID(), commandID, command) } // DeleteCommand creates a new command for this guild func (d DisgoImpl) DeleteCommand(command api.Command) (*api.Command, error) { - return d.RestClient().CreateGlobalCommand(d.SelfUserID(), command) + return d.RestClient().CreateGlobalCommand(d.ApplicationID(), command) } // SetCommands overrides all commands for this guild func (d DisgoImpl) SetCommands(commands ...api.Command) ([]*api.Command, error) { - return d.RestClient().SetGlobalCommands(d.SelfUserID(), commands...) + return d.RestClient().SetGlobalCommands(d.ApplicationID(), commands...) } diff --git a/internal/gateway_impl.go b/internal/gateway_impl.go index 3217dcd9..3f41846c 100644 --- a/internal/gateway_impl.go +++ b/internal/gateway_impl.go @@ -227,6 +227,10 @@ func (g *GatewayImpl) closeWithCode(code int) error { return nil } +func (g *GatewayImpl) Conn() *websocket.Conn { + return g.conn +} + func (g *GatewayImpl) heartbeat() { defer func() { if r := recover(); r != nil { @@ -251,7 +255,7 @@ func (g *GatewayImpl) heartbeat() { } func (g *GatewayImpl) sendHeartbeat() { - g.Disgo().Logger().Debug("sending heartbeat...") + //g.Disgo().Logger().Debug("sending heartbeat...") heartbeatEvent := events.HeartbeatEvent{ GenericEvent: events.NewEvent(g.Disgo(), 0), @@ -344,13 +348,13 @@ func (g *GatewayImpl) listen() { e.Handle(*event.T, nil, *event.S, event.D) case api.OpHeartbeat: - g.Disgo().Logger().Debugf("received: OpHeartbeat") + //g.Disgo().Logger().Debugf("received: OpHeartbeat") g.sendHeartbeat() case api.OpReconnect: g.Disgo().Logger().Debugf("received: OpReconnect") g.Close(true) - g.reconnect(1*time.Second) + g.reconnect(1 * time.Second) case api.OpInvalidSession: g.Disgo().Logger().Debugf("received: OpInvalidSession") @@ -358,10 +362,10 @@ func (g *GatewayImpl) listen() { // clear reconnect info g.sessionID = nil g.lastSequenceReceived = nil - g.reconnect(5*time.Second) + g.reconnect(5 * time.Second) case api.OpHeartbeatACK: - g.Disgo().Logger().Debugf("received: OpHeartbeatACK") + //g.Disgo().Logger().Debugf("received: OpHeartbeatACK") g.lastHeartbeatReceived = time.Now().UTC() } diff --git a/internal/handlers/application_command_create.go b/internal/handlers/application_command_create.go index 3bcb4e49..71d6de9e 100644 --- a/internal/handlers/application_command_create.go +++ b/internal/handlers/application_command_create.go @@ -25,21 +25,27 @@ func (h ApplicationCommandCreateHandler) HandleGatewayEvent(disgo api.Disgo, eve return } + // only cache our own commands + cacheStrategy := api.CacheStrategyNo + if command.ApplicationID == disgo.ApplicationID() { + cacheStrategy = api.CacheStrategyYes + } + if command.FromGuild() { - command = disgo.EntityBuilder().CreateGuildCommand(*command.GuildID, command, api.CacheStrategyYes) + command = disgo.EntityBuilder().CreateGuildCommand(*command.GuildID, command, cacheStrategy) } else { - command = disgo.EntityBuilder().CreateGlobalCommand(command, api.CacheStrategyYes) + command = disgo.EntityBuilder().CreateGlobalCommand(command, cacheStrategy) } genericApplicationCommandEvent := events.GenericApplicationCommandEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), CommandID: command.ID, + Command: command, GuildID: command.GuildID, } eventManager.Dispatch(genericApplicationCommandEvent) eventManager.Dispatch(events.ApplicationCommandCreateEvent{ GenericApplicationCommandEvent: genericApplicationCommandEvent, - Command: command, }) } diff --git a/internal/handlers/application_command_delete.go b/internal/handlers/application_command_delete.go index 34ba42fd..f7a50e4f 100644 --- a/internal/handlers/application_command_delete.go +++ b/internal/handlers/application_command_delete.go @@ -25,7 +25,11 @@ func (h ApplicationCommandDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eve return } - disgo.Cache().UncacheCommand(command.ID) + // we only cache our own commands + if command.ApplicationID == disgo.ApplicationID() { + disgo.Cache().UncacheCommand(command.ID) + } + if command.FromGuild() { command = disgo.EntityBuilder().CreateGuildCommand(*command.GuildID, command, api.CacheStrategyNo) @@ -36,12 +40,12 @@ func (h ApplicationCommandDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eve genericApplicationCommandEvent := events.GenericApplicationCommandEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), CommandID: command.ID, + Command: command, GuildID: command.GuildID, } eventManager.Dispatch(genericApplicationCommandEvent) eventManager.Dispatch(events.ApplicationCommandDeleteEvent{ GenericApplicationCommandEvent: genericApplicationCommandEvent, - Command: command, }) } diff --git a/internal/handlers/application_command_update.go b/internal/handlers/application_command_update.go index 53cfb498..341d7edc 100644 --- a/internal/handlers/application_command_update.go +++ b/internal/handlers/application_command_update.go @@ -25,9 +25,12 @@ func (h ApplicationCommandUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eve return } - oldCommand := disgo.Cache().Command(command.ID) - if oldCommand != nil { - oldCommand = &*oldCommand + var oldCommand *api.Command + if command.ApplicationID == disgo.ApplicationID() { + oldCommand = disgo.Cache().Command(command.ID) + if oldCommand != nil { + oldCommand = &*oldCommand + } } if command.FromGuild() { @@ -39,13 +42,14 @@ func (h ApplicationCommandUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eve genericApplicationCommandEvent := events.GenericApplicationCommandEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), CommandID: command.ID, + Command: command, GuildID: command.GuildID, } eventManager.Dispatch(genericApplicationCommandEvent) eventManager.Dispatch(events.ApplicationCommandUpdateEvent{ GenericApplicationCommandEvent: genericApplicationCommandEvent, - NewCommand: command, + // always nil for not our own commands OldCommand: oldCommand, }) } diff --git a/internal/handlers/channel_create_handler.go b/internal/handlers/channel_create_handler.go index bf167aba..23ef93e1 100644 --- a/internal/handlers/channel_create_handler.go +++ b/internal/handlers/channel_create_handler.go @@ -37,12 +37,12 @@ func (h ChannelCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a genericDMChannelEvent := events.GenericDMChannelEvent{ GenericChannelEvent: genericChannelEvent, + DMChannel: dmChannel, } eventManager.Dispatch(genericDMChannelEvent) eventManager.Dispatch(events.DMChannelCreateEvent{ GenericDMChannelEvent: genericDMChannelEvent, - DMChannel: dmChannel, }) case api.ChannelTypeGroupDM: @@ -53,12 +53,12 @@ func (h ChannelCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a genericTextChannelEvent := events.GenericTextChannelEvent{ GenericChannelEvent: genericChannelEvent, + TextChannel: textChannel, } eventManager.Dispatch(genericTextChannelEvent) eventManager.Dispatch(events.TextChannelCreateEvent{ GenericTextChannelEvent: genericTextChannelEvent, - TextChannel: textChannel, }) case api.ChannelTypeStore: @@ -66,12 +66,12 @@ func (h ChannelCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a genericStoreChannelEvent := events.GenericStoreChannelEvent{ GenericChannelEvent: genericChannelEvent, + StoreChannel: storeChannel, } eventManager.Dispatch(genericStoreChannelEvent) eventManager.Dispatch(events.StoreChannelCreateEvent{ GenericStoreChannelEvent: genericStoreChannelEvent, - StoreChannel: storeChannel, }) case api.ChannelTypeCategory: @@ -79,12 +79,12 @@ func (h ChannelCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a genericCategoryEvent := events.GenericCategoryEvent{ GenericChannelEvent: genericChannelEvent, + Category: category, } eventManager.Dispatch(genericCategoryEvent) eventManager.Dispatch(events.CategoryCreateEvent{ GenericCategoryEvent: genericCategoryEvent, - Category: category, }) case api.ChannelTypeVoice: @@ -92,12 +92,12 @@ func (h ChannelCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a genericVoiceChannelEvent := events.GenericVoiceChannelEvent{ GenericChannelEvent: genericChannelEvent, + VoiceChannel: voiceChannel, } eventManager.Dispatch(genericVoiceChannelEvent) eventManager.Dispatch(events.VoiceChannelCreateEvent{ GenericVoiceChannelEvent: genericVoiceChannelEvent, - VoiceChannel: voiceChannel, }) default: diff --git a/internal/handlers/channel_delete_handler.go b/internal/handlers/channel_delete_handler.go index 3cd6920d..5a06361d 100644 --- a/internal/handlers/channel_delete_handler.go +++ b/internal/handlers/channel_delete_handler.go @@ -34,16 +34,15 @@ func (h ChannelDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a switch channel.Type { case api.ChannelTypeDM: disgo.Cache().UncacheDMChannel(channel.ID) - dmChannel := disgo.EntityBuilder().CreateDMChannel(channel, api.CacheStrategyNo) genericDMChannelEvent := events.GenericDMChannelEvent{ GenericChannelEvent: genericChannelEvent, + DMChannel: disgo.EntityBuilder().CreateDMChannel(channel, api.CacheStrategyNo), } eventManager.Dispatch(genericDMChannelEvent) eventManager.Dispatch(events.DMChannelCreateEvent{ GenericDMChannelEvent: genericDMChannelEvent, - DMChannel: dmChannel, }) case api.ChannelTypeGroupDM: @@ -51,58 +50,54 @@ func (h ChannelDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a case api.ChannelTypeText, api.ChannelTypeNews: disgo.Cache().UncacheTextChannel(*channel.GuildID, channel.ID) - textChannel := disgo.EntityBuilder().CreateTextChannel(channel, api.CacheStrategyNo) genericTextChannelEvent := events.GenericTextChannelEvent{ GenericChannelEvent: genericChannelEvent, + TextChannel: disgo.EntityBuilder().CreateTextChannel(channel, api.CacheStrategyNo), } eventManager.Dispatch(genericTextChannelEvent) eventManager.Dispatch(events.TextChannelCreateEvent{ GenericTextChannelEvent: genericTextChannelEvent, - TextChannel: textChannel, }) case api.ChannelTypeStore: disgo.Cache().UncacheStoreChannel(*channel.GuildID, channel.ID) - storeChannel := disgo.EntityBuilder().CreateStoreChannel(channel, api.CacheStrategyNo) genericStoreChannelEvent := events.GenericStoreChannelEvent{ GenericChannelEvent: genericChannelEvent, + StoreChannel: disgo.EntityBuilder().CreateStoreChannel(channel, api.CacheStrategyNo), } eventManager.Dispatch(genericStoreChannelEvent) eventManager.Dispatch(events.StoreChannelCreateEvent{ GenericStoreChannelEvent: genericStoreChannelEvent, - StoreChannel: storeChannel, }) case api.ChannelTypeCategory: disgo.Cache().UncacheCategory(*channel.GuildID, channel.ID) - category := disgo.EntityBuilder().CreateCategory(channel, api.CacheStrategyNo) genericCategoryEvent := events.GenericCategoryEvent{ GenericChannelEvent: genericChannelEvent, + Category: disgo.EntityBuilder().CreateCategory(channel, api.CacheStrategyNo), } eventManager.Dispatch(genericCategoryEvent) eventManager.Dispatch(events.CategoryCreateEvent{ GenericCategoryEvent: genericCategoryEvent, - Category: category, }) case api.ChannelTypeVoice: disgo.Cache().UncacheVoiceChannel(*channel.GuildID, channel.ID) - voiceChannel := disgo.EntityBuilder().CreateVoiceChannel(channel, api.CacheStrategyNo) genericVoiceChannelEvent := events.GenericVoiceChannelEvent{ GenericChannelEvent: genericChannelEvent, + VoiceChannel: disgo.EntityBuilder().CreateVoiceChannel(channel, api.CacheStrategyNo), } eventManager.Dispatch(genericVoiceChannelEvent) eventManager.Dispatch(events.VoiceChannelCreateEvent{ GenericVoiceChannelEvent: genericVoiceChannelEvent, - VoiceChannel: voiceChannel, }) default: diff --git a/internal/handlers/channel_update_handler.go b/internal/handlers/channel_update_handler.go index 40e4e73a..2320b53c 100644 --- a/internal/handlers/channel_update_handler.go +++ b/internal/handlers/channel_update_handler.go @@ -37,17 +37,16 @@ func (h ChannelUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a if oldDMChannel != nil { oldDMChannel = &*oldDMChannel } - newDMChannel := disgo.EntityBuilder().CreateDMChannel(channel, api.CacheStrategyYes) genericDMChannelEvent := events.GenericDMChannelEvent{ GenericChannelEvent: genericChannelEvent, + DMChannel: disgo.EntityBuilder().CreateDMChannel(channel, api.CacheStrategyYes), } eventManager.Dispatch(genericDMChannelEvent) eventManager.Dispatch(events.DMChannelUpdateEvent{ GenericDMChannelEvent: genericDMChannelEvent, - NewDMChannel: newDMChannel, - OldDMChannel: oldDMChannel, + OldDMChannel: oldDMChannel, }) case api.ChannelTypeGroupDM: @@ -58,17 +57,16 @@ func (h ChannelUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a if oldTextChannel != nil { oldTextChannel = &*oldTextChannel } - newTextChannel := disgo.EntityBuilder().CreateTextChannel(channel, api.CacheStrategyYes) genericTextChannelEvent := events.GenericTextChannelEvent{ GenericChannelEvent: genericChannelEvent, + TextChannel: disgo.EntityBuilder().CreateTextChannel(channel, api.CacheStrategyYes), } eventManager.Dispatch(genericTextChannelEvent) eventManager.Dispatch(events.TextChannelUpdateEvent{ GenericTextChannelEvent: genericTextChannelEvent, - NewTextChannel: newTextChannel, - OldTextChannel: oldTextChannel, + OldTextChannel: oldTextChannel, }) case api.ChannelTypeStore: @@ -76,17 +74,16 @@ func (h ChannelUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a if oldStoreChannel != nil { oldStoreChannel = &*oldStoreChannel } - newStoreChannel := disgo.EntityBuilder().CreateStoreChannel(channel, api.CacheStrategyYes) genericStoreChannelEvent := events.GenericStoreChannelEvent{ GenericChannelEvent: genericChannelEvent, + StoreChannel: disgo.EntityBuilder().CreateStoreChannel(channel, api.CacheStrategyYes), } eventManager.Dispatch(genericStoreChannelEvent) eventManager.Dispatch(events.StoreChannelUpdateEvent{ GenericStoreChannelEvent: genericStoreChannelEvent, - NewStoreChannel: newStoreChannel, - OldStoreChannel: oldStoreChannel, + OldStoreChannel: oldStoreChannel, }) case api.ChannelTypeCategory: @@ -94,17 +91,16 @@ func (h ChannelUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a if oldCategory != nil { oldCategory = &*oldCategory } - newCategory := disgo.EntityBuilder().CreateCategory(channel, api.CacheStrategyYes) genericCategoryEvent := events.GenericCategoryEvent{ GenericChannelEvent: genericChannelEvent, + Category: disgo.EntityBuilder().CreateCategory(channel, api.CacheStrategyYes), } eventManager.Dispatch(genericCategoryEvent) eventManager.Dispatch(events.CategoryUpdateEvent{ GenericCategoryEvent: genericCategoryEvent, - NewCategory: newCategory, - OldCategory: oldCategory, + OldCategory: oldCategory, }) case api.ChannelTypeVoice: @@ -112,17 +108,16 @@ func (h ChannelUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a if oldVoiceChannel != nil { oldVoiceChannel = &*oldVoiceChannel } - newVoiceChannel := disgo.EntityBuilder().CreateVoiceChannel(channel, api.CacheStrategyYes) genericVoiceChannelEvent := events.GenericVoiceChannelEvent{ GenericChannelEvent: genericChannelEvent, + VoiceChannel: disgo.EntityBuilder().CreateVoiceChannel(channel, api.CacheStrategyYes), } eventManager.Dispatch(genericVoiceChannelEvent) eventManager.Dispatch(events.VoiceChannelUpdateEvent{ GenericVoiceChannelEvent: genericVoiceChannelEvent, - NewVoiceChannel: newVoiceChannel, - OldVoiceChannel: oldVoiceChannel, + OldVoiceChannel: oldVoiceChannel, }) default: diff --git a/internal/handlers/guild_create_handler.go b/internal/handlers/guild_create_handler.go index 34218032..b52d6eaf 100644 --- a/internal/handlers/guild_create_handler.go +++ b/internal/handlers/guild_create_handler.go @@ -77,7 +77,7 @@ func (h GuildCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api genericGuildEvent := events.GenericGuildEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), - GuildID: guild.ID, + Guild: guild, } eventManager.Dispatch(genericGuildEvent) @@ -85,12 +85,10 @@ func (h GuildCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api if wasUnavailable { eventManager.Dispatch(events.GuildAvailableEvent{ GenericGuildEvent: genericGuildEvent, - Guild: guild, }) } else { eventManager.Dispatch(events.GuildJoinEvent{ GenericGuildEvent: genericGuildEvent, - Guild: guild, }) } } diff --git a/internal/handlers/guild_delete_handler.go b/internal/handlers/guild_delete_handler.go index 0ec12c69..9cf926db 100644 --- a/internal/handlers/guild_delete_handler.go +++ b/internal/handlers/guild_delete_handler.go @@ -27,28 +27,25 @@ func (h GuildDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api guild = disgo.EntityBuilder().CreateGuild(guild, api.CacheStrategyNo) + genericGuildEvent := events.GenericGuildEvent{ + GenericEvent: events.NewEvent(disgo, sequenceNumber), + Guild: guild, + } + eventManager.Dispatch(genericGuildEvent) + if guild.Unavailable { // set guild to unavail for now disgo.Cache().Guild(guild.ID).Unavailable = true eventManager.Dispatch(events.GuildUnavailableEvent{ - GenericGuildEvent: events.GenericGuildEvent{ - GenericEvent: events.NewEvent(disgo, sequenceNumber), - GuildID: guild.ID, - }, + GenericGuildEvent: genericGuildEvent, }) } else { guild = disgo.Cache().Guild(guild.ID) disgo.Cache().UncacheGuild(guild.ID) - genericGuildEvent := events.GenericGuildEvent{ - GenericEvent: events.NewEvent(disgo, sequenceNumber), - GuildID: guild.ID, - } - eventManager.Dispatch(genericGuildEvent) eventManager.Dispatch(events.GuildLeaveEvent{ GenericGuildEvent: genericGuildEvent, - Guild: guild, }) } } diff --git a/internal/handlers/guild_member_add_handler.go b/internal/handlers/guild_member_add_handler.go index 2d5246ca..4ed0b7ab 100644 --- a/internal/handlers/guild_member_add_handler.go +++ b/internal/handlers/guild_member_add_handler.go @@ -25,22 +25,26 @@ func (h GuildMemberAddHandler) HandleGatewayEvent(disgo api.Disgo, eventManager return } + guild := disgo.Cache().Guild(member.GuildID) + if guild == nil { + // todo: replay event later. maybe guild is not cached yet but in a few seconds + return + } member = disgo.EntityBuilder().CreateMember(member.GuildID, member, api.CacheStrategyYes) genericGuildEvent := events.GenericGuildEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), - GuildID: member.GuildID, + Guild: guild, } eventManager.Dispatch(genericGuildEvent) genericGuildMemberEvent := events.GenericGuildMemberEvent{ GenericGuildEvent: genericGuildEvent, - UserID: member.User.ID, + Member: member, } eventManager.Dispatch(genericGuildMemberEvent) eventManager.Dispatch(events.GuildMemberJoinEvent{ GenericGuildMemberEvent: genericGuildMemberEvent, - Member: member, }) } diff --git a/internal/handlers/guild_member_remove_handler.go b/internal/handlers/guild_member_remove_handler.go index 572b603e..6918e9e5 100644 --- a/internal/handlers/guild_member_remove_handler.go +++ b/internal/handlers/guild_member_remove_handler.go @@ -25,30 +25,34 @@ func (h GuildMemberRemoveHandler) New() interface{} { // HandleGatewayEvent handles the specific raw gateway event func (h GuildMemberRemoveHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { - member, ok := i.(*guildMemberRemoveData) + memberData, ok := i.(*guildMemberRemoveData) if !ok { return } - member.User = disgo.EntityBuilder().CreateUser(member.User, api.CacheStrategyYes) + guild := disgo.Cache().Guild(memberData.GuildID) + if guild == nil { + // todo: replay event later. maybe guild is not cached yet but in a few seconds + return + } + memberData.User = disgo.EntityBuilder().CreateUser(memberData.User, api.CacheStrategyYes) - oldMember := disgo.Cache().Member(member.GuildID, member.User.ID) - disgo.Cache().UncacheMember(member.GuildID, member.User.ID) + member := disgo.Cache().Member(memberData.GuildID, memberData.User.ID) + disgo.Cache().UncacheMember(memberData.GuildID, memberData.User.ID) genericGuildEvent := events.GenericGuildEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), - GuildID: member.GuildID, + Guild: guild, } eventManager.Dispatch(genericGuildEvent) genericGuildMemberEvent := events.GenericGuildMemberEvent{ GenericGuildEvent: genericGuildEvent, - UserID: member.User.ID, + Member: member, } eventManager.Dispatch(genericGuildMemberEvent) eventManager.Dispatch(events.GuildMemberLeaveEvent{ GenericGuildMemberEvent: genericGuildMemberEvent, - Member: oldMember, }) } diff --git a/internal/handlers/guild_member_update_handler.go b/internal/handlers/guild_member_update_handler.go index f482c749..7fc6a6f0 100644 --- a/internal/handlers/guild_member_update_handler.go +++ b/internal/handlers/guild_member_update_handler.go @@ -20,32 +20,37 @@ func (h GuildMemberUpdateHandler) New() interface{} { // HandleGatewayEvent handles the specific raw gateway event func (h GuildMemberUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { - newMember, ok := i.(*api.Member) + member, ok := i.(*api.Member) if !ok { return } - oldMember := disgo.Cache().Member(newMember.GuildID, newMember.User.ID) + guild := disgo.Cache().Guild(member.GuildID) + if guild == nil { + // todo: replay event later. maybe guild is not cached yet but in a few seconds + return + } + + oldMember := disgo.Cache().Member(member.GuildID, member.User.ID) if oldMember != nil { oldMember = &*oldMember } - newMember = disgo.EntityBuilder().CreateMember(newMember.GuildID, newMember, api.CacheStrategyYes) + member = disgo.EntityBuilder().CreateMember(member.GuildID, member, api.CacheStrategyYes) genericGuildEvent := events.GenericGuildEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), - GuildID: newMember.GuildID, + Guild: guild, } eventManager.Dispatch(genericGuildEvent) genericGuildMemberEvent := events.GenericGuildMemberEvent{ GenericGuildEvent: genericGuildEvent, - UserID: newMember.User.ID, + Member: member, } eventManager.Dispatch(genericGuildMemberEvent) eventManager.Dispatch(events.GuildMemberUpdateEvent{ GenericGuildMemberEvent: genericGuildMemberEvent, - NewMember: newMember, OldMember: oldMember, }) } diff --git a/internal/handlers/guild_role_create_handler.go b/internal/handlers/guild_role_create_handler.go index 429ce03d..bfa10b7a 100644 --- a/internal/handlers/guild_role_create_handler.go +++ b/internal/handlers/guild_role_create_handler.go @@ -30,22 +30,28 @@ func (h GuildRoleCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager return } + guild := disgo.Cache().Guild(roleCreateData.GuildID) + if guild == nil { + // todo: replay event later. maybe guild is not cached yet but in a few seconds + return + } + role := disgo.EntityBuilder().CreateRole(roleCreateData.GuildID, roleCreateData.Role, api.CacheStrategyYes) genericGuildEvent := events.GenericGuildEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), - GuildID: role.GuildID, + Guild: guild, } eventManager.Dispatch(genericGuildEvent) genericRoleEvent := events.GenericRoleEvent{ GenericGuildEvent: genericGuildEvent, RoleID: role.ID, + Role: role, } eventManager.Dispatch(genericRoleEvent) eventManager.Dispatch(events.RoleCreateEvent{ GenericGuildEvent: genericGuildEvent, - Role: role, }) } diff --git a/internal/handlers/guild_role_delete_handler.go b/internal/handlers/guild_role_delete_handler.go index 97c230b8..b835541d 100644 --- a/internal/handlers/guild_role_delete_handler.go +++ b/internal/handlers/guild_role_delete_handler.go @@ -30,23 +30,31 @@ func (h GuildRoleDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eventManager return } + guild := disgo.Cache().Guild(roleDeleteData.GuildID) + if guild == nil { + // todo: replay event later. maybe guild is not cached yet but in a few seconds + return + } + role := disgo.Cache().Role(roleDeleteData.RoleID) - disgo.Cache().UncacheRole(roleDeleteData.GuildID, roleDeleteData.RoleID) + if role != nil { + disgo.Cache().UncacheRole(roleDeleteData.GuildID, roleDeleteData.RoleID) + } genericGuildEvent := events.GenericGuildEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), - GuildID: role.GuildID, + Guild: guild, } eventManager.Dispatch(genericGuildEvent) genericRoleEvent := events.GenericRoleEvent{ GenericGuildEvent: genericGuildEvent, - RoleID: role.ID, + RoleID: roleDeleteData.RoleID, + Role: role, } eventManager.Dispatch(genericRoleEvent) eventManager.Dispatch(events.RoleDeleteEvent{ GenericGuildEvent: genericGuildEvent, - Role: role, }) } diff --git a/internal/handlers/guild_role_update_handler.go b/internal/handlers/guild_role_update_handler.go index 4e56a83d..2182612e 100644 --- a/internal/handlers/guild_role_update_handler.go +++ b/internal/handlers/guild_role_update_handler.go @@ -30,27 +30,33 @@ func (h GuildRoleUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager return } + guild := disgo.Cache().Guild(roleUpdateData.GuildID) + if guild == nil { + // todo: replay event later. maybe guild is not cached yet but in a few seconds + return + } + oldRole := disgo.Cache().Role(roleUpdateData.Role.ID) if oldRole != nil { oldRole = &*oldRole } - newRole := disgo.EntityBuilder().CreateRole(roleUpdateData.GuildID, roleUpdateData.Role, api.CacheStrategyYes) + role := disgo.EntityBuilder().CreateRole(roleUpdateData.GuildID, roleUpdateData.Role, api.CacheStrategyYes) genericGuildEvent := events.GenericGuildEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), - GuildID: newRole.GuildID, + Guild: guild, } eventManager.Dispatch(genericGuildEvent) genericRoleEvent := events.GenericRoleEvent{ GenericGuildEvent: genericGuildEvent, - RoleID: newRole.ID, + RoleID: roleUpdateData.Role.ID, + Role: role, } eventManager.Dispatch(genericRoleEvent) eventManager.Dispatch(events.RoleUpdateEvent{ GenericGuildEvent: genericGuildEvent, - NewRole: newRole, OldRole: oldRole, }) } diff --git a/internal/handlers/guild_update_handler.go b/internal/handlers/guild_update_handler.go index 2a8a5da5..e335ee98 100644 --- a/internal/handlers/guild_update_handler.go +++ b/internal/handlers/guild_update_handler.go @@ -20,26 +20,25 @@ func (h GuildUpdateHandler) New() interface{} { // HandleGatewayEvent handles the specific raw gateway event func (h GuildUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { - newGuild, ok := i.(*api.Guild) + guild, ok := i.(*api.Guild) if !ok { return } - oldGuild := disgo.Cache().Guild(newGuild.ID) + oldGuild := disgo.Cache().Guild(guild.ID) if oldGuild != nil { oldGuild = &*oldGuild } - newGuild = disgo.EntityBuilder().CreateGuild(newGuild, api.CacheStrategyYes) + guild = disgo.EntityBuilder().CreateGuild(guild, api.CacheStrategyYes) genericGuildEvent := events.GenericGuildEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), - GuildID: newGuild.ID, + Guild: guild, } eventManager.Dispatch(genericGuildEvent) eventManager.Dispatch(events.GuildUpdateEvent{ GenericGuildEvent: genericGuildEvent, - NewGuild: newGuild, OldGuild: oldGuild, }) diff --git a/internal/handlers/interaction_create_handler.go b/internal/handlers/interaction_create_handler.go index ecd2af6e..861fa375 100644 --- a/internal/handlers/interaction_create_handler.go +++ b/internal/handlers/interaction_create_handler.go @@ -72,7 +72,7 @@ func handleInteraction(disgo api.Disgo, eventManager api.EventManager, sequenceN genericInteractionEvent := events.GenericInteractionEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), - Interaction: *interaction, + Interaction: interaction, } eventManager.Dispatch(genericInteractionEvent) diff --git a/internal/handlers/message_create_handler.go b/internal/handlers/message_create_handler.go index ed560e6b..391511ae 100644 --- a/internal/handlers/message_create_handler.go +++ b/internal/handlers/message_create_handler.go @@ -30,14 +30,14 @@ func (h MessageCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a genericMessageEvent := events.GenericMessageEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), - ChannelID: message.ChannelID, MessageID: message.ID, + Message: message, + ChannelID: message.ChannelID, } eventManager.Dispatch(genericMessageEvent) eventManager.Dispatch(events.MessageReceivedEvent{ GenericMessageEvent: genericMessageEvent, - Message: message, }) if message.GuildID == nil { @@ -48,7 +48,6 @@ func (h MessageCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a eventManager.Dispatch(events.DMMessageReceivedEvent{ GenericDMMessageEvent: genericDMMessageEvent, - Message: message, }) } else { genericGuildMessageEvent := events.GenericGuildMessageEvent{ @@ -59,7 +58,6 @@ func (h MessageCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a eventManager.Dispatch(events.GuildMessageReceivedEvent{ GenericGuildMessageEvent: genericGuildMessageEvent, - Message: message, }) } diff --git a/internal/handlers/voice_state_update_handler.go b/internal/handlers/voice_state_update_handler.go index f4884756..124149b9 100644 --- a/internal/handlers/voice_state_update_handler.go +++ b/internal/handlers/voice_state_update_handler.go @@ -34,7 +34,7 @@ func (h VoiceStateUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManage // TODO update voice state cache // TODO fire several events - if disgo.SelfUserID() == voiceStateUpdate.UserID { + if disgo.ApplicationID() == voiceStateUpdate.UserID { if interceptor := disgo.VoiceDispatchInterceptor(); interceptor != nil { interceptor.OnVoiceStateUpdate(voiceStateUpdate) } diff --git a/internal/restclient_impl.go b/internal/restclient_impl.go index 8c24cf8d..f46e669c 100644 --- a/internal/restclient_impl.go +++ b/internal/restclient_impl.go @@ -229,7 +229,7 @@ func (r RestClientImpl) UpdateSelfNick(guildID api.Snowflake, nick *string) (new var updateNick *api.UpdateSelfNick err = r.Request(*compiledRoute, api.UpdateSelfNick{Nick: nick}, &updateNick) if err == nil && api.CacheStrategyNoWs(r.Disgo()) { - r.Disgo().Cache().Member(guildID, r.Disgo().SelfUserID()).Nick = updateNick.Nick + r.Disgo().Cache().Member(guildID, r.Disgo().ApplicationID()).Nick = updateNick.Nick newNick = updateNick.Nick } return diff --git a/testbot/testbot.go b/testbot/testbot.go index 3c852135..c2d628e3 100644 --- a/testbot/testbot.go +++ b/testbot/testbot.go @@ -119,7 +119,7 @@ func main() { } // using the api.RestClient directly to avoid the guild needing to be cached - cmds, err := dgo.RestClient().SetGuildCommands(dgo.SelfUserID(), guildID, rawCmds...) + cmds, err := dgo.RestClient().SetGuildCommands(dgo.ApplicationID(), guildID, rawCmds...) if err != nil { logger.Errorf("error while registering guild commands: %s", err) } @@ -145,7 +145,7 @@ func main() { Permissions: []api.CommandPermission{perms}, }) } - if _, err = dgo.RestClient().SetGuildCommandsPermissions(dgo.SelfUserID(), guildID, cmdsPermissions...); err != nil { + if _, err = dgo.RestClient().SetGuildCommandsPermissions(dgo.ApplicationID(), guildID, cmdsPermissions...); err != nil { logger.Errorf("error while setting command permissions: %s", err) } @@ -163,7 +163,7 @@ func main() { } func guildAvailListener(event *events.GuildAvailableEvent) { - logger.Printf("guild loaded: %s", event.GuildID) + logger.Printf("guild loaded: %s", event.Guild.ID) } func slashCommandListener(event *events.SlashCommandEvent) { From ff68bf4a3230abab032404e6170b2b40768735cf Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Tue, 13 Apr 2021 10:11:11 +0200 Subject: [PATCH 62/65] made pointer funcs --- api/voice_dispatch_interceptor.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api/voice_dispatch_interceptor.go b/api/voice_dispatch_interceptor.go index d113f48b..eae50a6d 100644 --- a/api/voice_dispatch_interceptor.go +++ b/api/voice_dispatch_interceptor.go @@ -7,7 +7,7 @@ type VoiceServerUpdateEvent struct { } // Guild returns the Guild for this VoiceServerUpdate from the Cache -func (u VoiceServerUpdateEvent) Guild() *Guild { +func (u *VoiceServerUpdateEvent) Guild() *Guild { return u.Disgo.Cache().Guild(u.GuildID) } @@ -18,12 +18,12 @@ type VoiceStateUpdateEvent struct { } // Guild returns the Guild for this VoiceStateUpdate from the Cache -func (u VoiceStateUpdateEvent) Guild() *Guild { +func (u *VoiceStateUpdateEvent) Guild() *Guild { return u.Disgo.Cache().Guild(u.GuildID) } // VoiceChannel returns the VoiceChannel for this VoiceStateUpdate from the Cache -func (u VoiceStateUpdateEvent) VoiceChannel() *VoiceChannel { +func (u *VoiceStateUpdateEvent) VoiceChannel() *VoiceChannel { if u.ChannelID == nil { return nil } From 68147d55e4ddc3ce6f299def6b0d0de38de79074 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Tue, 13 Apr 2021 10:23:01 +0200 Subject: [PATCH 63/65] renamed MessageReceived to MessageCreate --- api/events/dm_message_event.go | 4 ++-- api/events/guild_message_events.go | 4 ++-- api/events/listener_adapter.go | 12 ++++++------ api/events/message_events.go | 4 ++-- internal/handlers/message_create_handler.go | 6 +++--- testbot/testbot.go | 4 ++-- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/api/events/dm_message_event.go b/api/events/dm_message_event.go index d34ee358..7d134537 100644 --- a/api/events/dm_message_event.go +++ b/api/events/dm_message_event.go @@ -14,8 +14,8 @@ func (e GenericDMMessageEvent) DMChannel() *api.DMChannel { return e.Disgo().Cache().DMChannel(e.ChannelID) } -// DMMessageReceivedEvent called upon receiving a api.Message in a api.DMChannel -type DMMessageReceivedEvent struct { +// DMMessageCreateEvent called upon receiving a api.Message in a api.DMChannel +type DMMessageCreateEvent struct { GenericDMMessageEvent } diff --git a/api/events/guild_message_events.go b/api/events/guild_message_events.go index 8829aecf..8a0c283c 100644 --- a/api/events/guild_message_events.go +++ b/api/events/guild_message_events.go @@ -20,8 +20,8 @@ func (e GenericGuildMessageEvent) TextChannel() *api.TextChannel { return e.Disgo().Cache().TextChannel(e.ChannelID) } -// GuildMessageReceivedEvent called upon receiving a api.Message in a api.DMChannel -type GuildMessageReceivedEvent struct { +// GuildMessageCreateEvent called upon receiving a api.Message in a api.DMChannel +type GuildMessageCreateEvent struct { GenericGuildMessageEvent } diff --git a/api/events/listener_adapter.go b/api/events/listener_adapter.go index a4e8c41c..b0c6bcc2 100644 --- a/api/events/listener_adapter.go +++ b/api/events/listener_adapter.go @@ -100,7 +100,7 @@ type ListenerAdapter struct { // api.Guild api.Message Events OnGenericGuildMessageEvent func(event *GenericGuildMessageEvent) - OnGuildMessageReceived func(event *GuildMessageReceivedEvent) + OnGuildMessageCreate func(event *GuildMessageCreateEvent) OnGuildMessageUpdate func(event *GuildMessageUpdateEvent) OnGuildMessageDelete func(event *GuildMessageDeleteEvent) @@ -129,7 +129,7 @@ type ListenerAdapter struct { // api.Message Events OnGenericMessageEvent func(event *GenericMessageEvent) - OnMessageReceived func(event *MessageReceivedEvent) + OnMessageCreate func(event *MessageCreateEvent) OnMessageUpdate func(event *MessageUpdateEvent) OnMessageDelete func(event *MessageDeleteEvent) @@ -440,8 +440,8 @@ func (l ListenerAdapter) OnEvent(event interface{}) { if listener := l.OnGenericGuildMessageEvent; listener != nil { listener(&e) } - case GuildMessageReceivedEvent: - if listener := l.OnGuildMessageReceived; listener != nil { + case GuildMessageCreateEvent: + if listener := l.OnGuildMessageCreate; listener != nil { listener(&e) } case GuildMessageUpdateEvent: @@ -526,8 +526,8 @@ func (l ListenerAdapter) OnEvent(event interface{}) { if listener := l.OnGenericMessageEvent; listener != nil { listener(&e) } - case MessageReceivedEvent: - if listener := l.OnMessageReceived; listener != nil { + case MessageCreateEvent: + if listener := l.OnMessageCreate; listener != nil { listener(&e) } case MessageUpdateEvent: diff --git a/api/events/message_events.go b/api/events/message_events.go index 7f96b5fd..7c8efa85 100644 --- a/api/events/message_events.go +++ b/api/events/message_events.go @@ -22,8 +22,8 @@ type MessageDeleteEvent struct { GenericMessageEvent } -// MessageReceivedEvent indicates a api.Message got received -type MessageReceivedEvent struct { +// MessageCreateEvent indicates a api.Message got received +type MessageCreateEvent struct { GenericMessageEvent } diff --git a/internal/handlers/message_create_handler.go b/internal/handlers/message_create_handler.go index 391511ae..80dba3ad 100644 --- a/internal/handlers/message_create_handler.go +++ b/internal/handlers/message_create_handler.go @@ -36,7 +36,7 @@ func (h MessageCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a } eventManager.Dispatch(genericMessageEvent) - eventManager.Dispatch(events.MessageReceivedEvent{ + eventManager.Dispatch(events.MessageCreateEvent{ GenericMessageEvent: genericMessageEvent, }) @@ -46,7 +46,7 @@ func (h MessageCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a } eventManager.Dispatch(genericDMMessageEvent) - eventManager.Dispatch(events.DMMessageReceivedEvent{ + eventManager.Dispatch(events.DMMessageCreateEvent{ GenericDMMessageEvent: genericDMMessageEvent, }) } else { @@ -56,7 +56,7 @@ func (h MessageCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager a } eventManager.Dispatch(genericGuildMessageEvent) - eventManager.Dispatch(events.GuildMessageReceivedEvent{ + eventManager.Dispatch(events.GuildMessageCreateEvent{ GenericGuildMessageEvent: genericGuildMessageEvent, }) } diff --git a/testbot/testbot.go b/testbot/testbot.go index c2d628e3..77a0ebd0 100644 --- a/testbot/testbot.go +++ b/testbot/testbot.go @@ -37,7 +37,7 @@ func main() { SetMemberCachePolicy(api.MemberCachePolicyAll). AddEventListeners(&events.ListenerAdapter{ OnGuildAvailable: guildAvailListener, - OnGuildMessageReceived: messageListener, + OnGuildMessageCreate: messageListener, OnSlashCommand: slashCommandListener, }). Build() @@ -279,7 +279,7 @@ func slashCommandListener(event *events.SlashCommandEvent) { } } -func messageListener(event *events.GuildMessageReceivedEvent) { +func messageListener(event *events.GuildMessageCreateEvent) { if event.Message.Author.IsBot { return } From 272f22660e33520aa3d82b71fa82387b7db79ae0 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Tue, 13 Apr 2021 12:33:03 +0200 Subject: [PATCH 64/65] added RawGatewayEvent toggle & event docs/cleanup --- api/audio_controller.go | 1 + api/channels.go | 1 + api/disgo.go | 1 + api/disgo_builder.go | 1 + api/endpoints/endpoints.go | 2 +- api/endpoints/token.go | 2 +- api/events/application_command_events.go | 5 ++++ api/events/category_events.go | 4 ++++ api/events/channel_events.go | 3 ++- api/events/dm_events.go | 9 ++++---- api/events/dm_message_event.go | 9 ++++---- api/events/dm_message_reaction_events.go | 5 ++++ api/events/emote_events.go | 4 ++++ api/events/exception_event.go | 5 ---- api/events/gateway_status_event.go | 11 ++++----- api/events/guild_events.go | 16 +++++++------ api/events/guild_invite_events.go | 20 ++++++++++++++-- api/events/guild_member_events.go | 4 +++- api/events/guild_message_events.go | 9 ++++---- api/events/guild_message_reaction_events.go | 7 ++++-- api/events/guild_voice_events.go | 6 +++-- api/events/heartbeat_event.go | 1 + api/events/http_request_events.go | 3 ++- api/events/interaction_events.go | 2 +- api/events/listener_adapter.go | 20 ++++------------ api/events/message_events.go | 8 +++---- api/events/message_reaction_events.go | 5 ++++ api/events/raw_gateway_event.go | 1 + api/events/ready_event.go | 1 - api/events/self_update_events.go | 3 ++- api/events/store_channel_events.go | 4 ++++ api/events/text_channel_events.go | 4 ++++ api/events/user_activity_events.go | 4 ++++ api/events/user_events.go | 15 +++++++++++- api/events/voice_channel_events.go | 4 ++++ api/guild.go | 1 + api/invite.go | 1 + api/options.go | 1 + internal/audio_controller_impl.go | 5 ++++ internal/disgo_builder_impl.go | 10 +++++++- internal/disgo_impl.go | 15 ++++++++---- internal/entity_builder_impl.go | 4 ++-- internal/gateway_impl.go | 23 ++++++++++--------- .../handlers/application_command_delete.go | 1 - internal/handlers/guild_delete_handler.go | 1 - internal/handlers/guild_member_add_handler.go | 2 +- internal/handlers/ready_handler.go | 10 ++++---- internal/restclient_impl.go | 2 +- 48 files changed, 185 insertions(+), 91 deletions(-) delete mode 100644 api/events/exception_event.go diff --git a/api/audio_controller.go b/api/audio_controller.go index 68672230..695a4a24 100644 --- a/api/audio_controller.go +++ b/api/audio_controller.go @@ -1,5 +1,6 @@ package api +// AudioController lets you Connect / Disconnect from a VoiceChannel type AudioController interface { Disgo() Disgo Connect(guildID Snowflake, channelID Snowflake) error diff --git a/api/channels.go b/api/channels.go index 5849817d..29e473ce 100644 --- a/api/channels.go +++ b/api/channels.go @@ -101,6 +101,7 @@ type VoiceChannel struct { GuildChannel } +// Connect sends a api.GatewayCommand to connect to this VoiceChannel func (c *VoiceChannel) Connect() error { return c.Disgo.AudioController().Connect(*c.GuildID, c.ID) } diff --git a/api/disgo.go b/api/disgo.go index 6e078ec5..90112a94 100644 --- a/api/disgo.go +++ b/api/disgo.go @@ -22,6 +22,7 @@ type Disgo interface { WebhookServer() WebhookServer Cache() Cache Intents() Intents + RawGatewayEventsEnabled() bool ApplicationID() Snowflake SelfUser() *User EntityBuilder() EntityBuilder diff --git a/api/disgo_builder.go b/api/disgo_builder.go index 3857909b..c38245a0 100644 --- a/api/disgo_builder.go +++ b/api/disgo_builder.go @@ -11,6 +11,7 @@ type DisgoBuilder interface { SetLogger(level log.Logger) DisgoBuilder SetToken(token endpoints.Token) DisgoBuilder SetIntents(intents Intents) DisgoBuilder + SetRawGatewayEventsEnabled(enabled bool) DisgoBuilder SetVoiceDispatchInterceptor(voiceDispatchInterceptor VoiceDispatchInterceptor) DisgoBuilder SetEntityBuilder(entityBuilder EntityBuilder) DisgoBuilder SetEventManager(eventManager EventManager) DisgoBuilder diff --git a/api/endpoints/endpoints.go b/api/endpoints/endpoints.go index 98d3ca66..d335c1f5 100644 --- a/api/endpoints/endpoints.go +++ b/api/endpoints/endpoints.go @@ -205,5 +205,5 @@ var ( // Other var ( - InviteURL = NewRoute("https://discord.gg/{code}") + InviteURL = NewRoute("https://discord.gg/{code}") ) diff --git a/api/endpoints/token.go b/api/endpoints/token.go index 887a321c..29e23dc9 100644 --- a/api/endpoints/token.go +++ b/api/endpoints/token.go @@ -9,7 +9,7 @@ type Token string // MarshalJSON makes sure we don#t send ********* to discords as tokens func (t Token) MarshalJSON() ([]byte, error) { - return []byte("\""+t+"\""), nil + return []byte("\"" + t + "\""), nil } // UnmarshalJSON makes sure we parse tokens from discord correctly diff --git a/api/events/application_command_events.go b/api/events/application_command_events.go index e712f3b1..3b427c71 100644 --- a/api/events/application_command_events.go +++ b/api/events/application_command_events.go @@ -4,6 +4,7 @@ import ( "github.com/DisgoOrg/disgo/api" ) +// GenericApplicationCommandEvent is called upon receiving either ApplicationCommandCreateEvent, ApplicationCommandUpdateEvent or ApplicationCommandDeleteEvent type GenericApplicationCommandEvent struct { GenericEvent CommandID api.Snowflake @@ -11,6 +12,7 @@ type GenericApplicationCommandEvent struct { GuildID *api.Snowflake } +// Guild returns the api.Guild the api.Event got called or nil for global api.Command(s) func (e GenericApplicationCommandEvent) Guild() *api.Guild { if e.GuildID == nil { return nil @@ -18,15 +20,18 @@ func (e GenericApplicationCommandEvent) Guild() *api.Guild { return e.Disgo().Cache().Guild(*e.GuildID) } +// ApplicationCommandCreateEvent indicates that a new api.Command got created(this can come from any bot!) type ApplicationCommandCreateEvent struct { GenericApplicationCommandEvent } +// ApplicationCommandUpdateEvent indicates that a api.Command got updated(this can come from any bot!) type ApplicationCommandUpdateEvent struct { GenericApplicationCommandEvent OldCommand *api.Command } +// ApplicationCommandDeleteEvent indicates that a api.Command got deleted(this can come from any bot!) type ApplicationCommandDeleteEvent struct { GenericApplicationCommandEvent } diff --git a/api/events/category_events.go b/api/events/category_events.go index 84993cd8..722cb544 100644 --- a/api/events/category_events.go +++ b/api/events/category_events.go @@ -4,20 +4,24 @@ import ( "github.com/DisgoOrg/disgo/api" ) +// GenericCategoryEvent is called upon receiving CategoryCreateEvent, CategoryUpdateEvent or CategoryDeleteEvent type GenericCategoryEvent struct { GenericChannelEvent Category *api.Category } +// CategoryCreateEvent indicates that a new api.Category got created in a api.Guild type CategoryCreateEvent struct { GenericCategoryEvent } +// CategoryUpdateEvent indicates that a api.Category got updated in a api.Guild type CategoryUpdateEvent struct { GenericCategoryEvent OldCategory *api.Category } +// CategoryDeleteEvent indicates that a api.Category got deleted in a api.Guild type CategoryDeleteEvent struct { GenericCategoryEvent } diff --git a/api/events/channel_events.go b/api/events/channel_events.go index 39d28344..949a1523 100644 --- a/api/events/channel_events.go +++ b/api/events/channel_events.go @@ -4,12 +4,13 @@ import ( "github.com/DisgoOrg/disgo/api" ) -// GenericChannelEvent is called upon receiving an event in a api.Channel +// GenericChannelEvent is called upon receiving any api.Channel api.Event type GenericChannelEvent struct { GenericEvent ChannelID api.Snowflake } +// Channel returns the api.Channel from the api.Cache if cached func (e GenericChannelEvent) Channel() *api.Channel { return e.Disgo().Cache().Channel(e.ChannelID) } diff --git a/api/events/dm_events.go b/api/events/dm_events.go index def543b9..6f271d81 100644 --- a/api/events/dm_events.go +++ b/api/events/dm_events.go @@ -4,28 +4,29 @@ import ( "github.com/DisgoOrg/disgo/api" ) +// GenericDMChannelEvent is called upon receiving DMChannelCreateEvent, DMChannelUpdateEvent, DMChannelDeleteEvent or DMUserTypingEvent type GenericDMChannelEvent struct { GenericChannelEvent DMChannel *api.DMChannel } +// DMChannelCreateEvent indicates that a new api.DMChannel got created type DMChannelCreateEvent struct { GenericDMChannelEvent } +// DMChannelUpdateEvent indicates that a api.DMChannel got updated type DMChannelUpdateEvent struct { GenericDMChannelEvent OldDMChannel *api.DMChannel } +// DMChannelDeleteEvent indicates that a api.DMChannel got deleted type DMChannelDeleteEvent struct { GenericDMChannelEvent } +// DMUserTypingEvent indicates that a api.User started typing in a api.DMChannel(requires api.IntentsDirectMessageTyping) type DMUserTypingEvent struct { GenericDMChannelEvent } - -func (e DMUserTypingEvent) DMChannel() *api.DMChannel { - return e.Disgo().Cache().DMChannel(e.ChannelID) -} diff --git a/api/events/dm_message_event.go b/api/events/dm_message_event.go index 7d134537..ee5aebc3 100644 --- a/api/events/dm_message_event.go +++ b/api/events/dm_message_event.go @@ -4,28 +4,29 @@ import ( "github.com/DisgoOrg/disgo/api" ) -// GenericDMMessageEvent generic api.DMChannel api.Message api.GenericEvent +// GenericDMMessageEvent is called upon receiving DMMessageCreateEvent, DMMessageUpdateEvent, DMMessageDeleteEvent, GenericDMMessageReactionEvent, DMMessageReactionAddEvent, DMMessageReactionRemoveEvent, DMMessageReactionRemoveEmoteEvent or DMMessageReactionRemoveAllEvent(requires api.IntentsDirectMessages) type GenericDMMessageEvent struct { GenericMessageEvent Message *api.Message } +// DMChannel returns the api.DMChannel where the GenericDMMessageEvent happened func (e GenericDMMessageEvent) DMChannel() *api.DMChannel { return e.Disgo().Cache().DMChannel(e.ChannelID) } -// DMMessageCreateEvent called upon receiving a api.Message in a api.DMChannel +// DMMessageCreateEvent is called upon receiving a api.Message in a api.DMChannel(requires api.IntentsDirectMessages) type DMMessageCreateEvent struct { GenericDMMessageEvent } -// DMMessageUpdateEvent called upon editing a api.Message in a api.DMChannel +// DMMessageUpdateEvent is called upon editing a api.Message in a api.DMChannel(requires api.IntentsDirectMessages) type DMMessageUpdateEvent struct { GenericDMMessageEvent OldMessage *api.Message } -// DMMessageDeleteEvent called upon deleting a api.Message in a api.DMChannel +// DMMessageDeleteEvent is called upon deleting a api.Message in a api.DMChannel(requires api.IntentsDirectMessages) type DMMessageDeleteEvent struct { GenericDMMessageEvent } diff --git a/api/events/dm_message_reaction_events.go b/api/events/dm_message_reaction_events.go index 85ce504c..40027fe9 100644 --- a/api/events/dm_message_reaction_events.go +++ b/api/events/dm_message_reaction_events.go @@ -2,6 +2,7 @@ package events import "github.com/DisgoOrg/disgo/api" +// GenericDMMessageReactionEvent is called upon receiving DMMessageReactionAddEvent or DMMessageReactionRemoveEvent(requires the api.IntentsDirectMessageReactions) type GenericDMMessageReactionEvent struct { GenericGuildMessageEvent UserID api.Snowflake @@ -9,19 +10,23 @@ type GenericDMMessageReactionEvent struct { MessageReaction api.MessageReaction } +// DMMessageReactionAddEvent indicates that a api.User added a api.MessageReaction to a api.Message in a api.DMChannel(requires the api.IntentsDirectMessageReactions) type DMMessageReactionAddEvent struct { GenericDMMessageReactionEvent } +// DMMessageReactionRemoveEvent indicates that a api.User removed a api.MessageReaction from a api.Message in a api.DMChannel(requires the api.IntentsDirectMessageReactions) type DMMessageReactionRemoveEvent struct { GenericDMMessageReactionEvent } +// DMMessageReactionRemoveEmoteEvent indicates someone removed all api.MessageReaction of a specific api.Emote from a api.Message in a api.DMChannel(requires the api.IntentsDirectMessageReactions) type DMMessageReactionRemoveEmoteEvent struct { GenericDMMessageEvent MessageReaction api.MessageReaction } +// DMMessageReactionRemoveAllEvent indicates someone removed all api.MessageReaction(s) from a api.Message in a api.DMChannel(requires the api.IntentsDirectMessageReactions) type DMMessageReactionRemoveAllEvent struct { GenericDMMessageEvent } diff --git a/api/events/emote_events.go b/api/events/emote_events.go index b5c8a295..7e6f6876 100644 --- a/api/events/emote_events.go +++ b/api/events/emote_events.go @@ -4,20 +4,24 @@ import ( "github.com/DisgoOrg/disgo/api" ) +// GenericEmoteEvent is called upon receiving EmoteCreateEvent, EmoteUpdateEvent or EmoteDeleteEvent(requires api.IntentsGuildEmojis) type GenericEmoteEvent struct { GenericGuildEvent Emote *api.Emote } +// EmoteCreateEvent indicates that a new api.Emote got created in a api.Guild(requires api.IntentsGuildEmojis) type EmoteCreateEvent struct { GenericEmoteEvent } +// EmoteUpdateEvent indicates that a api.Emote got updated in a api.Guild(requires api.IntentsGuildEmojis) type EmoteUpdateEvent struct { GenericEmoteEvent OldEmote *api.Emote } +// EmoteDeleteEvent indicates that a api.Emote got deleted in a api.Guild(requires api.IntentsGuildEmojis) type EmoteDeleteEvent struct { GenericEmoteEvent } diff --git a/api/events/exception_event.go b/api/events/exception_event.go deleted file mode 100644 index 0938e2ac..00000000 --- a/api/events/exception_event.go +++ /dev/null @@ -1,5 +0,0 @@ -package events - -type ErrorEvent struct { - Error error -} diff --git a/api/events/gateway_status_event.go b/api/events/gateway_status_event.go index 6831a0b9..17ad0f5e 100644 --- a/api/events/gateway_status_event.go +++ b/api/events/gateway_status_event.go @@ -4,29 +4,28 @@ import ( "github.com/DisgoOrg/disgo/api" ) +// GenericGatewayStatusEvent is called upon receiving ConnectedEvent, ReconnectedEvent, ResumedEvent, DisconnectedEvent or ShutdownEvent type GenericGatewayStatusEvent struct { GenericEvent Status api.GatewayStatus } +// ConnectedEvent indicates disgo connected to the api.Gateway type ConnectedEvent struct { GenericGatewayStatusEvent } +// ReconnectedEvent indicates disgo reconnected to the api.Gateway type ReconnectedEvent struct { GenericGatewayStatusEvent } +// ResumedEvent indicates disgo resumed to the api.Gateway type ResumedEvent struct { GenericGatewayStatusEvent } +// DisconnectedEvent indicates disgo disconnected to the api.Gateway type DisconnectedEvent struct { GenericGatewayStatusEvent } - -type ShutdownEvent struct { - GenericGatewayStatusEvent -} - - diff --git a/api/events/guild_events.go b/api/events/guild_events.go index b3df8c6d..aa214bae 100644 --- a/api/events/guild_events.go +++ b/api/events/guild_events.go @@ -4,48 +4,50 @@ import ( "github.com/DisgoOrg/disgo/api" ) -// GenericGuildEvent generic api.Guild api.GenericEvent +// GenericGuildEvent is called upon receiving GuildUpdateEvent, GuildAvailableEvent, GuildUnavailableEvent, GuildJoinEvent, GuildLeaveEvent, GuildReadyEvent, GuildBanEvent, GuildUnbanEvent type GenericGuildEvent struct { GenericEvent Guild *api.Guild } -// GuildUpdateEvent called upon receiving api.Guild updates +// GuildUpdateEvent is called upon receiving api.Guild updates type GuildUpdateEvent struct { GenericGuildEvent OldGuild *api.Guild } -// GuildAvailableEvent called when an unavailable api.Guild becomes available +// GuildAvailableEvent is called when an unavailable api.Guild becomes available type GuildAvailableEvent struct { GenericGuildEvent } -// GuildUnavailableEvent called when an available api.Guild becomes unavailable +// GuildUnavailableEvent is called when an available api.Guild becomes unavailable type GuildUnavailableEvent struct { GenericGuildEvent } -// GuildJoinEvent called when the bot joins a api.Guild +// GuildJoinEvent is called when the bot joins a api.Guild type GuildJoinEvent struct { GenericGuildEvent } -// GuildLeaveEvent called when the bot leaves a api.Guild +// GuildLeaveEvent is called when the bot leaves a api.Guild type GuildLeaveEvent struct { GenericGuildEvent } -// GuildReadyEvent called when the loaded the api.Guild in login phase +// GuildReadyEvent is called when the loaded the api.Guild in login phase type GuildReadyEvent struct { GenericGuildEvent } +// GuildBanEvent is called when a api.Member/api.User is banned from the api.Guild type GuildBanEvent struct { GenericGuildEvent User *api.User } +// GuildUnbanEvent is called when a api.Member/api.User is unbanned from the api.Guild type GuildUnbanEvent struct { GenericGuildEvent User *api.User diff --git a/api/events/guild_invite_events.go b/api/events/guild_invite_events.go index 7e257778..0fa4c812 100644 --- a/api/events/guild_invite_events.go +++ b/api/events/guild_invite_events.go @@ -4,37 +4,53 @@ import ( "github.com/DisgoOrg/disgo/api" ) +// GenericGuildInviteEvent is called upon receiving GuildInviteCreateEvent or GuildInviteDeleteEvent(requires api.IntentsGuildInvites) type GenericGuildInviteEvent struct { GenericGuildEvent Code string ChannelID api.Snowflake } +// Channel returns the api.Channel the GenericGuildInviteEvent happened in(returns nil if the api.Channel is uncached or api.Cache is disabled) +func (e GenericGuildInviteEvent) Channel() *api.Channel { + return e.Disgo().Cache().Channel(e.ChannelID) +} + +// GuildChannel returns the api.GuildChannel the GenericGuildInviteEvent happened in(returns nil if the api.GuildChannel is uncached or api.Cache is disabled) func (e GenericGuildInviteEvent) GuildChannel() *api.GuildChannel { return e.Disgo().Cache().GuildChannel(e.ChannelID) } +// MessageChannel returns the api.MessageChannel the GenericGuildInviteEvent happened in(returns nil if the api.MessageChannel is uncached or api.Cache is disabled) +func (e GenericGuildInviteEvent) MessageChannel() *api.TextChannel { + return e.Disgo().Cache().TextChannel(e.ChannelID) +} + +// TextChannel returns the api.TextChannel the GenericGuildInviteEvent happened in(returns nil if the api.TextChannel is uncached or api.CacheFlagTextChannels is disabled) func (e GenericGuildInviteEvent) TextChannel() *api.TextChannel { return e.Disgo().Cache().TextChannel(e.ChannelID) } +// VoiceChannel returns the api.VoiceChannel the GenericGuildInviteEvent happened in(returns nil if the api.VoiceChannel is uncached or api.CacheFlagVoiceChannels is disabled) func (e GenericGuildInviteEvent) VoiceChannel() *api.VoiceChannel { return e.Disgo().Cache().VoiceChannel(e.ChannelID) } - +// StoreChannel returns the api.StoreChannel the GenericGuildInviteEvent happened in(returns nil if the api.StoreChannel is uncached or api.CacheFlagStoreChannels is disabled) func (e GenericGuildInviteEvent) StoreChannel() *api.StoreChannel { return e.Disgo().Cache().StoreChannel(e.ChannelID) } - +// Category returns the api.Category the GenericGuildInviteEvent happened in(returns nil if the api.Category is uncached or api.CacheFlagCategories is disabled) func (e GenericGuildInviteEvent) Category() *api.Category { return e.Disgo().Cache().Category(e.ChannelID) } +// GuildInviteCreateEvent is called upon creation of a new api.Invite in a api.Guild(requires api.IntentsGuildInvites) type GuildInviteCreateEvent struct { GenericGuildInviteEvent Invite *api.Invite } +// GuildInviteDeleteEvent is called upon deletion of a new api.Invite in a api.Guild(requires api.IntentsGuildInvites) type GuildInviteDeleteEvent struct { GenericGuildInviteEvent } diff --git a/api/events/guild_member_events.go b/api/events/guild_member_events.go index 7736387c..32ce9a55 100644 --- a/api/events/guild_member_events.go +++ b/api/events/guild_member_events.go @@ -35,11 +35,13 @@ type GuildMemberLeaveEvent struct { User *api.User } +// GuildMemberTypingEvent indicates that a api.Member started typing in a api.TextChannel(requires api.IntentsGuildMessageTyping) type GuildMemberTypingEvent struct { GenericGuildMemberEvent ChannelID api.Snowflake } +// TextChannel returns the api.TextChannel the GuildMemberTypingEvent happened in func (e GuildMemberTypingEvent) TextChannel() *api.TextChannel { return e.Disgo().Cache().TextChannel(e.ChannelID) -} \ No newline at end of file +} diff --git a/api/events/guild_message_events.go b/api/events/guild_message_events.go index 8a0c283c..4fd3ba57 100644 --- a/api/events/guild_message_events.go +++ b/api/events/guild_message_events.go @@ -4,13 +4,14 @@ import ( "github.com/DisgoOrg/disgo/api" ) -// GenericGuildMessageEvent generic api.DMChannel api.Message api.GenericEvent +// GenericGuildMessageEvent is called upon receiving GuildMessageCreateEvent, GuildMessageUpdateEvent or GuildMessageDeleteEvent type GenericGuildMessageEvent struct { GenericMessageEvent GuildID api.Snowflake Message *api.Message } +// Guild returns the api.Guild the GenericGuildMessageEvent happened in func (e GenericGuildMessageEvent) Guild() *api.Guild { return e.Disgo().Cache().Guild(e.GuildID) } @@ -20,18 +21,18 @@ func (e GenericGuildMessageEvent) TextChannel() *api.TextChannel { return e.Disgo().Cache().TextChannel(e.ChannelID) } -// GuildMessageCreateEvent called upon receiving a api.Message in a api.DMChannel +// GuildMessageCreateEvent is called upon receiving a api.Message in a api.DMChannel type GuildMessageCreateEvent struct { GenericGuildMessageEvent } -// GuildMessageUpdateEvent called upon editing a api.Message in a api.DMChannel +// GuildMessageUpdateEvent is called upon editing a api.Message in a api.DMChannel type GuildMessageUpdateEvent struct { GenericGuildMessageEvent OldMessage *api.Message } -// GuildMessageDeleteEvent called upon deleting a api.Message in a api.DMChannel +// GuildMessageDeleteEvent is called upon deleting a api.Message in a api.DMChannel type GuildMessageDeleteEvent struct { GenericGuildMessageEvent } diff --git a/api/events/guild_message_reaction_events.go b/api/events/guild_message_reaction_events.go index df2fd2ea..77f0f7ed 100644 --- a/api/events/guild_message_reaction_events.go +++ b/api/events/guild_message_reaction_events.go @@ -1,27 +1,30 @@ package events import "github.com/DisgoOrg/disgo/api" - +// GenericGuildMessageReactionEvent is called upon receiving DMMessageReactionAddEvent or DMMessageReactionRemoveEvent type GenericGuildMessageReactionEvent struct { GenericGuildMessageEvent UserID api.Snowflake Member *api.Member MessageReaction api.MessageReaction } - +// GuildMessageReactionAddEvent indicates that a api.Member added a api.MessageReaction to a api.Message in a api.TextChannel(requires the api.IntentsGuildMessageReactions) type GuildMessageReactionAddEvent struct { GenericGuildMessageReactionEvent } +// GuildMessageReactionRemoveEvent indicates that a api.Member removed a api.MessageReaction from a api.Message in a api.TextChannel(requires the api.IntentsGuildMessageReactions) type GuildMessageReactionRemoveEvent struct { GenericGuildMessageReactionEvent } +// GuildMessageReactionRemoveEmoteEvent indicates someone removed all api.MessageReaction of a specific api.Emote from a api.Message in a api.TextChannel(requires the api.IntentsGuildMessageReactions) type GuildMessageReactionRemoveEmoteEvent struct { GenericGuildMessageEvent MessageReaction api.MessageReaction } +// GuildMessageReactionRemoveAllEvent indicates someone removed all api.MessageReaction(s) from a api.Message in a api.TextChannel(requires the api.IntentsGuildMessageReactions) type GuildMessageReactionRemoveAllEvent struct { GenericGuildMessageEvent } diff --git a/api/events/guild_voice_events.go b/api/events/guild_voice_events.go index 01ddb409..60d14088 100644 --- a/api/events/guild_voice_events.go +++ b/api/events/guild_voice_events.go @@ -4,22 +4,24 @@ import ( "github.com/DisgoOrg/disgo/api" ) +// GenericGuildVoiceEvent is called upon receiving GuildVoiceJoinEvent, GuildVoiceUpdateEvent, GuildVoiceLeaveEvent type GenericGuildVoiceEvent struct { GenericGuildMemberEvent VoiceState *api.VoiceState } +// GuildVoiceJoinEvent indicates that a api.Member joined a api.VoiceChannel(requires api.IntentsGuildVoiceStates) type GuildVoiceJoinEvent struct { GenericGuildVoiceEvent - GenericVoiceChannelEvent } +// GuildVoiceUpdateEvent indicates that a api.Member moved a api.VoiceChannel(requires api.IntentsGuildVoiceStates) type GuildVoiceUpdateEvent struct { GenericGuildVoiceEvent OldVoiceState *api.VoiceState } +// GuildVoiceLeaveEvent indicates that a api.Member left a api.VoiceChannel(requires api.IntentsGuildVoiceStates) type GuildVoiceLeaveEvent struct { GenericGuildVoiceEvent - GenericVoiceChannelEvent } diff --git a/api/events/heartbeat_event.go b/api/events/heartbeat_event.go index 5767363b..7ab07a74 100644 --- a/api/events/heartbeat_event.go +++ b/api/events/heartbeat_event.go @@ -2,6 +2,7 @@ package events import "time" +// HeartbeatEvent is called upon sending a heartbeat to the api.Gateway type HeartbeatEvent struct { GenericEvent NewPing time.Duration diff --git a/api/events/http_request_events.go b/api/events/http_request_events.go index 071debe1..29185042 100644 --- a/api/events/http_request_events.go +++ b/api/events/http_request_events.go @@ -4,7 +4,8 @@ import ( "net/http" ) -type HttpRequestEvent struct { +// HTTPRequestEvent indicates a new http.Request was made and can be used to collect data of StatusCodes as an example +type HTTPRequestEvent struct { GenericEvent Request *http.Request Response *http.Response diff --git a/api/events/interaction_events.go b/api/events/interaction_events.go index 6b819076..fe691428 100644 --- a/api/events/interaction_events.go +++ b/api/events/interaction_events.go @@ -52,7 +52,7 @@ func (e GenericInteractionEvent) GuildChannel() *api.GuildChannel { return e.Disgo().Cache().GuildChannel(*e.Interaction.ChannelID) } -// SlashCommandEvent indicates a slash api.Command was ran in a api.Guild +// SlashCommandEvent indicates that a slash api.Command was ran in a api.Guild type SlashCommandEvent struct { GenericInteractionEvent ResponseChannel chan interface{} diff --git a/api/events/listener_adapter.go b/api/events/listener_adapter.go index b0c6bcc2..7c0f6978 100644 --- a/api/events/listener_adapter.go +++ b/api/events/listener_adapter.go @@ -11,8 +11,7 @@ type ListenerAdapter struct { // Other events OnGenericEvent func(event *GenericEvent) OnHeartbeat func(event *HeartbeatEvent) - OnError func(event *ErrorEvent) - OnHttpRequest func(event *HttpRequestEvent) + OnHTTPRequest func(event *HTTPRequestEvent) OnRawGateway func(event *RawGatewayEvent) OnReadyEvent func(event *ReadyEvent) @@ -74,7 +73,6 @@ type ListenerAdapter struct { OnReconnected func(event *ReconnectedEvent) OnResumed func(event *ResumedEvent) OnDisconnected func(event *DisconnectedEvent) - OnShutdown func(event *ShutdownEvent) // api.Guild Events OnGenericGuildEvent func(event *GenericGuildEvent) @@ -100,7 +98,7 @@ type ListenerAdapter struct { // api.Guild api.Message Events OnGenericGuildMessageEvent func(event *GenericGuildMessageEvent) - OnGuildMessageCreate func(event *GuildMessageCreateEvent) + OnGuildMessageCreate func(event *GuildMessageCreateEvent) OnGuildMessageUpdate func(event *GuildMessageUpdateEvent) OnGuildMessageDelete func(event *GuildMessageDeleteEvent) @@ -129,7 +127,7 @@ type ListenerAdapter struct { // api.Message Events OnGenericMessageEvent func(event *GenericMessageEvent) - OnMessageCreate func(event *MessageCreateEvent) + OnMessageCreate func(event *MessageCreateEvent) OnMessageUpdate func(event *MessageUpdateEvent) OnMessageDelete func(event *MessageDeleteEvent) @@ -168,12 +166,8 @@ func (l ListenerAdapter) OnEvent(event interface{}) { if listener := l.OnHeartbeat; listener != nil { listener(&e) } - case HttpRequestEvent: - if listener := l.OnHttpRequest; listener != nil { - listener(&e) - } - case ErrorEvent: - if listener := l.OnError; listener != nil { + case HTTPRequestEvent: + if listener := l.OnHTTPRequest; listener != nil { listener(&e) } case RawGatewayEvent: @@ -360,10 +354,6 @@ func (l ListenerAdapter) OnEvent(event interface{}) { if listener := l.OnDisconnected; listener != nil { listener(&e) } - case ShutdownEvent: - if listener := l.OnShutdown; listener != nil { - listener(&e) - } // api.Guild Events case GenericGuildEvent: diff --git a/api/events/message_events.go b/api/events/message_events.go index 7c8efa85..e1e22c76 100644 --- a/api/events/message_events.go +++ b/api/events/message_events.go @@ -12,22 +12,22 @@ type GenericMessageEvent struct { ChannelID api.Snowflake } -// MessageChannel returns the api.MessageChannel where this api.message got received +// MessageChannel returns the api.MessageChannel where the GenericMessageEvent happened func (e *GenericMessageEvent) MessageChannel() *api.MessageChannel { return e.Disgo().Cache().MessageChannel(e.ChannelID) } -// MessageDeleteEvent indicates a api.Message got deleted +// MessageDeleteEvent indicates that a api.Message got deleted type MessageDeleteEvent struct { GenericMessageEvent } -// MessageCreateEvent indicates a api.Message got received +// MessageCreateEvent indicates that a api.Message got received type MessageCreateEvent struct { GenericMessageEvent } -// MessageUpdateEvent indicates a api.Message got update +// MessageUpdateEvent indicates that a api.Message got update type MessageUpdateEvent struct { GenericMessageEvent OldMessage *api.Message diff --git a/api/events/message_reaction_events.go b/api/events/message_reaction_events.go index 8333b8d8..fc4cf972 100644 --- a/api/events/message_reaction_events.go +++ b/api/events/message_reaction_events.go @@ -2,6 +2,7 @@ package events import "github.com/DisgoOrg/disgo/api" +// GenericReactionEvents is called upon receiving MessageReactionAddEvent or MessageReactionRemoveEvent type GenericReactionEvents struct { GenericMessageEvent UserID api.Snowflake @@ -9,19 +10,23 @@ type GenericReactionEvents struct { MessageReaction api.MessageReaction } +// MessageReactionAddEvent indicates that a api.User added a api.MessageReaction to a api.Message in a api.Channel(this+++ requires the api.IntentsGuildMessageReactions and/or api.IntentsDirectMessageReactions) type MessageReactionAddEvent struct { GenericReactionEvents } +// MessageReactionRemoveEvent indicates that a api.User removed a api.MessageReaction from a api.Message in a api.Channel(requires the api.IntentsGuildMessageReactions and/or api.IntentsDirectMessageReactions) type MessageReactionRemoveEvent struct { GenericReactionEvents } +// MessageReactionRemoveEmoteEvent indicates someone removed all api.MessageReaction of a specific api.Emote from a api.Message in a api.Channel(requires the api.IntentsGuildMessageReactions and/or api.IntentsDirectMessageReactions) type MessageReactionRemoveEmoteEvent struct { GenericMessageEvent MessageReaction api.MessageReaction } +// MessageReactionRemoveAllEvent indicates someone removed all api.MessageReaction(s) from a api.Message in a api.Channel(requires the api.IntentsGuildMessageReactions and/or api.IntentsDirectMessageReactionss) type MessageReactionRemoveAllEvent struct { GenericMessageEvent } diff --git a/api/events/raw_gateway_event.go b/api/events/raw_gateway_event.go index ac136681..bb632eea 100644 --- a/api/events/raw_gateway_event.go +++ b/api/events/raw_gateway_event.go @@ -6,6 +6,7 @@ import ( "github.com/DisgoOrg/disgo/api" ) +// RawGatewayEvent is called for any api.GatewayEventType we receive if enabled in the api.DisgoBuilder/api.Options type RawGatewayEvent struct { GenericEvent Type api.GatewayEventType diff --git a/api/events/ready_event.go b/api/events/ready_event.go index c919381b..77bcb301 100644 --- a/api/events/ready_event.go +++ b/api/events/ready_event.go @@ -7,4 +7,3 @@ type ReadyEvent struct { GenericEvent api.ReadyGatewayEvent } - diff --git a/api/events/self_update_events.go b/api/events/self_update_events.go index 907c2d2e..4a12a6c4 100644 --- a/api/events/self_update_events.go +++ b/api/events/self_update_events.go @@ -4,8 +4,9 @@ import ( "github.com/DisgoOrg/disgo/api" ) +// SelfUpdateEvent is called when something about this api.User updates type SelfUpdateEvent struct { GenericEvent - NewSelf *api.User + Self *api.User OldSelf *api.User } diff --git a/api/events/store_channel_events.go b/api/events/store_channel_events.go index d3837271..fffc1b5d 100644 --- a/api/events/store_channel_events.go +++ b/api/events/store_channel_events.go @@ -4,20 +4,24 @@ import ( "github.com/DisgoOrg/disgo/api" ) +// GenericStoreChannelEvent is called upon receiving StoreChannelCreateEvent, StoreChannelUpdateEvent or StoreChannelDeleteEvent type GenericStoreChannelEvent struct { GenericChannelEvent StoreChannel *api.StoreChannel } +// StoreChannelCreateEvent indicates that a new api.StoreChannel got created in a api.Guild type StoreChannelCreateEvent struct { GenericStoreChannelEvent } +// StoreChannelUpdateEvent indicates that a api.StoreChannel got updated in a api.Guild type StoreChannelUpdateEvent struct { GenericStoreChannelEvent OldStoreChannel *api.StoreChannel } +// StoreChannelDeleteEvent indicates that a api.StoreChannel got deleted in a api.Guild type StoreChannelDeleteEvent struct { GenericStoreChannelEvent } diff --git a/api/events/text_channel_events.go b/api/events/text_channel_events.go index 05c30f87..7ddc08f0 100644 --- a/api/events/text_channel_events.go +++ b/api/events/text_channel_events.go @@ -4,20 +4,24 @@ import ( "github.com/DisgoOrg/disgo/api" ) +// GenericTextChannelEvent is called upon receiving TextChannelCreateEvent, TextChannelUpdateEvent or TextChannelDeleteEvent type GenericTextChannelEvent struct { GenericChannelEvent TextChannel *api.TextChannel } +// TextChannelCreateEvent indicates that a new api.TextChannel got created in a api.Guild type TextChannelCreateEvent struct { GenericTextChannelEvent } +// TextChannelUpdateEvent indicates that a api.TextChannel got updated in a api.Guild type TextChannelUpdateEvent struct { GenericTextChannelEvent OldTextChannel *api.TextChannel } +// TextChannelDeleteEvent indicates that a api.TextChannel got deleted in a api.Guild type TextChannelDeleteEvent struct { GenericTextChannelEvent } diff --git a/api/events/user_activity_events.go b/api/events/user_activity_events.go index 7518e195..3aa5a942 100644 --- a/api/events/user_activity_events.go +++ b/api/events/user_activity_events.go @@ -4,22 +4,26 @@ import ( "github.com/DisgoOrg/disgo/api" ) +// GenericUserActivityEvent is called upon receiving UserActivityStartEvent, UserActivityUpdateEvent or UserActivityEndEvent(requires the api.IntentsGuildPresences) type GenericUserActivityEvent struct { GenericGuildMemberEvent Member *api.Member } +// UserActivityStartEvent indicates that a api.User started a new api.Activity(requires the api.IntentsGuildPresences) type UserActivityStartEvent struct { GenericUserActivityEvent Activity *api.Activity } +// UserActivityUpdateEvent indicates that a api.User's api.Activity(s) updated(requires the api.IntentsGuildPresences) type UserActivityUpdateEvent struct { GenericUserActivityEvent NewActivities *api.Activity OldActivities *api.Activity } +// UserActivityEndEvent indicates that a api.User ended a api.Activity(requires the api.IntentsGuildPresences) type UserActivityEndEvent struct { GenericUserActivityEvent Activity *api.Activity diff --git a/api/events/user_events.go b/api/events/user_events.go index 385e6ee8..c961ccbf 100644 --- a/api/events/user_events.go +++ b/api/events/user_events.go @@ -4,22 +4,35 @@ import ( "github.com/DisgoOrg/disgo/api" ) +// GenericUserEvent is called upon receiving UserUpdateEvent or UserTypingEvent type GenericUserEvent struct { GenericEvent UserID api.Snowflake User *api.User } +// UserUpdateEvent indicates that a api.User updated type UserUpdateEvent struct { GenericUserEvent OldUser *api.User } - +// UserTypingEvent indicates that a api.User started typing in a api.DMChannel or api.TextChannel(requires the api.IntentsDirectMessageTyping and/or api.IntentsGuildMessageTyping) type UserTypingEvent struct { GenericUserEvent ChannelID api.Snowflake } +// Channel returns the api.Channel the api.User started typing in func (e UserTypingEvent) Channel() *api.Channel { return e.Disgo().Cache().Channel(e.ChannelID) } + +// DMChannel returns the api.DMChannel the api.User started typing in +func (e UserTypingEvent) DMChannel() *api.DMChannel { + return e.Disgo().Cache().DMChannel(e.ChannelID) +} + +// TextChannel returns the api.TextChannel the api.User started typing in +func (e UserTypingEvent) TextChannel() *api.TextChannel { + return e.Disgo().Cache().TextChannel(e.ChannelID) +} diff --git a/api/events/voice_channel_events.go b/api/events/voice_channel_events.go index 56d0fbd1..d2de4cb2 100644 --- a/api/events/voice_channel_events.go +++ b/api/events/voice_channel_events.go @@ -4,20 +4,24 @@ import ( "github.com/DisgoOrg/disgo/api" ) +// GenericVoiceChannelEvent is called upon receiving VoiceChannelCreateEvent, VoiceChannelUpdateEvent or VoiceChannelDeleteEvent type GenericVoiceChannelEvent struct { GenericChannelEvent VoiceChannel *api.VoiceChannel } +// VoiceChannelCreateEvent indicates that a new api.VoiceChannel got created in a api.Guild type VoiceChannelCreateEvent struct { GenericVoiceChannelEvent } +// VoiceChannelUpdateEvent indicates that a api.VoiceChannel got updated in a api.Guild type VoiceChannelUpdateEvent struct { GenericVoiceChannelEvent OldVoiceChannel *api.VoiceChannel } +// VoiceChannelDeleteEvent indicates that a api.VoiceChannel got deleted in a api.Guild type VoiceChannelDeleteEvent struct { GenericVoiceChannelEvent } diff --git a/api/guild.go b/api/guild.go index 1d3514cb..3e607f9a 100644 --- a/api/guild.go +++ b/api/guild.go @@ -171,6 +171,7 @@ type Guild struct { WelcomeScreen *GuildWelcomeScreen `json:"welcome_screen"` } +// Disconnect sends a api.GatewayCommand to disconnect from this Guild func (g *Guild) Disconnect() error { return g.Disgo.AudioController().Disconnect(g.ID) } diff --git a/api/invite.go b/api/invite.go index 10fbead4..d12396b8 100644 --- a/api/invite.go +++ b/api/invite.go @@ -29,6 +29,7 @@ type Invite struct { ApproximateMemberCount *int `json:"approximate_member_count"` } +// URL returns the invite url in format like https://discord.gg/{code} func (i Invite) URL() string { url, err := endpoints.InviteURL.Compile(i.Code) if err != nil { diff --git a/api/options.go b/api/options.go index 87398788..90da003c 100644 --- a/api/options.go +++ b/api/options.go @@ -12,4 +12,5 @@ type Options struct { ListenURL string PublicKey string LargeThreshold int + RawGatewayEventsEnabled bool } diff --git a/internal/audio_controller_impl.go b/internal/audio_controller_impl.go index 52f45327..a25b915b 100644 --- a/internal/audio_controller_impl.go +++ b/internal/audio_controller_impl.go @@ -6,20 +6,25 @@ func newAudioControllerImpl(disgo api.Disgo) api.AudioController { return &AudioControllerImpl{disgo: disgo} } +// AudioControllerImpl lets you Connect / Disconnect from a api.VoiceChannel type AudioControllerImpl struct { disgo api.Disgo } +// Disgo returns the api.Disgo instance func (c *AudioControllerImpl) Disgo() api.Disgo { return c.disgo } +// Connect sends a api.GatewayCommand to connect to a api.VoiceChannel func (c *AudioControllerImpl) Connect(guildID api.Snowflake, channelID api.Snowflake) error { return c.Disgo().Gateway().Conn().WriteJSON(api.NewGatewayCommand(api.OpVoiceStateUpdate, api.UpdateVoiceStateCommand{ GuildID: guildID, ChannelID: &channelID, })) } + +// Disconnect sends a api.GatewayCommand to disconnect from a api.VoiceChannel func (c *AudioControllerImpl) Disconnect(guildID api.Snowflake) error { return c.Disgo().Gateway().Conn().WriteJSON(api.NewGatewayCommand(api.OpVoiceStateUpdate, api.UpdateVoiceStateCommand{ GuildID: guildID, diff --git a/internal/disgo_builder_impl.go b/internal/disgo_builder_impl.go index caa03814..31e9003d 100644 --- a/internal/disgo_builder_impl.go +++ b/internal/disgo_builder_impl.go @@ -30,6 +30,7 @@ type DisgoBuilderImpl struct { messageCachePolicy api.MessageCachePolicy cacheFlags api.CacheFlags intents api.Intents + rawGatewayEventsEnabled bool entityBuilder api.EntityBuilder eventManager api.EventManager voiceDispatchInterceptor api.VoiceDispatchInterceptor @@ -58,6 +59,12 @@ func (b *DisgoBuilderImpl) SetIntents(intents api.Intents) api.DisgoBuilder { return b } +// SetRawGatewayEventsEnabled enables/disables the events.RawGatewayEvent +func (b *DisgoBuilderImpl) SetRawGatewayEventsEnabled(enabled bool) api.DisgoBuilder { + b.rawGatewayEventsEnabled = enabled + return b +} + // SetEntityBuilder lets you inject your own api.EntityBuilder func (b *DisgoBuilderImpl) SetEntityBuilder(entityBuilder api.EntityBuilder) api.DisgoBuilder { b.entityBuilder = entityBuilder @@ -156,7 +163,8 @@ func (b *DisgoBuilderImpl) SetGateway(gateway api.Gateway) api.DisgoBuilder { func (b *DisgoBuilderImpl) Build() (api.Disgo, error) { disgo := &DisgoImpl{ - logger: b.logger, + logger: b.logger, + rawGatewayEventsEnabled: b.rawGatewayEventsEnabled, } if b.BotToken == "" { return nil, errors.New("please specify the BotToken") diff --git a/internal/disgo_impl.go b/internal/disgo_impl.go index 00266ca4..2a9a4686 100644 --- a/internal/disgo_impl.go +++ b/internal/disgo_impl.go @@ -18,10 +18,11 @@ func New(token endpoints.Token, options api.Options) (api.Disgo, error) { } disgo := &DisgoImpl{ - BotToken: token, - intents: options.Intents, - largeThreshold: options.LargeThreshold, - logger: options.Logger, + BotToken: token, + intents: options.Intents, + largeThreshold: options.LargeThreshold, + logger: options.Logger, + rawGatewayEventsEnabled: options.RawGatewayEventsEnabled, } id, err := IDFromToken(token) @@ -57,6 +58,7 @@ type DisgoImpl struct { gateway api.Gateway restClient api.RestClient intents api.Intents + rawGatewayEventsEnabled bool entityBuilder api.EntityBuilder eventManager api.EventManager voiceDispatchInterceptor api.VoiceDispatchInterceptor @@ -163,6 +165,11 @@ func (d *DisgoImpl) Intents() api.Intents { return c } +// RawGatewayEventsEnabled returns if the events.RawGatewayEvent is enabled/disabled +func (d *DisgoImpl) RawGatewayEventsEnabled() bool { + return d.rawGatewayEventsEnabled +} + // ApplicationID returns the current application id func (d *DisgoImpl) ApplicationID() api.Snowflake { return d.selfUserID diff --git a/internal/entity_builder_impl.go b/internal/entity_builder_impl.go index 3bd49807..d3c4976c 100644 --- a/internal/entity_builder_impl.go +++ b/internal/entity_builder_impl.go @@ -186,9 +186,9 @@ func (b EntityBuilderImpl) CreateDMChannel(channel *api.Channel, updateCache api } // CreateEmote returns a new api.Emote entity -func (b EntityBuilderImpl) CreateEmote(guildId api.Snowflake, emote *api.Emote, updateCache api.CacheStrategy) *api.Emote { +func (b EntityBuilderImpl) CreateEmote(guildID api.Snowflake, emote *api.Emote, updateCache api.CacheStrategy) *api.Emote { emote.Disgo = b.Disgo() - emote.GuildID = guildId + emote.GuildID = guildID if updateCache(b.Disgo()) { return b.Disgo().Cache().CacheEmote(emote) } diff --git a/internal/gateway_impl.go b/internal/gateway_impl.go index 3f41846c..9c988fe1 100644 --- a/internal/gateway_impl.go +++ b/internal/gateway_impl.go @@ -227,6 +227,7 @@ func (g *GatewayImpl) closeWithCode(code int) error { return nil } +// Conn returns the underlying websocket.Conn of this api.Gateway func (g *GatewayImpl) Conn() *websocket.Conn { return g.conn } @@ -330,18 +331,18 @@ func (g *GatewayImpl) listen() { g.Disgo().Logger().Info("ready event received") } - // TODO: add setting to enable raw gateway events? - var payload map[string]interface{} - if err = g.parseEventToStruct(event, &payload); err != nil { - g.Disgo().Logger().Errorf("Error parsing event: %s", err) - continue + if g.Disgo().RawGatewayEventsEnabled() { + var payload map[string]interface{} + if err = g.parseEventToStruct(event, &payload); err != nil { + g.Disgo().Logger().Errorf("Error parsing raw gateway event: %s", err) + } + g.Disgo().EventManager().Dispatch(events.RawGatewayEvent{ + GenericEvent: events.NewEvent(g.Disgo(), *event.S), + Type: *event.T, + RawPayload: event.D, + Payload: payload, + }) } - g.Disgo().EventManager().Dispatch(events.RawGatewayEvent{ - GenericEvent: events.NewEvent(g.Disgo(), *event.S), - Type: *event.T, - RawPayload: event.D, - Payload: payload, - }) d := g.Disgo() e := d.EventManager() diff --git a/internal/handlers/application_command_delete.go b/internal/handlers/application_command_delete.go index f7a50e4f..d4353758 100644 --- a/internal/handlers/application_command_delete.go +++ b/internal/handlers/application_command_delete.go @@ -30,7 +30,6 @@ func (h ApplicationCommandDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eve disgo.Cache().UncacheCommand(command.ID) } - if command.FromGuild() { command = disgo.EntityBuilder().CreateGuildCommand(*command.GuildID, command, api.CacheStrategyNo) } else { diff --git a/internal/handlers/guild_delete_handler.go b/internal/handlers/guild_delete_handler.go index 9cf926db..4387938a 100644 --- a/internal/handlers/guild_delete_handler.go +++ b/internal/handlers/guild_delete_handler.go @@ -43,7 +43,6 @@ func (h GuildDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api guild = disgo.Cache().Guild(guild.ID) disgo.Cache().UncacheGuild(guild.ID) - eventManager.Dispatch(events.GuildLeaveEvent{ GenericGuildEvent: genericGuildEvent, }) diff --git a/internal/handlers/guild_member_add_handler.go b/internal/handlers/guild_member_add_handler.go index 4ed0b7ab..fc10eace 100644 --- a/internal/handlers/guild_member_add_handler.go +++ b/internal/handlers/guild_member_add_handler.go @@ -34,7 +34,7 @@ func (h GuildMemberAddHandler) HandleGatewayEvent(disgo api.Disgo, eventManager genericGuildEvent := events.GenericGuildEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), - Guild: guild, + Guild: guild, } eventManager.Dispatch(genericGuildEvent) diff --git a/internal/handlers/ready_handler.go b/internal/handlers/ready_handler.go index 4a0d9fe1..76a998b7 100644 --- a/internal/handlers/ready_handler.go +++ b/internal/handlers/ready_handler.go @@ -5,11 +5,11 @@ import ( ) type readyEventData struct { - Version int `json:"v"` - SelfUser api.User `json:"user"` - Guilds []*api.Guild `json:"guilds"` - SessionID string `json:"session_id"` - Shard *[2]int `json:"shard,omitempty"` + Version int `json:"v"` + SelfUser api.User `json:"user"` + Guilds []*api.Guild `json:"guilds"` + SessionID string `json:"session_id"` + Shard *[2]int `json:"shard,omitempty"` } // ReadyHandler handles api.ReadyGatewayEvent diff --git a/internal/restclient_impl.go b/internal/restclient_impl.go index f46e669c..b56f66fb 100644 --- a/internal/restclient_impl.go +++ b/internal/restclient_impl.go @@ -88,7 +88,7 @@ func (r RestClientImpl) Request(route endpoints.CompiledAPIRoute, rqBody interfa r.Disgo().Logger().Debugf("code: %d, response: %s", rs.StatusCode, string(rawRsBody)) - r.Disgo().EventManager().Dispatch(events.HttpRequestEvent{ + r.Disgo().EventManager().Dispatch(events.HTTPRequestEvent{ GenericEvent: events.NewEvent(r.Disgo(), 0), Request: rq, Response: rs, From 31bfe90f38134321ff62dac48289f346e29dab11 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Tue, 13 Apr 2021 16:22:57 +0200 Subject: [PATCH 65/65] reenabled logging for heartbeat, fixed reconnect & updated guild create/update/delete handler --- api/audio_controller.go | 8 +++ api/events/dm_message_event.go | 1 - api/events/guild_message_events.go | 1 - api/gateway.go | 2 +- api/gateway_events.go | 12 ++-- internal/audio_controller_impl.go | 29 +++++++- internal/disgo_impl.go | 2 +- internal/gateway_impl.go | 81 +++++++++++------------ internal/handlers/guild_create_handler.go | 34 ++++------ internal/handlers/guild_delete_handler.go | 2 +- internal/handlers/guild_update_handler.go | 2 +- internal/handlers/ready_handler.go | 12 +--- 12 files changed, 96 insertions(+), 90 deletions(-) diff --git a/api/audio_controller.go b/api/audio_controller.go index 695a4a24..4819ca7a 100644 --- a/api/audio_controller.go +++ b/api/audio_controller.go @@ -1,5 +1,13 @@ package api +import "errors" + +// errors returned when no gateway or ws conn exists +var ( + ErrNoGateway = errors.New("no gateway initialized") + ErrNoGatewayConn = errors.New("no active gateway connection found") +) + // AudioController lets you Connect / Disconnect from a VoiceChannel type AudioController interface { Disgo() Disgo diff --git a/api/events/dm_message_event.go b/api/events/dm_message_event.go index ee5aebc3..39b012be 100644 --- a/api/events/dm_message_event.go +++ b/api/events/dm_message_event.go @@ -7,7 +7,6 @@ import ( // GenericDMMessageEvent is called upon receiving DMMessageCreateEvent, DMMessageUpdateEvent, DMMessageDeleteEvent, GenericDMMessageReactionEvent, DMMessageReactionAddEvent, DMMessageReactionRemoveEvent, DMMessageReactionRemoveEmoteEvent or DMMessageReactionRemoveAllEvent(requires api.IntentsDirectMessages) type GenericDMMessageEvent struct { GenericMessageEvent - Message *api.Message } // DMChannel returns the api.DMChannel where the GenericDMMessageEvent happened diff --git a/api/events/guild_message_events.go b/api/events/guild_message_events.go index 4fd3ba57..15407c44 100644 --- a/api/events/guild_message_events.go +++ b/api/events/guild_message_events.go @@ -8,7 +8,6 @@ import ( type GenericGuildMessageEvent struct { GenericMessageEvent GuildID api.Snowflake - Message *api.Message } // Guild returns the api.Guild the GenericGuildMessageEvent happened in diff --git a/api/gateway.go b/api/gateway.go index 7c4fb17c..6b47acaa 100644 --- a/api/gateway.go +++ b/api/gateway.go @@ -28,7 +28,7 @@ type Gateway interface { Disgo() Disgo Open() error Status() GatewayStatus - Close(bool) + Close() Conn() *websocket.Conn Latency() time.Duration } diff --git a/api/gateway_events.go b/api/gateway_events.go index 2b687f13..85565b65 100644 --- a/api/gateway_events.go +++ b/api/gateway_events.go @@ -20,13 +20,11 @@ type RawGatewayEvent struct { // ReadyGatewayEvent is the event sent by discord when you successfully Identify type ReadyGatewayEvent struct { - GatewayPacket - D struct { - User User `json:"user"` - Guilds []Guild `json:"guild_events"` - SessionID string `json:"session_id"` - Shard [2]int `json:"shard,omitempty"` - } `json:"d"` + Version int `json:"v"` + SelfUser User `json:"user"` + Guilds []*Guild `json:"guilds"` + SessionID string `json:"session_id"` + Shard *[2]int `json:"shard,omitempty"` } // HelloGatewayEventData is sent when we connect to the gateway diff --git a/internal/audio_controller_impl.go b/internal/audio_controller_impl.go index a25b915b..6b201ff5 100644 --- a/internal/audio_controller_impl.go +++ b/internal/audio_controller_impl.go @@ -1,6 +1,9 @@ package internal -import "github.com/DisgoOrg/disgo/api" +import ( + "github.com/DisgoOrg/disgo/api" + "github.com/gorilla/websocket" +) func newAudioControllerImpl(disgo api.Disgo) api.AudioController { return &AudioControllerImpl{disgo: disgo} @@ -18,7 +21,11 @@ func (c *AudioControllerImpl) Disgo() api.Disgo { // Connect sends a api.GatewayCommand to connect to a api.VoiceChannel func (c *AudioControllerImpl) Connect(guildID api.Snowflake, channelID api.Snowflake) error { - return c.Disgo().Gateway().Conn().WriteJSON(api.NewGatewayCommand(api.OpVoiceStateUpdate, api.UpdateVoiceStateCommand{ + conn, err := c.getConn() + if err != nil { + return err + } + return conn.WriteJSON(api.NewGatewayCommand(api.OpVoiceStateUpdate, api.UpdateVoiceStateCommand{ GuildID: guildID, ChannelID: &channelID, })) @@ -26,8 +33,24 @@ func (c *AudioControllerImpl) Connect(guildID api.Snowflake, channelID api.Snowf // Disconnect sends a api.GatewayCommand to disconnect from a api.VoiceChannel func (c *AudioControllerImpl) Disconnect(guildID api.Snowflake) error { - return c.Disgo().Gateway().Conn().WriteJSON(api.NewGatewayCommand(api.OpVoiceStateUpdate, api.UpdateVoiceStateCommand{ + conn, err := c.getConn() + if err != nil { + return err + } + return conn.WriteJSON(api.NewGatewayCommand(api.OpVoiceStateUpdate, api.UpdateVoiceStateCommand{ GuildID: guildID, ChannelID: nil, })) } + +func (c *AudioControllerImpl) getConn() (*websocket.Conn, error) { + gateway := c.Disgo().Gateway() + if gateway == nil { + return nil, api.ErrNoGateway + } + conn := gateway.Conn() + if conn == nil { + return nil, api.ErrNoGatewayConn + } + return conn, nil +} diff --git a/internal/disgo_impl.go b/internal/disgo_impl.go index 2a9a4686..6b4dfc4f 100644 --- a/internal/disgo_impl.go +++ b/internal/disgo_impl.go @@ -98,7 +98,7 @@ func (d *DisgoImpl) Close() { d.WebhookServer().Close() } if d.Gateway() != nil { - d.Gateway().Close(false) + d.Gateway().Close() } if d.EventManager() != nil { d.EventManager().Close() diff --git a/internal/gateway_impl.go b/internal/gateway_impl.go index 9c988fe1..f0856e80 100644 --- a/internal/gateway_impl.go +++ b/internal/gateway_impl.go @@ -86,7 +86,7 @@ func (g *GatewayImpl) Open() error { gatewayURL := *g.url + "?v=" + endpoints.APIVersion + "&encoding=json" wsConn, rs, err := websocket.DefaultDialer.Dial(gatewayURL, nil) if err != nil { - g.Close(false) + g.Close() var body string if rs != nil && rs.Body != nil { rawBody, err := ioutil.ReadAll(rs.Body) @@ -152,15 +152,15 @@ func (g *GatewayImpl) Open() error { } g.status = api.WaitingForReady } else { - g.Disgo().Logger().Infof("sending Resuming command...") g.status = api.Resuming - if err = wsConn.WriteJSON( - api.NewGatewayCommand(api.OpResume, api.ResumeCommand{ - Token: g.Disgo().Token(), - SessionID: *g.sessionID, - Seq: *g.lastSequenceReceived, - }), - ); err != nil { + cmd := api.NewGatewayCommand(api.OpResume, api.ResumeCommand{ + Token: g.Disgo().Token(), + SessionID: *g.sessionID, + Seq: *g.lastSequenceReceived, + }) + g.Disgo().Logger().Infof("sending Resuming command...") + + if err = wsConn.WriteJSON(cmd); err != nil { return err } } @@ -184,8 +184,11 @@ func (g *GatewayImpl) Latency() time.Duration { } // Close cleans up the gateway internals -func (g *GatewayImpl) Close(toReconnect bool) { - g.status = api.Disconnected +func (g *GatewayImpl) Close() { + g.closeWithCode(websocket.CloseNormalClosure) +} + +func (g *GatewayImpl) closeWithCode(code int) { if g.quit != nil { g.Disgo().Logger().Info("closing gateway goroutines...") close(g.quit) @@ -193,38 +196,20 @@ func (g *GatewayImpl) Close(toReconnect bool) { g.Disgo().Logger().Info("closed gateway goroutines") } if g.conn != nil { - var err error - if toReconnect { - err = g.conn.Close() - g.conn = nil - } else { - err = g.closeWithCode(websocket.CloseNormalClosure) - } - if err != nil { - g.Disgo().Logger().Errorf("error while closing wsconn: %s", err) - } - } -} - -func (g *GatewayImpl) closeWithCode(code int) error { - if g.conn != nil { - err := g.conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(code, "")) if err != nil { - return err + g.Disgo().Logger().Errorf("error writing close code: %s", err) } // TODO: Wait for Discord to actually close the connection. time.Sleep(1 * time.Second) err = g.conn.Close() - g.conn = nil if err != nil { - return err + g.Disgo().Logger().Errorf("error closing conn: %s", err) } - + g.conn = nil } - return nil } // Conn returns the underlying websocket.Conn of this api.Gateway @@ -256,7 +241,7 @@ func (g *GatewayImpl) heartbeat() { } func (g *GatewayImpl) sendHeartbeat() { - //g.Disgo().Logger().Debug("sending heartbeat...") + g.Disgo().Logger().Debug("sending heartbeat...") heartbeatEvent := events.HeartbeatEvent{ GenericEvent: events.NewEvent(g.Disgo(), 0), @@ -265,7 +250,7 @@ func (g *GatewayImpl) sendHeartbeat() { if err := g.conn.WriteJSON(api.NewGatewayCommand(api.OpHeartbeat, g.lastSequenceReceived)); err != nil { g.Disgo().Logger().Errorf("failed to send heartbeat with error: %s", err) - g.Close(true) + g.closeWithCode(websocket.CloseServiceRestart) g.reconnect(1 * time.Second) } g.lastHeartbeatSent = time.Now().UTC() @@ -296,7 +281,7 @@ func (g *GatewayImpl) listen() { mt, data, err := g.conn.ReadMessage() if err != nil { g.Disgo().Logger().Errorf("error while reading from ws. error: %s", err) - g.Close(true) + g.closeWithCode(websocket.CloseServiceRestart) g.reconnect(1 * time.Second) return } @@ -326,7 +311,7 @@ func (g *GatewayImpl) listen() { g.Disgo().Logger().Errorf("Error parsing ready event: %s", err) continue } - g.sessionID = &readyEvent.D.SessionID + g.sessionID = &readyEvent.SessionID g.Disgo().Logger().Info("ready event received") } @@ -349,24 +334,32 @@ func (g *GatewayImpl) listen() { e.Handle(*event.T, nil, *event.S, event.D) case api.OpHeartbeat: - //g.Disgo().Logger().Debugf("received: OpHeartbeat") + g.Disgo().Logger().Debugf("received: OpHeartbeat") g.sendHeartbeat() case api.OpReconnect: g.Disgo().Logger().Debugf("received: OpReconnect") - g.Close(true) + g.closeWithCode(websocket.CloseServiceRestart) g.reconnect(1 * time.Second) case api.OpInvalidSession: - g.Disgo().Logger().Debugf("received: OpInvalidSession") - g.Close(false) - // clear reconnect info - g.sessionID = nil - g.lastSequenceReceived = nil + var resumable bool + if err = g.parseEventToStruct(event, &resumable); err != nil { + g.Disgo().Logger().Errorf("Error parsing invalid session data: %s", err) + } + g.Disgo().Logger().Debugf("received: OpInvalidSession, resumable: %b", resumable) + if resumable { + g.closeWithCode(websocket.CloseServiceRestart) + } else { + g.Close() + // clear reconnect info + g.sessionID = nil + g.lastSequenceReceived = nil + } g.reconnect(5 * time.Second) case api.OpHeartbeatACK: - //g.Disgo().Logger().Debugf("received: OpHeartbeatACK") + g.Disgo().Logger().Debugf("received: OpHeartbeatACK") g.lastHeartbeatReceived = time.Now().UTC() } diff --git a/internal/handlers/guild_create_handler.go b/internal/handlers/guild_create_handler.go index b52d6eaf..b0405f3e 100644 --- a/internal/handlers/guild_create_handler.go +++ b/internal/handlers/guild_create_handler.go @@ -25,20 +25,15 @@ func (h GuildCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api return } - guild := fullGuild.Guild - - guild.Disgo = disgo - oldGuild := disgo.Cache().Guild(guild.ID) - var wasUnavailable bool - if oldGuild == nil { - wasUnavailable = true - } else { + oldGuild := disgo.Cache().Guild(fullGuild.ID) + wasUnavailable := true + if oldGuild != nil { + oldGuild = &*oldGuild wasUnavailable = oldGuild.Unavailable } + guild := disgo.EntityBuilder().CreateGuild(fullGuild.Guild, api.CacheStrategyYes) - disgo.Cache().CacheGuild(guild) - for i := range fullGuild.Channels { - channel := fullGuild.Channels[i] + for _, channel := range fullGuild.Channels { channel.GuildID = &guild.ID switch channel.Type { case api.ChannelTypeText, api.ChannelTypeNews: @@ -52,20 +47,20 @@ func (h GuildCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api } } - for i := range fullGuild.Roles { - disgo.EntityBuilder().CreateRole(guild.ID, fullGuild.Roles[i], api.CacheStrategyYes) + for _, role := range fullGuild.Roles { + disgo.EntityBuilder().CreateRole(guild.ID, role, api.CacheStrategyYes) } - for i := range fullGuild.Members { - disgo.EntityBuilder().CreateMember(guild.ID, fullGuild.Members[i], api.CacheStrategyYes) + for _, member := range fullGuild.Members { + disgo.EntityBuilder().CreateMember(guild.ID, member, api.CacheStrategyYes) } - for i := range fullGuild.VoiceStates { - disgo.EntityBuilder().CreateVoiceState(fullGuild.VoiceStates[i], api.CacheStrategyYes) + for _, voiceState := range fullGuild.VoiceStates { + disgo.EntityBuilder().CreateVoiceState(voiceState, api.CacheStrategyYes) } - for i := range fullGuild.Emotes { - disgo.EntityBuilder().CreateEmote(guild.ID, fullGuild.Emotes[i], api.CacheStrategyYes) + for _, emote := range fullGuild.Emotes { + disgo.EntityBuilder().CreateEmote(guild.ID, emote, api.CacheStrategyYes) } // TODO: presence @@ -79,7 +74,6 @@ func (h GuildCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api GenericEvent: events.NewEvent(disgo, sequenceNumber), Guild: guild, } - eventManager.Dispatch(genericGuildEvent) if wasUnavailable { diff --git a/internal/handlers/guild_delete_handler.go b/internal/handlers/guild_delete_handler.go index 4387938a..1c4add1e 100644 --- a/internal/handlers/guild_delete_handler.go +++ b/internal/handlers/guild_delete_handler.go @@ -36,11 +36,11 @@ func (h GuildDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api if guild.Unavailable { // set guild to unavail for now disgo.Cache().Guild(guild.ID).Unavailable = true + eventManager.Dispatch(events.GuildUnavailableEvent{ GenericGuildEvent: genericGuildEvent, }) } else { - guild = disgo.Cache().Guild(guild.ID) disgo.Cache().UncacheGuild(guild.ID) eventManager.Dispatch(events.GuildLeaveEvent{ diff --git a/internal/handlers/guild_update_handler.go b/internal/handlers/guild_update_handler.go index e335ee98..0179d101 100644 --- a/internal/handlers/guild_update_handler.go +++ b/internal/handlers/guild_update_handler.go @@ -35,8 +35,8 @@ func (h GuildUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api GenericEvent: events.NewEvent(disgo, sequenceNumber), Guild: guild, } - eventManager.Dispatch(genericGuildEvent) + eventManager.Dispatch(events.GuildUpdateEvent{ GenericGuildEvent: genericGuildEvent, OldGuild: oldGuild, diff --git a/internal/handlers/ready_handler.go b/internal/handlers/ready_handler.go index 76a998b7..e2c95db3 100644 --- a/internal/handlers/ready_handler.go +++ b/internal/handlers/ready_handler.go @@ -4,14 +4,6 @@ import ( "github.com/DisgoOrg/disgo/api" ) -type readyEventData struct { - Version int `json:"v"` - SelfUser api.User `json:"user"` - Guilds []*api.Guild `json:"guilds"` - SessionID string `json:"session_id"` - Shard *[2]int `json:"shard,omitempty"` -} - // ReadyHandler handles api.ReadyGatewayEvent type ReadyHandler struct{} @@ -22,12 +14,12 @@ func (h ReadyHandler) Event() api.GatewayEventType { // New constructs a new payload receiver for the raw gateway event func (h ReadyHandler) New() interface{} { - return &readyEventData{} + return &api.ReadyGatewayEvent{} } // HandleGatewayEvent handles the specific raw gateway event func (h ReadyHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { - readyEvent, ok := i.(*readyEventData) + readyEvent, ok := i.(*api.ReadyGatewayEvent) if !ok { return }