statestore.go 5.4 KB

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