187 lines
5.5 KiB
Go
187 lines
5.5 KiB
Go
package appservice
|
|
|
|
import (
|
|
"maunium.net/go/gomatrix"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type StateStore interface {
|
|
IsRegistered(userID string) bool
|
|
MarkRegistered(userID string)
|
|
|
|
IsTyping(roomID, userID string) bool
|
|
SetTyping(roomID, userID string, timeout int64)
|
|
|
|
IsInRoom(roomID, userID string) bool
|
|
IsInvited(roomID, userID string) bool
|
|
IsMembership(roomID, userID string, allowedMemberships ...string) bool
|
|
SetMembership(roomID, userID, membership string)
|
|
|
|
SetPowerLevels(roomID string, levels *gomatrix.PowerLevels)
|
|
GetPowerLevels(roomID string) *gomatrix.PowerLevels
|
|
GetPowerLevel(roomID, userID string) int
|
|
GetPowerLevelRequirement(roomID string, eventType gomatrix.EventType) int
|
|
HasPowerLevel(roomID, userID string, eventType gomatrix.EventType) bool
|
|
}
|
|
|
|
func (as *AppService) UpdateState(evt *gomatrix.Event) {
|
|
switch evt.Type {
|
|
case gomatrix.StateMember:
|
|
as.StateStore.SetMembership(evt.RoomID, evt.GetStateKey(), evt.Content.Membership)
|
|
case gomatrix.StatePowerLevels:
|
|
as.StateStore.SetPowerLevels(evt.RoomID, &evt.Content.PowerLevels)
|
|
}
|
|
}
|
|
|
|
type BasicStateStore struct {
|
|
registrationsLock sync.RWMutex `json:"-"`
|
|
Registrations map[string]bool `json:"registrations"`
|
|
membershipsLock sync.RWMutex `json:"-"`
|
|
Memberships map[string]map[string]string `json:"memberships"`
|
|
powerLevelsLock sync.RWMutex `json:"-"`
|
|
PowerLevels map[string]*gomatrix.PowerLevels `json:"power_levels"`
|
|
|
|
Typing map[string]map[string]int64 `json:"-"`
|
|
typingLock sync.RWMutex `json:"-"`
|
|
}
|
|
|
|
func NewBasicStateStore() StateStore {
|
|
return &BasicStateStore{
|
|
Registrations: make(map[string]bool),
|
|
Memberships: make(map[string]map[string]string),
|
|
PowerLevels: make(map[string]*gomatrix.PowerLevels),
|
|
Typing: make(map[string]map[string]int64),
|
|
}
|
|
}
|
|
|
|
func (store *BasicStateStore) IsRegistered(userID string) bool {
|
|
store.registrationsLock.RLock()
|
|
defer store.registrationsLock.RUnlock()
|
|
registered, ok := store.Registrations[userID]
|
|
return ok && registered
|
|
}
|
|
|
|
func (store *BasicStateStore) MarkRegistered(userID string) {
|
|
store.registrationsLock.Lock()
|
|
defer store.registrationsLock.Unlock()
|
|
store.Registrations[userID] = true
|
|
}
|
|
|
|
func (store *BasicStateStore) IsTyping(roomID, userID string) bool {
|
|
store.typingLock.RLock()
|
|
defer store.typingLock.RUnlock()
|
|
roomTyping, ok := store.Typing[roomID]
|
|
if !ok {
|
|
return false
|
|
}
|
|
typingEndsAt, _ := roomTyping[userID]
|
|
return typingEndsAt >= time.Now().Unix()
|
|
}
|
|
|
|
func (store *BasicStateStore) SetTyping(roomID, userID string, timeout int64) {
|
|
store.typingLock.Lock()
|
|
defer store.typingLock.Unlock()
|
|
roomTyping, ok := store.Typing[roomID]
|
|
if !ok {
|
|
if timeout >= 0 {
|
|
roomTyping = map[string]int64{
|
|
userID: time.Now().Unix() + timeout,
|
|
}
|
|
} else {
|
|
roomTyping = make(map[string]int64)
|
|
}
|
|
} else {
|
|
if timeout >= 0 {
|
|
roomTyping[userID] = time.Now().Unix() + timeout
|
|
} else {
|
|
delete(roomTyping, userID)
|
|
}
|
|
}
|
|
store.Typing[roomID] = roomTyping
|
|
}
|
|
|
|
func (store *BasicStateStore) GetRoomMemberships(roomID string) map[string]string {
|
|
store.membershipsLock.RLock()
|
|
memberships, ok := store.Memberships[roomID]
|
|
store.membershipsLock.RUnlock()
|
|
if !ok {
|
|
memberships = make(map[string]string)
|
|
store.membershipsLock.Lock()
|
|
store.Memberships[roomID] = memberships
|
|
store.membershipsLock.Unlock()
|
|
}
|
|
return memberships
|
|
}
|
|
|
|
func (store *BasicStateStore) GetMembership(roomID, userID string) string {
|
|
store.membershipsLock.RLock()
|
|
defer store.membershipsLock.RUnlock()
|
|
memberships, ok := store.Memberships[roomID]
|
|
if !ok {
|
|
return "leave"
|
|
}
|
|
membership, ok := memberships[userID]
|
|
if !ok {
|
|
return "leave"
|
|
}
|
|
return membership
|
|
}
|
|
|
|
func (store *BasicStateStore) IsInRoom(roomID, userID string) bool {
|
|
return store.IsMembership(roomID, userID, "join")
|
|
}
|
|
|
|
func (store *BasicStateStore) IsInvited(roomID, userID string) bool {
|
|
return store.IsMembership(roomID, userID, "join", "invite")
|
|
}
|
|
|
|
func (store *BasicStateStore) IsMembership(roomID, userID string, allowedMemberships ...string) bool {
|
|
membership := store.GetMembership(roomID, userID)
|
|
for _, allowedMembership := range allowedMemberships {
|
|
if allowedMembership == membership {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (store *BasicStateStore) SetMembership(roomID, userID, membership string) {
|
|
store.membershipsLock.Lock()
|
|
memberships, ok := store.Memberships[roomID]
|
|
if !ok {
|
|
memberships = map[string]string{
|
|
userID: strings.ToLower(membership),
|
|
}
|
|
} else {
|
|
memberships[userID] = strings.ToLower(membership)
|
|
}
|
|
store.Memberships[roomID] = memberships
|
|
store.membershipsLock.Unlock()
|
|
}
|
|
|
|
func (store *BasicStateStore) SetPowerLevels(roomID string, levels *gomatrix.PowerLevels) {
|
|
store.powerLevelsLock.Lock()
|
|
store.PowerLevels[roomID] = levels
|
|
store.powerLevelsLock.Unlock()
|
|
}
|
|
|
|
func (store *BasicStateStore) GetPowerLevels(roomID string) (levels *gomatrix.PowerLevels) {
|
|
store.powerLevelsLock.RLock()
|
|
levels, _ = store.PowerLevels[roomID]
|
|
store.powerLevelsLock.RUnlock()
|
|
return
|
|
}
|
|
|
|
func (store *BasicStateStore) GetPowerLevel(roomID, userID string) int {
|
|
return store.GetPowerLevels(roomID).GetUserLevel(userID)
|
|
}
|
|
|
|
func (store *BasicStateStore) GetPowerLevelRequirement(roomID string, eventType gomatrix.EventType) int {
|
|
return store.GetPowerLevels(roomID).GetEventLevel(eventType)
|
|
}
|
|
|
|
func (store *BasicStateStore) HasPowerLevel(roomID, userID string, eventType gomatrix.EventType) bool {
|
|
return store.GetPowerLevel(roomID, userID) >= store.GetPowerLevelRequirement(roomID, eventType)
|
|
}
|