2018-03-09 20:44:13 +00:00
|
|
|
package model
|
|
|
|
|
|
|
|
import (
|
2018-04-28 17:52:59 +00:00
|
|
|
"sort"
|
2018-04-02 21:10:29 +00:00
|
|
|
"sync"
|
2018-03-09 20:44:13 +00:00
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
2019-02-03 01:18:33 +00:00
|
|
|
// Timeline encapsulates a collection of ordered Messages, and a mechanism to access them
|
2018-05-16 20:53:09 +00:00
|
|
|
// in a threadsafe manner.
|
2018-04-02 21:10:29 +00:00
|
|
|
type Timeline struct {
|
2019-02-03 01:18:33 +00:00
|
|
|
Messages []Message
|
2018-06-15 16:21:07 +00:00
|
|
|
SignedGroupID []byte
|
2018-05-28 17:44:47 +00:00
|
|
|
lock sync.Mutex
|
2018-04-02 21:10:29 +00:00
|
|
|
}
|
|
|
|
|
2018-03-15 16:33:26 +00:00
|
|
|
// Message is a local representation of a given message sent over a group chat channel.
|
2018-03-09 20:44:13 +00:00
|
|
|
type Message struct {
|
2018-04-02 21:10:29 +00:00
|
|
|
Timestamp time.Time
|
2018-05-09 19:09:00 +00:00
|
|
|
Received time.Time
|
2018-04-02 21:10:29 +00:00
|
|
|
PeerID string
|
|
|
|
Message string
|
|
|
|
Signature []byte
|
|
|
|
PreviousMessageSig []byte
|
|
|
|
}
|
|
|
|
|
2019-01-29 20:56:59 +00:00
|
|
|
// MessageBaseSize is a rough estimate of the base number of bytes the struct uses before strings are populated
|
|
|
|
const MessageBaseSize = 104
|
|
|
|
|
2018-04-02 21:10:29 +00:00
|
|
|
func compareSignatures(a []byte, b []byte) bool {
|
|
|
|
if len(a) != len(b) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
for i := range a {
|
|
|
|
if a[i] != b[i] {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2018-06-15 16:21:07 +00:00
|
|
|
// GetMessages returns a copy of the entire timeline
|
2018-05-20 19:58:16 +00:00
|
|
|
func (t *Timeline) GetMessages() []Message {
|
2018-05-20 18:29:46 +00:00
|
|
|
t.lock.Lock()
|
2019-02-03 01:18:33 +00:00
|
|
|
messages := make([]Message, len(t.Messages))
|
|
|
|
copy(messages[:], t.Messages[:])
|
2018-05-20 18:29:46 +00:00
|
|
|
t.lock.Unlock()
|
2018-05-20 19:58:16 +00:00
|
|
|
return messages
|
2018-05-20 18:29:46 +00:00
|
|
|
}
|
|
|
|
|
2019-02-03 01:18:33 +00:00
|
|
|
// SetMessages sets the Messages of this timeline. Only to be used in loading/initialization
|
2019-01-29 20:56:59 +00:00
|
|
|
func (t *Timeline) SetMessages(messages []Message) {
|
|
|
|
t.lock.Lock()
|
|
|
|
defer t.lock.Unlock()
|
2019-02-03 01:18:33 +00:00
|
|
|
t.Messages = messages
|
2019-01-29 20:56:59 +00:00
|
|
|
}
|
|
|
|
|
2018-05-16 20:53:09 +00:00
|
|
|
// Len gets the length of the timeline
|
2018-05-20 18:29:46 +00:00
|
|
|
func (t *Timeline) Len() int {
|
2019-02-03 01:18:33 +00:00
|
|
|
return len(t.Messages)
|
2018-04-28 17:52:59 +00:00
|
|
|
}
|
2018-05-16 20:53:09 +00:00
|
|
|
|
2019-02-03 01:18:33 +00:00
|
|
|
// Swap swaps 2 Messages on the timeline.
|
2018-05-20 18:29:46 +00:00
|
|
|
func (t *Timeline) Swap(i, j int) {
|
2019-02-03 01:18:33 +00:00
|
|
|
t.Messages[i], t.Messages[j] = t.Messages[j], t.Messages[i]
|
2018-04-28 17:52:59 +00:00
|
|
|
}
|
2018-05-16 20:53:09 +00:00
|
|
|
|
2019-02-03 01:18:33 +00:00
|
|
|
// Less checks 2 Messages (i and j) in the timeline and returns true if i occurred before j, else false
|
2018-05-20 18:29:46 +00:00
|
|
|
func (t *Timeline) Less(i, j int) bool {
|
2018-04-02 21:10:29 +00:00
|
|
|
|
2019-02-03 01:18:33 +00:00
|
|
|
if t.Messages[i].Timestamp.Before(t.Messages[j].Timestamp) {
|
2018-12-03 19:12:34 +00:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// Short circuit false if j is before i, signature checks will give a wrong order in this case.
|
2019-02-03 01:18:33 +00:00
|
|
|
if t.Messages[j].Timestamp.Before(t.Messages[i].Timestamp) {
|
2018-11-21 21:23:59 +00:00
|
|
|
return false
|
2018-04-28 17:52:59 +00:00
|
|
|
}
|
2018-04-02 21:10:29 +00:00
|
|
|
|
2019-02-03 01:18:33 +00:00
|
|
|
if compareSignatures(t.Messages[i].PreviousMessageSig, t.SignedGroupID) {
|
2018-04-28 17:52:59 +00:00
|
|
|
return true
|
2018-04-02 21:10:29 +00:00
|
|
|
}
|
|
|
|
|
2019-02-03 01:18:33 +00:00
|
|
|
if compareSignatures(t.Messages[i].Signature, t.Messages[j].PreviousMessageSig) {
|
2018-04-28 17:52:59 +00:00
|
|
|
return true
|
2018-04-02 21:10:29 +00:00
|
|
|
}
|
2018-04-28 17:52:59 +00:00
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2018-12-03 19:12:34 +00:00
|
|
|
// Sort sorts the timeline in a canonical order.
|
|
|
|
// TODO: There is almost definitely a more efficient way of doing things that involve not calling this method on every timeline load.
|
|
|
|
func (t *Timeline) Sort() {
|
|
|
|
t.lock.Lock()
|
|
|
|
defer t.lock.Unlock()
|
|
|
|
sort.Sort(t)
|
|
|
|
}
|
|
|
|
|
2018-05-16 20:53:09 +00:00
|
|
|
// Insert inserts a message into the timeline in a thread safe way.
|
2018-10-05 03:18:34 +00:00
|
|
|
func (t *Timeline) Insert(mi *Message) bool {
|
2018-04-28 17:52:59 +00:00
|
|
|
t.lock.Lock()
|
2018-06-03 19:02:42 +00:00
|
|
|
defer t.lock.Unlock()
|
2018-05-03 04:12:45 +00:00
|
|
|
|
2019-02-03 01:18:33 +00:00
|
|
|
for _, m := range t.Messages {
|
2018-06-03 19:02:42 +00:00
|
|
|
// If the message already exists, then we don't add it
|
2018-05-03 04:12:45 +00:00
|
|
|
if compareSignatures(m.Signature, mi.Signature) {
|
2018-10-05 03:18:34 +00:00
|
|
|
return true
|
2018-05-03 04:12:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-03 01:18:33 +00:00
|
|
|
t.Messages = append(t.Messages, *mi)
|
2018-04-28 17:52:59 +00:00
|
|
|
sort.Sort(t)
|
2018-10-05 03:18:34 +00:00
|
|
|
return false
|
2018-03-09 20:44:13 +00:00
|
|
|
}
|