statestore.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. package appservice
  2. import (
  3. "maunium.net/go/gomatrix"
  4. "sync"
  5. "time"
  6. )
  7. type StateStore interface {
  8. IsRegistered(userID string) bool
  9. MarkRegistered(userID string)
  10. IsTyping(roomID, userID string) bool
  11. SetTyping(roomID, userID string, timeout int64)
  12. IsInRoom(roomID, userID string) bool
  13. IsInvited(roomID, userID string) bool
  14. IsMembership(roomID, userID string, allowedMemberships ...gomatrix.Membership) bool
  15. SetMembership(roomID, userID string, membership gomatrix.Membership)
  16. SetPowerLevels(roomID string, levels *gomatrix.PowerLevels)
  17. GetPowerLevels(roomID string) *gomatrix.PowerLevels
  18. GetPowerLevel(roomID, userID string) int
  19. GetPowerLevelRequirement(roomID string, eventType gomatrix.EventType) int
  20. HasPowerLevel(roomID, userID string, eventType gomatrix.EventType) bool
  21. }
  22. func (as *AppService) UpdateState(evt *gomatrix.Event) {
  23. switch evt.Type {
  24. case gomatrix.StateMember:
  25. as.StateStore.SetMembership(evt.RoomID, evt.GetStateKey(), evt.Content.Membership)
  26. case gomatrix.StatePowerLevels:
  27. as.StateStore.SetPowerLevels(evt.RoomID, &evt.Content.PowerLevels)
  28. }
  29. }
  30. type BasicStateStore struct {
  31. registrationsLock sync.RWMutex `json:"-"`
  32. Registrations map[string]bool `json:"registrations"`
  33. membershipsLock sync.RWMutex `json:"-"`
  34. Memberships map[string]map[string]gomatrix.Membership `json:"memberships"`
  35. powerLevelsLock sync.RWMutex `json:"-"`
  36. PowerLevels map[string]*gomatrix.PowerLevels `json:"power_levels"`
  37. Typing map[string]map[string]int64 `json:"-"`
  38. typingLock sync.RWMutex `json:"-"`
  39. }
  40. func NewBasicStateStore() StateStore {
  41. return &BasicStateStore{
  42. Registrations: make(map[string]bool),
  43. Memberships: make(map[string]map[string]gomatrix.Membership),
  44. PowerLevels: make(map[string]*gomatrix.PowerLevels),
  45. Typing: make(map[string]map[string]int64),
  46. }
  47. }
  48. func (store *BasicStateStore) IsRegistered(userID string) bool {
  49. store.registrationsLock.RLock()
  50. defer store.registrationsLock.RUnlock()
  51. registered, ok := store.Registrations[userID]
  52. return ok && registered
  53. }
  54. func (store *BasicStateStore) MarkRegistered(userID string) {
  55. store.registrationsLock.Lock()
  56. defer store.registrationsLock.Unlock()
  57. store.Registrations[userID] = true
  58. }
  59. func (store *BasicStateStore) IsTyping(roomID, userID string) bool {
  60. store.typingLock.RLock()
  61. defer store.typingLock.RUnlock()
  62. roomTyping, ok := store.Typing[roomID]
  63. if !ok {
  64. return false
  65. }
  66. typingEndsAt, _ := roomTyping[userID]
  67. return typingEndsAt >= time.Now().Unix()
  68. }
  69. func (store *BasicStateStore) SetTyping(roomID, userID string, timeout int64) {
  70. store.typingLock.Lock()
  71. defer store.typingLock.Unlock()
  72. roomTyping, ok := store.Typing[roomID]
  73. if !ok {
  74. if timeout >= 0 {
  75. roomTyping = map[string]int64{
  76. userID: time.Now().Unix() + timeout,
  77. }
  78. } else {
  79. roomTyping = make(map[string]int64)
  80. }
  81. } else {
  82. if timeout >= 0 {
  83. roomTyping[userID] = time.Now().Unix() + timeout
  84. } else {
  85. delete(roomTyping, userID)
  86. }
  87. }
  88. store.Typing[roomID] = roomTyping
  89. }
  90. func (store *BasicStateStore) GetRoomMemberships(roomID string) map[string]gomatrix.Membership {
  91. store.membershipsLock.RLock()
  92. memberships, ok := store.Memberships[roomID]
  93. store.membershipsLock.RUnlock()
  94. if !ok {
  95. memberships = make(map[string]gomatrix.Membership)
  96. store.membershipsLock.Lock()
  97. store.Memberships[roomID] = memberships
  98. store.membershipsLock.Unlock()
  99. }
  100. return memberships
  101. }
  102. func (store *BasicStateStore) GetMembership(roomID, userID string) gomatrix.Membership {
  103. store.membershipsLock.RLock()
  104. defer store.membershipsLock.RUnlock()
  105. memberships, ok := store.Memberships[roomID]
  106. if !ok {
  107. return gomatrix.MembershipLeave
  108. }
  109. membership, ok := memberships[userID]
  110. if !ok {
  111. return gomatrix.MembershipLeave
  112. }
  113. return membership
  114. }
  115. func (store *BasicStateStore) IsInRoom(roomID, userID string) bool {
  116. return store.IsMembership(roomID, userID, "join")
  117. }
  118. func (store *BasicStateStore) IsInvited(roomID, userID string) bool {
  119. return store.IsMembership(roomID, userID, "join", "invite")
  120. }
  121. func (store *BasicStateStore) IsMembership(roomID, userID string, allowedMemberships ...gomatrix.Membership) bool {
  122. membership := store.GetMembership(roomID, userID)
  123. for _, allowedMembership := range allowedMemberships {
  124. if allowedMembership == membership {
  125. return true
  126. }
  127. }
  128. return false
  129. }
  130. func (store *BasicStateStore) SetMembership(roomID, userID string, membership gomatrix.Membership) {
  131. store.membershipsLock.Lock()
  132. memberships, ok := store.Memberships[roomID]
  133. if !ok {
  134. memberships = map[string]gomatrix.Membership{
  135. userID: membership,
  136. }
  137. } else {
  138. memberships[userID] = membership
  139. }
  140. store.Memberships[roomID] = memberships
  141. store.membershipsLock.Unlock()
  142. }
  143. func (store *BasicStateStore) SetPowerLevels(roomID string, levels *gomatrix.PowerLevels) {
  144. store.powerLevelsLock.Lock()
  145. store.PowerLevels[roomID] = levels
  146. store.powerLevelsLock.Unlock()
  147. }
  148. func (store *BasicStateStore) GetPowerLevels(roomID string) (levels *gomatrix.PowerLevels) {
  149. store.powerLevelsLock.RLock()
  150. levels, _ = store.PowerLevels[roomID]
  151. store.powerLevelsLock.RUnlock()
  152. return
  153. }
  154. func (store *BasicStateStore) GetPowerLevel(roomID, userID string) int {
  155. return store.GetPowerLevels(roomID).GetUserLevel(userID)
  156. }
  157. func (store *BasicStateStore) GetPowerLevelRequirement(roomID string, eventType gomatrix.EventType) int {
  158. return store.GetPowerLevels(roomID).GetEventLevel(eventType)
  159. }
  160. func (store *BasicStateStore) HasPowerLevel(roomID, userID string, eventType gomatrix.EventType) bool {
  161. return store.GetPowerLevel(roomID, userID) >= store.GetPowerLevelRequirement(roomID, eventType)
  162. }