mirror of
https://github.com/hoernschen/dendrite.git
synced 2025-08-01 13:52:46 +00:00
Move GMSL client types to Dendrite (#3045)
GMSL is intended for Federation only. Sister PR to https://github.com/matrix-org/gomatrixserverlib/pull/357
This commit is contained in:
parent
985298cfc4
commit
3691423626
58 changed files with 692 additions and 234 deletions
88
syncapi/synctypes/clientevent.go
Normal file
88
syncapi/synctypes/clientevent.go
Normal file
|
@ -0,0 +1,88 @@
|
|||
/* Copyright 2017 Vector Creations Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package synctypes
|
||||
|
||||
import "github.com/matrix-org/gomatrixserverlib"
|
||||
|
||||
type ClientEventFormat int
|
||||
|
||||
const (
|
||||
// FormatAll will include all client event keys
|
||||
FormatAll ClientEventFormat = iota
|
||||
// FormatSync will include only the event keys required by the /sync API. Notably, this
|
||||
// means the 'room_id' will be missing from the events.
|
||||
FormatSync
|
||||
)
|
||||
|
||||
// ClientEvent is an event which is fit for consumption by clients, in accordance with the specification.
|
||||
type ClientEvent struct {
|
||||
Content gomatrixserverlib.RawJSON `json:"content"`
|
||||
EventID string `json:"event_id,omitempty"` // EventID is omitted on receipt events
|
||||
OriginServerTS gomatrixserverlib.Timestamp `json:"origin_server_ts,omitempty"` // OriginServerTS is omitted on receipt events
|
||||
RoomID string `json:"room_id,omitempty"` // RoomID is omitted on /sync responses
|
||||
Sender string `json:"sender,omitempty"` // Sender is omitted on receipt events
|
||||
StateKey *string `json:"state_key,omitempty"`
|
||||
Type string `json:"type"`
|
||||
Unsigned gomatrixserverlib.RawJSON `json:"unsigned,omitempty"`
|
||||
Redacts string `json:"redacts,omitempty"`
|
||||
}
|
||||
|
||||
// ToClientEvents converts server events to client events.
|
||||
func ToClientEvents(serverEvs []*gomatrixserverlib.Event, format ClientEventFormat) []ClientEvent {
|
||||
evs := make([]ClientEvent, 0, len(serverEvs))
|
||||
for _, se := range serverEvs {
|
||||
if se == nil {
|
||||
continue // TODO: shouldn't happen?
|
||||
}
|
||||
evs = append(evs, ToClientEvent(se, format))
|
||||
}
|
||||
return evs
|
||||
}
|
||||
|
||||
// HeaderedToClientEvents converts headered server events to client events.
|
||||
func HeaderedToClientEvents(serverEvs []*gomatrixserverlib.HeaderedEvent, format ClientEventFormat) []ClientEvent {
|
||||
evs := make([]ClientEvent, 0, len(serverEvs))
|
||||
for _, se := range serverEvs {
|
||||
if se == nil {
|
||||
continue // TODO: shouldn't happen?
|
||||
}
|
||||
evs = append(evs, HeaderedToClientEvent(se, format))
|
||||
}
|
||||
return evs
|
||||
}
|
||||
|
||||
// ToClientEvent converts a single server event to a client event.
|
||||
func ToClientEvent(se *gomatrixserverlib.Event, format ClientEventFormat) ClientEvent {
|
||||
ce := ClientEvent{
|
||||
Content: gomatrixserverlib.RawJSON(se.Content()),
|
||||
Sender: se.Sender(),
|
||||
Type: se.Type(),
|
||||
StateKey: se.StateKey(),
|
||||
Unsigned: gomatrixserverlib.RawJSON(se.Unsigned()),
|
||||
OriginServerTS: se.OriginServerTS(),
|
||||
EventID: se.EventID(),
|
||||
Redacts: se.Redacts(),
|
||||
}
|
||||
if format == FormatAll {
|
||||
ce.RoomID = se.RoomID()
|
||||
}
|
||||
return ce
|
||||
}
|
||||
|
||||
// HeaderedToClientEvent converts a single headered server event to a client event.
|
||||
func HeaderedToClientEvent(se *gomatrixserverlib.HeaderedEvent, format ClientEventFormat) ClientEvent {
|
||||
return ToClientEvent(se.Event, format)
|
||||
}
|
105
syncapi/synctypes/clientevent_test.go
Normal file
105
syncapi/synctypes/clientevent_test.go
Normal file
|
@ -0,0 +1,105 @@
|
|||
/* Copyright 2017 Vector Creations Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package synctypes
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
)
|
||||
|
||||
func TestToClientEvent(t *testing.T) { // nolint: gocyclo
|
||||
ev, err := gomatrixserverlib.NewEventFromTrustedJSON([]byte(`{
|
||||
"type": "m.room.name",
|
||||
"state_key": "",
|
||||
"event_id": "$test:localhost",
|
||||
"room_id": "!test:localhost",
|
||||
"sender": "@test:localhost",
|
||||
"content": {
|
||||
"name": "Hello World"
|
||||
},
|
||||
"origin_server_ts": 123456,
|
||||
"unsigned": {
|
||||
"prev_content": {
|
||||
"name": "Goodbye World"
|
||||
}
|
||||
}
|
||||
}`), false, gomatrixserverlib.RoomVersionV1)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create Event: %s", err)
|
||||
}
|
||||
ce := ToClientEvent(ev, FormatAll)
|
||||
if ce.EventID != ev.EventID() {
|
||||
t.Errorf("ClientEvent.EventID: wanted %s, got %s", ev.EventID(), ce.EventID)
|
||||
}
|
||||
if ce.OriginServerTS != ev.OriginServerTS() {
|
||||
t.Errorf("ClientEvent.OriginServerTS: wanted %d, got %d", ev.OriginServerTS(), ce.OriginServerTS)
|
||||
}
|
||||
if ce.StateKey == nil || *ce.StateKey != "" {
|
||||
t.Errorf("ClientEvent.StateKey: wanted '', got %v", ce.StateKey)
|
||||
}
|
||||
if ce.Type != ev.Type() {
|
||||
t.Errorf("ClientEvent.Type: wanted %s, got %s", ev.Type(), ce.Type)
|
||||
}
|
||||
if !bytes.Equal(ce.Content, ev.Content()) {
|
||||
t.Errorf("ClientEvent.Content: wanted %s, got %s", string(ev.Content()), string(ce.Content))
|
||||
}
|
||||
if !bytes.Equal(ce.Unsigned, ev.Unsigned()) {
|
||||
t.Errorf("ClientEvent.Unsigned: wanted %s, got %s", string(ev.Unsigned()), string(ce.Unsigned))
|
||||
}
|
||||
if ce.Sender != ev.Sender() {
|
||||
t.Errorf("ClientEvent.Sender: wanted %s, got %s", ev.Sender(), ce.Sender)
|
||||
}
|
||||
j, err := json.Marshal(ce)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to Marshal ClientEvent: %s", err)
|
||||
}
|
||||
// Marshal sorts keys in structs by the order they are defined in the struct, which is alphabetical
|
||||
out := `{"content":{"name":"Hello World"},"event_id":"$test:localhost","origin_server_ts":123456,` +
|
||||
`"room_id":"!test:localhost","sender":"@test:localhost","state_key":"","type":"m.room.name",` +
|
||||
`"unsigned":{"prev_content":{"name":"Goodbye World"}}}`
|
||||
if !bytes.Equal([]byte(out), j) {
|
||||
t.Errorf("ClientEvent marshalled to wrong bytes: wanted %s, got %s", out, string(j))
|
||||
}
|
||||
}
|
||||
|
||||
func TestToClientFormatSync(t *testing.T) {
|
||||
ev, err := gomatrixserverlib.NewEventFromTrustedJSON([]byte(`{
|
||||
"type": "m.room.name",
|
||||
"state_key": "",
|
||||
"event_id": "$test:localhost",
|
||||
"room_id": "!test:localhost",
|
||||
"sender": "@test:localhost",
|
||||
"content": {
|
||||
"name": "Hello World"
|
||||
},
|
||||
"origin_server_ts": 123456,
|
||||
"unsigned": {
|
||||
"prev_content": {
|
||||
"name": "Goodbye World"
|
||||
}
|
||||
}
|
||||
}`), false, gomatrixserverlib.RoomVersionV1)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create Event: %s", err)
|
||||
}
|
||||
ce := ToClientEvent(ev, FormatSync)
|
||||
if ce.RoomID != "" {
|
||||
t.Errorf("ClientEvent.RoomID: wanted '', got %s", ce.RoomID)
|
||||
}
|
||||
}
|
152
syncapi/synctypes/filter.go
Normal file
152
syncapi/synctypes/filter.go
Normal file
|
@ -0,0 +1,152 @@
|
|||
// Copyright 2017 Jan Christian Grünhage
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package synctypes
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
// Filter is used by clients to specify how the server should filter responses to e.g. sync requests
|
||||
// Specified by: https://spec.matrix.org/v1.6/client-server-api/#filtering
|
||||
type Filter struct {
|
||||
EventFields []string `json:"event_fields,omitempty"`
|
||||
EventFormat string `json:"event_format,omitempty"`
|
||||
Presence EventFilter `json:"presence,omitempty"`
|
||||
AccountData EventFilter `json:"account_data,omitempty"`
|
||||
Room RoomFilter `json:"room,omitempty"`
|
||||
}
|
||||
|
||||
// EventFilter is used to define filtering rules for events
|
||||
type EventFilter struct {
|
||||
Limit int `json:"limit,omitempty"`
|
||||
NotSenders *[]string `json:"not_senders,omitempty"`
|
||||
NotTypes *[]string `json:"not_types,omitempty"`
|
||||
Senders *[]string `json:"senders,omitempty"`
|
||||
Types *[]string `json:"types,omitempty"`
|
||||
}
|
||||
|
||||
// RoomFilter is used to define filtering rules for room-related events
|
||||
type RoomFilter struct {
|
||||
NotRooms *[]string `json:"not_rooms,omitempty"`
|
||||
Rooms *[]string `json:"rooms,omitempty"`
|
||||
Ephemeral RoomEventFilter `json:"ephemeral,omitempty"`
|
||||
IncludeLeave bool `json:"include_leave,omitempty"`
|
||||
State StateFilter `json:"state,omitempty"`
|
||||
Timeline RoomEventFilter `json:"timeline,omitempty"`
|
||||
AccountData RoomEventFilter `json:"account_data,omitempty"`
|
||||
}
|
||||
|
||||
// StateFilter is used to define filtering rules for state events
|
||||
type StateFilter struct {
|
||||
NotSenders *[]string `json:"not_senders,omitempty"`
|
||||
NotTypes *[]string `json:"not_types,omitempty"`
|
||||
Senders *[]string `json:"senders,omitempty"`
|
||||
Types *[]string `json:"types,omitempty"`
|
||||
LazyLoadMembers bool `json:"lazy_load_members,omitempty"`
|
||||
IncludeRedundantMembers bool `json:"include_redundant_members,omitempty"`
|
||||
NotRooms *[]string `json:"not_rooms,omitempty"`
|
||||
Rooms *[]string `json:"rooms,omitempty"`
|
||||
Limit int `json:"limit,omitempty"`
|
||||
UnreadThreadNotifications bool `json:"unread_thread_notifications,omitempty"`
|
||||
ContainsURL *bool `json:"contains_url,omitempty"`
|
||||
}
|
||||
|
||||
// RoomEventFilter is used to define filtering rules for events in rooms
|
||||
type RoomEventFilter struct {
|
||||
Limit int `json:"limit,omitempty"`
|
||||
NotSenders *[]string `json:"not_senders,omitempty"`
|
||||
NotTypes *[]string `json:"not_types,omitempty"`
|
||||
Senders *[]string `json:"senders,omitempty"`
|
||||
Types *[]string `json:"types,omitempty"`
|
||||
LazyLoadMembers bool `json:"lazy_load_members,omitempty"`
|
||||
IncludeRedundantMembers bool `json:"include_redundant_members,omitempty"`
|
||||
NotRooms *[]string `json:"not_rooms,omitempty"`
|
||||
Rooms *[]string `json:"rooms,omitempty"`
|
||||
UnreadThreadNotifications bool `json:"unread_thread_notifications,omitempty"`
|
||||
ContainsURL *bool `json:"contains_url,omitempty"`
|
||||
}
|
||||
|
||||
// Validate checks if the filter contains valid property values
|
||||
func (filter *Filter) Validate() error {
|
||||
if filter.EventFormat != "" && filter.EventFormat != "client" && filter.EventFormat != "federation" {
|
||||
return errors.New("Bad event_format value. Must be one of [\"client\", \"federation\"]")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DefaultFilter returns the default filter used by the Matrix server if no filter is provided in
|
||||
// the request
|
||||
func DefaultFilter() Filter {
|
||||
return Filter{
|
||||
AccountData: DefaultEventFilter(),
|
||||
EventFields: nil,
|
||||
EventFormat: "client",
|
||||
Presence: DefaultEventFilter(),
|
||||
Room: RoomFilter{
|
||||
AccountData: DefaultRoomEventFilter(),
|
||||
Ephemeral: DefaultRoomEventFilter(),
|
||||
IncludeLeave: false,
|
||||
NotRooms: nil,
|
||||
Rooms: nil,
|
||||
State: DefaultStateFilter(),
|
||||
Timeline: DefaultRoomEventFilter(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultEventFilter returns the default event filter used by the Matrix server if no filter is
|
||||
// provided in the request
|
||||
func DefaultEventFilter() EventFilter {
|
||||
return EventFilter{
|
||||
// parity with synapse: https://github.com/matrix-org/synapse/blob/v1.80.0/synapse/api/filtering.py#L336
|
||||
Limit: 10,
|
||||
NotSenders: nil,
|
||||
NotTypes: nil,
|
||||
Senders: nil,
|
||||
Types: nil,
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultStateFilter returns the default state event filter used by the Matrix server if no filter
|
||||
// is provided in the request
|
||||
func DefaultStateFilter() StateFilter {
|
||||
return StateFilter{
|
||||
NotSenders: nil,
|
||||
NotTypes: nil,
|
||||
Senders: nil,
|
||||
Types: nil,
|
||||
LazyLoadMembers: false,
|
||||
IncludeRedundantMembers: false,
|
||||
NotRooms: nil,
|
||||
Rooms: nil,
|
||||
ContainsURL: nil,
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultRoomEventFilter returns the default room event filter used by the Matrix server if no
|
||||
// filter is provided in the request
|
||||
func DefaultRoomEventFilter() RoomEventFilter {
|
||||
return RoomEventFilter{
|
||||
// parity with synapse: https://github.com/matrix-org/synapse/blob/v1.80.0/synapse/api/filtering.py#L336
|
||||
Limit: 10,
|
||||
NotSenders: nil,
|
||||
NotTypes: nil,
|
||||
Senders: nil,
|
||||
Types: nil,
|
||||
NotRooms: nil,
|
||||
Rooms: nil,
|
||||
ContainsURL: nil,
|
||||
}
|
||||
}
|
60
syncapi/synctypes/filter_test.go
Normal file
60
syncapi/synctypes/filter_test.go
Normal file
|
@ -0,0 +1,60 @@
|
|||
package synctypes
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_Filter(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input []byte
|
||||
want RoomEventFilter
|
||||
}{
|
||||
{
|
||||
name: "empty types filter",
|
||||
input: []byte(`{ "types": [] }`),
|
||||
want: RoomEventFilter{
|
||||
Limit: 0,
|
||||
NotSenders: nil,
|
||||
NotTypes: nil,
|
||||
Senders: nil,
|
||||
Types: &[]string{},
|
||||
LazyLoadMembers: false,
|
||||
IncludeRedundantMembers: false,
|
||||
NotRooms: nil,
|
||||
Rooms: nil,
|
||||
ContainsURL: nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "absent types filter",
|
||||
input: []byte(`{}`),
|
||||
want: RoomEventFilter{
|
||||
Limit: 0,
|
||||
NotSenders: nil,
|
||||
NotTypes: nil,
|
||||
Senders: nil,
|
||||
Types: nil,
|
||||
LazyLoadMembers: false,
|
||||
IncludeRedundantMembers: false,
|
||||
NotRooms: nil,
|
||||
Rooms: nil,
|
||||
ContainsURL: nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var f RoomEventFilter
|
||||
if err := json.Unmarshal(tt.input, &f); err != nil {
|
||||
t.Fatalf("unable to parse filter: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(f, tt.want) {
|
||||
t.Fatalf("Expected %+v\ngot %+v", tt.want, f)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue