Events rework

Now Event is an interface. Moved all events stuff to separate events module.
This commit is contained in:
nxshock 2019-08-10 12:48:55 +05:00
parent 18566511c9
commit 197b296a24
14 changed files with 123 additions and 151 deletions

View File

@ -5,7 +5,7 @@ import (
"github.com/signaller-matrix/signaller/internal/models/common"
"github.com/signaller-matrix/signaller/internal/models/createroom"
"github.com/signaller-matrix/signaller/internal/models/devices"
"github.com/signaller-matrix/signaller/internal/models/rooms"
"github.com/signaller-matrix/signaller/internal/models/events"
"github.com/signaller-matrix/signaller/internal/models/sync"
)
@ -18,10 +18,10 @@ type Backend interface {
Sync(token string, request sync.SyncRequest) (response *sync.SyncReply, err models.ApiError)
PublicRooms(filter string) []Room
ValidateUsernameFunc() func(string) error
GetEventByID(id string) rooms.Event
PutEvent(rooms.Event) error
GetEventByID(id string) events.Event
PutEvent(events.Event) error
GetRoomByAlias(string) Room
GetEventsSince(user User, sinceToken string, limit int) []rooms.Event
GetEventsSince(user User, sinceToken string, limit int) []events.Event
}
type Room interface {

View File

@ -2,6 +2,7 @@ package memory
import (
"fmt"
"reflect"
"regexp"
"sort"
"strings"
@ -12,7 +13,7 @@ import (
"github.com/signaller-matrix/signaller/internal/models"
"github.com/signaller-matrix/signaller/internal/models/common"
"github.com/signaller-matrix/signaller/internal/models/createroom"
"github.com/signaller-matrix/signaller/internal/models/rooms"
"github.com/signaller-matrix/signaller/internal/models/events"
mSync "github.com/signaller-matrix/signaller/internal/models/sync"
"github.com/wangjia184/sortedset"
)
@ -185,32 +186,32 @@ func defaultValidationUsernameFunc(userName string) error {
return nil
}
func (backend *Backend) GetEventByID(id string) rooms.Event {
func (backend *Backend) GetEventByID(id string) events.Event {
backend.mutex.RLock()
defer backend.mutex.RUnlock()
return backend.events.GetByKey(id).Value.(rooms.Event)
return backend.events.GetByKey(id).Value.(events.Event)
}
func (backend *Backend) PutEvent(event rooms.Event) error {
func (backend *Backend) PutEvent(event events.Event) error {
backend.mutex.Lock()
defer backend.mutex.Unlock()
backend.events.AddOrUpdate(event.EventID, sortedset.SCORE(time.Now().Unix()), event)
backend.events.AddOrUpdate(event.ID(), sortedset.SCORE(time.Now().Unix()), event)
return nil
}
func (backend *Backend) GetEventsSince(user internal.User, sinceToken string, limit int) []rooms.Event {
func (backend *Backend) GetEventsSince(user internal.User, sinceToken string, limit int) []events.Event {
sinceEventNode := backend.events.GetByKey(sinceToken)
sEvents := backend.events.GetByScoreRange(sinceEventNode.Score(), -1, &sortedset.GetByScoreRangeOptions{
Limit: limit,
})
events := extractEventsFromNodes(sEvents)
eventsSlice := extractEventsFromNodes(sEvents)
var returnEvents []rooms.Event
for _, event := range events {
var returnEvents []events.Event
for _, event := range eventsSlice {
if isEventRelatedToUser(event, user) {
returnEvents = append(returnEvents, event)
}
@ -219,17 +220,21 @@ func (backend *Backend) GetEventsSince(user internal.User, sinceToken string, li
return returnEvents
}
func extractEventsFromNodes(nodes []*sortedset.SortedSetNode) []rooms.Event {
var events []rooms.Event
func extractEventsFromNodes(nodes []*sortedset.SortedSetNode) []events.Event {
var eventsSlice []events.Event
for _, e := range nodes {
events = append(events, e.Value.(rooms.Event))
eventsSlice = append(eventsSlice, e.Value.(events.Event))
}
return events
return eventsSlice
}
func isEventRelatedToUser(event rooms.Event, user internal.User) bool {
if internal.InArray(event.RoomID, extractRoomIDsFromModel(user.JoinedRooms())) {
func isEventRelatedToUser(event events.Event, user internal.User) bool {
// get RoomID field from event interface
// TODO: what if there are no RoomID field?
roomID := reflect.ValueOf(event).Elem().FieldByName("RoomID").Addr().Interface().(string)
if internal.InArray(roomID, extractRoomIDsFromModel(user.JoinedRooms())) {
return true
}
return false

View File

@ -1,31 +1,12 @@
package memory
import (
"encoding/json"
"time"
"github.com/signaller-matrix/signaller/internal"
"github.com/signaller-matrix/signaller/internal/models/common"
"github.com/signaller-matrix/signaller/internal/models/rooms"
)
/*
type RoomEvent struct {
Content json.RawMessage
Type common.EventType
Type events.EventType
EventID string
Sender internal.User
OriginServerTS time.Time
Room internal.Room
}
func (roomEvent *RoomEvent) ToEvent() rooms.Event {
event := rooms.Event{
Content: roomEvent.Content,
Type: roomEvent.Type,
EventID: roomEvent.EventID,
Sender: roomEvent.Sender.ID(),
OriginServerTS: roomEvent.OriginServerTS.Unix(),
RoomID: roomEvent.Room.ID()}
return event
}
*/

View File

@ -10,6 +10,7 @@ import (
"github.com/signaller-matrix/signaller/internal/models/common"
"github.com/signaller-matrix/signaller/internal/models/createroom"
"github.com/signaller-matrix/signaller/internal/models/devices"
"github.com/signaller-matrix/signaller/internal/models/events"
)
type User struct {
@ -42,46 +43,46 @@ func (user *User) CreateRoom(request createroom.Request) (internal.Room, models.
}
}
t := time.Now()
currentUnixTime := time.Now().Unix()
events := make([]RoomEvent, 0)
eventsSlice := make([]events.RoomEvent, 0)
// Create room event
events = append(events, RoomEvent{
Content: nil,
Type: common.Create,
eventsSlice = append(eventsSlice, events.RoomEvent{
ContentData: nil,
EType: events.Create,
EventID: internal.RandomString(eventIDSize),
Sender: user,
OriginServerTS: t})
Sender: user.ID(),
OriginServerTs: currentUnixTime})
// TODO: Add join room event
// Set join rules event
events = append(events, RoomEvent{
Content: []byte(request.Visibility), // TODO: check visibility vs join rules
Type: common.JoinRules,
eventsSlice = append(eventsSlice, events.RoomEvent{
ContentData: []byte(request.Visibility), // TODO: check visibility vs join rules
EType: events.JoinRules,
EventID: internal.RandomString(eventIDSize),
Sender: user,
OriginServerTS: t})
Sender: user.ID(),
OriginServerTs: currentUnixTime})
// Set room name event
if request.Name != "" {
events = append(events, RoomEvent{
Content: nil, // TODO: add
Type: common.Name,
eventsSlice = append(eventsSlice, events.RoomEvent{
ContentData: nil, // TODO: add
EType: events.Name,
EventID: internal.RandomString(eventIDSize),
Sender: user,
OriginServerTS: t})
Sender: user.ID(),
OriginServerTs: currentUnixTime})
}
// Set room alias event
if request.RoomAliasName != "" {
events = append(events, RoomEvent{
Content: nil, // TODO: add
Type: common.CanonicalAlias,
eventsSlice = append(eventsSlice, events.RoomEvent{
ContentData: nil, // TODO: add
EType: events.CanonicalAlias,
EventID: internal.RandomString(eventIDSize),
Sender: user,
OriginServerTS: t})
Sender: user.ID(),
OriginServerTs: currentUnixTime})
}
room := &Room{
@ -95,13 +96,12 @@ func (user *User) CreateRoom(request createroom.Request) (internal.Room, models.
server: user.backend,
state: request.Preset}
for i, _ := range events {
events[i].Room = room
//v.Room = room
for i, _ := range eventsSlice {
eventsSlice[i].RoomID = room.id
}
for i, _ := range events {
user.backend.PutEvent(events[i].ToEvent())
for i, _ := range eventsSlice {
user.backend.PutEvent(&eventsSlice[i])
}
user.backend.rooms[room.ID()] = room
@ -123,13 +123,13 @@ func (user *User) SetTopic(room internal.Room, topic string) models.ApiError {
memRoom.mutex.Unlock()
rEvent := &RoomEvent{
Type: common.Topic,
Sender: user,
OriginServerTS: time.Now(),
Room: room}
rEvent := &events.RoomEvent{
EType: events.Topic,
Sender: user.ID(),
OriginServerTs: time.Now().Unix(),
RoomID: memRoom.id}
user.backend.PutEvent(rEvent.ToEvent())
user.backend.PutEvent(rEvent)
return nil
}
@ -203,15 +203,15 @@ func (user *User) SendMessage(room internal.Room, text string) models.ApiError {
return models.NewError(models.M_FORBIDDEN, "")
}
rEvent := &RoomEvent{
Content: nil,
Type: common.Message,
rEvent := &events.RoomEvent{
ContentData: nil,
EType: events.Message,
EventID: internal.RandomString(defaultTokenSize),
Sender: user,
OriginServerTS: time.Now(),
Room: room}
Sender: user.ID(),
OriginServerTs: time.Now().Unix(),
RoomID: memRoom.id}
user.backend.PutEvent(rEvent.ToEvent())
user.backend.PutEvent(rEvent)
return nil
}

View File

@ -1,5 +0,0 @@
package common
type Presence struct {
events []Event `json:"events"` // List of events.
}

View File

@ -1,6 +0,0 @@
package common
// TODO: проверить правильность выбора типа
type ToDevice struct {
events []Event `json:"events` // List of send-to-device messages
}

View File

@ -1,7 +0,0 @@
package common
type UnsignedData struct {
Age int `json:"age"` // The time in milliseconds that has elapsed since the event was sent. This field is generated by the local homeserver, and may be incorrect if the local time on at least one of the two servers is out of sync, which can cause the age to either be negative or greater than it actually is.
RedactedBecause Event `json:"redacted_because"` // Optional. The event that redacted this event, if any.
TransactionID string `json:"transaction_id"` // The client-supplied transaction ID, if the client being given the event is the same one which sent it.
}

View File

@ -1,8 +1,6 @@
package createroom
import (
common "github.com/signaller-matrix/signaller/internal/models/common"
)
import "github.com/signaller-matrix/signaller/internal/models/events"
// https://matrix.org/docs/spec/client_server/latest#post-matrix-client-r0-createroom
type VisibilityType string
@ -40,7 +38,7 @@ type Request struct {
RoomVersion string `json:"room_version,omitempty"` // The room version to set for the room. If not provided, the homeserver is to use its configured default. If provided, the homeserver will return a 400 error with the errcode M_UNSUPPORTED_ROOM_VERSION if it does not support the room version.
// TODO: проверить тип
// CreationContent CreationContentType `json:"creation_content,omitempty"`
InitialState []common.StateEvent `json:"initial_state,omitempty"` // A list of state events to set in the new room. This allows the user to override the default state events set in the new room. The expected format of the state events are an object with type, state_key and content keys set. Takes precedence over events set by preset, but gets overriden by name and topic keys.
InitialState []events.StateEvent `json:"initial_state,omitempty"` // A list of state events to set in the new room. This allows the user to override the default state events set in the new room. The expected format of the state events are an object with type, state_key and content keys set. Takes precedence over events set by preset, but gets overriden by name and topic keys.
Preset Preset `json:"preset,omitempty"` // Convenience parameter for setting various default state events based on a preset. If unspecified, the server should use the visibility to determine which preset to use. A visbility of public equates to a preset of public_chat and private visibility equates to a preset of private_chat. One of: ["private_chat", "public_chat", "trusted_private_chat"]
IsDirect bool `json:"is_direct,omitempty"` // This flag makes the server set the is_direct flag on the m.room.member events sent to the users in invite and invite_3pid.
// PowerLevelContentOverride `json:"power_level_content_override"`

View File

@ -1,4 +1,4 @@
package common
package events
type DeviceLists struct {
Changed []string `json:"changed"` // List of users who have updated their device identity keys, or who now share an encrypted room with the client since the previous sync response.

View File

@ -1,4 +1,4 @@
package common
package events
import "encoding/json"
@ -56,10 +56,10 @@ const (
PinnedEvents EventType = "m.room.pinned_events"
)
type Event struct {
// TODO: object
Content json.RawMessage `json:"content"` // Required. The fields in this object will vary depending on the type of event. When interacting with the REST API, this is the HTTP body.
Type string `json:"type"` // Required. The type of event. This SHOULD be namespaced similar to Java package naming conventions e.g. 'com.example.subdomain.event.type'
type Event interface {
Content() json.RawMessage // Required. The fields in this object will vary depending on the type of event. When interacting with the REST API, this is the HTTP body.
Type() EventType // Required. The type of event. This SHOULD be namespaced similar to Java package naming conventions e.g. 'com.example.subdomain.event.type'
ID() string
}
type EventContent struct {
@ -111,3 +111,17 @@ type StrippedState struct {
Type string `json:"type"` // Required. The type for the event.
Sender string `json:"sender"` // Required. The sender for the event.
}
type UnsignedData struct {
Age int `json:"age"` // The time in milliseconds that has elapsed since the event was sent. This field is generated by the local homeserver, and may be incorrect if the local time on at least one of the two servers is out of sync, which can cause the age to either be negative or greater than it actually is.
RedactedBecause Event `json:"redacted_because"` // Optional. The event that redacted this event, if any.
TransactionID string `json:"transaction_id"` // The client-supplied transaction ID, if the client being given the event is the same one which sent it.
}
type Presence struct {
Events []Event `json:"events"` // List of events.
}
type ToDevice struct {
Events []Event `json:"events` // List of send-to-device messages
}

View File

@ -1,4 +1,4 @@
package common
package events
// https://matrix.org/docs/spec/client_server/r0.4.0.html#get-matrix-client-r0-rooms-roomid-members
type MemberEvent struct {

View File

@ -1,21 +1,30 @@
package common
package events
import "encoding/json"
type Timeline struct {
Events []RoomEvent `json:"events"` // List of events.
Limited bool `json:"limited"` // True if the number of events returned was limited by the limit on the filter.
PrevBatch string `json:"prev_batch"` // A token that can be supplied to the from parameter of the rooms/{roomId}/messages endpoint.
}
import (
"encoding/json"
)
type RoomEvent struct {
// TODO: object
Content json.RawMessage `json:"content"` // Required. The fields in this object will vary depending on the type of event. When interacting with the REST API, this is the HTTP body.
Type string `json:"type"` // Required. The type of event. This SHOULD be namespaced similar to Java package naming conventions e.g. 'com.example.subdomain.event.type'
ContentData json.RawMessage `json:"content"` // Required. The fields in this object will vary depending on the type of event. When interacting with the REST API, this is the HTTP body.
EType EventType `json:"type"` // Required. The type of event. This SHOULD be namespaced similar to Java package naming conventions e.g. 'com.example.subdomain.event.type'
EventID string `json:"event_id"` // Required. The globally unique event identifier.
Sender string `json:"sender"` // Required. Contains the fully-qualified ID of the user who sent this event.
OriginServerTs int64 `json:"origin_server_ts"` // Required. Timestamp in milliseconds on originating homeserver when this event was sent.
Unsigned UnsignedData `json:"unsigned"` // Contains optional extra information about the event.
RoomID string `json:"room_id"` // Required. The ID of the room associated with this event. Will not be present on events that arrive through /sync, despite being required everywhere else.
}
func (roomEvent *RoomEvent) Content() json.RawMessage {
return roomEvent.ContentData
}
func (roomEvent *RoomEvent) ID() string {
return roomEvent.EventID
}
func (roomEvent *RoomEvent) Type() EventType {
return roomEvent.EType
}
type JoinedRoom struct {
@ -48,3 +57,9 @@ type InvitedRoom struct {
type InviteState struct {
Events []StrippedState `json:"events"` // The StrippedState events that form the invite state.
}
type Timeline struct {
Events []RoomEvent `json:"events"` // List of events.
Limited bool `json:"limited"` // True if the number of events returned was limited by the limit on the filter.
PrevBatch string `json:"prev_batch"` // A token that can be supplied to the from parameter of the rooms/{roomId}/messages endpoint.
}

View File

@ -1,11 +1,5 @@
package rooms
import (
"encoding/json"
"github.com/signaller-matrix/signaller/internal/models/common"
)
type JoinRule string
const (
@ -14,20 +8,3 @@ const (
Invite = "invite"
Private = "private"
)
// https://matrix.org/docs/spec/client_server/latest#room-event-fields
type Event struct {
Content json.RawMessage `json:"content"` // Required. The fields in this object will vary depending on the type of event. When interacting with the REST API, this is the HTTP body.
Type common.EventType `json:"type"` // Required. The type of event. This SHOULD be namespaced similar to Java package naming conventions e.g. 'com.example.subdomain.event.type'
EventID string `json:"event_id"` // Required. The globally unique event identifier.
Sender string `json:"sender"` // Required. Contains the fully-qualified ID of the user who sent this event.
OriginServerTS int64 `json:"origin_server_ts"` // Required. Timestamp in milliseconds on originating homeserver when this event was sent.
Unsigned UnsignedData `json:"unsigned,omitempty"` // Contains optional extra information about the event.
RoomID string `json:"room_id"` // Required. The ID of the room associated with this event. Will not be present on events that arrive through /sync, despite being required everywhere else.
}
type UnsignedData struct {
Age int `json:"age"` // The time in milliseconds that has elapsed since the event was sent. This field is generated by the local homeserver, and may be incorrect if the local time on at least one of the two servers is out of sync, which can cause the age to either be negative or greater than it actually is.
RedactedBecause common.Event `json:"redacted_because,omitempty"` // Optional. The event that redacted this event, if any.
TransactionID string `json:"transaction_id"` // The client-supplied transaction ID, if the client being given the event is the same one which sent it.
}

View File

@ -1,21 +1,21 @@
package sync
import (
common "github.com/signaller-matrix/signaller/internal/models/common"
"github.com/signaller-matrix/signaller/internal/models/events"
)
type SyncReply struct {
NextBatch string `json:"next_batch"` // Required. The batch token to supply in the since param of the next /sync request.
Rooms RoomsSyncReply `json:"rooms"` // Updates to rooms.
Presence common.Presence `json:"presence"` // The updates to the presence status of other users.
AccountData common.AccountData `json:"account_data"` // The global private data created by this user.
ToDevice common.ToDevice `json:"to_device"` // Information on the send-to-device messages for the client device, as defined in Send-to-Device messaging.
DeviceLists common.DeviceLists `json:"device_lists"` // Information on end-to-end device updates, as specified in End-to-end encryption.
Presence events.Presence `json:"presence"` // The updates to the presence status of other users.
AccountData events.AccountData `json:"account_data"` // The global private data created by this user.
ToDevice events.ToDevice `json:"to_device"` // Information on the send-to-device messages for the client device, as defined in Send-to-Device messaging.
DeviceLists events.DeviceLists `json:"device_lists"` // Information on end-to-end device updates, as specified in End-to-end encryption.
DeviceOneTimeKeysCount map[string]int `json:"device_one_time_keys_count"` // Information on end-to-end encryption keys, as specified in End-to-end encryption.
}
type RoomsSyncReply struct {
Join map[string]common.JoinedRoom `json:"join"` // The rooms that the user has joined.
Invite map[string]common.InvitedRoom `json:"invite"` // The rooms that the user has been invited to.
Leave map[string]common.LeftRoom `json:"leave"` // The rooms that the user has left or been banned from.
Join map[string]events.JoinedRoom `json:"join"` // The rooms that the user has joined.
Invite map[string]events.InvitedRoom `json:"invite"` // The rooms that the user has been invited to.
Leave map[string]events.LeftRoom `json:"leave"` // The rooms that the user has left or been banned from.
}