mirror of
https://github.com/diamondburned/arikawa.git
synced 2025-11-09 03:55:10 +00:00
state: Add paginating State.Messages (#213)
* Store,State: Add update param to all store.XXXStore.XXXSet methods * State: add paginating Messages * Store: Fix test error * store: merge shouldPrependMessage and shouldAppendMessage into single messageInsertPosition
This commit is contained in:
parent
40e1a3757d
commit
a808b52f00
143
state/state.go
143
state/state.go
|
|
@ -335,7 +335,7 @@ func (s *State) Me() (*discord.User, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return u, s.Cabinet.MyselfSet(*u)
|
||||
return u, s.Cabinet.MyselfSet(*u, false)
|
||||
}
|
||||
|
||||
////
|
||||
|
|
@ -352,7 +352,7 @@ func (s *State) Channel(id discord.ChannelID) (c *discord.Channel, err error) {
|
|||
}
|
||||
|
||||
if s.tracksChannel(c) {
|
||||
err = s.Cabinet.ChannelSet(*c)
|
||||
err = s.Cabinet.ChannelSet(*c, false)
|
||||
}
|
||||
|
||||
return
|
||||
|
|
@ -373,7 +373,7 @@ func (s *State) Channels(guildID discord.GuildID) (cs []discord.Channel, err err
|
|||
|
||||
if s.Gateway.HasIntents(gateway.IntentGuilds) {
|
||||
for _, c := range cs {
|
||||
if err = s.Cabinet.ChannelSet(c); err != nil {
|
||||
if err = s.Cabinet.ChannelSet(c, false); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
@ -393,7 +393,7 @@ func (s *State) CreatePrivateChannel(recipient discord.UserID) (*discord.Channel
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return c, s.Cabinet.ChannelSet(*c)
|
||||
return c, s.Cabinet.ChannelSet(*c, false)
|
||||
}
|
||||
|
||||
// PrivateChannels gets the direct messages of the user.
|
||||
|
|
@ -410,7 +410,7 @@ func (s *State) PrivateChannels() ([]discord.Channel, error) {
|
|||
}
|
||||
|
||||
for _, c := range cs {
|
||||
if err := s.Cabinet.ChannelSet(c); err != nil {
|
||||
if err := s.Cabinet.ChannelSet(c, false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
|
@ -437,7 +437,7 @@ func (s *State) Emoji(
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if err = s.Cabinet.EmojiSet(guildID, es); err != nil {
|
||||
if err = s.Cabinet.EmojiSet(guildID, es, false); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -464,7 +464,7 @@ func (s *State) Emojis(guildID discord.GuildID) (es []discord.Emoji, err error)
|
|||
}
|
||||
|
||||
if s.Gateway.HasIntents(gateway.IntentGuildEmojis) {
|
||||
err = s.Cabinet.EmojiSet(guildID, es)
|
||||
err = s.Cabinet.EmojiSet(guildID, es, false)
|
||||
}
|
||||
|
||||
return
|
||||
|
|
@ -499,7 +499,7 @@ func (s *State) Guilds() (gs []discord.Guild, err error) {
|
|||
|
||||
if s.Gateway.HasIntents(gateway.IntentGuilds) {
|
||||
for _, g := range gs {
|
||||
if err = s.Cabinet.GuildSet(g); err != nil {
|
||||
if err = s.Cabinet.GuildSet(g, false); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
@ -536,7 +536,7 @@ func (s *State) Members(guildID discord.GuildID) (ms []discord.Member, err error
|
|||
|
||||
if s.Gateway.HasIntents(gateway.IntentGuildMembers) {
|
||||
for _, m := range ms {
|
||||
if err = s.Cabinet.MemberSet(guildID, m); err != nil {
|
||||
if err = s.Cabinet.MemberSet(guildID, m, false); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
@ -568,7 +568,7 @@ func (s *State) Message(
|
|||
go func() {
|
||||
c, cerr = s.Session.Channel(channelID)
|
||||
if cerr == nil && s.Gateway.HasIntents(gateway.IntentGuilds) {
|
||||
cerr = s.Cabinet.ChannelSet(*c)
|
||||
cerr = s.Cabinet.ChannelSet(*c, false)
|
||||
}
|
||||
|
||||
wg.Done()
|
||||
|
|
@ -589,78 +589,97 @@ func (s *State) Message(
|
|||
m.ChannelID = c.ID
|
||||
m.GuildID = c.GuildID
|
||||
|
||||
if s.tracksMessage(m) {
|
||||
err = s.Cabinet.MessageSet(*m)
|
||||
}
|
||||
|
||||
return m, err
|
||||
}
|
||||
|
||||
// Messages fetches maximum 100 messages from the API, if it has to. There is
|
||||
// no limit if it's from the State storage.
|
||||
func (s *State) Messages(channelID discord.ChannelID) ([]discord.Message, error) {
|
||||
// TODO: Think of a design that doesn't rely on MaxMessages().
|
||||
var maxMsgs = s.MaxMessages()
|
||||
|
||||
ms, err := s.Cabinet.Messages(channelID)
|
||||
if err == nil && (len(ms) == 0 || s.tracksMessage(&ms[0])) {
|
||||
// If the state already has as many messages as it can, skip the API.
|
||||
if maxMsgs <= len(ms) {
|
||||
return ms, nil
|
||||
}
|
||||
|
||||
// Messages returns a slice filled with the most recent messages sent in the
|
||||
// channel with the passed ID. The method automatically paginates until it
|
||||
// reaches the passed limit, or, if the limit is set to 0, has fetched all
|
||||
// messages in the channel.
|
||||
//
|
||||
// As the underlying endpoint is capped at a maximum of 100 messages per
|
||||
// request, at maximum a total of limit/100 rounded up requests will be made,
|
||||
// although they may be less, if no more messages are available or there are
|
||||
// cached messages.
|
||||
// When fetching the messages, those with the highest ID, will be fetched
|
||||
// first. The returned slice will be sorted from latest to oldest.
|
||||
func (s *State) Messages(channelID discord.ChannelID, limit uint) ([]discord.Message, error) {
|
||||
storeMessages, err := s.Cabinet.Messages(channelID)
|
||||
if err == nil && s.tracksMessage(&storeMessages[0]) {
|
||||
// Is the channel tiny?
|
||||
s.fewMutex.Lock()
|
||||
if _, ok := s.fewMessages[channelID]; ok {
|
||||
s.fewMutex.Unlock()
|
||||
return ms, nil
|
||||
return storeMessages, nil
|
||||
}
|
||||
|
||||
// No, fetch from the state.
|
||||
// No, fetch from the API.
|
||||
s.fewMutex.Unlock()
|
||||
} else {
|
||||
// Something wrong with the cached messages, make sure they aren't
|
||||
// returned.
|
||||
storeMessages = nil
|
||||
}
|
||||
|
||||
ms, err = s.Session.Messages(channelID, uint(maxMsgs))
|
||||
// Store already has enough messages.
|
||||
if len(storeMessages) >= int(limit) && limit > 0 {
|
||||
return storeMessages[:limit], nil
|
||||
}
|
||||
|
||||
// Decrease the limit, if we aren't fetching all messages.
|
||||
if limit > 0 {
|
||||
limit -= uint(len(storeMessages))
|
||||
}
|
||||
|
||||
var before discord.MessageID = 0
|
||||
if len(storeMessages) > 0 {
|
||||
before = storeMessages[len(storeMessages)-1].ID
|
||||
}
|
||||
|
||||
apiMessages, err := s.Session.MessagesBefore(channelID, before, limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// New messages fetched weirdly does not have GuildID filled. We'll try and
|
||||
// get it for consistency with incoming message creates.
|
||||
var guildID discord.GuildID
|
||||
|
||||
// A bit too convoluted, but whatever.
|
||||
c, err := s.Channel(channelID)
|
||||
if err == nil {
|
||||
// If it's 0, it's 0 anyway. We don't need a check here.
|
||||
guildID = c.GuildID
|
||||
if len(storeMessages)+len(apiMessages) < s.MaxMessages() {
|
||||
// Tiny channel, store this.
|
||||
s.fewMutex.Lock()
|
||||
s.fewMessages[channelID] = struct{}{}
|
||||
s.fewMutex.Unlock()
|
||||
}
|
||||
|
||||
if len(ms) > 0 && s.tracksMessage(&ms[0]) {
|
||||
// Iterate in reverse, since the store is expected to prepend the latest
|
||||
// messages.
|
||||
for i := len(ms) - 1; i >= 0; i-- {
|
||||
// Set the guild ID, fine if it's 0 (it's already 0 anyway).
|
||||
ms[i].GuildID = guildID
|
||||
if len(apiMessages) == 0 {
|
||||
return storeMessages, nil
|
||||
}
|
||||
|
||||
if err := s.Cabinet.MessageSet(ms[i]); err != nil {
|
||||
// New messages fetched weirdly does not have GuildID filled. If we have
|
||||
// cached messages, we can use their GuildID. Otherwise, we need to fetch
|
||||
// it from the api.
|
||||
var guildID discord.GuildID
|
||||
if len(storeMessages) > 0 {
|
||||
guildID = storeMessages[0].GuildID
|
||||
} else {
|
||||
c, err := s.Channel(channelID)
|
||||
if err == nil {
|
||||
// If it's 0, it's 0 anyway. We don't need a check here.
|
||||
guildID = c.GuildID
|
||||
}
|
||||
}
|
||||
|
||||
for _, m := range apiMessages {
|
||||
m.GuildID = guildID
|
||||
}
|
||||
|
||||
if s.tracksMessage(&apiMessages[0]) && len(storeMessages) < s.MaxMessages() {
|
||||
// Only add as many messages as the store can hold.
|
||||
for _, m := range apiMessages[:s.MaxMessages()-len(storeMessages)] {
|
||||
if err := s.Cabinet.MessageSet(m, false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(ms) < maxMsgs {
|
||||
// Tiny channel, store this.
|
||||
s.fewMutex.Lock()
|
||||
s.fewMessages[channelID] = struct{}{}
|
||||
s.fewMutex.Unlock()
|
||||
|
||||
return ms, nil
|
||||
}
|
||||
|
||||
// Since the latest messages are at the end and we already know the maxMsgs,
|
||||
// we could slice this right away.
|
||||
return ms[:maxMsgs], nil
|
||||
return append(storeMessages, apiMessages...), nil
|
||||
}
|
||||
|
||||
////
|
||||
|
|
@ -717,7 +736,7 @@ func (s *State) Role(guildID discord.GuildID, roleID discord.RoleID) (target *di
|
|||
}
|
||||
|
||||
if s.Gateway.HasIntents(gateway.IntentGuilds) {
|
||||
if err = s.RoleSet(guildID, r); err != nil {
|
||||
if err = s.RoleSet(guildID, r, false); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
@ -743,7 +762,7 @@ func (s *State) Roles(guildID discord.GuildID) ([]discord.Role, error) {
|
|||
|
||||
if s.Gateway.HasIntents(gateway.IntentGuilds) {
|
||||
for _, r := range rs {
|
||||
if err := s.RoleSet(guildID, r); err != nil {
|
||||
if err := s.RoleSet(guildID, r, false); err != nil {
|
||||
return rs, err
|
||||
}
|
||||
}
|
||||
|
|
@ -755,7 +774,7 @@ func (s *State) Roles(guildID discord.GuildID) ([]discord.Role, error) {
|
|||
func (s *State) fetchGuild(id discord.GuildID) (g *discord.Guild, err error) {
|
||||
g, err = s.Session.Guild(id)
|
||||
if err == nil && s.Gateway.HasIntents(gateway.IntentGuilds) {
|
||||
err = s.Cabinet.GuildSet(*g)
|
||||
err = s.Cabinet.GuildSet(*g, false)
|
||||
}
|
||||
|
||||
return
|
||||
|
|
@ -764,7 +783,7 @@ func (s *State) fetchGuild(id discord.GuildID) (g *discord.Guild, err error) {
|
|||
func (s *State) fetchMember(gID discord.GuildID, uID discord.UserID) (m *discord.Member, err error) {
|
||||
m, err = s.Session.Member(gID, uID)
|
||||
if err == nil && s.Gateway.HasIntents(gateway.IntentGuildMembers) {
|
||||
err = s.Cabinet.MemberSet(gID, *m)
|
||||
err = s.Cabinet.MemberSet(gID, *m, false)
|
||||
}
|
||||
|
||||
return
|
||||
|
|
|
|||
|
|
@ -69,20 +69,20 @@ func (s *State) onEvent(iface interface{}) {
|
|||
|
||||
// Handle guild presences
|
||||
for _, p := range ev.Presences {
|
||||
if err := s.Cabinet.PresenceSet(p.GuildID, p); err != nil {
|
||||
if err := s.Cabinet.PresenceSet(p.GuildID, p, false); err != nil {
|
||||
s.stateErr(err, "failed to set presence in Ready")
|
||||
}
|
||||
}
|
||||
|
||||
// Handle private channels
|
||||
for _, ch := range ev.PrivateChannels {
|
||||
if err := s.Cabinet.ChannelSet(ch); err != nil {
|
||||
if err := s.Cabinet.ChannelSet(ch, false); err != nil {
|
||||
s.stateErr(err, "failed to set channel in Ready")
|
||||
}
|
||||
}
|
||||
|
||||
// Handle user
|
||||
if err := s.Cabinet.MyselfSet(ev.User); err != nil {
|
||||
if err := s.Cabinet.MyselfSet(ev.User, false); err != nil {
|
||||
s.stateErr(err, "failed to set self in Ready")
|
||||
}
|
||||
|
||||
|
|
@ -91,7 +91,7 @@ func (s *State) onEvent(iface interface{}) {
|
|||
for _, guild := range ev.Guilds {
|
||||
// Handle guild voice states
|
||||
for _, v := range guild.VoiceStates {
|
||||
if err := s.Cabinet.VoiceStateSet(guild.ID, v); err != nil {
|
||||
if err := s.Cabinet.VoiceStateSet(guild.ID, v, false); err != nil {
|
||||
s.stateErr(err, "failed to set guild voice state in Ready Supplemental")
|
||||
}
|
||||
}
|
||||
|
|
@ -99,7 +99,7 @@ func (s *State) onEvent(iface interface{}) {
|
|||
|
||||
for _, friend := range ev.MergedPresences.Friends {
|
||||
sPresence := gateway.ConvertSupplementalPresence(friend)
|
||||
if err := s.Cabinet.PresenceSet(0, sPresence); err != nil {
|
||||
if err := s.Cabinet.PresenceSet(0, sPresence, false); err != nil {
|
||||
s.stateErr(err, "failed to set friend presence in Ready Supplemental")
|
||||
}
|
||||
}
|
||||
|
|
@ -112,14 +112,14 @@ func (s *State) onEvent(iface interface{}) {
|
|||
|
||||
for _, member := range ev.MergedMembers[i] {
|
||||
sMember := gateway.ConvertSupplementalMember(member)
|
||||
if err := s.Cabinet.MemberSet(guild.ID, sMember); err != nil {
|
||||
if err := s.Cabinet.MemberSet(guild.ID, sMember, false); err != nil {
|
||||
s.stateErr(err, "failed to set friend presence in Ready Supplemental")
|
||||
}
|
||||
}
|
||||
|
||||
for _, member := range ev.MergedPresences.Guilds[i] {
|
||||
sPresence := gateway.ConvertSupplementalPresence(member)
|
||||
if err := s.Cabinet.PresenceSet(guild.ID, sPresence); err != nil {
|
||||
if err := s.Cabinet.PresenceSet(guild.ID, sPresence, false); err != nil {
|
||||
s.stateErr(err, "failed to set member presence in Ready Supplemental")
|
||||
}
|
||||
}
|
||||
|
|
@ -129,7 +129,7 @@ func (s *State) onEvent(iface interface{}) {
|
|||
s.batchLog(storeGuildCreate(s.Cabinet, ev))
|
||||
|
||||
case *gateway.GuildUpdateEvent:
|
||||
if err := s.Cabinet.GuildSet(ev.Guild); err != nil {
|
||||
if err := s.Cabinet.GuildSet(ev.Guild, true); err != nil {
|
||||
s.stateErr(err, "failed to update guild in state")
|
||||
}
|
||||
|
||||
|
|
@ -139,7 +139,7 @@ func (s *State) onEvent(iface interface{}) {
|
|||
}
|
||||
|
||||
case *gateway.GuildMemberAddEvent:
|
||||
if err := s.Cabinet.MemberSet(ev.GuildID, ev.Member); err != nil {
|
||||
if err := s.Cabinet.MemberSet(ev.GuildID, ev.Member, false); err != nil {
|
||||
s.stateErr(err, "failed to add a member in state")
|
||||
}
|
||||
|
||||
|
|
@ -153,7 +153,7 @@ func (s *State) onEvent(iface interface{}) {
|
|||
// Update available fields from ev into m
|
||||
ev.Update(m)
|
||||
|
||||
if err := s.Cabinet.MemberSet(ev.GuildID, *m); err != nil {
|
||||
if err := s.Cabinet.MemberSet(ev.GuildID, *m, true); err != nil {
|
||||
s.stateErr(err, "failed to update a member in state")
|
||||
}
|
||||
|
||||
|
|
@ -164,24 +164,24 @@ func (s *State) onEvent(iface interface{}) {
|
|||
|
||||
case *gateway.GuildMembersChunkEvent:
|
||||
for _, m := range ev.Members {
|
||||
if err := s.Cabinet.MemberSet(ev.GuildID, m); err != nil {
|
||||
if err := s.Cabinet.MemberSet(ev.GuildID, m, false); err != nil {
|
||||
s.stateErr(err, "failed to add a member from chunk in state")
|
||||
}
|
||||
}
|
||||
|
||||
for _, p := range ev.Presences {
|
||||
if err := s.Cabinet.PresenceSet(ev.GuildID, p); err != nil {
|
||||
if err := s.Cabinet.PresenceSet(ev.GuildID, p, false); err != nil {
|
||||
s.stateErr(err, "failed to add a presence from chunk in state")
|
||||
}
|
||||
}
|
||||
|
||||
case *gateway.GuildRoleCreateEvent:
|
||||
if err := s.Cabinet.RoleSet(ev.GuildID, ev.Role); err != nil {
|
||||
if err := s.Cabinet.RoleSet(ev.GuildID, ev.Role, false); err != nil {
|
||||
s.stateErr(err, "failed to add a role in state")
|
||||
}
|
||||
|
||||
case *gateway.GuildRoleUpdateEvent:
|
||||
if err := s.Cabinet.RoleSet(ev.GuildID, ev.Role); err != nil {
|
||||
if err := s.Cabinet.RoleSet(ev.GuildID, ev.Role, true); err != nil {
|
||||
s.stateErr(err, "failed to update a role in state")
|
||||
}
|
||||
|
||||
|
|
@ -191,17 +191,17 @@ func (s *State) onEvent(iface interface{}) {
|
|||
}
|
||||
|
||||
case *gateway.GuildEmojisUpdateEvent:
|
||||
if err := s.Cabinet.EmojiSet(ev.GuildID, ev.Emojis); err != nil {
|
||||
if err := s.Cabinet.EmojiSet(ev.GuildID, ev.Emojis, true); err != nil {
|
||||
s.stateErr(err, "failed to update emojis in state")
|
||||
}
|
||||
|
||||
case *gateway.ChannelCreateEvent:
|
||||
if err := s.Cabinet.ChannelSet(ev.Channel); err != nil {
|
||||
if err := s.Cabinet.ChannelSet(ev.Channel, false); err != nil {
|
||||
s.stateErr(err, "failed to create a channel in state")
|
||||
}
|
||||
|
||||
case *gateway.ChannelUpdateEvent:
|
||||
if err := s.Cabinet.ChannelSet(ev.Channel); err != nil {
|
||||
if err := s.Cabinet.ChannelSet(ev.Channel, true); err != nil {
|
||||
s.stateErr(err, "failed to update a channel in state")
|
||||
}
|
||||
|
||||
|
|
@ -214,12 +214,12 @@ func (s *State) onEvent(iface interface{}) {
|
|||
// not tracked.
|
||||
|
||||
case *gateway.MessageCreateEvent:
|
||||
if err := s.Cabinet.MessageSet(ev.Message); err != nil {
|
||||
if err := s.Cabinet.MessageSet(ev.Message, false); err != nil {
|
||||
s.stateErr(err, "failed to add a message in state")
|
||||
}
|
||||
|
||||
case *gateway.MessageUpdateEvent:
|
||||
if err := s.Cabinet.MessageSet(ev.Message); err != nil {
|
||||
if err := s.Cabinet.MessageSet(ev.Message, true); err != nil {
|
||||
s.stateErr(err, "failed to update a message in state")
|
||||
}
|
||||
|
||||
|
|
@ -295,13 +295,13 @@ func (s *State) onEvent(iface interface{}) {
|
|||
})
|
||||
|
||||
case *gateway.PresenceUpdateEvent:
|
||||
if err := s.Cabinet.PresenceSet(ev.GuildID, ev.Presence); err != nil {
|
||||
if err := s.Cabinet.PresenceSet(ev.GuildID, ev.Presence, true); err != nil {
|
||||
s.stateErr(err, "failed to update presence in state")
|
||||
}
|
||||
|
||||
case *gateway.PresencesReplaceEvent:
|
||||
for _, p := range *ev {
|
||||
if err := s.Cabinet.PresenceSet(p.GuildID, p.Presence); err != nil {
|
||||
if err := s.Cabinet.PresenceSet(p.GuildID, p.Presence, true); err != nil {
|
||||
s.stateErr(err, "failed to update presence in state")
|
||||
}
|
||||
}
|
||||
|
|
@ -321,7 +321,7 @@ func (s *State) onEvent(iface interface{}) {
|
|||
// TODO
|
||||
|
||||
case *gateway.UserUpdateEvent:
|
||||
if err := s.Cabinet.MyselfSet(ev.User); err != nil {
|
||||
if err := s.Cabinet.MyselfSet(ev.User, true); err != nil {
|
||||
s.stateErr(err, "failed to update myself from USER_UPDATE")
|
||||
}
|
||||
|
||||
|
|
@ -332,7 +332,7 @@ func (s *State) onEvent(iface interface{}) {
|
|||
s.stateErr(err, "failed to remove voice state from state")
|
||||
}
|
||||
} else {
|
||||
if err := s.Cabinet.VoiceStateSet(vs.GuildID, *vs); err != nil {
|
||||
if err := s.Cabinet.VoiceStateSet(vs.GuildID, *vs, true); err != nil {
|
||||
s.stateErr(err, "failed to update voice state in state")
|
||||
}
|
||||
}
|
||||
|
|
@ -358,7 +358,7 @@ func (s *State) editMessage(ch discord.ChannelID, msg discord.MessageID, fn func
|
|||
if !fn(m) {
|
||||
return
|
||||
}
|
||||
if err := s.Cabinet.MessageSet(*m); err != nil {
|
||||
if err := s.Cabinet.MessageSet(*m, true); err != nil {
|
||||
s.stateErr(err, "failed to save message in reaction add")
|
||||
}
|
||||
}
|
||||
|
|
@ -379,20 +379,20 @@ func storeGuildCreate(cab store.Cabinet, guild *gateway.GuildCreateEvent) []erro
|
|||
|
||||
stack, errs := newErrorStack()
|
||||
|
||||
if err := cab.GuildSet(guild.Guild); err != nil {
|
||||
if err := cab.GuildSet(guild.Guild, false); err != nil {
|
||||
errs(err, "failed to set guild in Ready")
|
||||
}
|
||||
|
||||
// Handle guild emojis
|
||||
if guild.Emojis != nil {
|
||||
if err := cab.EmojiSet(guild.ID, guild.Emojis); err != nil {
|
||||
if err := cab.EmojiSet(guild.ID, guild.Emojis, false); err != nil {
|
||||
errs(err, "failed to set guild emojis")
|
||||
}
|
||||
}
|
||||
|
||||
// Handle guild member
|
||||
for _, m := range guild.Members {
|
||||
if err := cab.MemberSet(guild.ID, m); err != nil {
|
||||
if err := cab.MemberSet(guild.ID, m, false); err != nil {
|
||||
errs(err, "failed to set guild member in Ready")
|
||||
}
|
||||
}
|
||||
|
|
@ -402,21 +402,21 @@ func storeGuildCreate(cab store.Cabinet, guild *gateway.GuildCreateEvent) []erro
|
|||
// I HATE Discord.
|
||||
ch.GuildID = guild.ID
|
||||
|
||||
if err := cab.ChannelSet(ch); err != nil {
|
||||
if err := cab.ChannelSet(ch, false); err != nil {
|
||||
errs(err, "failed to set guild channel in Ready")
|
||||
}
|
||||
}
|
||||
|
||||
// Handle guild presences
|
||||
for _, p := range guild.Presences {
|
||||
if err := cab.PresenceSet(guild.ID, p); err != nil {
|
||||
if err := cab.PresenceSet(guild.ID, p, false); err != nil {
|
||||
errs(err, "failed to set guild presence in Ready")
|
||||
}
|
||||
}
|
||||
|
||||
// Handle guild voice states
|
||||
for _, v := range guild.VoiceStates {
|
||||
if err := cab.VoiceStateSet(guild.ID, v); err != nil {
|
||||
if err := cab.VoiceStateSet(guild.ID, v, false); err != nil {
|
||||
errs(err, "failed to set guild voice state in Ready")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,13 +105,15 @@ func (s *Channel) PrivateChannels() ([]discord.Channel, error) {
|
|||
}
|
||||
|
||||
// ChannelSet sets the Direct Message or Guild channel into the state.
|
||||
func (s *Channel) ChannelSet(channel discord.Channel) error {
|
||||
func (s *Channel) ChannelSet(channel discord.Channel, update bool) error {
|
||||
s.mut.Lock()
|
||||
defer s.mut.Unlock()
|
||||
|
||||
// Update the reference if we can.
|
||||
if ch, ok := s.channels[channel.ID]; ok {
|
||||
*ch = channel
|
||||
if update {
|
||||
*ch = channel
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -71,8 +71,11 @@ func (s *Emoji) Emojis(guildID discord.GuildID) ([]discord.Emoji, error) {
|
|||
return es.emojis, nil
|
||||
}
|
||||
|
||||
func (s *Emoji) EmojiSet(guildID discord.GuildID, allEmojis []discord.Emoji) error {
|
||||
iv, _ := s.guilds.LoadOrStore(guildID)
|
||||
func (s *Emoji) EmojiSet(guildID discord.GuildID, allEmojis []discord.Emoji, update bool) error {
|
||||
iv, loaded := s.guilds.LoadOrStore(guildID)
|
||||
if loaded && !update {
|
||||
return nil
|
||||
}
|
||||
|
||||
es := iv.(*emojis)
|
||||
|
||||
|
|
|
|||
|
|
@ -58,10 +58,13 @@ func (s *Guild) Guilds() ([]discord.Guild, error) {
|
|||
return gs, nil
|
||||
}
|
||||
|
||||
func (s *Guild) GuildSet(guild discord.Guild) error {
|
||||
func (s *Guild) GuildSet(guild discord.Guild, update bool) error {
|
||||
s.mut.Lock()
|
||||
s.guilds[guild.ID] = guild
|
||||
if _, ok := s.guilds[guild.ID]; !ok || update {
|
||||
s.guilds[guild.ID] = guild
|
||||
}
|
||||
s.mut.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,9 +38,11 @@ func (m *Me) Me() (*discord.User, error) {
|
|||
return &self, nil
|
||||
}
|
||||
|
||||
func (m *Me) MyselfSet(me discord.User) error {
|
||||
func (m *Me) MyselfSet(me discord.User, update bool) error {
|
||||
m.mut.Lock()
|
||||
m.self = me
|
||||
if !m.self.ID.IsValid() || update {
|
||||
m.self = me
|
||||
}
|
||||
m.mut.Unlock()
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -71,12 +71,14 @@ func (s *Member) Members(guildID discord.GuildID) ([]discord.Member, error) {
|
|||
return members, nil
|
||||
}
|
||||
|
||||
func (s *Member) MemberSet(guildID discord.GuildID, member discord.Member) error {
|
||||
func (s *Member) MemberSet(guildID discord.GuildID, m discord.Member, update bool) error {
|
||||
iv, _ := s.guilds.LoadOrStore(guildID)
|
||||
gm := iv.(*guildMembers)
|
||||
|
||||
gm.mut.Lock()
|
||||
gm.members[member.User.ID] = member
|
||||
if _, ok := gm.members[m.User.ID]; !ok || update {
|
||||
gm.members[m.User.ID] = m
|
||||
}
|
||||
gm.mut.Unlock()
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -73,7 +73,11 @@ func (s *Message) MaxMessages() int {
|
|||
return s.maxMsgs
|
||||
}
|
||||
|
||||
func (s *Message) MessageSet(message discord.Message) error {
|
||||
func (s *Message) MessageSet(message discord.Message, update bool) error {
|
||||
if s.maxMsgs <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
iv, _ := s.channels.LoadOrStore(message.ChannelID)
|
||||
|
||||
msgs := iv.(*messages)
|
||||
|
|
@ -81,62 +85,103 @@ func (s *Message) MessageSet(message discord.Message) error {
|
|||
msgs.mut.Lock()
|
||||
defer msgs.mut.Unlock()
|
||||
|
||||
for i, m := range msgs.messages {
|
||||
if m.ID == message.ID {
|
||||
DiffMessage(message, &m)
|
||||
msgs.messages[i] = m
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Order: latest to earliest, similar to the API.
|
||||
|
||||
// Check if we already have the message. Try to derive the order otherwise.
|
||||
var insertAt int
|
||||
|
||||
// Since we make the order guarantee ourselves, we can trust that we're
|
||||
// iterating from latest to earliest.
|
||||
for insertAt < len(msgs.messages) {
|
||||
// Check if the new message is older. If it is, then we should insert it
|
||||
// right after this message (or before this message in the list; i-1).
|
||||
if message.ID > msgs.messages[insertAt].ID {
|
||||
break
|
||||
if update {
|
||||
// Opt for a linear latest-to-oldest search in favor of something like
|
||||
// sort.Search, since more recent messages are more likely to be edited
|
||||
// than older ones.
|
||||
for i, oldMessage := range msgs.messages {
|
||||
// We found a match, update it.
|
||||
if oldMessage.ID == message.ID {
|
||||
DiffMessage(message, &oldMessage)
|
||||
msgs.messages[i] = oldMessage // Now updated.
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
insertAt++
|
||||
return nil
|
||||
}
|
||||
|
||||
end := len(msgs.messages)
|
||||
max := s.MaxMessages()
|
||||
if len(msgs.messages) == 0 {
|
||||
msgs.messages = []discord.Message{message}
|
||||
}
|
||||
|
||||
if end == max {
|
||||
// If insertAt is larger than the length, then the message is older than
|
||||
// every other messages we have. We have to discard this message here,
|
||||
// since the store is already full.
|
||||
if insertAt == end {
|
||||
return nil
|
||||
if pos := messageInsertPosition(message, msgs.messages); pos < 0 {
|
||||
// Messages are full, drop the oldest messages to make room.
|
||||
if len(msgs.messages) == s.maxMsgs {
|
||||
copy(msgs.messages[1:], msgs.messages)
|
||||
msgs.messages[0] = message
|
||||
} else {
|
||||
msgs.messages = append([]discord.Message{message}, msgs.messages...)
|
||||
}
|
||||
|
||||
// If the end (length) is approaching the maximum amount, then cap it.
|
||||
end = max
|
||||
} else {
|
||||
// Else, append an empty message to the end.
|
||||
msgs.messages = append(msgs.messages, discord.Message{})
|
||||
// Increment to update the length.
|
||||
end++
|
||||
} else if pos > 0 && len(msgs.messages) < s.maxMsgs {
|
||||
msgs.messages = append(msgs.messages, message)
|
||||
}
|
||||
|
||||
// Shift the slice right-wards if the current item is not the last.
|
||||
if start := insertAt + 1; start < end {
|
||||
copy(msgs.messages[insertAt+1:], msgs.messages[insertAt:end-1])
|
||||
}
|
||||
|
||||
// Then, set the nth entry.
|
||||
msgs.messages[insertAt] = message
|
||||
|
||||
// We already have this message or we can't append any more messages.
|
||||
return nil
|
||||
}
|
||||
|
||||
// messageInsertPosition checks if the message should be appended or prepended
|
||||
// into the passed messages, ordered by time of creation from latest to oldest.
|
||||
// If the message should be prepended, messageInsertPosition returns -1, and if
|
||||
// the message should be appended it returns 1. As a third option it returns 0,
|
||||
// if the message should not be added to the slice, because it would disrupt
|
||||
// the order.
|
||||
//
|
||||
// messageInsertPosition is biased as it will recommend adding the message even
|
||||
// if timestamps just match, even though the true order cannot be determined in
|
||||
// that case.
|
||||
func messageInsertPosition(target discord.Message, messages []discord.Message) int8 {
|
||||
var (
|
||||
targetTime = target.ID.Time()
|
||||
firstTime = messages[0].ID.Time()
|
||||
lastTime = messages[len(messages)-1].ID.Time()
|
||||
)
|
||||
|
||||
if targetTime.After(firstTime) {
|
||||
return -1
|
||||
} else if targetTime.Before(lastTime) {
|
||||
return 1
|
||||
}
|
||||
|
||||
// Two cases remain, the timestamp is equal to either the latest or oldest
|
||||
// message, or the message is already contained in message.
|
||||
// So we compare timestamps. If they are equal, make sure messages doesn't
|
||||
// contain a message with the same id, in order to prevent insertion of a
|
||||
// duplicate. If they are not equal, we return 0 as the message would
|
||||
// violate the order of messages.
|
||||
// ID timestamps are used, as they provide millisecond accuracy in contrast
|
||||
// to the second accuracy of discord.Message.Timestamp.
|
||||
if targetTime.Equal(firstTime) {
|
||||
// Only iterate as long as timestamps are equal, or there are no more
|
||||
// messages.
|
||||
for i := 0; i < len(messages) && targetTime.Equal(messages[i].ID.Time()); i++ {
|
||||
// Duplicate, don't insert.
|
||||
if messages[i].ID == target.ID {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// No duplicate of message found, so safe to prepend.
|
||||
return -1
|
||||
} else if targetTime.Equal(lastTime) {
|
||||
// Only iterate as long as timestamps are equal, or there are no more
|
||||
// messages.
|
||||
for i := len(messages) - 1; i >= 0 && targetTime.Equal(messages[i].ID.Time()); i-- {
|
||||
// Duplicate, don't insert.
|
||||
if messages[i].ID == target.ID {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// No duplicate of message found, so safe to append.
|
||||
return 1
|
||||
}
|
||||
|
||||
// Message would violate the order of messages, don't add it.
|
||||
return 0
|
||||
}
|
||||
|
||||
// DiffMessage fills non-empty fields from src to dst.
|
||||
func DiffMessage(src discord.Message, dst *discord.Message) {
|
||||
// Thanks, Discord.
|
||||
|
|
|
|||
|
|
@ -10,23 +10,27 @@ func populate12Store() *Message {
|
|||
store := NewMessage(10)
|
||||
|
||||
// Insert a regular list of messages.
|
||||
store.MessageSet(discord.Message{ID: 11, ChannelID: 1})
|
||||
store.MessageSet(discord.Message{ID: 9, ChannelID: 1})
|
||||
store.MessageSet(discord.Message{ID: 7, ChannelID: 1})
|
||||
store.MessageSet(discord.Message{ID: 5, ChannelID: 1})
|
||||
store.MessageSet(discord.Message{ID: 3, ChannelID: 1})
|
||||
store.MessageSet(discord.Message{ID: 1, ChannelID: 1})
|
||||
store.MessageSet(discord.Message{ID: 1 << 29, ChannelID: 1}, false)
|
||||
store.MessageSet(discord.Message{ID: 1 << 28, ChannelID: 1}, false)
|
||||
store.MessageSet(discord.Message{ID: 1 << 27, ChannelID: 1}, false)
|
||||
store.MessageSet(discord.Message{ID: 1 << 26, ChannelID: 1}, false)
|
||||
store.MessageSet(discord.Message{ID: 1 << 25, ChannelID: 1}, false)
|
||||
store.MessageSet(discord.Message{ID: 1 << 24, ChannelID: 1}, false)
|
||||
|
||||
// Try to insert newer messages after inserting new messages.
|
||||
store.MessageSet(discord.Message{ID: 12, ChannelID: 1})
|
||||
store.MessageSet(discord.Message{ID: 10, ChannelID: 1})
|
||||
store.MessageSet(discord.Message{ID: 8, ChannelID: 1})
|
||||
store.MessageSet(discord.Message{ID: 6, ChannelID: 1})
|
||||
store.MessageSet(discord.Message{ID: 4, ChannelID: 1})
|
||||
store.MessageSet(discord.Message{ID: 1 << 30, ChannelID: 1}, false)
|
||||
store.MessageSet(discord.Message{ID: 1 << 31, ChannelID: 1}, false)
|
||||
store.MessageSet(discord.Message{ID: 1 << 32, ChannelID: 1}, false)
|
||||
store.MessageSet(discord.Message{ID: 1 << 33, ChannelID: 1}, false)
|
||||
store.MessageSet(discord.Message{ID: 1 << 34, ChannelID: 1}, false)
|
||||
|
||||
// These messages should be discarded.
|
||||
store.MessageSet(discord.Message{ID: 2, ChannelID: 1})
|
||||
store.MessageSet(discord.Message{ID: 0, ChannelID: 1})
|
||||
// TThese messages should be discarded, due to age.
|
||||
store.MessageSet(discord.Message{ID: 1 << 23, ChannelID: 1}, false)
|
||||
store.MessageSet(discord.Message{ID: 1 << 22, ChannelID: 1}, false)
|
||||
|
||||
// These should be prepended.
|
||||
store.MessageSet(discord.Message{ID: 1 << 35, ChannelID: 1}, false)
|
||||
store.MessageSet(discord.Message{ID: 1 << 36, ChannelID: 1}, false)
|
||||
|
||||
return store
|
||||
}
|
||||
|
|
@ -35,18 +39,17 @@ func TestMessageSet(t *testing.T) {
|
|||
store := populate12Store()
|
||||
|
||||
messages, _ := store.Messages(1)
|
||||
if len(messages) < store.MaxMessages() {
|
||||
t.Errorf("store can store %d messages, but only returned %d", store.MaxMessages(),
|
||||
len(messages))
|
||||
}
|
||||
|
||||
const (
|
||||
start discord.MessageID = 2
|
||||
end discord.MessageID = 12
|
||||
)
|
||||
maxShift := 36
|
||||
|
||||
for i := start; i < end; i++ {
|
||||
index := i - start
|
||||
expect := end - i + start
|
||||
|
||||
if msgID := messages[index].ID; msgID != expect {
|
||||
t.Errorf("message at %d has mismatch ID %d, expecting %d", i, msgID, expect)
|
||||
for i, actual := range messages {
|
||||
expectID := discord.MessageID(1) << (maxShift - i)
|
||||
if actual.ID != expectID {
|
||||
t.Errorf("message at %d has mismatch ID %d, expecting %d", i, actual.ID, expectID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -54,9 +57,9 @@ func TestMessageSet(t *testing.T) {
|
|||
func TestMessagesUpdate(t *testing.T) {
|
||||
store := populate12Store()
|
||||
|
||||
store.MessageSet(discord.Message{ID: 5, ChannelID: 1, Content: "edited 1"})
|
||||
store.MessageSet(discord.Message{ID: 6, ChannelID: 1, Content: "edited 2"})
|
||||
store.MessageSet(discord.Message{ID: 5, ChannelID: 1, Content: "edited 3"})
|
||||
store.MessageSet(discord.Message{ID: 5, ChannelID: 1, Content: "edited 1"}, true)
|
||||
store.MessageSet(discord.Message{ID: 6, ChannelID: 1, Content: "edited 2"}, true)
|
||||
store.MessageSet(discord.Message{ID: 5, ChannelID: 1, Content: "edited 3"}, true)
|
||||
|
||||
expect := map[discord.MessageID]string{
|
||||
5: "edited 3",
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ func (s *Presence) Presences(guildID discord.GuildID) ([]gateway.Presence, error
|
|||
return presences, nil
|
||||
}
|
||||
|
||||
func (s *Presence) PresenceSet(guildID discord.GuildID, presence gateway.Presence) error {
|
||||
func (s *Presence) PresenceSet(guildID discord.GuildID, p gateway.Presence, update bool) error {
|
||||
iv, _ := s.guilds.LoadOrStore(guildID)
|
||||
|
||||
ps := iv.(*presences)
|
||||
|
|
@ -85,7 +85,9 @@ func (s *Presence) PresenceSet(guildID discord.GuildID, presence gateway.Presenc
|
|||
ps.presences = make(map[discord.UserID]gateway.Presence, 1)
|
||||
}
|
||||
|
||||
ps.presences[presence.User.ID] = presence
|
||||
if _, ok := ps.presences[p.User.ID]; !ok || update {
|
||||
ps.presences[p.User.ID] = p
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,13 +71,15 @@ func (s *Role) Roles(guildID discord.GuildID) ([]discord.Role, error) {
|
|||
return roles, nil
|
||||
}
|
||||
|
||||
func (s *Role) RoleSet(guildID discord.GuildID, role discord.Role) error {
|
||||
func (s *Role) RoleSet(guildID discord.GuildID, role discord.Role, update bool) error {
|
||||
iv, _ := s.guilds.LoadOrStore(guildID)
|
||||
|
||||
rs := iv.(*roles)
|
||||
|
||||
rs.mut.Lock()
|
||||
rs.roles[role.ID] = role
|
||||
if _, ok := rs.roles[role.ID]; !ok || update {
|
||||
rs.roles[role.ID] = role
|
||||
}
|
||||
rs.mut.Unlock()
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -73,13 +73,17 @@ func (s *VoiceState) VoiceStates(guildID discord.GuildID) ([]discord.VoiceState,
|
|||
return states, nil
|
||||
}
|
||||
|
||||
func (s *VoiceState) VoiceStateSet(guildID discord.GuildID, voiceState discord.VoiceState) error {
|
||||
func (s *VoiceState) VoiceStateSet(
|
||||
guildID discord.GuildID, voiceState discord.VoiceState, update bool) error {
|
||||
|
||||
iv, _ := s.guilds.LoadOrStore(guildID)
|
||||
|
||||
vs := iv.(*voiceStates)
|
||||
|
||||
vs.mut.Lock()
|
||||
vs.voiceStates[voiceState.UserID] = voiceState
|
||||
if _, ok := vs.voiceStates[voiceState.UserID]; !ok || update {
|
||||
vs.voiceStates[voiceState.UserID] = voiceState
|
||||
}
|
||||
vs.mut.Unlock()
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ func (errs *ResetErrors) append(err error) {
|
|||
// Noop is the value for a NoopStore.
|
||||
var Noop = NoopStore{}
|
||||
|
||||
// Noop is a no-op implementation of all store interfaces. Its getters will
|
||||
// NoopStore is a no-op implementation of all store interfaces. Its getters will
|
||||
// always return ErrNotFound, and its setters will never return an error.
|
||||
type NoopStore = noop
|
||||
|
||||
|
|
@ -153,19 +153,19 @@ type MeStore interface {
|
|||
Resetter
|
||||
|
||||
Me() (*discord.User, error)
|
||||
MyselfSet(me discord.User) error
|
||||
MyselfSet(me discord.User, update bool) error
|
||||
}
|
||||
|
||||
func (noop) Me() (*discord.User, error) { return nil, ErrNotFound }
|
||||
func (noop) MyselfSet(discord.User) error { return nil }
|
||||
func (noop) Me() (*discord.User, error) { return nil, ErrNotFound }
|
||||
func (noop) MyselfSet(discord.User, bool) error { return nil }
|
||||
|
||||
// ChannelStore is the store interface for all channels.
|
||||
type ChannelStore interface {
|
||||
Resetter
|
||||
|
||||
// ChannelStore searches for both DM and guild channels.
|
||||
// Channel searches for both DM and guild channels.
|
||||
Channel(discord.ChannelID) (*discord.Channel, error)
|
||||
// CreatePrivateChannelStore searches for private channels by the recipient ID.
|
||||
// CreatePrivateChannel searches for private channels by the recipient ID.
|
||||
// It has the same API as *api.Client does.
|
||||
CreatePrivateChannel(recipient discord.UserID) (*discord.Channel, error)
|
||||
|
||||
|
|
@ -177,7 +177,7 @@ type ChannelStore interface {
|
|||
// Both ChannelSet and ChannelRemove should switch on Type to know if it's a
|
||||
// private channel or not.
|
||||
|
||||
ChannelSet(discord.Channel) error
|
||||
ChannelSet(c discord.Channel, update bool) error
|
||||
ChannelRemove(discord.Channel) error
|
||||
}
|
||||
|
||||
|
|
@ -195,7 +195,7 @@ func (noop) Channels(discord.GuildID) ([]discord.Channel, error) {
|
|||
func (noop) PrivateChannels() ([]discord.Channel, error) {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
func (noop) ChannelSet(discord.Channel) error {
|
||||
func (noop) ChannelSet(discord.Channel, bool) error {
|
||||
return nil
|
||||
}
|
||||
func (noop) ChannelRemove(discord.Channel) error {
|
||||
|
|
@ -211,7 +211,7 @@ type EmojiStore interface {
|
|||
|
||||
// EmojiSet should delete all old emojis before setting new ones. The given
|
||||
// emojis slice will be a complete list of all emojis.
|
||||
EmojiSet(discord.GuildID, []discord.Emoji) error
|
||||
EmojiSet(guildID discord.GuildID, emojis []discord.Emoji, update bool) error
|
||||
}
|
||||
|
||||
var _ EmojiStore = (*noop)(nil)
|
||||
|
|
@ -222,7 +222,7 @@ func (noop) Emoji(discord.GuildID, discord.EmojiID) (*discord.Emoji, error) {
|
|||
func (noop) Emojis(discord.GuildID) ([]discord.Emoji, error) {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
func (noop) EmojiSet(discord.GuildID, []discord.Emoji) error {
|
||||
func (noop) EmojiSet(discord.GuildID, []discord.Emoji, bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -233,7 +233,7 @@ type GuildStore interface {
|
|||
Guild(discord.GuildID) (*discord.Guild, error)
|
||||
Guilds() ([]discord.Guild, error)
|
||||
|
||||
GuildSet(discord.Guild) error
|
||||
GuildSet(g discord.Guild, update bool) error
|
||||
GuildRemove(id discord.GuildID) error
|
||||
}
|
||||
|
||||
|
|
@ -241,7 +241,7 @@ var _ GuildStore = (*noop)(nil)
|
|||
|
||||
func (noop) Guild(discord.GuildID) (*discord.Guild, error) { return nil, ErrNotFound }
|
||||
func (noop) Guilds() ([]discord.Guild, error) { return nil, ErrNotFound }
|
||||
func (noop) GuildSet(discord.Guild) error { return nil }
|
||||
func (noop) GuildSet(discord.Guild, bool) error { return nil }
|
||||
func (noop) GuildRemove(discord.GuildID) error { return nil }
|
||||
|
||||
// MemberStore is the store interface for all members.
|
||||
|
|
@ -251,7 +251,7 @@ type MemberStore interface {
|
|||
Member(discord.GuildID, discord.UserID) (*discord.Member, error)
|
||||
Members(discord.GuildID) ([]discord.Member, error)
|
||||
|
||||
MemberSet(discord.GuildID, discord.Member) error
|
||||
MemberSet(guildID discord.GuildID, m discord.Member, update bool) error
|
||||
MemberRemove(discord.GuildID, discord.UserID) error
|
||||
}
|
||||
|
||||
|
|
@ -263,7 +263,7 @@ func (noop) Member(discord.GuildID, discord.UserID) (*discord.Member, error) {
|
|||
func (noop) Members(discord.GuildID) ([]discord.Member, error) {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
func (noop) MemberSet(discord.GuildID, discord.Member) error {
|
||||
func (noop) MemberSet(discord.GuildID, discord.Member, bool) error {
|
||||
return nil
|
||||
}
|
||||
func (noop) MemberRemove(discord.GuildID, discord.UserID) error {
|
||||
|
|
@ -282,9 +282,15 @@ type MessageStore interface {
|
|||
// Messages should return messages ordered from latest to earliest.
|
||||
Messages(discord.ChannelID) ([]discord.Message, error)
|
||||
|
||||
// MessageSet should prepend messages into the slice, the latest being in
|
||||
// front.
|
||||
MessageSet(discord.Message) error
|
||||
// MessageSet either updates or adds a new message.
|
||||
//
|
||||
// A new message can be added, by setting update to false. Depending on
|
||||
// timestamp of the message, it will either be prepended or appended.
|
||||
//
|
||||
// If update is set to true, MessageSet will check if a message with the
|
||||
// id of the passed message is stored, and update it if so. Otherwise, if
|
||||
// there is no such message, it will be discarded.
|
||||
MessageSet(m discord.Message, update bool) error
|
||||
MessageRemove(discord.ChannelID, discord.MessageID) error
|
||||
}
|
||||
|
||||
|
|
@ -299,7 +305,7 @@ func (noop) Message(discord.ChannelID, discord.MessageID) (*discord.Message, err
|
|||
func (noop) Messages(discord.ChannelID) ([]discord.Message, error) {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
func (noop) MessageSet(discord.Message) error {
|
||||
func (noop) MessageSet(discord.Message, bool) error {
|
||||
return nil
|
||||
}
|
||||
func (noop) MessageRemove(discord.ChannelID, discord.MessageID) error {
|
||||
|
|
@ -314,7 +320,7 @@ type PresenceStore interface {
|
|||
Presence(discord.GuildID, discord.UserID) (*gateway.Presence, error)
|
||||
Presences(discord.GuildID) ([]gateway.Presence, error)
|
||||
|
||||
PresenceSet(discord.GuildID, gateway.Presence) error
|
||||
PresenceSet(guildID discord.GuildID, p gateway.Presence, update bool) error
|
||||
PresenceRemove(discord.GuildID, discord.UserID) error
|
||||
}
|
||||
|
||||
|
|
@ -326,7 +332,7 @@ func (noop) Presence(discord.GuildID, discord.UserID) (*gateway.Presence, error)
|
|||
func (noop) Presences(discord.GuildID) ([]gateway.Presence, error) {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
func (noop) PresenceSet(discord.GuildID, gateway.Presence) error {
|
||||
func (noop) PresenceSet(discord.GuildID, gateway.Presence, bool) error {
|
||||
return nil
|
||||
}
|
||||
func (noop) PresenceRemove(discord.GuildID, discord.UserID) error {
|
||||
|
|
@ -340,7 +346,7 @@ type RoleStore interface {
|
|||
Role(discord.GuildID, discord.RoleID) (*discord.Role, error)
|
||||
Roles(discord.GuildID) ([]discord.Role, error)
|
||||
|
||||
RoleSet(discord.GuildID, discord.Role) error
|
||||
RoleSet(guildID discord.GuildID, r discord.Role, update bool) error
|
||||
RoleRemove(discord.GuildID, discord.RoleID) error
|
||||
}
|
||||
|
||||
|
|
@ -348,7 +354,7 @@ var _ RoleStore = (*noop)(nil)
|
|||
|
||||
func (noop) Role(discord.GuildID, discord.RoleID) (*discord.Role, error) { return nil, ErrNotFound }
|
||||
func (noop) Roles(discord.GuildID) ([]discord.Role, error) { return nil, ErrNotFound }
|
||||
func (noop) RoleSet(discord.GuildID, discord.Role) error { return nil }
|
||||
func (noop) RoleSet(discord.GuildID, discord.Role, bool) error { return nil }
|
||||
func (noop) RoleRemove(discord.GuildID, discord.RoleID) error { return nil }
|
||||
|
||||
// VoiceStateStore is the store interface for all voice states.
|
||||
|
|
@ -358,7 +364,7 @@ type VoiceStateStore interface {
|
|||
VoiceState(discord.GuildID, discord.UserID) (*discord.VoiceState, error)
|
||||
VoiceStates(discord.GuildID) ([]discord.VoiceState, error)
|
||||
|
||||
VoiceStateSet(discord.GuildID, discord.VoiceState) error
|
||||
VoiceStateSet(guildID discord.GuildID, s discord.VoiceState, update bool) error
|
||||
VoiceStateRemove(discord.GuildID, discord.UserID) error
|
||||
}
|
||||
|
||||
|
|
@ -370,7 +376,7 @@ func (noop) VoiceState(discord.GuildID, discord.UserID) (*discord.VoiceState, er
|
|||
func (noop) VoiceStates(discord.GuildID) ([]discord.VoiceState, error) {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
func (noop) VoiceStateSet(discord.GuildID, discord.VoiceState) error {
|
||||
func (noop) VoiceStateSet(discord.GuildID, discord.VoiceState, bool) error {
|
||||
return nil
|
||||
}
|
||||
func (noop) VoiceStateRemove(discord.GuildID, discord.UserID) error {
|
||||
|
|
|
|||
Loading…
Reference in a new issue