diff --git a/roomserver/internal/perform_join.go b/roomserver/internal/perform_join.go index 99e10d974..c11f52011 100644 --- a/roomserver/internal/perform_join.go +++ b/roomserver/internal/perform_join.go @@ -121,6 +121,22 @@ func (r *RoomserverInternalAPI) performJoinRoomByID( return fmt.Errorf("eb.SetContent: %w", err) } + // First work out if this is in response to an existing invite. + // If it is then we avoid the situation where we might think we + // know about a room in the following section but don't know the + // latest state as all of our users have left. + isInvitePending, inviteSender, err := r.isInvitePending(ctx, req.RoomIDOrAlias, req.UserID) + if err == nil && isInvitePending { + // Add the server of the person who invited us to the server list, + // as they should be a fairly good bet. + if _, inviterDomain, ierr := gomatrixserverlib.SplitID('!', inviteSender); ierr == nil { + req.ServerNames = append(req.ServerNames, inviterDomain) + } + + // Perform a federated room join. + return r.performFederatedJoinRoomByID(ctx, req, res) + } + // Try to construct an actual join event from the template. // If this succeeds then it is a sign that the room already exists // locally on the homeserver. @@ -178,21 +194,32 @@ func (r *RoomserverInternalAPI) performJoinRoomByID( return fmt.Errorf("Room ID %q does not exist", req.RoomIDOrAlias) } - // Try joining by all of the supplied server names. - fedReq := fsAPI.PerformJoinRequest{ - RoomID: req.RoomIDOrAlias, // the room ID to try and join - UserID: req.UserID, // the user ID joining the room - ServerNames: req.ServerNames, // the server to try joining with - Content: req.Content, // the membership event content - } - fedRes := fsAPI.PerformJoinResponse{} - err = r.fsAPI.PerformJoin(ctx, &fedReq, &fedRes) - if err != nil { - return fmt.Errorf("Error joining federated room: %q", err) - } + // Perform a federated room join. + return r.performFederatedJoinRoomByID(ctx, req, res) default: - return fmt.Errorf("Error joining room %q: %w", req.RoomIDOrAlias, err) + // Something else went wrong. + return fmt.Errorf("Error joining local room: %q", err) + } + + return nil +} + +func (r *RoomserverInternalAPI) performFederatedJoinRoomByID( + ctx context.Context, + req *api.PerformJoinRequest, + res *api.PerformJoinResponse, // nolint:unparam +) error { + // Try joining by all of the supplied server names. + fedReq := fsAPI.PerformJoinRequest{ + RoomID: req.RoomIDOrAlias, // the room ID to try and join + UserID: req.UserID, // the user ID joining the room + ServerNames: req.ServerNames, // the server to try joining with + Content: req.Content, // the membership event content + } + fedRes := fsAPI.PerformJoinResponse{} + if err := r.fsAPI.PerformJoin(ctx, &fedReq, &fedRes); err != nil { + return fmt.Errorf("Error joining federated room: %q", err) } return nil diff --git a/roomserver/internal/perform_leave.go b/roomserver/internal/perform_leave.go index 422748e6a..5d9b251c9 100644 --- a/roomserver/internal/perform_leave.go +++ b/roomserver/internal/perform_leave.go @@ -38,7 +38,7 @@ func (r *RoomserverInternalAPI) performLeaveRoomByID( ) error { // If there's an invite outstanding for the room then respond to // that. - isInvitePending, senderUser, err := r.isInvitePending(ctx, req, res) + isInvitePending, senderUser, err := r.isInvitePending(ctx, req.RoomID, req.UserID) if err == nil && isInvitePending { return r.performRejectInvite(ctx, req, res, senderUser) } @@ -160,23 +160,22 @@ func (r *RoomserverInternalAPI) performRejectInvite( func (r *RoomserverInternalAPI) isInvitePending( ctx context.Context, - req *api.PerformLeaveRequest, - res *api.PerformLeaveResponse, // nolint:unparam + roomID, userID string, ) (bool, string, error) { // Look up the room NID for the supplied room ID. - roomNID, err := r.DB.RoomNID(ctx, req.RoomID) + roomNID, err := r.DB.RoomNID(ctx, roomID) if err != nil { return false, "", fmt.Errorf("r.DB.RoomNID: %w", err) } // Look up the state key NID for the supplied user ID. - targetUserNIDs, err := r.DB.EventStateKeyNIDs(ctx, []string{req.UserID}) + targetUserNIDs, err := r.DB.EventStateKeyNIDs(ctx, []string{userID}) if err != nil { return false, "", fmt.Errorf("r.DB.EventStateKeyNIDs: %w", err) } - targetUserNID, targetUserFound := targetUserNIDs[req.UserID] + targetUserNID, targetUserFound := targetUserNIDs[userID] if !targetUserFound { - return false, "", fmt.Errorf("missing NID for user %q (%+v)", req.UserID, targetUserNIDs) + return false, "", fmt.Errorf("missing NID for user %q (%+v)", userID, targetUserNIDs) } // Let's see if we have an event active for the user in the room. If