Initial desegregation of users and automatic config updating

This commit is contained in:
Tulir Asokan
2018-08-29 00:40:54 +03:00
parent 55c3ab2d4f
commit c7348f29b0
24 changed files with 806 additions and 475 deletions

View File

@ -463,7 +463,7 @@ func (cli *Client) SetAvatarURL(url string) (err error) {
// contentJSON should be a pointer to something that can be encoded as JSON using json.Marshal.
func (cli *Client) SendMessageEvent(roomID string, eventType EventType, contentJSON interface{}) (resp *RespSendEvent, err error) {
txnID := txnID()
urlPath := cli.BuildURL("rooms", roomID, "send", string(eventType), txnID)
urlPath := cli.BuildURL("rooms", roomID, "send", eventType.String(), txnID)
_, err = cli.MakeRequest("PUT", urlPath, contentJSON, &resp)
return
}
@ -472,7 +472,7 @@ func (cli *Client) SendMessageEvent(roomID string, eventType EventType, contentJ
// contentJSON should be a pointer to something that can be encoded as JSON using json.Marshal.
func (cli *Client) SendMassagedMessageEvent(roomID string, eventType EventType, contentJSON interface{}, ts int64) (resp *RespSendEvent, err error) {
txnID := txnID()
urlPath := cli.BuildURLWithQuery([]string{"rooms", roomID, "send", string(eventType), txnID}, map[string]string{
urlPath := cli.BuildURLWithQuery([]string{"rooms", roomID, "send", eventType.String(), txnID}, map[string]string{
"ts": strconv.FormatInt(ts, 10),
})
_, err = cli.MakeRequest("PUT", urlPath, contentJSON, &resp)
@ -482,7 +482,7 @@ func (cli *Client) SendMassagedMessageEvent(roomID string, eventType EventType,
// SendStateEvent sends a state event into a room. See http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-state-eventtype-statekey
// contentJSON should be a pointer to something that can be encoded as JSON using json.Marshal.
func (cli *Client) SendStateEvent(roomID string, eventType EventType, stateKey string, contentJSON interface{}) (resp *RespSendEvent, err error) {
urlPath := cli.BuildURL("rooms", roomID, "state", string(eventType), stateKey)
urlPath := cli.BuildURL("rooms", roomID, "state", eventType.String(), stateKey)
_, err = cli.MakeRequest("PUT", urlPath, contentJSON, &resp)
return
}
@ -490,7 +490,7 @@ func (cli *Client) SendStateEvent(roomID string, eventType EventType, stateKey s
// SendStateEvent sends a state event into a room. See http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-state-eventtype-statekey
// contentJSON should be a pointer to something that can be encoded as JSON using json.Marshal.
func (cli *Client) SendMassagedStateEvent(roomID string, eventType EventType, stateKey string, contentJSON interface{}, ts int64) (resp *RespSendEvent, err error) {
urlPath := cli.BuildURLWithQuery([]string{"rooms", roomID, "state", string(eventType), stateKey}, map[string]string{
urlPath := cli.BuildURLWithQuery([]string{"rooms", roomID, "state", eventType.String(), stateKey}, map[string]string{
"ts": strconv.FormatInt(ts, 10),
})
_, err = cli.MakeRequest("PUT", urlPath, contentJSON, &resp)
@ -500,7 +500,7 @@ func (cli *Client) SendMassagedStateEvent(roomID string, eventType EventType, st
// SendText sends an m.room.message event into the given room with a msgtype of m.text
// See http://matrix.org/docs/spec/client_server/r0.2.0.html#m-text
func (cli *Client) SendText(roomID, text string) (*RespSendEvent, error) {
return cli.SendMessageEvent(roomID, "m.room.message", Content{
return cli.SendMessageEvent(roomID, EventMessage, Content{
MsgType: MsgText,
Body: text,
})
@ -509,7 +509,7 @@ func (cli *Client) SendText(roomID, text string) (*RespSendEvent, error) {
// SendImage sends an m.room.message event into the given room with a msgtype of m.image
// See https://matrix.org/docs/spec/client_server/r0.2.0.html#m-image
func (cli *Client) SendImage(roomID, body, url string) (*RespSendEvent, error) {
return cli.SendMessageEvent(roomID, "m.room.message", Content{
return cli.SendMessageEvent(roomID, EventMessage, Content{
MsgType: MsgImage,
Body: body,
URL: url,
@ -519,7 +519,7 @@ func (cli *Client) SendImage(roomID, body, url string) (*RespSendEvent, error) {
// SendVideo sends an m.room.message event into the given room with a msgtype of m.video
// See https://matrix.org/docs/spec/client_server/r0.2.0.html#m-video
func (cli *Client) SendVideo(roomID, body, url string) (*RespSendEvent, error) {
return cli.SendMessageEvent(roomID, "m.room.message", Content{
return cli.SendMessageEvent(roomID, EventMessage, Content{
MsgType: MsgVideo,
Body: body,
URL: url,
@ -529,7 +529,7 @@ func (cli *Client) SendVideo(roomID, body, url string) (*RespSendEvent, error) {
// SendNotice sends an m.room.message event into the given room with a msgtype of m.notice
// See http://matrix.org/docs/spec/client_server/r0.2.0.html#m-notice
func (cli *Client) SendNotice(roomID, text string) (*RespSendEvent, error) {
return cli.SendMessageEvent(roomID, "m.room.message", Content{
return cli.SendMessageEvent(roomID, EventMessage, Content{
MsgType: MsgNotice,
Body: text,
})
@ -622,7 +622,7 @@ func (cli *Client) SetPresence(status string) (err error) {
// the HTTP response body, or return an error.
// See http://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-rooms-roomid-state-eventtype-statekey
func (cli *Client) StateEvent(roomID string, eventType EventType, stateKey string, outContent interface{}) (err error) {
u := cli.BuildURL("rooms", roomID, "state", string(eventType), stateKey)
u := cli.BuildURL("rooms", roomID, "state", eventType.String(), stateKey)
_, err = cli.MakeRequest("GET", u, nil, outContent)
return
}

View File

@ -5,28 +5,44 @@ import (
"sync"
)
type EventType string
type EventType struct {
Type string
IsState bool
}
func (et *EventType) UnmarshalJSON(data []byte) error {
return json.Unmarshal(data, &et.Type)
}
func (et *EventType) MarshalJSON() ([]byte, error) {
return json.Marshal(&et.Type)
}
func (et *EventType) String() string {
return et.Type
}
type MessageType string
// State events
const (
StateAliases EventType = "m.room.aliases"
StateCanonicalAlias = "m.room.canonical_alias"
StateCreate = "m.room.create"
StateJoinRules = "m.room.join_rules"
StateMember = "m.room.member"
StatePowerLevels = "m.room.power_levels"
StateRoomName = "m.room.name"
StateTopic = "m.room.topic"
StateRoomAvatar = "m.room.avatar"
StatePinnedEvents = "m.room.pinned_events"
var (
StateAliases = EventType{"m.room.aliases", true}
StateCanonicalAlias = EventType{"m.room.canonical_alias", true}
StateCreate = EventType{"m.room.create", true}
StateJoinRules = EventType{"m.room.join_rules", true}
StateMember = EventType{"m.room.member", true}
StatePowerLevels = EventType{"m.room.power_levels", true}
StateRoomName = EventType{"m.room.name", true}
StateTopic = EventType{"m.room.topic", true}
StateRoomAvatar = EventType{"m.room.avatar", true}
StatePinnedEvents = EventType{"m.room.pinned_events", true}
)
// Message events
const (
EventRedaction EventType = "m.room.redaction"
EventMessage = "m.room.message"
EventSticker = "m.sticker"
var (
EventRedaction = EventType{"m.room.redaction", false}
EventMessage = EventType{"m.room.message", false}
EventSticker = EventType{"m.sticker", false}
)
// Msgtypes
@ -258,12 +274,12 @@ func (pl *PowerLevels) EnsureUserLevel(userID string, level int) bool {
return false
}
func (pl *PowerLevels) GetEventLevel(eventType EventType, isState bool) int {
func (pl *PowerLevels) GetEventLevel(eventType EventType) int {
pl.eventsLock.RLock()
defer pl.eventsLock.RUnlock()
level, ok := pl.Events[eventType]
if !ok {
if isState {
if eventType.IsState {
return pl.StateDefault()
}
return pl.EventsDefault
@ -271,20 +287,20 @@ func (pl *PowerLevels) GetEventLevel(eventType EventType, isState bool) int {
return level
}
func (pl *PowerLevels) SetEventLevel(eventType EventType, isState bool, level int) {
func (pl *PowerLevels) SetEventLevel(eventType EventType, level int) {
pl.eventsLock.Lock()
defer pl.eventsLock.Unlock()
if (isState && level == pl.StateDefault()) || (!isState && level == pl.EventsDefault) {
if (eventType.IsState && level == pl.StateDefault()) || (!eventType.IsState && level == pl.EventsDefault) {
delete(pl.Events, eventType)
} else {
pl.Events[eventType] = level
}
}
func (pl *PowerLevels) EnsureEventLevel(eventType EventType, isState bool, level int) bool {
existingLevel := pl.GetEventLevel(eventType, isState)
func (pl *PowerLevels) EnsureEventLevel(eventType EventType, level int) bool {
existingLevel := pl.GetEventLevel(eventType)
if existingLevel != level {
pl.SetEventLevel(eventType, isState, level)
pl.SetEventLevel(eventType, level)
return true
}
return false

View File

@ -2,17 +2,19 @@ package appservice
import (
"fmt"
"html/template"
"io/ioutil"
"os"
"path/filepath"
"gopkg.in/yaml.v2"
"maunium.net/go/maulogger"
"strings"
"net/http"
"errors"
"maunium.net/go/gomatrix"
"maunium.net/go/maulogger"
"net/http"
"regexp"
"strings"
)
// EventChannelSize is the size for the Events channel in Appservice instances.
@ -263,15 +265,24 @@ func CreateLogConfig() LogConfig {
}
}
type FileFormatData struct {
Date string
Index int
}
// GetFileFormat returns a mauLogger-compatible logger file format based on the data in the struct.
func (lc LogConfig) GetFileFormat() maulogger.LoggerFileFormat {
path := lc.FileNameFormat
if len(lc.Directory) > 0 {
path = lc.Directory + "/" + path
}
os.MkdirAll(lc.Directory, 0700)
path := filepath.Join(lc.Directory, lc.FileNameFormat)
tpl, _ := template.New("fileformat").Parse(path)
return func(now string, i int) string {
return fmt.Sprintf(path, now, i)
var buf strings.Builder
tpl.Execute(&buf, FileFormatData{
Date: now,
Index: i,
})
return buf.String()
}
}

View File

@ -201,19 +201,19 @@ func (intent *IntentAPI) RedactEvent(roomID, eventID string, req *gomatrix.ReqRe
}
func (intent *IntentAPI) SetRoomName(roomID, roomName string) (*gomatrix.RespSendEvent, error) {
return intent.SendStateEvent(roomID, "m.room.name", "", map[string]interface{}{
return intent.SendStateEvent(roomID, gomatrix.StateRoomName, "", map[string]interface{}{
"name": roomName,
})
}
func (intent *IntentAPI) SetRoomAvatar(roomID, avatarURL string) (*gomatrix.RespSendEvent, error) {
return intent.SendStateEvent(roomID, "m.room.avatar", "", map[string]interface{}{
return intent.SendStateEvent(roomID, gomatrix.StateRoomAvatar, "", map[string]interface{}{
"url": avatarURL,
})
}
func (intent *IntentAPI) SetRoomTopic(roomID, topic string) (*gomatrix.RespSendEvent, error) {
return intent.SendStateEvent(roomID, "m.room.topic", "", map[string]interface{}{
return intent.SendStateEvent(roomID, gomatrix.StateTopic, "", map[string]interface{}{
"topic": topic,
})
}

View File

@ -15,13 +15,15 @@ type StateStore interface {
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, isState bool) int
HasPowerLevel(roomID, userID string, eventType gomatrix.EventType, isState bool) bool
GetPowerLevelRequirement(roomID string, eventType gomatrix.EventType) int
HasPowerLevel(roomID, userID string, eventType gomatrix.EventType) bool
}
func (as *AppService) UpdateState(evt *gomatrix.Event) {
@ -126,7 +128,21 @@ func (store *BasicStateStore) GetMembership(roomID, userID string) string {
}
func (store *BasicStateStore) IsInRoom(roomID, userID string) bool {
return store.GetMembership(roomID, userID) == "join"
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) {
@ -160,19 +176,10 @@ func (store *BasicStateStore) GetPowerLevel(roomID, userID string) int {
return store.GetPowerLevels(roomID).GetUserLevel(userID)
}
func (store *BasicStateStore) GetPowerLevelRequirement(roomID string, eventType gomatrix.EventType, isState bool) int {
levels := store.GetPowerLevels(roomID)
switch eventType {
case "kick":
return levels.Kick()
case "invite":
return levels.Invite()
case "redact":
return levels.Redact()
}
return levels.GetEventLevel(eventType, isState)
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, isState bool) bool {
return store.GetPowerLevel(roomID, userID) >= store.GetPowerLevelRequirement(roomID, eventType, isState)
func (store *BasicStateStore) HasPowerLevel(roomID, userID string, eventType gomatrix.EventType) bool {
return store.GetPowerLevel(roomID, userID) >= store.GetPowerLevelRequirement(roomID, eventType)
}