feat/broadcast-mentions #76

Merged
longjacksonle merged 7 commits from feat/broadcast-mentions into main 2026-05-12 13:55:12 +02:00
No description provided.
Lay the groundwork for phase 21 broadcast mentions. Adds `usernames_and_status_for_ids` to `db::auth` for bulk status lookups (used by `@here` to filter DND users in one query), two resolver functions `resolve_here_targets` and `resolve_channel_targets` in `routes/room.rs`, broadcast chip rendering in `render_body` for `@here`/`@channel` without needing a MentionRef, and an ignored scale sanity test that seeds 10K mention rows and verifies `count_unread_mentions_per_room` and `mark_mentions_read_for_room` both complete under 50ms. Also adds the phase 21 implementation plan doc.
Replace the inline per-handler username-only lookup loops in `post_message` and `patch_message` with a shared `resolve_tokens_for_room` helper that dispatches `@here`, `@channel`, and `@username` tokens through their respective resolvers. Deduplicates by user_id so a user matched by multiple tokens writes one mention row. Also adds a test confirming `@here` chip-renders in DM bodies despite the DM gate suppressing broadcast rows (option A decision), and pins the DM chip-rendering rationale in the phase 21 plan doc.
Replace the sequential per-mention dispatch loop in post_message and patch_message with a shared fanout_mention_events helper. WS broadcasts remain synchronous (cheap local mpsc sends); Push HTTP requests are dispatched concurrently but capped at FANOUT_CONCURRENCY=16 via a Tokio Semaphore so a large @channel mention does not enqueue hundreds of simultaneous outbound HTTPS requests.
Broadcast tokens appear before user rows (Slack-style) and are suppressed in DM rooms where broadcast resolution is a no-op. The `MentionSuggestion` type grows a `kind` discriminator and two convenience constructors (`user`/`broadcast`); the popover template branches on `kind` to render a distinct badge row for broadcast entries. Three new integration tests cover ordering, prefix matching, and DM suppression.
Wire the `/api/rooms/{id}/broadcast-count` endpoint into the composer script via a 300 ms debounced htmx.ajax call. The hint appears in a new `#lc-broadcast-count` slot below the staged-attachments row and is cleared on successful send, on blur, when the cursor moves off the broadcast token, or when the composer is torn down (pending timer cancelled).
refactor(mentions): move push concurrency cap to per-send level in dispatch
Some checks failed
Check / clippy + fmt + tests (pull_request) Failing after 22s
9c7047adca
The semaphore previously lived in `fanout_mention_events`, capping the number of concurrent per-user `dispatch` calls. That forced the HTTP handler to await `join_all` until every dispatch settled, and capped at the wrong boundary - a user with 3 devices still serialized 3 subscription sends inside each outer slot.

Moving the semaphore into `push::dispatch` as a process-global `OnceLock<Semaphore>` acquired inside each spawned send task means: (1) the cap now binds actual HTTP calls to FCM/autopush, not orchestration, and (2) `fanout_mention_events` becomes a true fire-and-forget spawn loop so the HTTP handler returns in microseconds regardless of recipient count.

Also adds `routes_broadcast_mentions` integration tests covering `@here`/`@channel` resolver semantics, the DM gate, dedup against explicit `@username`, edit reconciliation, mute-skip, and a `CountingPushClient` that asserts peak concurrent sends stay within `PUSH_FANOUT_CONCURRENCY`.
longjacksonle deleted branch feat/broadcast-mentions 2026-05-12 13:55:12 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/lets-chat!76
No description provided.