Official cwtch.im peer and server implementations. https://cwtch.im
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

message.go 3.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. package model
  2. import (
  3. "encoding/json"
  4. "sort"
  5. "sync"
  6. "time"
  7. )
  8. // Timeline encapsulates a collection of ordered Messages, and a mechanism to access them
  9. // in a threadsafe manner.
  10. type Timeline struct {
  11. Messages []Message
  12. SignedGroupID []byte
  13. lock sync.Mutex
  14. }
  15. // Message is a local representation of a given message sent over a group chat channel.
  16. type Message struct {
  17. Timestamp time.Time
  18. Received time.Time
  19. PeerID string
  20. Message string
  21. Signature []byte
  22. PreviousMessageSig []byte
  23. }
  24. // MessageBaseSize is a rough estimate of the base number of bytes the struct uses before strings are populated
  25. const MessageBaseSize = 104
  26. func compareSignatures(a []byte, b []byte) bool {
  27. if len(a) != len(b) {
  28. return false
  29. }
  30. for i := range a {
  31. if a[i] != b[i] {
  32. return false
  33. }
  34. }
  35. return true
  36. }
  37. // GetMessages returns a copy of the entire timeline
  38. func (t *Timeline) GetMessages() []Message {
  39. t.lock.Lock()
  40. messages := make([]Message, len(t.Messages))
  41. copy(messages[:], t.Messages[:])
  42. t.lock.Unlock()
  43. return messages
  44. }
  45. // GetCopy returns a duplicate of the Timeline
  46. func (t *Timeline) GetCopy() *Timeline {
  47. t.lock.Lock()
  48. defer t.lock.Unlock()
  49. bytes, _ := json.Marshal(t)
  50. newt := &Timeline{}
  51. json.Unmarshal(bytes, newt)
  52. return newt
  53. }
  54. // SetMessages sets the Messages of this timeline. Only to be used in loading/initialization
  55. func (t *Timeline) SetMessages(messages []Message) {
  56. t.lock.Lock()
  57. defer t.lock.Unlock()
  58. t.Messages = messages
  59. }
  60. // Len gets the length of the timeline
  61. func (t *Timeline) Len() int {
  62. return len(t.Messages)
  63. }
  64. // Swap swaps 2 Messages on the timeline.
  65. func (t *Timeline) Swap(i, j int) {
  66. t.Messages[i], t.Messages[j] = t.Messages[j], t.Messages[i]
  67. }
  68. // Less checks 2 Messages (i and j) in the timeline and returns true if i occurred before j, else false
  69. func (t *Timeline) Less(i, j int) bool {
  70. if t.Messages[i].Timestamp.Before(t.Messages[j].Timestamp) {
  71. return true
  72. }
  73. // Short circuit false if j is before i, signature checks will give a wrong order in this case.
  74. if t.Messages[j].Timestamp.Before(t.Messages[i].Timestamp) {
  75. return false
  76. }
  77. if compareSignatures(t.Messages[i].PreviousMessageSig, t.SignedGroupID) {
  78. return true
  79. }
  80. if compareSignatures(t.Messages[i].Signature, t.Messages[j].PreviousMessageSig) {
  81. return true
  82. }
  83. return false
  84. }
  85. // Sort sorts the timeline in a canonical order.
  86. // TODO: There is almost definitely a more efficient way of doing things that involve not calling this method on every timeline load.
  87. func (t *Timeline) Sort() {
  88. t.lock.Lock()
  89. defer t.lock.Unlock()
  90. sort.Sort(t)
  91. }
  92. // Insert inserts a message into the timeline in a thread safe way.
  93. func (t *Timeline) Insert(mi *Message) bool {
  94. t.lock.Lock()
  95. defer t.lock.Unlock()
  96. for _, m := range t.Messages {
  97. // If the message already exists, then we don't add it
  98. if compareSignatures(m.Signature, mi.Signature) {
  99. return true
  100. }
  101. }
  102. t.Messages = append(t.Messages, *mi)
  103. sort.Sort(t)
  104. return false
  105. }