add timeline paging for older messages
This commit is contained in:
@@ -136,6 +136,12 @@ GroupsRegistry ──ensure relay──► Group entity ◄──ingest── ba
|
||||
UI later: GroupPanel (Vec<Message>), JoinDialog (naddr)
|
||||
```
|
||||
|
||||
A group's subscriptions are the standing `grp-<hash>` REQ (timeline + state +
|
||||
membership, the timeline replayed up to 100 events) and, on demand, a
|
||||
`pg-<hash>` REQ that re-asks the same timeline filter with `until` set to the
|
||||
oldest event hydrated so far. Both are recognised by the same pump and land in
|
||||
the same envelope cache, so paging needs no separate read path.
|
||||
|
||||
## Phase 0 — `crates/nip29/src/protocol.rs` (pure, no I/O)
|
||||
|
||||
The protocol is expressed as types with `impl` blocks: a parsed thing is a struct
|
||||
@@ -437,7 +443,32 @@ group's relay only, and treat the relay's `OK` as the truth.
|
||||
`metadata_tags` re-emits them — `9002` requires it, an edit that drops a
|
||||
child is rejected. `parent`/`children` are per-relay, so assembling the tree
|
||||
from `Group::metadata()` is UI work; there is no backend tree helper.
|
||||
4. Range backfill: page the timeline with `until` for "load more".
|
||||
4. Range backfill: page the timeline with `until` for "load more". **Done.**
|
||||
`GroupId::timeline_page(limit, until)` is `timeline_filter` plus `.until(..)`,
|
||||
and `Group::load_page` sends it as a `pg-<hash>` subscription (auto-close on
|
||||
EOSE, 10s cap) alongside the standing `grp-<hash>` one, which keeps running so
|
||||
paging cannot replace the live tail. The read path is the usual one: `pg-`
|
||||
joins `is_own_subscription`, the id is registered in `routes` against the same
|
||||
key, and `handle_event` therefore caches each page event and `reload`s the
|
||||
group, so it arrives through the envelope cache and the timeline like any
|
||||
other event. `GroupsRegistry::load_more(key, cx)` is the entry point: it does
|
||||
nothing while a page is in flight (`Group::loading_more`) or before anything is
|
||||
cached, and registers the route before `Group::load_page` sets the flag.
|
||||
`handle_eose` and a page `CLOSED` remove the route and call
|
||||
`Group::page_finished`, which clears the flag and emits `GroupEvent::Updated`
|
||||
so a panel's spinner can settle. The cursor is `Group::oldest()`, the oldest
|
||||
`h`-tagged event ever hydrated, updated by `track` next to `window.push` —
|
||||
*not* read from `TimelineWindow`, which keeps only the newest 50 events, so a
|
||||
cursor taken from it would never move and would page the same window forever.
|
||||
`until` is inclusive, so a page repeats the event it starts from; `hydrate`
|
||||
dedups by id, so that costs one redundant fetch, never a gap. `forget` also
|
||||
drops and unsubscribes the `pg-` route (`reset` already sweeps `routes`). Two
|
||||
gaps left for the UI phase: a relay that accepts the REQ but never EOSEs leaves
|
||||
`loading_more` true (the auto-close timeout closes the subscription locally and
|
||||
emits no notification — the same stickiness as `Browse::loading`), and a group
|
||||
whose next page shares the `until` second cannot advance the cursor, so it can
|
||||
re-fetch the same page. Neither loops on its own; both need a "load older
|
||||
messages" button bound to `Group::loading_more()` to be observable at all.
|
||||
5. LiveKit AV (`livekit` tag, `39004`, the `/.well-known/nip29/livekit` token
|
||||
endpoint with a NIP-98 `27235` authorization event) and fork/migration
|
||||
detection through the admins' `10009`.
|
||||
@@ -449,6 +480,7 @@ group's relay only, and treat the relay's `OK` as the truth.
|
||||
| Paste an naddr and join (or retry a refused join) | `GroupReference::parse` → `GroupsRegistry::join` |
|
||||
| Open a group | `GroupsRegistry::group(&key, cx)` → panel subscribes to `GroupEvent` |
|
||||
| Timeline | `Group::messages()` (already `chat::Message`s) |
|
||||
| Load older messages | `GroupsRegistry::load_more(&key, cx)`; spinner from `Group::loading_more()` |
|
||||
| Send / react | `Group::send_message` / `send_reaction` |
|
||||
| Members, admins, roles, flags | `Group::members/admins/roles/metadata` |
|
||||
| Membership badge (member, pending, refused, removed) | `Group::membership()` |
|
||||
|
||||
Reference in New Issue
Block a user