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.

91 lines
1.9KB

  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. func (t *Timeline) GetMessages() []Message {
  36. t.lock.Lock()
  37. messages := make([]Message, len(t.Messages))
  38. copy(messages[:], t.Messages[:])
  39. t.lock.Unlock()
  40. return messages
  41. }
  42. // Len gets the length of the timeline
  43. func (t *Timeline) Len() int {
  44. return len(t.Messages)
  45. }
  46. // Swap swaps 2 messages on the timeline.
  47. func (t *Timeline) Swap(i, j int) {
  48. t.Messages[i], t.Messages[j] = t.Messages[j], t.Messages[i]
  49. }
  50. // Less checks 2 messages (i and j) in the timeline and returns true if i occcured before j, else false
  51. func (t *Timeline) Less(i, j int) bool {
  52. if t.Messages[i].Timestamp.Before(t.Messages[j].Timestamp) {
  53. return true
  54. }
  55. if compareSignatures(t.Messages[i].PreviousMessageSig, t.SignedGroupId) {
  56. return true
  57. }
  58. if compareSignatures(t.Messages[i].Signature, t.Messages[j].PreviousMessageSig) {
  59. return true
  60. }
  61. return false
  62. }
  63. // Insert inserts a message into the timeline in a thread safe way.
  64. func (t *Timeline) Insert(mi *Message) {
  65. t.lock.Lock()
  66. defer t.lock.Unlock()
  67. for _, m := range t.Messages {
  68. // If the message already exists, then we don't add it
  69. if compareSignatures(m.Signature, mi.Signature) {
  70. return
  71. }
  72. }
  73. t.Messages = append(t.Messages, *mi)
  74. sort.Sort(t)
  75. }