diff --git a/src/github.com/matrix-org/dendrite/cmd/dendrite-monolith-server/main.go b/src/github.com/matrix-org/dendrite/cmd/dendrite-monolith-server/main.go index 3b5975763..ea71fed98 100644 --- a/src/github.com/matrix-org/dendrite/cmd/dendrite-monolith-server/main.go +++ b/src/github.com/matrix-org/dendrite/cmd/dendrite-monolith-server/main.go @@ -330,7 +330,7 @@ func (m *monolith) setupAPIs() { syncapi_routing.Setup(m.api, syncapi_sync.NewRequestPool( m.syncAPIDB, m.syncAPINotifier, m.accountDB, - ), m.deviceDB) + ), m.syncAPIDB, m.deviceDB) federationapi_routing.Setup( m.api, *m.cfg, m.queryAPI, m.roomServerProducer, m.keyRing, m.federation, diff --git a/src/github.com/matrix-org/dendrite/cmd/dendrite-sync-api-server/main.go b/src/github.com/matrix-org/dendrite/cmd/dendrite-sync-api-server/main.go index fb81b0e3d..e7f83a60d 100644 --- a/src/github.com/matrix-org/dendrite/cmd/dendrite-sync-api-server/main.go +++ b/src/github.com/matrix-org/dendrite/cmd/dendrite-sync-api-server/main.go @@ -104,7 +104,7 @@ func main() { log.Info("Starting sync server on ", cfg.Listen.SyncAPI) api := mux.NewRouter() - routing.Setup(api, sync.NewRequestPool(db, n, adb), deviceDB) + routing.Setup(api, sync.NewRequestPool(db, n, adb), db, deviceDB) common.SetupHTTPAPI(http.DefaultServeMux, api) log.Fatal(http.ListenAndServe(string(cfg.Listen.SyncAPI), nil)) diff --git a/src/github.com/matrix-org/dendrite/syncapi/routing/routing.go b/src/github.com/matrix-org/dendrite/syncapi/routing/routing.go index 15ca267a0..6cdbe992a 100644 --- a/src/github.com/matrix-org/dendrite/syncapi/routing/routing.go +++ b/src/github.com/matrix-org/dendrite/syncapi/routing/routing.go @@ -21,6 +21,7 @@ import ( "github.com/matrix-org/dendrite/clientapi/auth/authtypes" "github.com/matrix-org/dendrite/clientapi/auth/storage/devices" "github.com/matrix-org/dendrite/common" + "github.com/matrix-org/dendrite/syncapi/storage" "github.com/matrix-org/dendrite/syncapi/sync" "github.com/matrix-org/util" ) @@ -28,7 +29,7 @@ import ( const pathPrefixR0 = "/_matrix/client/r0" // Setup configures the given mux with sync-server listeners -func Setup(apiMux *mux.Router, srp *sync.RequestPool, deviceDB *devices.Database) { +func Setup(apiMux *mux.Router, srp *sync.RequestPool, syncDB *storage.SyncServerDatabase, deviceDB *devices.Database) { r0mux := apiMux.PathPrefix(pathPrefixR0).Subrouter() r0mux.Handle("/sync", common.MakeAuthAPI("sync", deviceDB, func(req *http.Request, device *authtypes.Device) util.JSONResponse { @@ -37,16 +38,16 @@ func Setup(apiMux *mux.Router, srp *sync.RequestPool, deviceDB *devices.Database r0mux.Handle("/rooms/{roomID}/state", common.MakeAuthAPI("room_state", deviceDB, func(req *http.Request, device *authtypes.Device) util.JSONResponse { vars := mux.Vars(req) - return srp.OnIncomingStateRequest(req, vars["roomID"]) + return OnIncomingStateRequest(req, syncDB, vars["roomID"]) })).Methods("GET") r0mux.Handle("/rooms/{roomID}/state/{type}", common.MakeAuthAPI("room_state", deviceDB, func(req *http.Request, device *authtypes.Device) util.JSONResponse { vars := mux.Vars(req) - return srp.OnIncomingStateTypeRequest(req, vars["roomID"], vars["type"], "") + return OnIncomingStateTypeRequest(req, syncDB, vars["roomID"], vars["type"], "") })).Methods("GET") r0mux.Handle("/rooms/{roomID}/state/{type}/{stateKey}", common.MakeAuthAPI("room_state", deviceDB, func(req *http.Request, device *authtypes.Device) util.JSONResponse { vars := mux.Vars(req) - return srp.OnIncomingStateTypeRequest(req, vars["roomID"], vars["type"], vars["stateKey"]) + return OnIncomingStateTypeRequest(req, syncDB, vars["roomID"], vars["type"], vars["stateKey"]) })).Methods("GET") } diff --git a/src/github.com/matrix-org/dendrite/syncapi/routing/state.go b/src/github.com/matrix-org/dendrite/syncapi/routing/state.go new file mode 100644 index 000000000..6c825fce8 --- /dev/null +++ b/src/github.com/matrix-org/dendrite/syncapi/routing/state.go @@ -0,0 +1,118 @@ +// Copyright 2017 Vector Creations Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package routing + +import ( + "encoding/json" + "net/http" + + "github.com/matrix-org/dendrite/clientapi/httputil" + "github.com/matrix-org/dendrite/clientapi/jsonerror" + "github.com/matrix-org/dendrite/syncapi/storage" + "github.com/matrix-org/dendrite/syncapi/types" + "github.com/matrix-org/gomatrixserverlib" + "github.com/matrix-org/util" + log "github.com/sirupsen/logrus" +) + +type stateEventInStateResp struct { + gomatrixserverlib.ClientEvent + PrevContent json.RawMessage `json:"prev_content,omitempty"` + ReplacesState string `json:"replaces_state,omitempty"` +} + +// OnIncomingStateRequest is called when a client makes a /rooms/{roomID}/state +// request. It will fetch all the state events from the specified room and will +// append the necessary keys to them if applicable before returning them. +// Returns an error if something went wrong in the process. +// 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.SyncServerDatabase, 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) + + stateEvents, err := db.GetStateEventsForRoom(req.Context(), roomID) + if err != nil { + return httputil.LogThenError(req, err) + } + + resp := []stateEventInStateResp{} + // Fill the prev_content and replaces_state keys if necessary + for _, event := range stateEvents { + stateEvent := stateEventInStateResp{ + ClientEvent: gomatrixserverlib.ToClientEvent(event, gomatrixserverlib.FormatAll), + } + var prevEventRef types.PrevEventRef + if len(event.Unsigned()) > 0 { + if err := json.Unmarshal(event.Unsigned(), &prevEventRef); err != nil { + return httputil.LogThenError(req, err) + } + // Fills the previous state event ID if the state event replaces another + // state event + if len(prevEventRef.ReplacesState) > 0 { + stateEvent.ReplacesState = prevEventRef.ReplacesState + } + // Fill the previous event if the state event references a previous event + if prevEventRef.PrevContent != nil { + stateEvent.PrevContent = prevEventRef.PrevContent + } + } + + resp = append(resp, stateEvent) + } + + return util.JSONResponse{ + Code: 200, + JSON: resp, + } +} + +// OnIncomingStateTypeRequest is called when a client makes a +// /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.SyncServerDatabase, 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{ + "roomID": roomID, + "evType": evType, + "stateKey": stateKey, + }).Info("Fetching state") + + event, err := db.GetStateEvent(req.Context(), roomID, evType, stateKey) + if err != nil { + return httputil.LogThenError(req, err) + } + + if event == nil { + return util.JSONResponse{ + Code: 404, + JSON: jsonerror.NotFound("cannot find state"), + } + } + + stateEvent := stateEventInStateResp{ + ClientEvent: gomatrixserverlib.ToClientEvent(*event, gomatrixserverlib.FormatAll), + } + + return util.JSONResponse{ + Code: 200, + JSON: stateEvent.Content, + } +} diff --git a/src/github.com/matrix-org/dendrite/syncapi/sync/requestpool.go b/src/github.com/matrix-org/dendrite/syncapi/sync/requestpool.go index ebfb140d1..3b6775618 100644 --- a/src/github.com/matrix-org/dendrite/syncapi/sync/requestpool.go +++ b/src/github.com/matrix-org/dendrite/syncapi/sync/requestpool.go @@ -15,7 +15,6 @@ package sync import ( - "encoding/json" "net/http" "time" @@ -120,96 +119,6 @@ func (rp *RequestPool) OnIncomingSyncRequest(req *http.Request, device *authtype } } -type stateEventInStateResp struct { - gomatrixserverlib.ClientEvent - PrevContent json.RawMessage `json:"prev_content,omitempty"` - ReplacesState string `json:"replaces_state,omitempty"` -} - -// OnIncomingStateRequest is called when a client makes a /rooms/{roomID}/state -// request. It will fetch all the state events from the specified room and will -// append the necessary keys to them if applicable before returning them. -// Returns an error if something went wrong in the process. -// 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 (rp *RequestPool) OnIncomingStateRequest(req *http.Request, 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) - - stateEvents, err := rp.db.GetStateEventsForRoom(req.Context(), roomID) - if err != nil { - return httputil.LogThenError(req, err) - } - - resp := []stateEventInStateResp{} - // Fill the prev_content and replaces_state keys if necessary - for _, event := range stateEvents { - stateEvent := stateEventInStateResp{ - ClientEvent: gomatrixserverlib.ToClientEvent(event, gomatrixserverlib.FormatAll), - } - var prevEventRef types.PrevEventRef - if len(event.Unsigned()) > 0 { - if err := json.Unmarshal(event.Unsigned(), &prevEventRef); err != nil { - return httputil.LogThenError(req, err) - } - // Fills the previous state event ID if the state event replaces another - // state event - if len(prevEventRef.ReplacesState) > 0 { - stateEvent.ReplacesState = prevEventRef.ReplacesState - } - // Fill the previous event if the state event references a previous event - if prevEventRef.PrevContent != nil { - stateEvent.PrevContent = prevEventRef.PrevContent - } - } - - resp = append(resp, stateEvent) - } - - return util.JSONResponse{ - Code: 200, - JSON: resp, - } -} - -// OnIncomingStateTypeRequest is called when a client makes a -// /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 (rp *RequestPool) OnIncomingStateTypeRequest(req *http.Request, 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{ - "roomID": roomID, - "evType": evType, - "stateKey": stateKey, - }).Info("Fetching state") - - event, err := rp.db.GetStateEvent(req.Context(), roomID, evType, stateKey) - if err != nil { - return httputil.LogThenError(req, err) - } - - if event == nil { - return util.JSONResponse{ - Code: 404, - JSON: jsonerror.NotFound("cannot find state"), - } - } - - stateEvent := stateEventInStateResp{ - ClientEvent: gomatrixserverlib.ToClientEvent(*event, gomatrixserverlib.FormatAll), - } - - return util.JSONResponse{ - Code: 200, - JSON: stateEvent.Content, - } -} - func (rp *RequestPool) currentSyncForUser(req syncRequest, currentPos types.StreamPosition) (res *types.Response, err error) { // TODO: handle ignored users if req.since == types.StreamPosition(0) {