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:
parent
f5dc90c2d4
commit
1ffbde98c5
|
@ -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
|
||||
}
|
||||
|
|
75
state/store/defaultstore/message_test.go
Normal file
75
state/store/defaultstore/message_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue