1
0
Fork 0
mirror of https://github.com/diamondburned/arikawa.git synced 2025-03-23 02:19:22 +00:00

State: Guarantee message order in store

This commit is contained in:
diamondburned 2021-02-25 23:57:45 -08:00
parent f5dc90c2d4
commit 1ffbde98c5
2 changed files with 109 additions and 9 deletions

View file

@ -81,7 +81,6 @@ func (s *Message) MessageSet(message discord.Message) error {
msgs.mut.Lock()
defer msgs.mut.Unlock()
// Check if we already have the message.
for i, m := range msgs.messages {
if m.ID == message.ID {
DiffMessage(message, &m)
@ -92,9 +91,33 @@ func (s *Message) MessageSet(message discord.Message) error {
// Order: latest to earliest, similar to the API.
var end = len(msgs.messages)
if max := s.MaxMessages(); end >= max {
// If the end (length) is larger than the maximum amount, then cap it.
// 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
}
insertAt++
}
end := len(msgs.messages)
max := s.MaxMessages()
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 the end (length) is approaching the maximum amount, then cap it.
end = max
} else {
// Else, append an empty message to the end.
@ -103,11 +126,13 @@ func (s *Message) MessageSet(message discord.Message) error {
end++
}
// Copy hack to prepend. This copies the 0th-(end-1)th entries to
// 1st-endth.
copy(msgs.messages[1:end], msgs.messages[0:end-1])
// Then, set the 0th entry.
msgs.messages[0] = 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
return nil
}

View file

@ -0,0 +1,75 @@
package defaultstore
import (
"testing"
"github.com/diamondburned/arikawa/v2/discord"
)
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})
// 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})
// These messages should be discarded.
store.MessageSet(discord.Message{ID: 2, ChannelID: 1})
store.MessageSet(discord.Message{ID: 0, ChannelID: 1})
return store
}
func TestMessageSet(t *testing.T) {
store := populate12Store()
messages, _ := store.Messages(1)
const (
start discord.MessageID = 2
end discord.MessageID = 12
)
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)
}
}
}
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"})
expect := map[discord.MessageID]string{
5: "edited 3",
6: "edited 2",
}
messages, _ := store.Messages(1)
for i := 0; i < store.MaxMessages(); i++ {
msg := messages[i]
content, ok := expect[msg.ID]
if ok && msg.Content != content {
t.Errorf("id %d expected %q, got %q", i, content, msg.Content)
}
}
}