statestore.go 5.5 KB

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