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.main
parent
db32692f2e
commit
7f85422471
|
@ -330,7 +330,7 @@ func (m *monolith) setupAPIs() {
|
||||||
|
|
||||||
syncapi_routing.Setup(m.api, syncapi_sync.NewRequestPool(
|
syncapi_routing.Setup(m.api, syncapi_sync.NewRequestPool(
|
||||||
m.syncAPIDB, m.syncAPINotifier, m.accountDB,
|
m.syncAPIDB, m.syncAPINotifier, m.accountDB,
|
||||||
), m.deviceDB)
|
), m.syncAPIDB, m.deviceDB)
|
||||||
|
|
||||||
federationapi_routing.Setup(
|
federationapi_routing.Setup(
|
||||||
m.api, *m.cfg, m.queryAPI, m.roomServerProducer, m.keyRing, m.federation,
|
m.api, *m.cfg, m.queryAPI, m.roomServerProducer, m.keyRing, m.federation,
|
||||||
|
|
|
@ -104,7 +104,7 @@ func main() {
|
||||||
log.Info("Starting sync server on ", cfg.Listen.SyncAPI)
|
log.Info("Starting sync server on ", cfg.Listen.SyncAPI)
|
||||||
|
|
||||||
api := mux.NewRouter()
|
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)
|
common.SetupHTTPAPI(http.DefaultServeMux, api)
|
||||||
|
|
||||||
log.Fatal(http.ListenAndServe(string(cfg.Listen.SyncAPI), nil))
|
log.Fatal(http.ListenAndServe(string(cfg.Listen.SyncAPI), nil))
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
||||||
"github.com/matrix-org/dendrite/clientapi/auth/storage/devices"
|
"github.com/matrix-org/dendrite/clientapi/auth/storage/devices"
|
||||||
"github.com/matrix-org/dendrite/common"
|
"github.com/matrix-org/dendrite/common"
|
||||||
|
"github.com/matrix-org/dendrite/syncapi/storage"
|
||||||
"github.com/matrix-org/dendrite/syncapi/sync"
|
"github.com/matrix-org/dendrite/syncapi/sync"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
)
|
)
|
||||||
|
@ -28,7 +29,7 @@ import (
|
||||||
const pathPrefixR0 = "/_matrix/client/r0"
|
const pathPrefixR0 = "/_matrix/client/r0"
|
||||||
|
|
||||||
// Setup configures the given mux with sync-server listeners
|
// 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 := apiMux.PathPrefix(pathPrefixR0).Subrouter()
|
||||||
|
|
||||||
r0mux.Handle("/sync", common.MakeAuthAPI("sync", deviceDB, func(req *http.Request, device *authtypes.Device) util.JSONResponse {
|
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 {
|
r0mux.Handle("/rooms/{roomID}/state", common.MakeAuthAPI("room_state", deviceDB, func(req *http.Request, device *authtypes.Device) util.JSONResponse {
|
||||||
vars := mux.Vars(req)
|
vars := mux.Vars(req)
|
||||||
return srp.OnIncomingStateRequest(req, vars["roomID"])
|
return OnIncomingStateRequest(req, syncDB, vars["roomID"])
|
||||||
})).Methods("GET")
|
})).Methods("GET")
|
||||||
|
|
||||||
r0mux.Handle("/rooms/{roomID}/state/{type}", common.MakeAuthAPI("room_state", deviceDB, func(req *http.Request, device *authtypes.Device) util.JSONResponse {
|
r0mux.Handle("/rooms/{roomID}/state/{type}", common.MakeAuthAPI("room_state", deviceDB, func(req *http.Request, device *authtypes.Device) util.JSONResponse {
|
||||||
vars := mux.Vars(req)
|
vars := mux.Vars(req)
|
||||||
return srp.OnIncomingStateTypeRequest(req, vars["roomID"], vars["type"], "")
|
return OnIncomingStateTypeRequest(req, syncDB, vars["roomID"], vars["type"], "")
|
||||||
})).Methods("GET")
|
})).Methods("GET")
|
||||||
|
|
||||||
r0mux.Handle("/rooms/{roomID}/state/{type}/{stateKey}", common.MakeAuthAPI("room_state", deviceDB, func(req *http.Request, device *authtypes.Device) util.JSONResponse {
|
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)
|
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")
|
})).Methods("GET")
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,7 +15,6 @@
|
||||||
package sync
|
package sync
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"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) {
|
func (rp *RequestPool) currentSyncForUser(req syncRequest, currentPos types.StreamPosition) (res *types.Response, err error) {
|
||||||
// TODO: handle ignored users
|
// TODO: handle ignored users
|
||||||
if req.since == types.StreamPosition(0) {
|
if req.since == types.StreamPosition(0) {
|
||||||
|
|
Loading…
Reference in New Issue