123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- package model
-
- import (
- "encoding/json"
- "sort"
- "sync"
- "time"
- )
-
- // Timeline encapsulates a collection of ordered Messages, and a mechanism to access them
- // in a threadsafe manner.
- type Timeline struct {
- Messages []Message
- SignedGroupID []byte
- lock sync.Mutex
- }
-
- // Message is a local representation of a given message sent over a group chat channel.
- type Message struct {
- Timestamp time.Time
- Received time.Time
- PeerID string
- Message string
- Signature []byte
- PreviousMessageSig []byte
- ReceivedByServer bool // messages sent to a server
- Acknowledged bool // peer to peer
- Error string `json:",omitempty"`
- }
-
- // MessageBaseSize is a rough estimate of the base number of bytes the struct uses before strings are populated
- const MessageBaseSize = 104
-
- 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
- }
-
- // GetMessages returns a copy of the entire timeline
- func (t *Timeline) GetMessages() []Message {
- t.lock.Lock()
- messages := make([]Message, len(t.Messages))
- copy(messages[:], t.Messages[:])
- t.lock.Unlock()
- return messages
- }
-
- // GetCopy returns a duplicate of the Timeline
- func (t *Timeline) GetCopy() *Timeline {
- t.lock.Lock()
- defer t.lock.Unlock()
- bytes, _ := json.Marshal(t)
- newt := &Timeline{}
- json.Unmarshal(bytes, newt)
- return newt
- }
-
- // SetMessages sets the Messages of this timeline. Only to be used in loading/initialization
- func (t *Timeline) SetMessages(messages []Message) {
- t.lock.Lock()
- defer t.lock.Unlock()
- t.Messages = messages
- }
-
- // Len gets the length of the timeline
- func (t *Timeline) Len() int {
- return len(t.Messages)
- }
-
- // Swap swaps 2 Messages on the timeline.
- func (t *Timeline) Swap(i, j int) {
- t.Messages[i], t.Messages[j] = t.Messages[j], t.Messages[i]
- }
-
- // Less checks 2 Messages (i and j) in the timeline and returns true if i occurred before j, else false
- func (t *Timeline) Less(i, j int) bool {
-
- if t.Messages[i].Timestamp.Before(t.Messages[j].Timestamp) {
- return true
- }
-
- // Short circuit false if j is before i, signature checks will give a wrong order in this case.
- if t.Messages[j].Timestamp.Before(t.Messages[i].Timestamp) {
- return false
- }
-
- if compareSignatures(t.Messages[i].PreviousMessageSig, t.SignedGroupID) {
- return true
- }
-
- if compareSignatures(t.Messages[i].Signature, t.Messages[j].PreviousMessageSig) {
- return true
- }
-
- return false
- }
-
- // 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)
- }
-
- // Insert inserts a message into the timeline in a thread safe way.
- func (t *Timeline) Insert(mi *Message) bool {
- t.lock.Lock()
- defer t.lock.Unlock()
-
- for _, m := range t.Messages {
- // If the message already exists, then we don't add it
- if compareSignatures(m.Signature, mi.Signature) {
- return true
- }
- }
-
- t.Messages = append(t.Messages, *mi)
- sort.Sort(t)
- return false
- }
|