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.

92 lines
2.0KB

  1. package model
  2. import (
  3. "sort"
  4. "sync"
  5. "time"
  6. )
  7. // Timeline encapsulates a collection of ordered messages, and a mechanism to access them
  8. // in a threadsafe manner.
  9. type Timeline struct {
  10. Messages []Message
  11. SignedGroupID []byte
  12. lock sync.Mutex
  13. }
  14. // Message is a local representation of a given message sent over a group chat channel.
  15. type Message struct {
  16. Timestamp time.Time
  17. Received time.Time
  18. PeerID string
  19. Message string
  20. Signature []byte
  21. Verified bool
  22. PreviousMessageSig []byte
  23. }
  24. func compareSignatures(a []byte, b []byte) bool {
  25. if len(a) != len(b) {
  26. return false
  27. }
  28. for i := range a {
  29. if a[i] != b[i] {
  30. return false
  31. }
  32. }
  33. return true
  34. }
  35. // GetMessages returns a copy of the entire timeline
  36. func (t *Timeline) GetMessages() []Message {
  37. t.lock.Lock()
  38. messages := make([]Message, len(t.Messages))
  39. copy(messages[:], t.Messages[:])
  40. t.lock.Unlock()
  41. return messages
  42. }
  43. // Len gets the length of the timeline
  44. func (t *Timeline) Len() int {
  45. return len(t.Messages)
  46. }
  47. // Swap swaps 2 messages on the timeline.
  48. func (t *Timeline) Swap(i, j int) {
  49. t.Messages[i], t.Messages[j] = t.Messages[j], t.Messages[i]
  50. }
  51. // Less checks 2 messages (i and j) in the timeline and returns true if i occcured before j, else false
  52. func (t *Timeline) Less(i, j int) bool {
  53. if t.Messages[i].Timestamp.Before(t.Messages[j].Timestamp) {
  54. return true
  55. }
  56. if compareSignatures(t.Messages[i].PreviousMessageSig, t.SignedGroupID) {
  57. return true
  58. }
  59. if compareSignatures(t.Messages[i].Signature, t.Messages[j].PreviousMessageSig) {
  60. return true
  61. }
  62. return false
  63. }
  64. // Insert inserts a message into the timeline in a thread safe way.
  65. func (t *Timeline) Insert(mi *Message) {
  66. t.lock.Lock()
  67. defer t.lock.Unlock()
  68. for _, m := range t.Messages {
  69. // If the message already exists, then we don't add it
  70. if compareSignatures(m.Signature, mi.Signature) {
  71. return
  72. }
  73. }
  74. t.Messages = append(t.Messages, *mi)
  75. sort.Sort(t)
  76. }