package clientapi import ( "net/http" "strconv" "strings" "github.com/dariuszjaniak/warp/server/internal/httputil" "github.com/dariuszjaniak/warp/server/internal/matrix/id" "github.com/dariuszjaniak/warp/server/internal/roomserver" "github.com/dariuszjaniak/warp/server/internal/userapi" ) // hierarchyResponse is what GET /hierarchy returns. type hierarchyResponse struct { Rooms []roomserver.SpaceRoom `json:"rooms"` NextBatch string `json:"next_batch,omitempty"` } // hierarchyTokenPrefix marks a /hierarchy token: how far into the walk // the next page starts. const hierarchyTokenPrefix = "h" // handleHierarchy implements GET /_matrix/client/v1/rooms/{roomID}/hierarchy. func (c *ClientAPI) handleHierarchy(w http.ResponseWriter, r *http.Request, auth userapi.Authenticated) error { roomID, err := pathRoomID(r) if err != nil { return err } query := r.URL.Query() limit, err := intParam(query.Get("limit")) if err != nil { return err } suggestedOnly, err := boolParam(query.Get("suggested_only")) if err != nil { return err } maxDepth := -1 if raw := query.Get("max_depth"); raw != "" { if maxDepth, err = strconv.Atoi(raw); err != nil || maxDepth < 0 { return httputil.InvalidParam("max_depth must be a non-negative integer") } } from := 0 if raw := query.Get("from"); raw != "" { body, ok := strings.CutPrefix(raw, hierarchyTokenPrefix) if from, err = strconv.Atoi(body); !ok || err != nil || from < 0 { return httputil.InvalidParam("%q is not a hierarchy token", raw) } } page, err := c.rooms.Hierarchy(r.Context(), roomserver.HierarchyRequest{ RoomID: roomID, User: auth.UserID, SuggestedOnly: suggestedOnly, MaxDepth: maxDepth, From: from, Limit: limit, }) if err != nil { return roomError(err) } resp := hierarchyResponse{Rooms: page.Rooms} if resp.Rooms == nil { resp.Rooms = []roomserver.SpaceRoom{} } if page.Next != 0 { resp.NextBatch = hierarchyTokenPrefix + strconv.Itoa(page.Next) } httputil.WriteJSON(w, http.StatusOK, resp) return nil } // handleRoomSummary implements // GET /_matrix/client/v1/room_summary/{roomIDOrAlias}. func (c *ClientAPI) handleRoomSummary(w http.ResponseWriter, r *http.Request, auth userapi.Authenticated) error { target := r.PathValue("roomIDOrAlias") via := r.URL.Query()["via"] roomID := target switch { case strings.HasPrefix(target, "#"): resolved, err := c.resolveAlias(r.Context(), target) if err != nil { return roomError(err) } roomID = resolved.RoomID via = append(via, resolved.Servers...) case id.ValidateRoomID(target) != nil: return httputil.InvalidParam("%s is not a room ID or alias", target) } resp, err := c.rooms.RoomSummary(r.Context(), roomserver.RoomSummaryRequest{ RoomID: roomID, User: auth.UserID, Via: via, }) if err != nil { return roomError(err) } httputil.WriteJSON(w, http.StatusOK, resp) return nil }