diff --git a/src/github.com/matrix-org/dendrite/roomserver/api/query.go b/src/github.com/matrix-org/dendrite/roomserver/api/query.go index 6f38da39a..14afb3e87 100644 --- a/src/github.com/matrix-org/dendrite/roomserver/api/query.go +++ b/src/github.com/matrix-org/dendrite/roomserver/api/query.go @@ -24,7 +24,7 @@ import ( // QueryLatestEventsAndStateRequest is a request to QueryLatestEventsAndState type QueryLatestEventsAndStateRequest struct { - // The roomID to query the latest events for. + // The room ID to query the latest events for. RoomID string // The state key tuples to fetch from the room current state. // If this list is empty or nil then no state events are returned. @@ -44,6 +44,30 @@ type QueryLatestEventsAndStateResponse struct { StateEvents []gomatrixserverlib.Event } +// QueryStateAfterEventsRequest is a request to QueryStateAfterEvents +type QueryStateAfterEventsRequest struct { + // The room ID to query the state in. + RoomID string + // The list of previous events to return the events after. + PrevEventIDs []string + // The state key tuples to fetch from the state + StateToFetch []gomatrixserverlib.StateKeyTuple +} + +// QueryStateAfterEventsResponse is a response to QueryStateAfterEvents +type QueryStateAfterEventsResponse struct { + // Copy of the request for debugging. + QueryStateAfterEventsRequest + // Does the room exist on this roomserver? + // If the room doesn't exist this will be false and StateEvents will be empty. + RoomExists bool + // Do all the previous events exist on this roomserver? + // If some of previous events do not exist this will be false and StateEvents will be empty. + PrevEventsExist bool + // The state events requested. + StateEvents []gomatrixserverlib.Event +} + // RoomserverQueryAPI is used to query information from the room server. type RoomserverQueryAPI interface { // Query the latest events and state for a room from the room server. @@ -51,11 +75,20 @@ type RoomserverQueryAPI interface { request *QueryLatestEventsAndStateRequest, response *QueryLatestEventsAndStateResponse, ) error + + // Query the state after a list of events in a room from the room server. + QueryStateAfterEvents( + request *QueryStateAfterEventsRequest, + response *QueryStateAfterEventsResponse, + ) error } // RoomserverQueryLatestEventsAndStatePath is the HTTP path for the QueryLatestEventsAndState API. const RoomserverQueryLatestEventsAndStatePath = "/api/roomserver/QueryLatestEventsAndState" +// RoomserverQueryStateAfterEventsPath is the HTTP path for the QueryStateAfterEvents API. +const RoomserverQueryStateAfterEventsPath = "/api/roomserver/QueryStateAfterEvents" + // NewRoomserverQueryAPIHTTP creates a RoomserverQueryAPI implemented by talking to a HTTP POST API. // If httpClient is nil then it uses the http.DefaultClient func NewRoomserverQueryAPIHTTP(roomserverURL string, httpClient *http.Client) RoomserverQueryAPI { @@ -79,6 +112,15 @@ func (h *httpRoomserverQueryAPI) QueryLatestEventsAndState( return postJSON(h.httpClient, apiURL, request, response) } +// QueryStateAfterEvents implements RoomserverQueryAPI +func (h *httpRoomserverQueryAPI) QueryStateAfterEvents( + request *QueryStateAfterEventsRequest, + response *QueryStateAfterEventsResponse, +) error { + apiURL := h.roomserverURL + RoomserverQueryStateAfterEventsPath + return postJSON(h.httpClient, apiURL, request, response) +} + func postJSON(httpClient http.Client, apiURL string, request, response interface{}) error { jsonBytes, err := json.Marshal(request) if err != nil { diff --git a/src/github.com/matrix-org/dendrite/roomserver/query/query.go b/src/github.com/matrix-org/dendrite/roomserver/query/query.go index bf15e6b97..c4a743300 100644 --- a/src/github.com/matrix-org/dendrite/roomserver/query/query.go +++ b/src/github.com/matrix-org/dendrite/roomserver/query/query.go @@ -38,6 +38,8 @@ type RoomserverQueryAPIDatabase interface { // Lookup the Events for a list of numeric event IDs. // Returns a list of events sorted by numeric event ID. Events(eventNIDs []types.EventNID) ([]types.Event, error) + // Lookup the state at a list of string event IDs. + StateAtEventIDs(eventIDs []string) ([]types.StateAtEvent, error) } // RoomserverQueryAPI is an implementation of RoomserverQueryAPI @@ -88,6 +90,33 @@ func (r *RoomserverQueryAPI) QueryLatestEventsAndState( return nil } +// QueryStateAfterEvents implements api.RoomserverQueryAPI +func (r *RoomserverQueryAPI) QueryStateAfterEvents( + request *api.QueryStateAfterEventsRequest, + response *api.QueryStateAfterEventsResponse, +) (err error) { + response.QueryStateAfterEventsRequest = *request + roomNID, err := r.DB.RoomNID(request.RoomID) + if err != nil { + return err + } + if roomNID == 0 { + return nil + } + response.RoomExists = true + + _, err = r.DB.StateAtEventIDs(request.PrevEventIDs) + if err != nil { + // TODO: Check if the error was because we are missing events from the + // database or are missing state at events from the database. + return err + } + response.PrevEventsExist = true + + // TODO: Calculate the state and return it. + return nil +} + // SetupHTTP adds the RoomserverQueryAPI handlers to the http.ServeMux. func (r *RoomserverQueryAPI) SetupHTTP(servMux *http.ServeMux) { servMux.Handle( @@ -104,6 +133,20 @@ func (r *RoomserverQueryAPI) SetupHTTP(servMux *http.ServeMux) { return util.JSONResponse{Code: 200, JSON: &response} }), ) + servMux.Handle( + api.RoomserverQueryStateAfterEventsPath, + makeAPI("query_state_after_events", func(req *http.Request) util.JSONResponse { + var request api.QueryStateAfterEventsRequest + var response api.QueryStateAfterEventsResponse + if err := json.NewDecoder(req.Body).Decode(&request); err != nil { + return util.ErrorResponse(err) + } + if err := r.QueryStateAfterEvents(&request, &response); err != nil { + return util.ErrorResponse(err) + } + return util.JSONResponse{Code: 200, JSON: &response} + }), + ) } func makeAPI(metric string, apiFunc func(req *http.Request) util.JSONResponse) http.Handler {