mirror of https://github.com/velour/catbase.git
history: add history module
This commit is contained in:
parent
6a11ddc98a
commit
fc0c6ccd46
|
@ -0,0 +1,84 @@
|
||||||
|
package history
|
||||||
|
|
||||||
|
import (
|
||||||
|
"container/ring"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/velour/catbase/bot/msg"
|
||||||
|
)
|
||||||
|
|
||||||
|
// History is a ring buffer of messages
|
||||||
|
type History struct {
|
||||||
|
r *ring.Ring
|
||||||
|
}
|
||||||
|
|
||||||
|
// New returns a history of sz size
|
||||||
|
func New(sz int) *History {
|
||||||
|
return &History{ring.New(sz)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Edit looks for an entry and ammends it
|
||||||
|
// returns error if the id is not found
|
||||||
|
func (h *History) Edit(id string, update *msg.Message) error {
|
||||||
|
r := h.r
|
||||||
|
for i := 0; i < r.Len(); i++ {
|
||||||
|
m := r.Value.(*msg.Message)
|
||||||
|
if m != nil && m.ID == id {
|
||||||
|
r.Value = update
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
r = r.Next()
|
||||||
|
}
|
||||||
|
return fmt.Errorf("entry not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append adds a message to the history
|
||||||
|
func (h *History) Append(m *msg.Message) {
|
||||||
|
h.r.Value = m
|
||||||
|
h.r = h.r.Next()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find looks for an entry by id and returns an error if not found
|
||||||
|
func (h *History) Find(id string) (*msg.Message, error) {
|
||||||
|
r := h.r
|
||||||
|
for i := 0; i < r.Len(); i++ {
|
||||||
|
m := r.Value.(*msg.Message)
|
||||||
|
if m != nil && m.ID == id {
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
r = r.Next()
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("entry not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Last gets the last known message
|
||||||
|
func (h *History) Last() *msg.Message {
|
||||||
|
return h.r.Prev().Value.(*msg.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LastInChannel searches backwards for the last message matching channel ch
|
||||||
|
func (h *History) LastInChannel(ch string) (*msg.Message, error) {
|
||||||
|
r := h.r
|
||||||
|
for i := 0; i < r.Len(); i++ {
|
||||||
|
m := r.Value.(*msg.Message)
|
||||||
|
if m != nil && m.Channel == ch {
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
r = r.Prev()
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("entry not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
// InChannel returns all knows messages from channel ch in reverse order
|
||||||
|
func (h *History) InChannel(ch string) []*msg.Message {
|
||||||
|
out := []*msg.Message{}
|
||||||
|
r := h.r
|
||||||
|
for i := 0; i < r.Len(); i++ {
|
||||||
|
m := r.Value.(*msg.Message)
|
||||||
|
if m != nil && m.Channel == ch {
|
||||||
|
out = append(out, m)
|
||||||
|
}
|
||||||
|
r = r.Prev()
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
package history
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/velour/catbase/bot/msg"
|
||||||
|
)
|
||||||
|
|
||||||
|
var sampleMessages []*msg.Message
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
sampleMessages = []*msg.Message{}
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
txt := fmt.Sprintf("Message #%d", i)
|
||||||
|
m := &msg.Message{
|
||||||
|
ID: txt,
|
||||||
|
Body: txt,
|
||||||
|
}
|
||||||
|
|
||||||
|
sampleMessages = append(sampleMessages, m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAppend(t *testing.T) {
|
||||||
|
h := New(10)
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
h.Append(sampleMessages[i])
|
||||||
|
}
|
||||||
|
previous := h.r.Prev().Value.(*msg.Message)
|
||||||
|
assert.Equal(t, sampleMessages[9].ID, previous.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFindExists(t *testing.T) {
|
||||||
|
h := New(10)
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
h.Append(sampleMessages[i])
|
||||||
|
}
|
||||||
|
id := sampleMessages[5].ID
|
||||||
|
elt, err := h.Find(id)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, id, elt.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFindMissing(t *testing.T) {
|
||||||
|
h := New(10)
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
h.Append(sampleMessages[i])
|
||||||
|
}
|
||||||
|
id := sampleMessages[15].ID
|
||||||
|
elt, err := h.Find(id)
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
assert.Nil(t, elt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEditExists(t *testing.T) {
|
||||||
|
h := New(10)
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
h.Append(sampleMessages[i])
|
||||||
|
}
|
||||||
|
id := sampleMessages[5].ID
|
||||||
|
m := sampleMessages[15]
|
||||||
|
m.ID = id
|
||||||
|
err := h.Edit(id, m)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
actual, err := h.Find(id)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, m.Body, actual.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEditMissing(t *testing.T) {
|
||||||
|
h := New(10)
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
h.Append(sampleMessages[i])
|
||||||
|
}
|
||||||
|
id := sampleMessages[10].ID
|
||||||
|
m := sampleMessages[6]
|
||||||
|
t.Logf("id: %s, editID: %s", id, m.ID)
|
||||||
|
err := h.Edit(id, m)
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
}
|
Loading…
Reference in New Issue