diff --git a/setup/mscs/msc2836/msc2836.go b/setup/mscs/msc2836/msc2836.go index 15811710d..00b536183 100644 --- a/setup/mscs/msc2836/msc2836.go +++ b/setup/mscs/msc2836/msc2836.go @@ -23,10 +23,12 @@ import ( "fmt" "io" "net/http" + "slices" "sort" "strings" "time" + "github.com/gorilla/mux" fs "github.com/matrix-org/dendrite/federationapi/api" "github.com/matrix-org/dendrite/internal/hooks" "github.com/matrix-org/dendrite/internal/httputil" @@ -146,6 +148,43 @@ func Enable( return federatedEventRelationship(req.Context(), fedReq, db, rsAPI, fsAPI) }, )).Methods(http.MethodPost, http.MethodOptions) + + if slices.Contains(cfg.MSCs.MSCs, "MSC3856") { + routers.Client.Handle("/unstable/org.matrix.msc3856/rooms/{roomID}/threads", httputil.MakeAuthAPI( + "msc3856_thread_list", userAPI, func(req *http.Request, d *userapi.Device) util.JSONResponse { + vars, err := httputil.URLDecodeMapValues(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } + + roomID := vars["roomID"] + + childrens, err := db.GetChildrensByRoomId(req.Context(), roomID, true) + if err != nil { + return util.ErrorResponse(err) + } + + chunks := make([]map[string]any, 0) + for _, child := range childrens { + chunks = append(chunks, + map[string]any{ + "event_id": child.EventID, + "origin_server_ts": child.OriginServerTS, + "room_id": child.RoomID, + }, + ) + } + + return util.JSONResponse{ + Code: 200, + JSON: map[string]any{ + "chunk": chunks, + "next_batch": "next_batch_token", + }, + } + }, + )) + } return nil } diff --git a/setup/mscs/msc2836/storage.go b/setup/mscs/msc2836/storage.go index 696d0b0da..8f971e90a 100644 --- a/setup/mscs/msc2836/storage.go +++ b/setup/mscs/msc2836/storage.go @@ -43,19 +43,23 @@ type Database interface { ChildMetadata(ctx context.Context, eventID string) (count int, hash []byte, explored bool, err error) // MarkChildrenExplored sets the 'explored' flag on this event to `true`. MarkChildrenExplored(ctx context.Context, eventID string) error + + GetChildrensByRoomId(ctx context.Context, roomID string, recentFirst bool) ([]eventInfo, error) } type DB struct { - db *sql.DB - writer sqlutil.Writer - insertEdgeStmt *sql.Stmt - insertNodeStmt *sql.Stmt - selectChildrenForParentOldestFirstStmt *sql.Stmt - selectChildrenForParentRecentFirstStmt *sql.Stmt - selectParentForChildStmt *sql.Stmt - updateChildMetadataStmt *sql.Stmt - selectChildMetadataStmt *sql.Stmt - updateChildMetadataExploredStmt *sql.Stmt + db *sql.DB + writer sqlutil.Writer + insertEdgeStmt *sql.Stmt + insertNodeStmt *sql.Stmt + selectChildrenByRoomIdForParentOldestFirstStmt *sql.Stmt + selectChildrenByRoomIdForParentRecentFirstStmt *sql.Stmt + selectChildrenForParentOldestFirstStmt *sql.Stmt + selectChildrenForParentRecentFirstStmt *sql.Stmt + selectParentForChildStmt *sql.Stmt + updateChildMetadataStmt *sql.Stmt + selectChildMetadataStmt *sql.Stmt + updateChildMetadataExploredStmt *sql.Stmt } // NewDatabase loads the database for msc2836 @@ -141,6 +145,18 @@ func newPostgresDatabase(conMan *sqlutil.Connections, dbOpts *config.DatabaseOpt `); err != nil { return nil, err } + selectChildrenByRoomIdQuery := ` + SELECT child_event_id, origin_server_ts, room_id FROM msc2836_edges + LEFT JOIN msc2836_nodes ON msc2836_edges.child_event_id = msc2836_nodes.event_id + WHERE room_id = $1 + ORDER BY origin_server_ts` + if d.selectChildrenByRoomIdForParentOldestFirstStmt, err = d.db.Prepare(selectChildrenByRoomIdQuery + "ASC"); err != nil { + return nil, err + } + if d.selectChildrenByRoomIdForParentRecentFirstStmt, err = d.db.Prepare(selectChildrenByRoomIdQuery + "DESC"); err != nil { + return nil, err + } + return &d, err } @@ -219,6 +235,17 @@ func newSQLiteDatabase(conMan *sqlutil.Connections, dbOpts *config.DatabaseOptio `); err != nil { return nil, err } + selectChildrenByRoomIdQuery := ` + SELECT child_event_id, origin_server_ts, room_id FROM msc2836_edges + LEFT JOIN msc2836_nodes ON msc2836_edges.child_event_id = msc2836_nodes.event_id + WHERE room_id = $1 + ORDER BY origin_server_ts` + if d.selectChildrenByRoomIdForParentOldestFirstStmt, err = d.db.Prepare(selectChildrenByRoomIdQuery + "ASC"); err != nil { + return nil, err + } + if d.selectChildrenByRoomIdForParentRecentFirstStmt, err = d.db.Prepare(selectChildrenByRoomIdQuery + "DESC"); err != nil { + return nil, err + } return &d, nil } @@ -315,6 +342,30 @@ func (p *DB) ParentForChild(ctx context.Context, eventID, relType string) (*even return &ei, nil } +func (p *DB) GetChildrensByRoomId(ctx context.Context, roomID string, recentFirst bool) ([]eventInfo, error) { + var rows *sql.Rows + var err error + if recentFirst { + rows, err = p.selectChildrenForParentRecentFirstStmt.QueryContext(ctx, roomID) + } else { + rows, err = p.selectChildrenByRoomIdForParentOldestFirstStmt.QueryContext(ctx, roomID) + } + if err != nil { + return nil, err + } + + defer rows.Close() // nolint: errcheck + var children []eventInfo + for rows.Next() { + var evInfo eventInfo + if err := rows.Scan(&evInfo.EventID, &evInfo.OriginServerTS, &evInfo.RoomID); err != nil { + return nil, err + } + children = append(children, evInfo) + } + return children, rows.Err() +} + func parentChildEventIDs(ev *types.HeaderedEvent) (parent, child, relType string) { if ev == nil { return