add GroupParticipants state event support
This commit is contained in:
@@ -19,7 +19,7 @@ models as two entities.
|
||||
| Group id | random string, relay-chosen | `h` tag on everything a user sends; `d` tag on relay state events |
|
||||
| Timeline | any event kind + `h` | v1 renders kinds `1`, `9`, `11`, `1111` and `7`; every other kind is cached for the `previous` window but not rendered, except the membership kinds below |
|
||||
| Timeline refs | `previous` tag, first 8 hex chars of event ids | built from the last 50 events seen on that relay (any kind — NIP-29 timeline references), excluding our own; send up to 3 |
|
||||
| Relay state | `39000` metadata, `39001` admins, `39002` members, `39003` roles | relay-signed, addressable by `d`; read, never written by the client |
|
||||
| Relay state | `39000` metadata, `39001` admins, `39002` members, `39003` roles, `39004` LiveKit participants | relay-signed, addressable by `d`; read, never written by the client |
|
||||
| Membership | `9021` join, `9022` leave (user-signed); relay answers with `9000` put-user / `9001` remove-user | membership = latest `9000`/`9001` naming our pubkey; no event means not a member, and `Pending`/`Refused` are tracked locally for private groups |
|
||||
| Own group list | `10009` (NIP-51 simple groups) | `["group", id, relay, name?]` plus `["r", relay]`; replaceable, published to NIP-65 relays |
|
||||
| Reference | `naddr1…` of kind `39000` with the relay self pubkey and a relay hint, optionally `?invite=<code>` | the self pubkey is the author of the fetched `39000`; no `39000` means no canonical naddr |
|
||||
@@ -235,6 +235,16 @@ impl GroupRoles {
|
||||
pub fn roles(&self) -> &[Role];
|
||||
}
|
||||
|
||||
/// kind:39004 — who is live in the group's AV room; `participant` tags, not `p`.
|
||||
/// Absence means nothing is known, which is not the same as an empty room.
|
||||
pub struct GroupParticipants(Vec<PublicKey>);
|
||||
|
||||
impl GroupParticipants {
|
||||
pub fn parse(event: &Event) -> Result<Self, Error>;
|
||||
pub fn contains(&self, public_key: &PublicKey) -> bool;
|
||||
pub fn iter(&self) -> impl Iterator<Item = &PublicKey>;
|
||||
}
|
||||
|
||||
/// kind:10009 — the account's own list.
|
||||
pub struct GroupList(Vec<GroupListEntry>);
|
||||
pub struct GroupListEntry { pub id: GroupId, pub relay: RelayUrl, pub name: Option<String> }
|
||||
@@ -469,9 +479,29 @@ group's relay only, and treat the relay's `OK` as the truth.
|
||||
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`.
|
||||
5. LiveKit AV and fork/migration detection, split in three:
|
||||
1. **`39004` participants. Done.** `GroupParticipants` joins `protocol.rs`
|
||||
with the same shape as `GroupMembers` but reads `participant` tags (the NIP
|
||||
does not use `p` here); one malformed pubkey fails the whole event, as in
|
||||
`GroupAdmins`. The kind joins `STATE_KINDS`, so the standing subscription
|
||||
already carries it, and `absorb_state` folds it into `Group::participants()`.
|
||||
Nothing is written by us — the relay publishes it and updates it as people
|
||||
come and go, so it rides the live tail like any other state event.
|
||||
"Absent" and "empty" are deliberately the same value here: unlike
|
||||
`supported_kinds`, the NIP gives the empty list no special meaning, so the
|
||||
UI reads "no one is live" either way.
|
||||
2. The `/.well-known/nip29/livekit/<group-id>` token endpoint: a NIP-98
|
||||
`27235` event in `Authorization`, returning the LiveKit JWT and server URL,
|
||||
plus the `204` probe at `/.well-known/nip29/livekit` that tells the UI
|
||||
whether a relay supports AV at all. Not started. This is the only part that
|
||||
needs an HTTP client in the crate, so it is where the dependency decision
|
||||
(if any) lands; `livekit` on `39000` is already parsed but currently inert.
|
||||
3. Fork/migration detection: read the `10009` of the group's admins (pubkeys
|
||||
from `39001`, cached locally) and compare the relay hint against the relay
|
||||
we are talking to; a different hint means the group may have moved or been
|
||||
forked, which is the client's cue to offer fetching from the new relay.
|
||||
Not started; the periodic — and MUST-when-offline — trigger is what
|
||||
`Monitor` would feed, so the two decisions go together.
|
||||
|
||||
## UI later — the hooks this backend leaves
|
||||
|
||||
@@ -483,6 +513,7 @@ group's relay only, and treat the relay's `OK` as the truth.
|
||||
| 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` |
|
||||
| Who is in the AV room | `Group::participants()` |
|
||||
| Membership badge (member, pending, refused, removed) | `Group::membership()` |
|
||||
| Copy an invite link | `GroupMetadata::naddr(relay, invite)` |
|
||||
| Leave | `GroupsRegistry::leave` |
|
||||
|
||||
Reference in New Issue
Block a user