Move /state request handling out of RequestPool
We should probably move the handling out from the syncapi, but that
requires the clientapi to stream the current state which it currently
doesn't. This at least stops the sync and state handling being done in
one file.
MODIFY
src/github.com/matrix-org/dendrite/cmd/dendrite-monolith-server/main.go
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,

MODIFY
src/github.com/matrix-org/dendrite/cmd/dendrite-sync-api-server/main.go
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))

MODIFY
src/github.com/matrix-org/dendrite/syncapi/routing/routing.go
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")
}

ADD
src/github.com/matrix-org/dendrite/syncapi/routing/state.go
+// 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,
+ }
+}

MODIFY
src/github.com/matrix-org/dendrite/syncapi/sync/requestpool.go
src/github.com/matrix-org/dendrite/syncapi/sync/requestpool.go
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) {

Move /state request handling out of RequestPool (#333)

We should probably move the handling out from the syncapi, but that
requires the clientapi to stream the current state which it currently
doesn't. This at least stops the sync and state handling being done in
one file.