statestore.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  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. Lock()
  22. Unlock()
  23. RLock()
  24. RUnlock()
  25. }
  26. func (as *AppService) UpdateState(evt *gomatrix.Event) {
  27. switch evt.Type {
  28. case gomatrix.StateMember:
  29. as.StateStore.SetMembership(evt.RoomID, evt.GetStateKey(), evt.Content.Membership)
  30. case gomatrix.StatePowerLevels:
  31. as.StateStore.SetPowerLevels(evt.RoomID, &evt.Content.PowerLevels)
  32. }
  33. }
  34. type BasicStateStore struct {
  35. globalLock sync.RWMutex `json:"-"`
  36. registrationsLock sync.RWMutex `json:"-"`
  37. Registrations map[string]bool `json:"registrations"`
  38. membershipsLock sync.RWMutex `json:"-"`
  39. Memberships map[string]map[string]gomatrix.Membership `json:"memberships"`
  40. powerLevelsLock sync.RWMutex `json:"-"`
  41. PowerLevels map[string]*gomatrix.PowerLevels `json:"power_levels"`
  42. Typing map[string]map[string]int64 `json:"-"`
  43. typingLock sync.RWMutex `json:"-"`
  44. }
  45. func NewBasicStateStore() StateStore {
  46. return &BasicStateStore{
  47. Registrations: make(map[string]bool),
  48. Memberships: make(map[string]map[string]gomatrix.Membership),
  49. PowerLevels: make(map[string]*gomatrix.PowerLevels),
  50. Typing: make(map[string]map[string]int64),
  51. }
  52. }
  53. func (store *BasicStateStore) RLock() {
  54. store.registrationsLock.RLock()
  55. store.membershipsLock.RLock()
  56. store.powerLevelsLock.RLock()
  57. store.typingLock.RLock()
  58. }
  59. func (store *BasicStateStore) RUnlock() {
  60. store.typingLock.RUnlock()
  61. store.powerLevelsLock.RUnlock()
  62. store.membershipsLock.RUnlock()
  63. store.registrationsLock.RUnlock()
  64. }
  65. func (store *BasicStateStore) Lock() {
  66. store.registrationsLock.Lock()
  67. store.membershipsLock.Lock()
  68. store.powerLevelsLock.Lock()
  69. store.typingLock.Lock()
  70. }
  71. func (store *BasicStateStore) Unlock() {
  72. store.typingLock.Unlock()
  73. store.powerLevelsLock.Unlock()
  74. store.membershipsLock.Unlock()
  75. store.registrationsLock.Unlock()
  76. }
  77. func (store *BasicStateStore) IsRegistered(userID string) bool {
  78. store.registrationsLock.RLock()
  79. defer store.registrationsLock.RUnlock()
  80. registered, ok := store.Registrations[userID]
  81. return ok && registered
  82. }
  83. func (store *BasicStateStore) MarkRegistered(userID string) {
  84. store.registrationsLock.Lock()
  85. defer store.registrationsLock.Unlock()
  86. store.Registrations[userID] = true
  87. }
  88. func (store *BasicStateStore) IsTyping(roomID, userID string) bool {
  89. store.typingLock.RLock()
  90. defer store.typingLock.RUnlock()
  91. roomTyping, ok := store.Typing[roomID]
  92. if !ok {
  93. return false
  94. }
  95. typingEndsAt, _ := roomTyping[userID]
  96. return typingEndsAt >= time.Now().Unix()
  97. }
  98. func (store *BasicStateStore) SetTyping(roomID, userID string, timeout int64) {
  99. store.typingLock.Lock()
  100. defer store.typingLock.Unlock()
  101. roomTyping, ok := store.Typing[roomID]
  102. if !ok {
  103. if timeout >= 0 {
  104. roomTyping = map[string]int64{
  105. userID: time.Now().Unix() + timeout,
  106. }
  107. } else {
  108. roomTyping = make(map[string]int64)
  109. }
  110. } else {
  111. if timeout >= 0 {
  112. roomTyping[userID] = time.Now().Unix() + timeout
  113. } else {
  114. delete(roomTyping, userID)
  115. }
  116. }
  117. store.Typing[roomID] = roomTyping
  118. }
  119. func (store *BasicStateStore) GetRoomMemberships(roomID string) map[string]gomatrix.Membership {
  120. store.membershipsLock.RLock()
  121. memberships, ok := store.Memberships[roomID]
  122. store.membershipsLock.RUnlock()
  123. if !ok {
  124. memberships = make(map[string]gomatrix.Membership)
  125. store.membershipsLock.Lock()
  126. store.Memberships[roomID] = memberships
  127. store.membershipsLock.Unlock()
  128. }
  129. return memberships
  130. }
  131. func (store *BasicStateStore) GetMembership(roomID, userID string) gomatrix.Membership {
  132. store.membershipsLock.RLock()
  133. defer store.membershipsLock.RUnlock()
  134. memberships, ok := store.Memberships[roomID]
  135. if !ok {
  136. return gomatrix.MembershipLeave
  137. }
  138. membership, ok := memberships[userID]
  139. if !ok {
  140. return gomatrix.MembershipLeave
  141. }
  142. return membership
  143. }
  144. func (store *BasicStateStore) IsInRoom(roomID, userID string) bool {
  145. return store.IsMembership(roomID, userID, "join")
  146. }
  147. func (store *BasicStateStore) IsInvited(roomID, userID string) bool {
  148. return store.IsMembership(roomID, userID, "join", "invite")
  149. }
  150. func (store *BasicStateStore) IsMembership(roomID, userID string, allowedMemberships ...gomatrix.Membership) bool {
  151. membership := store.GetMembership(roomID, userID)
  152. for _, allowedMembership := range allowedMemberships {
  153. if allowedMembership == membership {
  154. return true
  155. }
  156. }
  157. return false
  158. }
  159. func (store *BasicStateStore) SetMembership(roomID, userID string, membership gomatrix.Membership) {
  160. store.membershipsLock.Lock()
  161. memberships, ok := store.Memberships[roomID]
  162. if !ok {
  163. memberships = map[string]gomatrix.Membership{
  164. userID: membership,
  165. }
  166. } else {
  167. memberships[userID] = membership
  168. }
  169. store.Memberships[roomID] = memberships
  170. store.membershipsLock.Unlock()
  171. }
  172. func (store *BasicStateStore) SetPowerLevels(roomID string, levels *gomatrix.PowerLevels) {
  173. store.powerLevelsLock.Lock()
  174. store.PowerLevels[roomID] = levels
  175. store.powerLevelsLock.Unlock()
  176. }
  177. func (store *BasicStateStore) GetPowerLevels(roomID string) (levels *gomatrix.PowerLevels) {
  178. store.powerLevelsLock.RLock()
  179. levels, _ = store.PowerLevels[roomID]
  180. store.powerLevelsLock.RUnlock()
  181. return
  182. }
  183. func (store *BasicStateStore) GetPowerLevel(roomID, userID string) int {
  184. return store.GetPowerLevels(roomID).GetUserLevel(userID)
  185. }
  186. func (store *BasicStateStore) GetPowerLevelRequirement(roomID string, eventType gomatrix.EventType) int {
  187. return store.GetPowerLevels(roomID).GetEventLevel(eventType)
  188. }
  189. func (store *BasicStateStore) HasPowerLevel(roomID, userID string, eventType gomatrix.EventType) bool {
  190. return store.GetPowerLevel(roomID, userID) >= store.GetPowerLevelRequirement(roomID, eventType)
  191. }