Don't generate stripped state in client API more times than necessary, generate output events on receiving end of federated invite

This commit is contained in:
Neil Alexander 2020-08-17 16:40:49 +01:00
parent 9dcc67122a
commit 91c6c694b2
No known key found for this signature in database
GPG key ID: A02A2019A2BB0944
2 changed files with 76 additions and 50 deletions

View file

@ -371,53 +371,60 @@ func createRoom(
} }
// If this is a direct message then we should invite the participants. // If this is a direct message then we should invite the participants.
for _, invitee := range r.Invite { if len(r.Invite) > 0 {
// Build the invite event.
inviteEvent, err := buildMembershipEvent(
req.Context(), invitee, "", accountDB, device, gomatrixserverlib.Invite,
roomID, true, cfg, evTime, rsAPI, asAPI,
)
if err != nil {
util.GetLogger(req.Context()).WithError(err).Error("buildMembershipEvent failed")
continue
}
// Build some stripped state for the invite. // Build some stripped state for the invite.
candidates := append(gomatrixserverlib.UnwrapEventHeaders(builtEvents), inviteEvent.Event)
var strippedState []gomatrixserverlib.InviteV2StrippedState var strippedState []gomatrixserverlib.InviteV2StrippedState
for _, event := range candidates { for _, event := range builtEvents {
switch event.Type() { switch event.Type() {
case gomatrixserverlib.MRoomName: case gomatrixserverlib.MRoomName:
fallthrough fallthrough
case gomatrixserverlib.MRoomCanonicalAlias: case gomatrixserverlib.MRoomCanonicalAlias:
fallthrough fallthrough
case "m.room.avatar": // TODO: move this to gmsl
fallthrough
case "m.room.encryption": // TODO: move this to gmsl case "m.room.encryption": // TODO: move this to gmsl
fallthrough fallthrough
case gomatrixserverlib.MRoomMember: case gomatrixserverlib.MRoomMember:
fallthrough fallthrough
case gomatrixserverlib.MRoomJoinRules: case gomatrixserverlib.MRoomJoinRules:
ev := event.Unwrap()
strippedState = append( strippedState = append(
strippedState, strippedState,
gomatrixserverlib.NewInviteV2StrippedState(&event), gomatrixserverlib.NewInviteV2StrippedState(&ev),
) )
} }
} }
// Send the invite event to the roomserver.
err = roomserverAPI.SendInvite( // Process the invites.
req.Context(), rsAPI, for _, invitee := range r.Invite {
inviteEvent.Headered(roomVersion), // Build the invite event.
strippedState, // invite room state inviteEvent, err := buildMembershipEvent(
cfg.Matrix.ServerName, // send as server req.Context(), invitee, "", accountDB, device, gomatrixserverlib.Invite,
nil, // transaction ID roomID, true, cfg, evTime, rsAPI, asAPI,
) )
switch e := err.(type) { if err != nil {
case *roomserverAPI.PerformError: util.GetLogger(req.Context()).WithError(err).Error("buildMembershipEvent failed")
return e.JSONResponse() continue
case nil: }
default: // Send the invite event to the roomserver.
util.GetLogger(req.Context()).WithError(err).Error("roomserverAPI.SendInvite failed") err = roomserverAPI.SendInvite(
return util.JSONResponse{ req.Context(),
Code: http.StatusInternalServerError, rsAPI,
JSON: jsonerror.InternalServerError(), inviteEvent.Headered(roomVersion),
strippedState, // invite room state
cfg.Matrix.ServerName, // send as server
nil, // transaction ID
)
switch e := err.(type) {
case *roomserverAPI.PerformError:
return e.JSONResponse()
case nil:
default:
util.GetLogger(req.Context()).WithError(err).Error("roomserverAPI.SendInvite failed")
return util.JSONResponse{
Code: http.StatusInternalServerError,
JSON: jsonerror.InternalServerError(),
}
} }
} }
} }

View file

@ -95,8 +95,10 @@ func (r *RoomserverInternalAPI) PerformInvite(
} }
if isOriginLocal { if isOriginLocal {
// check that the user is allowed to do this. We can only do this check if it is // The invite originated locally. Therefore we have a responsibility to
// a local invite as we have the auth events, else we have to take it on trust. // try and see if the user is allowed to make this invite. We can't do
// this for invites coming in over federation - we have to take those on
// trust.
_, err = checkAuthEvents(ctx, r.DB, event, event.AuthEventIDs()) _, err = checkAuthEvents(ctx, r.DB, event, event.AuthEventIDs())
if err != nil { if err != nil {
log.WithError(err).WithField("event_id", event.EventID()).WithField("auth_event_ids", event.AuthEventIDs()).Error( log.WithError(err).WithField("event_id", event.EventID()).WithField("auth_event_ids", event.AuthEventIDs()).Error(
@ -133,27 +135,44 @@ func (r *RoomserverInternalAPI) PerformInvite(
} }
event = fsRes.Event event = fsRes.Event
} }
}
// Send the invite event to the roomserver input stream. This will // Send the invite event to the roomserver input stream. This will
// notify existing users in the room about the invite, update the // notify existing users in the room about the invite, update the
// membership table and ensure that the event is ready and available // membership table and ensure that the event is ready and available
// to use as an auth event when accepting the invite. We don't // to use as an auth event when accepting the invite.
// check the return value here because it may be possible that we inputReq := &api.InputRoomEventsRequest{
// don't know about this room yet if we received the invite over InputRoomEvents: []api.InputRoomEvent{
// federation. {
inputReq := &api.InputRoomEventsRequest{ Kind: api.KindNew,
InputRoomEvents: []api.InputRoomEvent{ Event: event,
{ AuthEventIDs: event.AuthEventIDs(),
Kind: api.KindNew, SendAsServer: string(r.Cfg.Matrix.ServerName),
Event: event, },
AuthEventIDs: event.AuthEventIDs(),
SendAsServer: string(r.Cfg.Matrix.ServerName),
}, },
}, }
inputRes := &api.InputRoomEventsResponse{}
if err = r.InputRoomEvents(context.Background(), inputReq, inputRes); err != nil {
return fmt.Errorf("r.InputRoomEvents: %w", err)
}
} else {
// The invite originated over federation. Process the membership
// update, which will notify the sync API etc about the incoming
// invite.
updater, err := r.DB.MembershipUpdater(ctx, roomID, targetUserID, isTargetLocal, req.RoomVersion)
if err != nil {
return fmt.Errorf("r.DB.MembershipUpdater: %w", err)
}
unwrapped := event.Unwrap()
outputUpdates, err := updateToInviteMembership(updater, &unwrapped, nil, req.Event.RoomVersion)
if err != nil {
return fmt.Errorf("updateToInviteMembership: %w", err)
}
if err = r.WriteOutputEvents(roomID, outputUpdates); err != nil {
return fmt.Errorf("r.WriteOutputEvents: %w", err)
}
} }
inputRes := &api.InputRoomEventsResponse{}
go r.InputRoomEvents(context.Background(), inputReq, inputRes) // nolint:errcheck
return nil return nil
} }