2020-01-18 21:04:12 +00:00
|
|
|
package state
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/diamondburned/arikawa/discord"
|
|
|
|
"github.com/diamondburned/arikawa/gateway"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
)
|
|
|
|
|
|
|
|
func (s *State) hookSession() error {
|
|
|
|
s.unhooker = s.Session.AddHandler(func(iface interface{}) {
|
|
|
|
if s.PreHandler != nil {
|
|
|
|
s.PreHandler.Call(iface)
|
|
|
|
}
|
|
|
|
s.onEvent(iface)
|
2020-02-25 05:50:13 +00:00
|
|
|
s.Handler.Call(iface)
|
2020-01-18 21:04:12 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *State) onEvent(iface interface{}) {
|
|
|
|
// TODO: voice states
|
|
|
|
|
|
|
|
switch ev := iface.(type) {
|
|
|
|
case *gateway.ReadyEvent:
|
2020-02-08 19:48:45 +00:00
|
|
|
// Set Ready to the state
|
|
|
|
s.Ready = *ev
|
|
|
|
|
2020-03-01 02:13:58 +00:00
|
|
|
// Handle presences
|
|
|
|
for _, p := range ev.Presences {
|
|
|
|
p := p
|
|
|
|
|
|
|
|
if err := s.Store.PresenceSet(0, &p); err != nil {
|
|
|
|
s.stateErr(err, "Failed to set global presence")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-18 21:04:12 +00:00
|
|
|
// Handle guilds
|
2020-03-01 02:13:58 +00:00
|
|
|
for i := range ev.Guilds {
|
2020-04-06 19:16:32 +00:00
|
|
|
s.batchLog(handleGuildCreate(s.Store, &ev.Guilds[i])...)
|
2020-01-18 21:04:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Handle private channels
|
2020-03-01 02:13:58 +00:00
|
|
|
for i := range ev.PrivateChannels {
|
|
|
|
if err := s.Store.ChannelSet(&ev.PrivateChannels[i]); err != nil {
|
2020-01-20 09:06:47 +00:00
|
|
|
s.stateErr(err, "Failed to set channel in state")
|
2020-01-18 21:04:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle user
|
2020-02-08 19:51:00 +00:00
|
|
|
if err := s.Store.MyselfSet(&ev.User); err != nil {
|
2020-01-20 09:06:47 +00:00
|
|
|
s.stateErr(err, "Failed to set self in state")
|
2020-01-18 21:04:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
case *gateway.GuildCreateEvent:
|
2020-04-06 19:16:32 +00:00
|
|
|
s.batchLog(handleGuildCreate(s.Store, ev)...)
|
2020-01-18 21:04:12 +00:00
|
|
|
|
|
|
|
case *gateway.GuildUpdateEvent:
|
|
|
|
if err := s.Store.GuildSet((*discord.Guild)(ev)); err != nil {
|
2020-01-20 09:06:47 +00:00
|
|
|
s.stateErr(err, "Failed to update guild in state")
|
2020-01-18 21:04:12 +00:00
|
|
|
}
|
|
|
|
case *gateway.GuildDeleteEvent:
|
|
|
|
if err := s.Store.GuildRemove(ev.ID); err != nil {
|
2020-01-20 09:06:47 +00:00
|
|
|
s.stateErr(err, "Failed to delete guild in state")
|
2020-01-18 21:04:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
case *gateway.GuildMemberAddEvent:
|
|
|
|
if err := s.Store.MemberSet(ev.GuildID, &ev.Member); err != nil {
|
2020-01-20 09:06:47 +00:00
|
|
|
s.stateErr(err, "Failed to add a member in state")
|
2020-01-18 21:04:12 +00:00
|
|
|
}
|
|
|
|
case *gateway.GuildMemberUpdateEvent:
|
|
|
|
m, err := s.Store.Member(ev.GuildID, ev.User.ID)
|
|
|
|
if err != nil {
|
|
|
|
// We can't do much here.
|
|
|
|
m = &discord.Member{}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update available fields from ev into m
|
|
|
|
ev.Update(m)
|
|
|
|
|
|
|
|
if err := s.Store.MemberSet(ev.GuildID, m); err != nil {
|
2020-01-20 09:06:47 +00:00
|
|
|
s.stateErr(err, "Failed to update a member in state")
|
2020-01-18 21:04:12 +00:00
|
|
|
}
|
|
|
|
case *gateway.GuildMemberRemoveEvent:
|
|
|
|
if err := s.Store.MemberRemove(ev.GuildID, ev.User.ID); err != nil {
|
2020-01-20 09:06:47 +00:00
|
|
|
s.stateErr(err, "Failed to remove a member in state")
|
2020-01-18 21:04:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
case *gateway.GuildMembersChunkEvent:
|
|
|
|
for _, m := range ev.Members {
|
2020-02-07 08:22:41 +00:00
|
|
|
m := m
|
|
|
|
|
2020-01-18 21:04:12 +00:00
|
|
|
if err := s.Store.MemberSet(ev.GuildID, &m); err != nil {
|
2020-01-20 09:06:47 +00:00
|
|
|
s.stateErr(err, "Failed to add a member from chunk in state")
|
2020-01-18 21:04:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, p := range ev.Presences {
|
2020-02-07 08:22:41 +00:00
|
|
|
p := p
|
|
|
|
|
2020-01-18 21:04:12 +00:00
|
|
|
if err := s.Store.PresenceSet(ev.GuildID, &p); err != nil {
|
2020-01-20 09:06:47 +00:00
|
|
|
s.stateErr(err, "Failed to add a presence from chunk in state")
|
2020-01-18 21:04:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
case *gateway.GuildRoleCreateEvent:
|
|
|
|
if err := s.Store.RoleSet(ev.GuildID, &ev.Role); err != nil {
|
2020-01-20 09:06:47 +00:00
|
|
|
s.stateErr(err, "Failed to add a role in state")
|
2020-01-18 21:04:12 +00:00
|
|
|
}
|
|
|
|
case *gateway.GuildRoleUpdateEvent:
|
|
|
|
if err := s.Store.RoleSet(ev.GuildID, &ev.Role); err != nil {
|
2020-01-20 09:06:47 +00:00
|
|
|
s.stateErr(err, "Failed to update a role in state")
|
2020-01-18 21:04:12 +00:00
|
|
|
}
|
|
|
|
case *gateway.GuildRoleDeleteEvent:
|
|
|
|
if err := s.Store.RoleRemove(ev.GuildID, ev.RoleID); err != nil {
|
2020-01-20 09:06:47 +00:00
|
|
|
s.stateErr(err, "Failed to remove a role in state")
|
2020-01-18 21:04:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
case *gateway.GuildEmojisUpdateEvent:
|
|
|
|
if err := s.Store.EmojiSet(ev.GuildID, ev.Emojis); err != nil {
|
2020-01-20 09:06:47 +00:00
|
|
|
s.stateErr(err, "Failed to update emojis in state")
|
2020-01-18 21:04:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
case *gateway.ChannelCreateEvent:
|
|
|
|
if err := s.Store.ChannelSet((*discord.Channel)(ev)); err != nil {
|
2020-01-20 09:06:47 +00:00
|
|
|
s.stateErr(err, "Failed to create a channel in state")
|
2020-01-18 21:04:12 +00:00
|
|
|
}
|
|
|
|
case *gateway.ChannelUpdateEvent:
|
|
|
|
if err := s.Store.ChannelSet((*discord.Channel)(ev)); err != nil {
|
2020-01-20 09:06:47 +00:00
|
|
|
s.stateErr(err, "Failed to update a channel in state")
|
2020-01-18 21:04:12 +00:00
|
|
|
}
|
|
|
|
case *gateway.ChannelDeleteEvent:
|
|
|
|
if err := s.Store.ChannelRemove((*discord.Channel)(ev)); err != nil {
|
2020-01-20 09:06:47 +00:00
|
|
|
s.stateErr(err, "Failed to remove a channel in state")
|
2020-01-18 21:04:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// *gateway.ChannelPinsUpdateEvent is not tracked.
|
|
|
|
|
|
|
|
case *gateway.MessageCreateEvent:
|
|
|
|
if err := s.Store.MessageSet((*discord.Message)(ev)); err != nil {
|
2020-01-20 09:06:47 +00:00
|
|
|
s.stateErr(err, "Failed to add a message in state")
|
2020-01-18 21:04:12 +00:00
|
|
|
}
|
|
|
|
case *gateway.MessageUpdateEvent:
|
|
|
|
if err := s.Store.MessageSet((*discord.Message)(ev)); err != nil {
|
2020-01-20 09:06:47 +00:00
|
|
|
s.stateErr(err, "Failed to update a message in state")
|
2020-01-18 21:04:12 +00:00
|
|
|
}
|
|
|
|
case *gateway.MessageDeleteEvent:
|
|
|
|
if err := s.Store.MessageRemove(ev.ChannelID, ev.ID); err != nil {
|
2020-01-20 09:06:47 +00:00
|
|
|
s.stateErr(err, "Failed to delete a message in state")
|
2020-01-18 21:04:12 +00:00
|
|
|
}
|
|
|
|
case *gateway.MessageDeleteBulkEvent:
|
|
|
|
for _, id := range ev.IDs {
|
|
|
|
if err := s.Store.MessageRemove(ev.ChannelID, id); err != nil {
|
2020-01-20 09:06:47 +00:00
|
|
|
s.stateErr(err, "Failed to delete bulk meessages in state")
|
2020-01-18 21:04:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
case *gateway.PresenceUpdateEvent:
|
2020-02-24 04:11:33 +00:00
|
|
|
presence := (*discord.Presence)(ev)
|
|
|
|
if err := s.Store.PresenceSet(ev.GuildID, presence); err != nil {
|
2020-01-20 09:06:47 +00:00
|
|
|
s.stateErr(err, "Failed to update presence in state")
|
2020-01-18 21:04:12 +00:00
|
|
|
}
|
2020-02-24 04:11:33 +00:00
|
|
|
|
|
|
|
case *gateway.PresencesReplaceEvent:
|
|
|
|
for i := range *ev {
|
|
|
|
p := (*ev)[i]
|
|
|
|
|
|
|
|
if err := s.Store.PresenceSet(p.GuildID, &p); err != nil {
|
|
|
|
s.stateErr(err, "Failed to update presence in state")
|
|
|
|
}
|
|
|
|
}
|
2020-02-25 05:50:13 +00:00
|
|
|
|
|
|
|
case *gateway.UserGuildSettingsUpdateEvent:
|
|
|
|
for i, ugs := range s.Ready.UserGuildSettings {
|
|
|
|
if ugs.GuildID == ev.GuildID {
|
|
|
|
s.Ready.UserGuildSettings[i] = gateway.UserGuildSettings(*ev)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
case *gateway.UserSettingsUpdateEvent:
|
|
|
|
s.Ready.Settings = (*gateway.UserSettings)(ev)
|
|
|
|
|
|
|
|
case *gateway.UserNoteUpdateEvent:
|
|
|
|
s.Ready.Notes[ev.ID] = ev.Note
|
|
|
|
|
|
|
|
case *gateway.UserUpdateEvent:
|
|
|
|
if err := s.Store.MyselfSet((*discord.User)(ev)); err != nil {
|
|
|
|
s.stateErr(err, "Failed to update myself from USER_UPDATE")
|
|
|
|
}
|
2020-01-18 21:04:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-20 09:06:47 +00:00
|
|
|
func (s *State) stateErr(err error, wrap string) {
|
2020-02-16 05:29:25 +00:00
|
|
|
s.StateLog(errors.Wrap(err, wrap))
|
2020-01-18 21:04:12 +00:00
|
|
|
}
|
2020-04-06 19:16:32 +00:00
|
|
|
func (s *State) batchLog(errors ...error) {
|
|
|
|
for _, err := range errors {
|
|
|
|
s.StateLog(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Helper functions
|
|
|
|
|
|
|
|
func handleGuildCreate(store Store, guild *gateway.GuildCreateEvent) []error {
|
|
|
|
// If a guild is unavailable, don't populate it in the state, as the guild
|
|
|
|
// data is very incomplete.
|
|
|
|
if guild.Unavailable {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
stack, error := newErrorStack()
|
|
|
|
|
|
|
|
if err := store.GuildSet(&guild.Guild); err != nil {
|
|
|
|
error(err, "Failed to set guild in Ready")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle guild emojis
|
|
|
|
if guild.Emojis != nil {
|
|
|
|
if err := store.EmojiSet(guild.ID, guild.Emojis); err != nil {
|
|
|
|
error(err, "Failed to set guild emojis")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle guild member
|
|
|
|
for i := range guild.Members {
|
|
|
|
if err := store.MemberSet(guild.ID, &guild.Members[i]); err != nil {
|
|
|
|
error(err, "Failed to set guild member in Ready")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle guild channels
|
|
|
|
for i := range guild.Channels {
|
|
|
|
if err := store.ChannelSet(&guild.Channels[i]); err != nil {
|
|
|
|
error(err, "Failed to set guild channel in Ready")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle guild presences
|
|
|
|
for i := range guild.Presences {
|
|
|
|
if err := store.PresenceSet(guild.ID, &guild.Presences[i]); err != nil {
|
|
|
|
error(err, "Failed to set guild presence in Ready")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return *stack
|
|
|
|
}
|
|
|
|
|
|
|
|
func newErrorStack() (*[]error, func(error, string)) {
|
|
|
|
var errs = new([]error)
|
|
|
|
return errs, func(err error, wrap string) {
|
|
|
|
*errs = append(*errs, errors.Wrap(err, wrap))
|
|
|
|
}
|
|
|
|
}
|