diff --git a/clientapi/routing/routing.go b/clientapi/routing/routing.go index 91a1588cb..5dc6d7db9 100644 --- a/clientapi/routing/routing.go +++ b/clientapi/routing/routing.go @@ -149,6 +149,31 @@ func Setup( return GetEvent(req, device, vars["roomID"], vars["eventID"], cfg, queryAPI, federation, keyRing) }), ).Methods(http.MethodGet, http.MethodOptions) + + r0mux.Handle("/rooms/{roomID}/state", common.MakeAuthAPI("room_state", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { + vars, err := common.URLDecodeMapValues(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } + return OnIncomingStateRequest(req.Context(), queryAPI, vars["roomID"]) + })).Methods(http.MethodGet, http.MethodOptions) + + r0mux.Handle("/rooms/{roomID}/state/{type}", common.MakeAuthAPI("room_state", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { + vars, err := common.URLDecodeMapValues(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } + return OnIncomingStateTypeRequest(req.Context(), queryAPI, vars["roomID"], vars["type"], "") + })).Methods(http.MethodGet, http.MethodOptions) + + r0mux.Handle("/rooms/{roomID}/state/{type}/{stateKey}", common.MakeAuthAPI("room_state", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { + vars, err := common.URLDecodeMapValues(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } + return OnIncomingStateTypeRequest(req.Context(), queryAPI, vars["roomID"], vars["type"], vars["stateKey"]) + })).Methods(http.MethodGet, http.MethodOptions) + r0mux.Handle("/rooms/{roomID}/state/{eventType:[^/]+/?}", common.MakeAuthAPI("send_message", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { vars, err := common.URLDecodeMapValues(mux.Vars(req)) @@ -164,6 +189,7 @@ func Setup( return SendEvent(req, device, vars["roomID"], eventType, nil, &emptyString, cfg, queryAPI, producer, nil) }), ).Methods(http.MethodPut, http.MethodOptions) + r0mux.Handle("/rooms/{roomID}/state/{eventType}/{stateKey}", common.MakeAuthAPI("send_message", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { vars, err := common.URLDecodeMapValues(mux.Vars(req)) diff --git a/syncapi/routing/state.go b/clientapi/routing/state.go similarity index 69% rename from syncapi/routing/state.go rename to clientapi/routing/state.go index 87b6396ac..c243eec0f 100644 --- a/syncapi/routing/state.go +++ b/clientapi/routing/state.go @@ -15,11 +15,12 @@ package routing import ( + "context" "encoding/json" "net/http" "github.com/matrix-org/dendrite/clientapi/jsonerror" - "github.com/matrix-org/dendrite/syncapi/storage" + "github.com/matrix-org/dendrite/roomserver/api" "github.com/matrix-org/dendrite/syncapi/types" "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/util" @@ -39,22 +40,29 @@ type stateEventInStateResp struct { // TODO: Check if the user is in the room. If not, check if the room's history // is publicly visible. Current behaviour is returning an empty array if the // user cannot see the room's history. -func OnIncomingStateRequest(req *http.Request, db storage.Database, roomID string) util.JSONResponse { +func OnIncomingStateRequest(ctx context.Context, queryAPI api.RoomserverQueryAPI, roomID string) util.JSONResponse { // TODO(#287): Auth request and handle the case where the user has left (where // we should return the state at the poin they left) + stateReq := api.QueryLatestEventsAndStateRequest{ + RoomID: roomID, + } + stateRes := api.QueryLatestEventsAndStateResponse{} - stateFilter := gomatrixserverlib.DefaultStateFilter() - // TODO: stateFilter should not limit the number of state events (or only limits abusive number of events) - - stateEvents, err := db.GetStateEventsForRoom(req.Context(), roomID, &stateFilter) - if err != nil { - util.GetLogger(req.Context()).WithError(err).Error("db.GetStateEventsForRoom failed") + if err := queryAPI.QueryLatestEventsAndState(ctx, &stateReq, &stateRes); err != nil { + util.GetLogger(ctx).WithError(err).Error("queryAPI.QueryLatestEventsAndState failed") return jsonerror.InternalServerError() } + if len(stateRes.StateEvents) == 0 { + return util.JSONResponse{ + Code: http.StatusNotFound, + JSON: jsonerror.NotFound("cannot find state"), + } + } + resp := []stateEventInStateResp{} // Fill the prev_content and replaces_state keys if necessary - for _, event := range stateEvents { + for _, event := range stateRes.StateEvents { stateEvent := stateEventInStateResp{ ClientEvent: gomatrixserverlib.HeaderedToClientEvents( []gomatrixserverlib.HeaderedEvent{event}, gomatrixserverlib.FormatAll, @@ -63,7 +71,7 @@ func OnIncomingStateRequest(req *http.Request, db storage.Database, roomID strin var prevEventRef types.PrevEventRef if len(event.Unsigned()) > 0 { if err := json.Unmarshal(event.Unsigned(), &prevEventRef); err != nil { - util.GetLogger(req.Context()).WithError(err).Error("json.Unmarshal failed") + util.GetLogger(ctx).WithError(err).Error("json.Unmarshal failed") return jsonerror.InternalServerError() } // Fills the previous state event ID if the state event replaces another @@ -90,24 +98,32 @@ func OnIncomingStateRequest(req *http.Request, db storage.Database, roomID strin // /rooms/{roomID}/state/{type}/{statekey} request. It will look in current // state to see if there is an event with that type and state key, if there // is then (by default) we return the content, otherwise a 404. -func OnIncomingStateTypeRequest(req *http.Request, db storage.Database, roomID string, evType, stateKey string) util.JSONResponse { +func OnIncomingStateTypeRequest(ctx context.Context, queryAPI api.RoomserverQueryAPI, roomID string, evType, stateKey string) util.JSONResponse { // TODO(#287): Auth request and handle the case where the user has left (where // we should return the state at the poin they left) - - logger := util.GetLogger(req.Context()) - logger.WithFields(log.Fields{ + util.GetLogger(ctx).WithFields(log.Fields{ "roomID": roomID, "evType": evType, "stateKey": stateKey, }).Info("Fetching state") - event, err := db.GetStateEvent(req.Context(), roomID, evType, stateKey) - if err != nil { - util.GetLogger(req.Context()).WithError(err).Error("db.GetStateEvent failed") + stateReq := api.QueryLatestEventsAndStateRequest{ + RoomID: roomID, + StateToFetch: []gomatrixserverlib.StateKeyTuple{ + gomatrixserverlib.StateKeyTuple{ + EventType: evType, + StateKey: stateKey, + }, + }, + } + stateRes := api.QueryLatestEventsAndStateResponse{} + + if err := queryAPI.QueryLatestEventsAndState(ctx, &stateReq, &stateRes); err != nil { + util.GetLogger(ctx).WithError(err).Error("queryAPI.QueryLatestEventsAndState failed") return jsonerror.InternalServerError() } - if event == nil { + if len(stateRes.StateEvents) == 0 { return util.JSONResponse{ Code: http.StatusNotFound, JSON: jsonerror.NotFound("cannot find state"), @@ -115,7 +131,7 @@ func OnIncomingStateTypeRequest(req *http.Request, db storage.Database, roomID s } stateEvent := stateEventInStateResp{ - ClientEvent: gomatrixserverlib.HeaderedToClientEvent(*event, gomatrixserverlib.FormatAll), + ClientEvent: gomatrixserverlib.HeaderedToClientEvent(stateRes.StateEvents[0], gomatrixserverlib.FormatAll), } return util.JSONResponse{ diff --git a/common/events.go b/common/events.go index adbdf3389..556b7b671 100644 --- a/common/events.go +++ b/common/events.go @@ -73,6 +73,10 @@ func AddPrevEventsToEvent( return fmt.Errorf("gomatrixserverlib.StateNeededForEventBuilder: %w", err) } + if len(eventsNeeded.Tuples()) == 0 { + return errors.New("expecting state tuples for event builder, got none") + } + // Ask the roomserver for information about this room queryReq := api.QueryLatestEventsAndStateRequest{ RoomID: builder.RoomID, diff --git a/federationapi/routing/threepid.go b/federationapi/routing/threepid.go index da7174730..f93d934ed 100644 --- a/federationapi/routing/threepid.go +++ b/federationapi/routing/threepid.go @@ -271,6 +271,10 @@ func buildMembershipEvent( return nil, err } + if len(eventsNeeded.Tuples()) == 0 { + return nil, errors.New("expecting state tuples for event builder, got none") + } + // Ask the roomserver for information about this room queryReq := roomserverAPI.QueryLatestEventsAndStateRequest{ RoomID: builder.RoomID, diff --git a/roomserver/alias/alias.go b/roomserver/alias/alias.go index 032b8da1c..eb606e5cd 100644 --- a/roomserver/alias/alias.go +++ b/roomserver/alias/alias.go @@ -17,6 +17,7 @@ package alias import ( "context" "encoding/json" + "errors" "net/http" "time" @@ -218,6 +219,9 @@ func (r *RoomserverAliasAPI) sendUpdatedAliasesEvent( if err != nil { return err } + if len(eventsNeeded.Tuples()) == 0 { + return errors.New("expecting state tuples for event builder, got none") + } req := roomserverAPI.QueryLatestEventsAndStateRequest{ RoomID: roomID, StateToFetch: eventsNeeded.Tuples(), diff --git a/roomserver/query/query.go b/roomserver/query/query.go index 7e05fe36f..12d8436ef 100644 --- a/roomserver/query/query.go +++ b/roomserver/query/query.go @@ -132,10 +132,18 @@ func (r *RoomserverQueryAPI) QueryLatestEventsAndState( return err } - // Look up the current state for the requested tuples. - stateEntries, err := roomState.LoadStateAtSnapshotForStringTuples( - ctx, currentStateSnapshotNID, request.StateToFetch, - ) + var stateEntries []types.StateEntry + if len(request.StateToFetch) == 0 { + // Look up all room state. + stateEntries, err = roomState.LoadStateAtSnapshot( + ctx, currentStateSnapshotNID, + ) + } else { + // Look up the current state for the requested tuples. + stateEntries, err = roomState.LoadStateAtSnapshotForStringTuples( + ctx, currentStateSnapshotNID, request.StateToFetch, + ) + } if err != nil { return err } diff --git a/syncapi/routing/routing.go b/syncapi/routing/routing.go index be90e0a07..9078b87ff 100644 --- a/syncapi/routing/routing.go +++ b/syncapi/routing/routing.go @@ -56,30 +56,6 @@ func Setup( return srp.OnIncomingSyncRequest(req, device) })).Methods(http.MethodGet, http.MethodOptions) - r0mux.Handle("/rooms/{roomID}/state", common.MakeAuthAPI("room_state", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { - vars, err := common.URLDecodeMapValues(mux.Vars(req)) - if err != nil { - return util.ErrorResponse(err) - } - return OnIncomingStateRequest(req, syncDB, vars["roomID"]) - })).Methods(http.MethodGet, http.MethodOptions) - - r0mux.Handle("/rooms/{roomID}/state/{type}", common.MakeAuthAPI("room_state", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { - vars, err := common.URLDecodeMapValues(mux.Vars(req)) - if err != nil { - return util.ErrorResponse(err) - } - return OnIncomingStateTypeRequest(req, syncDB, vars["roomID"], vars["type"], "") - })).Methods(http.MethodGet, http.MethodOptions) - - r0mux.Handle("/rooms/{roomID}/state/{type}/{stateKey}", common.MakeAuthAPI("room_state", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { - vars, err := common.URLDecodeMapValues(mux.Vars(req)) - if err != nil { - return util.ErrorResponse(err) - } - return OnIncomingStateTypeRequest(req, syncDB, vars["roomID"], vars["type"], vars["stateKey"]) - })).Methods(http.MethodGet, http.MethodOptions) - r0mux.Handle("/rooms/{roomID}/messages", common.MakeAuthAPI("room_messages", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { vars, err := common.URLDecodeMapValues(mux.Vars(req)) if err != nil {