1
0
Fork 0
mirror of https://github.com/diamondburned/arikawa.git synced 2025-10-26 19:55:34 +00:00

Added state handlers

This commit is contained in:
diamondburned (Forefront) 2020-01-18 13:04:12 -08:00
parent 958f592cb4
commit b11b3e1a42
8 changed files with 397 additions and 207 deletions

View file

@ -36,16 +36,6 @@ type Guild struct {
WidgetChannelID Snowflake `json:"widget_channel_id,string,omitempty"` WidgetChannelID Snowflake `json:"widget_channel_id,string,omitempty"`
SystemChannelID Snowflake `json:"system_channel_id,string,omitempty"` SystemChannelID Snowflake `json:"system_channel_id,string,omitempty"`
// GUILD_CREATE only.
Joined Timestamp `json:"timestamp,omitempty"`
Large bool `json:"large,omitempty"`
Unavailable bool `json:"unavailable,omitempty"`
MemberCount uint64 `json:"member_count,omitempty"`
VoiceStates []VoiceState `json:"voice_state,omitempty"`
Members []Member `json:"members,omitempty"`
Channels []Channel `json:"channel,omitempty"`
Presences []Presence `json:"presences,omitempty"`
// It's DefaultMaxPresences when MaxPresences is 0. // It's DefaultMaxPresences when MaxPresences is 0.
MaxPresences uint64 `json:"max_presences,omitempty"` MaxPresences uint64 `json:"max_presences,omitempty"`
MaxMembers uint64 `json:"max_members,omitempty"` MaxMembers uint64 `json:"max_members,omitempty"`
@ -78,6 +68,24 @@ type Role struct {
type Presence struct { type Presence struct {
User User `json:"user"` User User `json:"user"`
RoleIDs []Snowflake `json:"roles"` RoleIDs []Snowflake `json:"roles"`
// These fields are only filled in gateway events, according to the
// documentation.
Nick string `json:"nick"`
GuildID Snowflake `json:"guild_id"`
PremiumSince Timestamp `json:"premium_since,omitempty"`
Game *Activity `json:"game"`
Activities []Activity `json:"activities"`
Status Status `json:"status"`
ClientStatus struct {
Desktop Status `json:"status,omitempty"`
Mobile Status `json:"mobile,omitempty"`
Web Status `json:"web,omitempty"`
} `json:"client_status"`
} }
type Member struct { type Member struct {

View file

@ -68,3 +68,78 @@ const (
ConnectionNotVisible ConnectionVisibility = iota ConnectionNotVisible ConnectionVisibility = iota
ConnectionVisibleEveryone ConnectionVisibleEveryone
) )
type Status string
const (
UnknownStatus Status = ""
OnlineStatus Status = "online"
DoNotDisturbStatus Status = "dnd"
IdleStatus Status = "idle"
InvisibleStatus Status = "invisible"
OfflineStatus Status = "offline"
)
type Activity struct {
Name string `json:"name"`
Type ActivityType `json:"type"`
URL URL `json:"url"`
// User only
CreatedAt UnixTimestamp `json:"created_at"`
Timestamps struct {
Start UnixMsTimestamp `json:"start,omitempty"`
End UnixMsTimestamp `json:"end,omitempty"`
} `json:"timestamps,omitempty"`
ApplicationID Snowflake `json:"application_id,omitempty"`
Details string `json:"details,omitempty"`
State string `json:"state,omitempty"` // party status
Emoji Emoji `json:"emoji,omitempty"`
Party struct {
ID string `json:"id,omitempty"`
Size [2]int `json:"size,omitempty"` // [ current, max ]
} `json:"party,omitempty"`
Assets struct {
LargeImage string `json:"large_image,omitempty"` // id
LargeText string `json:"large_text,omitempty"`
SmallImage string `json:"small_image,omitempty"` // id
SmallText string `json:"small_text,omitempty"`
} `json:"assets,omitempty"`
Secrets struct {
Join string `json:"join,omitempty"`
Spectate string `json:"spectate,omitempty"`
Match string `json:"match,omitempty"`
} `json:"secrets,omitempty"`
Instance bool `json:"instance,omitempty"`
Flags ActivityFlags `json:"flags,omitempty"`
}
type ActivityType uint8
const (
// Playing $name
GameActivity ActivityType = iota
// Streaming $details
StreamingActivity
// Listening to $name
ListeningActivity
// $emoji $name
CustomActivity
)
type ActivityFlags uint8
const (
InstanceActivity ActivityFlags = 1 << iota
JoinActivity
SpectateActivity
JoinRequestActivity
SyncActivity
PlayActivity
)

View file

@ -1,78 +0,0 @@
package gateway
import "github.com/diamondburned/arikawa/discord"
type Status string
const (
UnknownStatus Status = ""
OnlineStatus Status = "online"
DoNotDisturbStatus Status = "dnd"
IdleStatus Status = "idle"
InvisibleStatus Status = "invisible"
OfflineStatus Status = "offline"
)
type Activity struct {
Name string `json:"name"`
Type ActivityType `json:"type"`
URL discord.URL `json:"url"`
// User only
CreatedAt discord.UnixTimestamp `json:"created_at"`
Timestamps struct {
Start discord.UnixMsTimestamp `json:"start,omitempty"`
End discord.UnixMsTimestamp `json:"end,omitempty"`
} `json:"timestamps,omitempty"`
ApplicationID discord.Snowflake `json:"application_id,omitempty"`
Details string `json:"details,omitempty"`
State string `json:"state,omitempty"` // party status
Emoji discord.Emoji `json:"emoji,omitempty"`
Party struct {
ID string `json:"id,omitempty"`
Size [2]int `json:"size,omitempty"` // [ current, max ]
} `json:"party,omitempty"`
Assets struct {
LargeImage string `json:"large_image,omitempty"` // id
LargeText string `json:"large_text,omitempty"`
SmallImage string `json:"small_image,omitempty"` // id
SmallText string `json:"small_text,omitempty"`
} `json:"assets,omitempty"`
Secrets struct {
Join string `json:"join,omitempty"`
Spectate string `json:"spectate,omitempty"`
Match string `json:"match,omitempty"`
} `json:"secrets,omitempty"`
Instance bool `json:"instance,omitempty"`
Flags ActivityFlags `json:"flags,omitempty"`
}
type ActivityType uint8
const (
// Playing $name
GameActivity ActivityType = iota
// Streaming $details
StreamingActivity
// Listening to $name
ListeningActivity
// $emoji $name
CustomActivity
)
type ActivityFlags uint8
const (
InstanceActivity ActivityFlags = 1 << iota
JoinActivity
SpectateActivity
JoinRequestActivity
SyncActivity
PlayActivity
)

View file

@ -20,6 +20,10 @@ type (
Guilds []discord.Guild `json:"guilds"` Guilds []discord.Guild `json:"guilds"`
Shard *Shard `json:"shard"` Shard *Shard `json:"shard"`
// Undocumented fields
Presences []discord.Presence `json:"presences,omitempty"`
Notes map[discord.Snowflake]string `json:"notes,omitempty"`
} }
ResumedEvent struct{} ResumedEvent struct{}
@ -42,7 +46,19 @@ type (
// https://discordapp.com/developers/docs/topics/gateway#guilds // https://discordapp.com/developers/docs/topics/gateway#guilds
type ( type (
GuildCreateEvent discord.Guild GuildCreateEvent struct {
discord.Guild
Joined discord.Timestamp `json:"timestamp,omitempty"`
Large bool `json:"large,omitempty"`
Unavailable bool `json:"unavailable,omitempty"`
MemberCount uint64 `json:"member_count,omitempty"`
VoiceStates []discord.VoiceState `json:"voice_state,omitempty"`
Members []discord.Member `json:"members,omitempty"`
Channels []discord.Channel `json:"channel,omitempty"`
Presences []discord.Presence `json:"presences,omitempty"`
}
GuildUpdateEvent discord.Guild GuildUpdateEvent discord.Guild
GuildDeleteEvent struct { GuildDeleteEvent struct {
ID discord.Snowflake `json:"id"` ID discord.Snowflake `json:"id"`
@ -78,7 +94,7 @@ type (
} }
GuildMemberUpdateEvent struct { GuildMemberUpdateEvent struct {
GuildID discord.Snowflake `json:"guild_id"` GuildID discord.Snowflake `json:"guild_id"`
Roles []discord.Snowflake `json:"roles"` RoleIDs []discord.Snowflake `json:"roles"`
User discord.User `json:"user"` User discord.User `json:"user"`
Nick string `json:"nick"` Nick string `json:"nick"`
} }
@ -109,6 +125,12 @@ type (
} }
) )
func (u GuildMemberUpdateEvent) Update(m *discord.Member) {
m.RoleIDs = u.RoleIDs
m.User = u.User
m.Nick = u.Nick
}
// https://discordapp.com/developers/docs/topics/gateway#messages // https://discordapp.com/developers/docs/topics/gateway#messages
type ( type (
MessageCreateEvent discord.Message MessageCreateEvent discord.Message
@ -151,25 +173,8 @@ type (
// https://discordapp.com/developers/docs/topics/gateway#presence // https://discordapp.com/developers/docs/topics/gateway#presence
type ( type (
// Clients may only update their game status 5 times per 20 seconds. // Clients may only update their game status 5 times per 20 seconds.
PresenceUpdateEvent struct { PresenceUpdateEvent discord.Presence
User discord.User `json:"user"` TypingStartEvent struct {
Nick string `json:"nick"`
Roles []discord.Snowflake `json:"roles"`
GuildID discord.Snowflake `json:"guild_id"`
PremiumSince discord.Timestamp `json:"premium_since,omitempty"`
Game *Activity `json:"game"`
Activities []Activity `json:"activities"`
Status Status `json:"status"`
ClientStatus struct {
Desktop Status `json:"status,omitempty"`
Mobile Status `json:"mobile,omitempty"`
Web Status `json:"web,omitempty"`
} `json:"client_status"`
}
TypingStartEvent struct {
ChannelID discord.Snowflake `json:"channel_id"` ChannelID discord.Snowflake `json:"channel_id"`
UserID discord.Snowflake `json:"user_id"` UserID discord.Snowflake `json:"user_id"`
Timestamp discord.Timestamp `json:"timestamp"` Timestamp discord.Timestamp `json:"timestamp"`
@ -180,6 +185,10 @@ type (
UserUpdateEvent discord.User UserUpdateEvent discord.User
) )
func (u PresenceUpdateEvent) Update(p *discord.Presence) {
}
// https://discordapp.com/developers/docs/topics/gateway#voice // https://discordapp.com/developers/docs/topics/gateway#voice
type ( type (
VoiceStateUpdateEvent discord.VoiceState VoiceStateUpdateEvent discord.VoiceState

View file

@ -3,7 +3,10 @@
package state package state
import ( import (
"log"
"github.com/diamondburned/arikawa/discord" "github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/gateway"
"github.com/diamondburned/arikawa/handler" "github.com/diamondburned/arikawa/handler"
"github.com/diamondburned/arikawa/session" "github.com/diamondburned/arikawa/session"
) )
@ -15,15 +18,22 @@ var (
type State struct { type State struct {
*session.Session *session.Session
Store
// Ready is not updated by the state.
Ready gateway.ReadyEvent
// ErrorLog logs all errors that handler might have, including state fails.
// This handler will also be used for Session, which would also be used for
// Gateway. Defaults to log.Println.
ErrorLog func(error)
// PreHandler is the manual hook that is executed before the State handler // PreHandler is the manual hook that is executed before the State handler
// is. This should only be used for low-level operations. // is. This should only be used for low-level operations.
// It's recommended to set Synchronous to true if you mutate the events. // It's recommended to set Synchronous to true if you mutate the events.
PreHandler *handler.Handler // default nil PreHandler *handler.Handler // default nil
MaxMessages uint // default 50 // *: State doesn't actually keep track of pinned messages.
Store
unhooker func() unhooker func()
} }
@ -32,6 +42,13 @@ func NewFromSession(s *session.Session, store Store) (*State, error) {
state := &State{ state := &State{
Session: s, Session: s,
Store: store, Store: store,
ErrorLog: func(err error) {
log.Println("arikawa/state error:", err)
},
}
s.ErrorLog = func(err error) {
state.ErrorLog(err)
} }
return state, state.hookSession() return state, state.hookSession()
@ -49,12 +66,7 @@ func NewWithStore(token string, store Store) (*State, error) {
return nil, err return nil, err
} }
state := &State{ return NewFromSession(s, store)
Session: s,
Store: store,
}
return state, state.hookSession()
} }
// Unhook removes all state handlers from the session handlers. // Unhook removes all state handlers from the session handlers.
@ -335,32 +347,3 @@ func (s *State) Roles(guildID discord.Snowflake) ([]discord.Role, error) {
return rs, nil return rs, nil
} }
////
func (s *State) hookSession() error {
/*
s.unhooker = s.Session.AddHandler(func(iface interface{}) {
if s.PreHandler != nil {
s.PreHandler.Call(iface)
}
s.mut.Lock()
defer s.mut.Unlock()
switch ev := iface.(type) {
case *gateway.ReadyEvent:
// Override
s.guilds = ev.Guilds
s.privates = ev.PrivateChannels
s.self = ev.User
case *gateway.MessageCreateEvent:
_ = ev
panic("IMPLEMENT ME")
}
})
*/
return nil
}

178
state/state_events.go Normal file
View file

@ -0,0 +1,178 @@
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)
})
return nil
}
func (s *State) onEvent(iface interface{}) {
// TODO: voice states
switch ev := iface.(type) {
case *gateway.ReadyEvent:
// Handle guilds
for _, g := range ev.Guilds {
if err := s.Store.GuildSet(&g); err != nil {
s.wrapErr(err, "Failed to set guild in state")
}
}
// Handle private channels
for _, ch := range ev.PrivateChannels {
if err := s.Store.ChannelSet(&ch); err != nil {
s.wrapErr(err, "Failed to set channel in state")
}
}
// Handle user
if err := s.Store.SelfSet(&ev.User); err != nil {
s.wrapErr(err, "Failed to set self in state")
}
// Set Ready to the state
s.Ready = *ev
case *gateway.GuildCreateEvent:
if err := s.Store.GuildSet(&ev.Guild); err != nil {
s.wrapErr(err, "Failed to create guild in state")
}
for _, m := range ev.Members {
if err := s.Store.MemberSet(ev.Guild.ID, &m); err != nil {
s.wrapErr(err, "Failed to add a member from guild in state")
}
}
for _, ch := range ev.Channels {
ch.GuildID = ev.Guild.ID // just to make sure
if err := s.Store.ChannelSet(&ch); err != nil {
s.wrapErr(err, "Failed to add a channel from guild in state")
}
}
for _, p := range ev.Presences {
if err := s.Store.PresenceSet(ev.Guild.ID, &p); err != nil {
s.wrapErr(err, "Failed to add a presence from guild in state")
}
}
case *gateway.GuildUpdateEvent:
if err := s.Store.GuildSet((*discord.Guild)(ev)); err != nil {
s.wrapErr(err, "Failed to update guild in state")
}
case *gateway.GuildDeleteEvent:
if err := s.Store.GuildRemove(ev.ID); err != nil {
s.wrapErr(err, "Failed to delete guild in state")
}
case *gateway.GuildMemberAddEvent:
if err := s.Store.MemberSet(ev.GuildID, &ev.Member); err != nil {
s.wrapErr(err, "Failed to add a member in state")
}
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 {
s.wrapErr(err, "Failed to update a member in state")
}
case *gateway.GuildMemberRemoveEvent:
if err := s.Store.MemberRemove(ev.GuildID, ev.User.ID); err != nil {
s.wrapErr(err, "Failed to remove a member in state")
}
case *gateway.GuildMembersChunkEvent:
for _, m := range ev.Members {
if err := s.Store.MemberSet(ev.GuildID, &m); err != nil {
s.wrapErr(err, "Failed to add a member from chunk in state")
}
}
for _, p := range ev.Presences {
if err := s.Store.PresenceSet(ev.GuildID, &p); err != nil {
s.wrapErr(err, "Failed to add a presence from chunk in state")
}
}
case *gateway.GuildRoleCreateEvent:
if err := s.Store.RoleSet(ev.GuildID, &ev.Role); err != nil {
s.wrapErr(err, "Failed to add a role in state")
}
case *gateway.GuildRoleUpdateEvent:
if err := s.Store.RoleSet(ev.GuildID, &ev.Role); err != nil {
s.wrapErr(err, "Failed to update a role in state")
}
case *gateway.GuildRoleDeleteEvent:
if err := s.Store.RoleRemove(ev.GuildID, ev.RoleID); err != nil {
s.wrapErr(err, "Failed to remove a role in state")
}
case *gateway.GuildEmojisUpdateEvent:
if err := s.Store.EmojiSet(ev.GuildID, ev.Emojis); err != nil {
s.wrapErr(err, "Failed to update emojis in state")
}
case *gateway.ChannelCreateEvent:
if err := s.Store.ChannelSet((*discord.Channel)(ev)); err != nil {
s.wrapErr(err, "Failed to create a channel in state")
}
case *gateway.ChannelUpdateEvent:
if err := s.Store.ChannelSet((*discord.Channel)(ev)); err != nil {
s.wrapErr(err, "Failed to update a channel in state")
}
case *gateway.ChannelDeleteEvent:
if err := s.Store.ChannelRemove((*discord.Channel)(ev)); err != nil {
s.wrapErr(err, "Failed to remove a channel in state")
}
// *gateway.ChannelPinsUpdateEvent is not tracked.
case *gateway.MessageCreateEvent:
if err := s.Store.MessageSet((*discord.Message)(ev)); err != nil {
s.wrapErr(err, "Failed to add a message in state")
}
case *gateway.MessageUpdateEvent:
if err := s.Store.MessageSet((*discord.Message)(ev)); err != nil {
s.wrapErr(err, "Failed to update a message in state")
}
case *gateway.MessageDeleteEvent:
if err := s.Store.MessageRemove(ev.ChannelID, ev.ID); err != nil {
s.wrapErr(err, "Failed to delete a message in state")
}
case *gateway.MessageDeleteBulkEvent:
for _, id := range ev.IDs {
if err := s.Store.MessageRemove(ev.ChannelID, id); err != nil {
s.wrapErr(err, "Failed to delete bulk meessages in state")
}
}
case *gateway.PresenceUpdateEvent:
if err := s.Store.PresenceSet(
ev.GuildID, (*discord.Presence)(ev)); err != nil {
s.wrapErr(err, "Failed to update presence in state")
}
}
}
func (s *State) wrapErr(err error, wrap string) {
s.ErrorLog(errors.Wrap(err, wrap))
}

View file

@ -46,19 +46,21 @@ type StoreGetter interface {
type StoreModifier interface { type StoreModifier interface {
SelfSet(me *discord.User) error SelfSet(me *discord.User) error
// ChannelSet should switch on Type to know if it's a private channel or
// not.
ChannelSet(*discord.Channel) error ChannelSet(*discord.Channel) error
ChannelRemove(*discord.Channel) error ChannelRemove(*discord.Channel) error
EmojiSet(guildID discord.Snowflake, emojis []discord.Emoji) error EmojiSet(guildID discord.Snowflake, emojis []discord.Emoji) error
GuildSet(*discord.Guild) error GuildSet(*discord.Guild) error
GuildRemove(*discord.Guild) error GuildRemove(id discord.Snowflake) error
MemberSet(guildID discord.Snowflake, member *discord.Member) error MemberSet(guildID discord.Snowflake, member *discord.Member) error
MemberRemove(guildID, userID discord.Snowflake) error MemberRemove(guildID, userID discord.Snowflake) error
MessageSet(*discord.Message) error MessageSet(*discord.Message) error
MessageRemove(*discord.Message) error MessageRemove(channelID, messageID discord.Snowflake) error
PresenceSet(guildID discord.Snowflake, presence *discord.Presence) error PresenceSet(guildID discord.Snowflake, presence *discord.Presence) error
PresenceRemove(guildID, userID discord.Snowflake) error PresenceRemove(guildID, userID discord.Snowflake) error

View file

@ -15,9 +15,13 @@ type DefaultStore struct {
self discord.User self discord.User
// includes normal and private // includes normal and private
privates map[discord.Snowflake]*discord.Channel // channelID:channel privates map[discord.Snowflake]*discord.Channel // channelID:channel
guilds map[discord.Snowflake]*discord.Guild // guildID:guild guilds map[discord.Snowflake]*discord.Guild // guildID:guild
messages map[discord.Snowflake][]discord.Message // channelID:messages
channels map[discord.Snowflake][]discord.Channel // guildID:channels
members map[discord.Snowflake][]discord.Member // guildID:members
presences map[discord.Snowflake][]discord.Presence // guildID:presences
messages map[discord.Snowflake][]discord.Message // channelID:messages
mut sync.Mutex mut sync.Mutex
} }
@ -40,7 +44,10 @@ func NewDefaultStore(opts *DefaultStoreOptions) *DefaultStore {
privates: map[discord.Snowflake]*discord.Channel{}, privates: map[discord.Snowflake]*discord.Channel{},
guilds: map[discord.Snowflake]*discord.Guild{}, guilds: map[discord.Snowflake]*discord.Guild{},
messages: map[discord.Snowflake][]discord.Message{},
channels: map[discord.Snowflake][]discord.Channel{},
presences: map[discord.Snowflake][]discord.Presence{},
messages: map[discord.Snowflake][]discord.Message{},
} }
} }
@ -84,8 +91,8 @@ func (s *DefaultStore) Channel(id discord.Snowflake) (*discord.Channel, error) {
s.mut.Lock() s.mut.Lock()
defer s.mut.Unlock() defer s.mut.Unlock()
for _, g := range s.guilds { for _, chs := range s.channels {
for _, ch := range g.Channels { for _, ch := range chs {
if ch.ID == id { if ch.ID == id {
return &ch, nil return &ch, nil
} }
@ -101,12 +108,12 @@ func (s *DefaultStore) Channels(
s.mut.Lock() s.mut.Lock()
defer s.mut.Unlock() defer s.mut.Unlock()
gd, ok := s.guilds[guildID] chs, ok := s.channels[guildID]
if !ok { if !ok {
return nil, ErrStoreNotFound return nil, ErrStoreNotFound
} }
return gd.Channels, nil return chs, nil
} }
func (s *DefaultStore) PrivateChannels() ([]discord.Channel, error) { func (s *DefaultStore) PrivateChannels() ([]discord.Channel, error) {
@ -136,20 +143,22 @@ func (s *DefaultStore) ChannelSet(channel *discord.Channel) error {
s.privates[channel.ID] = channel s.privates[channel.ID] = channel
default: default:
gd, ok := s.guilds[channel.GuildID] chs, ok := s.channels[channel.GuildID]
if !ok { if !ok {
return ErrStoreNotFound return ErrStoreNotFound
} }
for i, ch := range gd.Channels { for i, ch := range chs {
if ch.ID == channel.ID { if ch.ID == channel.ID {
// Found, just edit // Found, just edit
gd.Channels[i] = *channel chs[i] = *channel
return nil return nil
} }
} }
gd.Channels = append(gd.Channels, *channel) chs = append(chs, *channel)
s.channels[channel.GuildID] = chs
} }
return nil return nil
@ -159,14 +168,16 @@ func (s *DefaultStore) ChannelRemove(channel *discord.Channel) error {
s.mut.Lock() s.mut.Lock()
defer s.mut.Unlock() defer s.mut.Unlock()
gd, ok := s.guilds[channel.GuildID] chs, ok := s.channels[channel.GuildID]
if !ok { if !ok {
return ErrStoreNotFound return ErrStoreNotFound
} }
for i, ch := range gd.Channels { for i, ch := range chs {
if ch.ID == channel.ID { if ch.ID == channel.ID {
gd.Channels = append(gd.Channels[:i], gd.Channels[i+1:]...) chs = append(chs[:i], chs[i+1:]...)
s.channels[channel.GuildID] = chs
return nil return nil
} }
} }
@ -277,26 +288,15 @@ func (s *DefaultStore) Guilds() ([]discord.Guild, error) {
func (s *DefaultStore) GuildSet(g *discord.Guild) error { func (s *DefaultStore) GuildSet(g *discord.Guild) error {
s.mut.Lock() s.mut.Lock()
defer s.mut.Unlock()
old := s.guilds[g.ID]
// Check the channels too
if len(old.Channels) == 0 {
return nil
}
if len(g.Channels) == 0 {
g.Channels = old.Channels
}
s.guilds[g.ID] = g s.guilds[g.ID] = g
s.mut.Unlock()
return nil return nil
} }
func (s *DefaultStore) GuildRemove(g *discord.Guild) error { func (s *DefaultStore) GuildRemove(id discord.Snowflake) error {
s.mut.Lock() s.mut.Lock()
delete(s.guilds, g.ID) delete(s.guilds, id)
s.mut.Unlock() s.mut.Unlock()
return nil return nil
@ -310,14 +310,14 @@ func (s *DefaultStore) Member(
s.mut.Lock() s.mut.Lock()
defer s.mut.Unlock() defer s.mut.Unlock()
gd, ok := s.guilds[guildID] ms, ok := s.members[guildID]
if !ok { if !ok {
return nil, ErrStoreNotFound return nil, ErrStoreNotFound
} }
for _, member := range gd.Members { for _, m := range ms {
if member.User.ID == userID { if m.User.ID == userID {
return &member, nil return &m, nil
} }
} }
@ -330,12 +330,12 @@ func (s *DefaultStore) Members(
s.mut.Lock() s.mut.Lock()
defer s.mut.Unlock() defer s.mut.Unlock()
gd, ok := s.guilds[guildID] ms, ok := s.members[guildID]
if !ok { if !ok {
return nil, ErrStoreNotFound return nil, ErrStoreNotFound
} }
return gd.Members, nil return ms, nil
} }
func (s *DefaultStore) MemberSet( func (s *DefaultStore) MemberSet(
@ -344,22 +344,26 @@ func (s *DefaultStore) MemberSet(
s.mut.Lock() s.mut.Lock()
defer s.mut.Unlock() defer s.mut.Unlock()
gd, ok := s.guilds[guildID] ms, ok := s.members[guildID]
if !ok { if !ok {
return ErrStoreNotFound return ErrStoreNotFound
} }
// Try and see if this member is already in the slice // Try and see if this member is already in the slice
for i, m := range gd.Members { for i, m := range ms {
if m.User.ID == member.User.ID { if m.User.ID == member.User.ID {
// If it is, we simply replace it // If it is, we simply replace it
gd.Members[i] = *member ms[i] = *member
s.members[guildID] = ms
return nil return nil
} }
} }
// Append the new member // Append the new member
gd.Members = append(gd.Members, *member) ms = append(ms, *member)
s.members[guildID] = ms
return nil return nil
} }
@ -367,15 +371,17 @@ func (s *DefaultStore) MemberRemove(guildID, userID discord.Snowflake) error {
s.mut.Lock() s.mut.Lock()
defer s.mut.Unlock() defer s.mut.Unlock()
gd, ok := s.guilds[guildID] ms, ok := s.members[guildID]
if !ok { if !ok {
return ErrStoreNotFound return ErrStoreNotFound
} }
// Try and see if this member is already in the slice // Try and see if this member is already in the slice
for i, m := range gd.Members { for i, m := range ms {
if m.User.ID == userID { if m.User.ID == userID {
gd.Members = append(gd.Members[:i], gd.Members[i+1:]...) ms = append(ms, ms[i+1:]...)
s.members[guildID] = ms
return nil return nil
} }
} }
@ -443,19 +449,21 @@ func (s *DefaultStore) MessageSet(message *discord.Message) error {
return nil return nil
} }
func (s *DefaultStore) MessageRemove(message *discord.Message) error { func (s *DefaultStore) MessageRemove(
channelID, messageID discord.Snowflake) error {
s.mut.Lock() s.mut.Lock()
defer s.mut.Unlock() defer s.mut.Unlock()
ms, ok := s.messages[message.ChannelID] ms, ok := s.messages[channelID]
if !ok { if !ok {
return ErrStoreNotFound return ErrStoreNotFound
} }
for i, m := range ms { for i, m := range ms {
if m.ID == message.ID { if m.ID == messageID {
ms = append(ms[:i], ms[i+1:]...) ms = append(ms[:i], ms[i+1:]...)
s.messages[message.ChannelID] = ms s.messages[channelID] = ms
return nil return nil
} }
} }
@ -471,12 +479,12 @@ func (s *DefaultStore) Presence(
s.mut.Lock() s.mut.Lock()
defer s.mut.Unlock() defer s.mut.Unlock()
gd, ok := s.guilds[guildID] ps, ok := s.presences[guildID]
if !ok { if !ok {
return nil, ErrStoreNotFound return nil, ErrStoreNotFound
} }
for _, p := range gd.Presences { for _, p := range ps {
if p.User.ID == userID { if p.User.ID == userID {
return &p, nil return &p, nil
} }
@ -491,12 +499,12 @@ func (s *DefaultStore) Presences(
s.mut.Lock() s.mut.Lock()
defer s.mut.Unlock() defer s.mut.Unlock()
gd, ok := s.guilds[guildID] ps, ok := s.presences[guildID]
if !ok { if !ok {
return nil, ErrStoreNotFound return nil, ErrStoreNotFound
} }
return gd.Presences, nil return ps, nil
} }
func (s *DefaultStore) PresenceSet( func (s *DefaultStore) PresenceSet(
@ -505,19 +513,22 @@ func (s *DefaultStore) PresenceSet(
s.mut.Lock() s.mut.Lock()
defer s.mut.Unlock() defer s.mut.Unlock()
gd, ok := s.guilds[guildID] ps, ok := s.presences[guildID]
if !ok { if !ok {
return ErrStoreNotFound return ErrStoreNotFound
} }
for i, p := range gd.Presences { for i, p := range ps {
if p.User.ID == presence.User.ID { if p.User.ID == presence.User.ID {
gd.Presences[i] = *presence ps[i] = *presence
s.presences[guildID] = ps
return nil return nil
} }
} }
gd.Presences = append(gd.Presences, *presence) ps = append(ps, *presence)
s.presences[guildID] = ps
return nil return nil
} }
@ -525,14 +536,16 @@ func (s *DefaultStore) PresenceRemove(guildID, userID discord.Snowflake) error {
s.mut.Lock() s.mut.Lock()
defer s.mut.Unlock() defer s.mut.Unlock()
gd, ok := s.guilds[guildID] ps, ok := s.presences[guildID]
if !ok { if !ok {
return ErrStoreNotFound return ErrStoreNotFound
} }
for i, p := range gd.Presences { for i, p := range ps {
if p.User.ID == userID { if p.User.ID == userID {
gd.Presences = append(gd.Presences[:i], gd.Presences[i+1:]...) ps = append(ps[:i], ps[i+1:]...)
s.presences[guildID] = ps
return nil return nil
} }
} }