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"`
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.
MaxPresences uint64 `json:"max_presences,omitempty"`
MaxMembers uint64 `json:"max_members,omitempty"`
@ -78,6 +68,24 @@ type Role struct {
type Presence struct {
User User `json:"user"`
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 {

View File

@ -68,3 +68,78 @@ const (
ConnectionNotVisible ConnectionVisibility = iota
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"`
Shard *Shard `json:"shard"`
// Undocumented fields
Presences []discord.Presence `json:"presences,omitempty"`
Notes map[discord.Snowflake]string `json:"notes,omitempty"`
}
ResumedEvent struct{}
@ -42,7 +46,19 @@ type (
// https://discordapp.com/developers/docs/topics/gateway#guilds
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
GuildDeleteEvent struct {
ID discord.Snowflake `json:"id"`
@ -78,7 +94,7 @@ type (
}
GuildMemberUpdateEvent struct {
GuildID discord.Snowflake `json:"guild_id"`
Roles []discord.Snowflake `json:"roles"`
RoleIDs []discord.Snowflake `json:"roles"`
User discord.User `json:"user"`
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
type (
MessageCreateEvent discord.Message
@ -151,25 +173,8 @@ type (
// https://discordapp.com/developers/docs/topics/gateway#presence
type (
// Clients may only update their game status 5 times per 20 seconds.
PresenceUpdateEvent struct {
User discord.User `json:"user"`
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 {
PresenceUpdateEvent discord.Presence
TypingStartEvent struct {
ChannelID discord.Snowflake `json:"channel_id"`
UserID discord.Snowflake `json:"user_id"`
Timestamp discord.Timestamp `json:"timestamp"`
@ -180,6 +185,10 @@ type (
UserUpdateEvent discord.User
)
func (u PresenceUpdateEvent) Update(p *discord.Presence) {
}
// https://discordapp.com/developers/docs/topics/gateway#voice
type (
VoiceStateUpdateEvent discord.VoiceState

View File

@ -3,7 +3,10 @@
package state
import (
"log"
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/gateway"
"github.com/diamondburned/arikawa/handler"
"github.com/diamondburned/arikawa/session"
)
@ -15,15 +18,22 @@ var (
type State struct {
*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
// is. This should only be used for low-level operations.
// It's recommended to set Synchronous to true if you mutate the events.
PreHandler *handler.Handler // default nil
MaxMessages uint // default 50
Store
// *: State doesn't actually keep track of pinned messages.
unhooker func()
}
@ -32,6 +42,13 @@ func NewFromSession(s *session.Session, store Store) (*State, error) {
state := &State{
Session: s,
Store: store,
ErrorLog: func(err error) {
log.Println("arikawa/state error:", err)
},
}
s.ErrorLog = func(err error) {
state.ErrorLog(err)
}
return state, state.hookSession()
@ -49,12 +66,7 @@ func NewWithStore(token string, store Store) (*State, error) {
return nil, err
}
state := &State{
Session: s,
Store: store,
}
return state, state.hookSession()
return NewFromSession(s, store)
}
// 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
}
////
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 {
SelfSet(me *discord.User) error
// ChannelSet should switch on Type to know if it's a private channel or
// not.
ChannelSet(*discord.Channel) error
ChannelRemove(*discord.Channel) error
EmojiSet(guildID discord.Snowflake, emojis []discord.Emoji) error
GuildSet(*discord.Guild) error
GuildRemove(*discord.Guild) error
GuildRemove(id discord.Snowflake) error
MemberSet(guildID discord.Snowflake, member *discord.Member) error
MemberRemove(guildID, userID discord.Snowflake) error
MessageSet(*discord.Message) error
MessageRemove(*discord.Message) error
MessageRemove(channelID, messageID discord.Snowflake) error
PresenceSet(guildID discord.Snowflake, presence *discord.Presence) error
PresenceRemove(guildID, userID discord.Snowflake) error

View File

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