mirror of
https://github.com/1f349/dendrite.git
synced 2024-11-22 11:41:38 +00:00
MSC2946: Treat federation responses the same way as local responses (#1724)
* Start treating fed rooms/events the same as local rooms/events * Share more code
This commit is contained in:
parent
b70238f2d5
commit
c08e38df2c
@ -239,33 +239,23 @@ func (w *walker) walk() *gomatrixserverlib.MSC2946SpacesResponse {
|
|||||||
// Mark this room as processed.
|
// Mark this room as processed.
|
||||||
processed[roomID] = true
|
processed[roomID] = true
|
||||||
|
|
||||||
// Is the caller currently joined to the room or is the room `world_readable`
|
// Collect rooms/events to send back (either locally or fetched via federation)
|
||||||
// If no, skip this room. If yes, continue.
|
var discoveredRooms []gomatrixserverlib.MSC2946Room
|
||||||
if !w.roomExists(roomID) || !w.authorised(roomID) {
|
var discoveredEvents []gomatrixserverlib.MSC2946StrippedEvent
|
||||||
// attempt to query this room over federation, as either we've never heard of it before
|
|
||||||
// or we've left it and hence are not authorised (but info may be exposed regardless)
|
// If we know about this room and the caller is authorised (joined/world_readable) then pull
|
||||||
fedRes, err := w.federatedRoomInfo(roomID)
|
// events locally
|
||||||
if err != nil {
|
if w.roomExists(roomID) && w.authorised(roomID) {
|
||||||
util.GetLogger(w.ctx).WithError(err).WithField("room_id", roomID).Errorf("failed to query federated spaces")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if fedRes != nil {
|
|
||||||
res = combineResponses(res, *fedRes)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// Get all `m.space.child` and `m.space.parent` state events for the room. *In addition*, get
|
// Get all `m.space.child` and `m.space.parent` state events for the room. *In addition*, get
|
||||||
// all `m.space.child` and `m.space.parent` state events which *point to* (via `state_key` or `content.room_id`)
|
// all `m.space.child` and `m.space.parent` state events which *point to* (via `state_key` or `content.room_id`)
|
||||||
// this room. This requires servers to store reverse lookups.
|
// this room. This requires servers to store reverse lookups.
|
||||||
refs, err := w.references(roomID)
|
events, err := w.references(roomID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.GetLogger(w.ctx).WithError(err).WithField("room_id", roomID).Error("failed to extract references for room")
|
util.GetLogger(w.ctx).WithError(err).WithField("room_id", roomID).Error("failed to extract references for room")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
discoveredEvents = events
|
||||||
|
|
||||||
// If this room has not ever been in `rooms` (across multiple requests), extract the
|
|
||||||
// `PublicRoomsChunk` for this room.
|
|
||||||
if !w.alreadySent(roomID) && !w.roomIsExcluded(roomID) {
|
|
||||||
pubRoom := w.publicRoomsChunk(roomID)
|
pubRoom := w.publicRoomsChunk(roomID)
|
||||||
roomType := ""
|
roomType := ""
|
||||||
create := w.stateEvent(roomID, gomatrixserverlib.MRoomCreate, "")
|
create := w.stateEvent(roomID, gomatrixserverlib.MRoomCreate, "")
|
||||||
@ -275,12 +265,31 @@ func (w *walker) walk() *gomatrixserverlib.MSC2946SpacesResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add the total number of events to `PublicRoomsChunk` under `num_refs`. Add `PublicRoomsChunk` to `rooms`.
|
// Add the total number of events to `PublicRoomsChunk` under `num_refs`. Add `PublicRoomsChunk` to `rooms`.
|
||||||
res.Rooms = append(res.Rooms, gomatrixserverlib.MSC2946Room{
|
discoveredRooms = append(discoveredRooms, gomatrixserverlib.MSC2946Room{
|
||||||
PublicRoom: *pubRoom,
|
PublicRoom: *pubRoom,
|
||||||
NumRefs: refs.len(),
|
NumRefs: len(discoveredEvents),
|
||||||
RoomType: roomType,
|
RoomType: roomType,
|
||||||
})
|
})
|
||||||
w.markSent(roomID)
|
} else {
|
||||||
|
// attempt to query this room over federation, as either we've never heard of it before
|
||||||
|
// or we've left it and hence are not authorised (but info may be exposed regardless)
|
||||||
|
fedRes, err := w.federatedRoomInfo(roomID)
|
||||||
|
if err != nil {
|
||||||
|
util.GetLogger(w.ctx).WithError(err).WithField("room_id", roomID).Errorf("failed to query federated spaces")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if fedRes != nil {
|
||||||
|
discoveredRooms = fedRes.Rooms
|
||||||
|
discoveredEvents = fedRes.Events
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this room has not ever been in `rooms` (across multiple requests), send it now
|
||||||
|
for _, room := range discoveredRooms {
|
||||||
|
if !w.alreadySent(room.RoomID) && !w.roomIsExcluded(room.RoomID) {
|
||||||
|
res.Rooms = append(res.Rooms, room)
|
||||||
|
w.markSent(room.RoomID)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uniqueRooms := make(set)
|
uniqueRooms := make(set)
|
||||||
@ -288,45 +297,37 @@ func (w *walker) walk() *gomatrixserverlib.MSC2946SpacesResponse {
|
|||||||
// If this is the root room from the original request, insert all these events into `events` if
|
// If this is the root room from the original request, insert all these events into `events` if
|
||||||
// they haven't been added before (across multiple requests).
|
// they haven't been added before (across multiple requests).
|
||||||
if w.rootRoomID == roomID {
|
if w.rootRoomID == roomID {
|
||||||
for _, ev := range refs.events() {
|
for _, ev := range discoveredEvents {
|
||||||
if !w.alreadySent(ev.EventID()) {
|
if !w.alreadySent(eventKey(&ev)) {
|
||||||
strip := stripped(ev.Event)
|
res.Events = append(res.Events, ev)
|
||||||
if strip == nil {
|
uniqueRooms[ev.RoomID] = true
|
||||||
continue
|
uniqueRooms[spaceTargetStripped(&ev)] = true
|
||||||
}
|
w.markSent(eventKey(&ev))
|
||||||
res.Events = append(res.Events, *strip)
|
|
||||||
uniqueRooms[ev.RoomID()] = true
|
|
||||||
uniqueRooms[SpaceTarget(ev)] = true
|
|
||||||
w.markSent(ev.EventID())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Else add them to `events` honouring the `limit` and `max_rooms_per_space` values. If either
|
// Else add them to `events` honouring the `limit` and `max_rooms_per_space` values. If either
|
||||||
// are exceeded, stop adding events. If the event has already been added, do not add it again.
|
// are exceeded, stop adding events. If the event has already been added, do not add it again.
|
||||||
numAdded := 0
|
numAdded := 0
|
||||||
for _, ev := range refs.events() {
|
for _, ev := range discoveredEvents {
|
||||||
if w.req.Limit > 0 && len(res.Events) >= w.req.Limit {
|
if w.req.Limit > 0 && len(res.Events) >= w.req.Limit {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if w.req.MaxRoomsPerSpace > 0 && numAdded >= w.req.MaxRoomsPerSpace {
|
if w.req.MaxRoomsPerSpace > 0 && numAdded >= w.req.MaxRoomsPerSpace {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if w.alreadySent(ev.EventID()) {
|
if w.alreadySent(eventKey(&ev)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Skip the room if it's part of exclude_rooms but ONLY IF the source matches, as we still
|
// Skip the room if it's part of exclude_rooms but ONLY IF the source matches, as we still
|
||||||
// want to catch arrows which point to excluded rooms.
|
// want to catch arrows which point to excluded rooms.
|
||||||
if w.roomIsExcluded(ev.RoomID()) {
|
if w.roomIsExcluded(ev.RoomID) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
strip := stripped(ev.Event)
|
res.Events = append(res.Events, ev)
|
||||||
if strip == nil {
|
uniqueRooms[ev.RoomID] = true
|
||||||
continue
|
uniqueRooms[spaceTargetStripped(&ev)] = true
|
||||||
}
|
w.markSent(eventKey(&ev))
|
||||||
res.Events = append(res.Events, *strip)
|
|
||||||
uniqueRooms[ev.RoomID()] = true
|
|
||||||
uniqueRooms[SpaceTarget(ev)] = true
|
|
||||||
w.markSent(ev.EventID())
|
|
||||||
// we don't distinguish between child state events and parent state events for the purposes of
|
// we don't distinguish between child state events and parent state events for the purposes of
|
||||||
// max_rooms_per_space, maybe we should?
|
// max_rooms_per_space, maybe we should?
|
||||||
numAdded++
|
numAdded++
|
||||||
@ -521,51 +522,27 @@ func (w *walker) authorisedUser(roomID string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// references returns all references pointing to or from this room.
|
// references returns all references pointing to or from this room.
|
||||||
func (w *walker) references(roomID string) (eventLookup, error) {
|
func (w *walker) references(roomID string) ([]gomatrixserverlib.MSC2946StrippedEvent, error) {
|
||||||
events, err := w.db.References(w.ctx, roomID)
|
events, err := w.db.References(w.ctx, roomID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
el := make(eventLookup)
|
el := make([]gomatrixserverlib.MSC2946StrippedEvent, 0, len(events))
|
||||||
for _, ev := range events {
|
for _, ev := range events {
|
||||||
// only return events that have a `via` key as per MSC1772
|
// only return events that have a `via` key as per MSC1772
|
||||||
// else we'll incorrectly walk redacted events (as the link
|
// else we'll incorrectly walk redacted events (as the link
|
||||||
// is in the state_key)
|
// is in the state_key)
|
||||||
if gjson.GetBytes(ev.Content(), "via").Exists() {
|
if gjson.GetBytes(ev.Content(), "via").Exists() {
|
||||||
el.set(ev)
|
strip := stripped(ev.Event)
|
||||||
|
if strip == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
el = append(el, *strip)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return el, nil
|
return el, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// state event lookup across multiple rooms keyed on event type
|
|
||||||
// NOT THREAD SAFE
|
|
||||||
type eventLookup map[string][]*gomatrixserverlib.HeaderedEvent
|
|
||||||
|
|
||||||
func (el eventLookup) set(ev *gomatrixserverlib.HeaderedEvent) {
|
|
||||||
evs := el[ev.Type()]
|
|
||||||
if evs == nil {
|
|
||||||
evs = make([]*gomatrixserverlib.HeaderedEvent, 0)
|
|
||||||
}
|
|
||||||
evs = append(evs, ev)
|
|
||||||
el[ev.Type()] = evs
|
|
||||||
}
|
|
||||||
|
|
||||||
func (el eventLookup) len() int {
|
|
||||||
sum := 0
|
|
||||||
for _, evs := range el {
|
|
||||||
sum += len(evs)
|
|
||||||
}
|
|
||||||
return sum
|
|
||||||
}
|
|
||||||
|
|
||||||
func (el eventLookup) events() (events []*gomatrixserverlib.HeaderedEvent) {
|
|
||||||
for _, evs := range el {
|
|
||||||
events = append(events, evs...)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type set map[string]bool
|
type set map[string]bool
|
||||||
|
|
||||||
func stripped(ev *gomatrixserverlib.Event) *gomatrixserverlib.MSC2946StrippedEvent {
|
func stripped(ev *gomatrixserverlib.Event) *gomatrixserverlib.MSC2946StrippedEvent {
|
||||||
@ -581,27 +558,19 @@ func stripped(ev *gomatrixserverlib.Event) *gomatrixserverlib.MSC2946StrippedEve
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func combineResponses(local, remote gomatrixserverlib.MSC2946SpacesResponse) gomatrixserverlib.MSC2946SpacesResponse {
|
func eventKey(event *gomatrixserverlib.MSC2946StrippedEvent) string {
|
||||||
knownRooms := make(set)
|
return event.RoomID + "|" + event.Type + "|" + event.StateKey
|
||||||
for _, room := range local.Rooms {
|
}
|
||||||
knownRooms[room.RoomID] = true
|
|
||||||
}
|
func spaceTargetStripped(event *gomatrixserverlib.MSC2946StrippedEvent) string {
|
||||||
knownEvents := make(set)
|
if event.StateKey == "" {
|
||||||
for _, event := range local.Events {
|
return "" // no-op
|
||||||
knownEvents[event.RoomID+event.Type+event.StateKey] = true
|
}
|
||||||
}
|
switch event.Type {
|
||||||
// mux in remote entries if and only if they aren't present already
|
case ConstSpaceParentEventType:
|
||||||
for _, room := range remote.Rooms {
|
return event.StateKey
|
||||||
if knownRooms[room.RoomID] {
|
case ConstSpaceChildEventType:
|
||||||
continue
|
return event.StateKey
|
||||||
}
|
}
|
||||||
local.Rooms = append(local.Rooms, room)
|
return ""
|
||||||
}
|
|
||||||
for _, event := range remote.Events {
|
|
||||||
if knownEvents[event.RoomID+event.Type+event.StateKey] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
local.Events = append(local.Events, event)
|
|
||||||
}
|
|
||||||
return local
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user