mirror of
https://github.com/matrix-org/dendrite.git
synced 2026-01-09 23:23:10 -06:00
151 lines
4.4 KiB
Go
151 lines
4.4 KiB
Go
// Copyright 2021 The Matrix.org Foundation C.I.C.
|
|
//
|
|
// 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 (
|
|
"net/http"
|
|
"strconv"
|
|
"sync"
|
|
|
|
"github.com/google/uuid"
|
|
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
|
|
"github.com/matrix-org/dendrite/roomserver/types"
|
|
userapi "github.com/matrix-org/dendrite/userapi/api"
|
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
|
"github.com/matrix-org/gomatrixserverlib/spec"
|
|
"github.com/matrix-org/util"
|
|
)
|
|
|
|
type RoomHierarchyPaginationCache struct {
|
|
cache map[string]roomserverAPI.CachedRoomHierarchyWalker
|
|
mu sync.Mutex
|
|
}
|
|
|
|
func NewRoomHierarchyPaginationCache() RoomHierarchyPaginationCache {
|
|
return RoomHierarchyPaginationCache{}
|
|
}
|
|
|
|
func (c *RoomHierarchyPaginationCache) Get(token string) roomserverAPI.CachedRoomHierarchyWalker {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
line := c.cache[token]
|
|
return line
|
|
}
|
|
|
|
func (c *RoomHierarchyPaginationCache) AddLine(line roomserverAPI.CachedRoomHierarchyWalker) string {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
token := uuid.NewString()
|
|
c.cache[token] = line
|
|
return token
|
|
}
|
|
|
|
func QueryRoomHierarchy(req *http.Request, device *userapi.Device, roomIDStr string, rsAPI roomserverAPI.ClientRoomserverAPI, paginationCache *RoomHierarchyPaginationCache) util.JSONResponse {
|
|
parsedRoomID, err := spec.NewRoomID(roomIDStr)
|
|
if err != nil {
|
|
return util.JSONResponse{
|
|
Code: http.StatusNotFound,
|
|
JSON: spec.InvalidParam("room is unknown/forbidden"),
|
|
}
|
|
}
|
|
roomID := *parsedRoomID
|
|
|
|
suggestedOnly := false // Defaults to false (spec-defined)
|
|
switch req.URL.Query().Get("suggested_only") {
|
|
case "true":
|
|
suggestedOnly = true
|
|
case "false":
|
|
case "": // Empty string is returned when query param is not set
|
|
default:
|
|
return util.JSONResponse{
|
|
Code: http.StatusBadRequest,
|
|
JSON: spec.InvalidParam("query parameter 'suggested_only', if set, must be 'true' or 'false'"),
|
|
}
|
|
}
|
|
|
|
limit := 1000 // Default to 1000
|
|
limitStr := req.URL.Query().Get("limit")
|
|
if limitStr != "" {
|
|
maybeLimit, err := strconv.Atoi(limitStr)
|
|
if err != nil || maybeLimit < 0 {
|
|
return util.JSONResponse{
|
|
Code: http.StatusBadRequest,
|
|
JSON: spec.InvalidParam("query parameter 'limit', if set, must be a positive integer"),
|
|
}
|
|
}
|
|
limit = maybeLimit
|
|
if limit > 1000 {
|
|
limit = 1000 // Maximum limit of 1000
|
|
}
|
|
}
|
|
|
|
maxDepth := -1 // '-1' representing no maximum depth
|
|
maxDepthStr := req.URL.Query().Get("max_depth")
|
|
if maxDepthStr != "" {
|
|
maybeMaxDepth, err := strconv.Atoi(maxDepthStr)
|
|
if err != nil || maybeMaxDepth < 0 {
|
|
return util.JSONResponse{
|
|
Code: http.StatusBadRequest,
|
|
JSON: spec.InvalidParam("query parameter 'max_depth', if set, must be a positive integer"),
|
|
}
|
|
}
|
|
maxDepth = maybeMaxDepth
|
|
}
|
|
|
|
from := req.URL.Query().Get("from")
|
|
|
|
var walker roomserverAPI.RoomHierarchyWalker
|
|
if from == "" { // No pagination token provided, so start new hierarchy walker
|
|
walker = rsAPI.QueryRoomHierarchy(req.Context(), types.NewDeviceNotServerName(*device), roomID, suggestedOnly, maxDepth)
|
|
} else { // Attempt to resume cached walker
|
|
cachedWalker := paginationCache.Get(from)
|
|
|
|
if cachedWalker == nil || !cachedWalker.ValidateParams(suggestedOnly, maxDepth) {
|
|
return util.JSONResponse{
|
|
Code: http.StatusBadRequest,
|
|
JSON: spec.InvalidParam("pagination not found for provided token ('from') with given 'max_depth', 'suggested_only' and room ID"),
|
|
}
|
|
}
|
|
|
|
walker = cachedWalker.GetWalker()
|
|
}
|
|
|
|
discoveredRooms, err := walker.NextPage(limit)
|
|
|
|
if err != nil {
|
|
// TODO
|
|
}
|
|
|
|
nextBatch := ""
|
|
if !walker.Done() {
|
|
cacheLine := walker.GetCached()
|
|
nextBatch = paginationCache.AddLine(cacheLine)
|
|
}
|
|
|
|
return util.JSONResponse{
|
|
Code: http.StatusOK,
|
|
JSON: RoomHierarchyClientResponse{
|
|
Rooms: discoveredRooms,
|
|
NextBatch: nextBatch,
|
|
},
|
|
}
|
|
|
|
}
|
|
|
|
type RoomHierarchyClientResponse struct {
|
|
Rooms []fclient.MSC2946Room `json:"rooms"`
|
|
NextBatch string `json:"next_batch,omitempty"`
|
|
}
|