Changeset 2a17f0a in Klonkt


Ignore:
Timestamp:
07/30/2026 11:54:08 PM (6 weeks ago)
Author:
Robin <roboburr@…>
Branches:
main
Children:
0f48411
Parents:
ef519a3
Message:

Long-poll op nieuws: de thread blijft live zonder pull-to-refresh

Robins vraag (31-7): pull-to-refresh in een thread dwingt omhoog
scrollen; een knop is een pleister; long-poll is de echte vorm. GET
/ap/users/:slug/inbox/wait (owner-bearer) blijft hangen tot er iets
push-waardigs voor dat account landt (bericht, reply, wave,
hulp-request; dezelfde momenten als de webpush, want de wekker haakt in
pushEvent) en antwoordt dan 200; na ~25s stilte 204 en de app her-wapent.
In-process met opzet: een Klonkt is een proces, een waiter een callback.

Changed files:
src/services/ActivityPubService.js

  • onNews/wakeNews (waiter-registry); pushEvent wekt de waiters

src/routes/activitypub.js

  • /ap/users/:slug/inbox/wait: 200 bij nieuws, 204 na timeout, opgeruimd bij client-close

New file:
test/long-poll.test.js

  • elke waiter een keer gewekt, alleen het eigen account, afgemeld blijft stil

-robo
Co-Authored-By: Claude Opus 4.8 <noreply@…>

Files:
1 added
2 edited

Legend:

Unmodified
Added
Removed
  • src/routes/activitypub.js

    ref519a3 r2a17f0a  
    174174  <p class="small">No Shaer? Any fediverse app can follow ${esc(handle)}.</p>
    175175</main></body></html>`);
     176});
     177
     178// ── Long-poll (owner only, Robins verzoek 31-7) ───────────────────
     179// Hold the request until something push-worthy lands for this account, then
     180// answer 200 (news: re-read your feed) or 204 after ~25s (nothing: re-arm).
     181// The thread in the app stays live without interval polling.
     182router.get('/ap/users/:slug/inbox/wait', (req, res) => {
     183  const auth = OAuth.verifyBearer(req.headers.authorization);
     184  if (!auth || auth.site.slug !== req.params.slug) return res.status(403).end();
     185  let settled = false;
     186  const done = (code) => {
     187    if (settled) return;
     188    settled = true;
     189    clearTimeout(timer);
     190    off();
     191    if (!res.headersSent) res.status(code).end();
     192  };
     193  const off = AP.onNews(auth.site.slug, () => done(200));
     194  const timer = setTimeout(() => done(204), 25_000);
     195  req.on('close', () => done(204));
    176196});
    177197
  • src/services/ActivityPubService.js

    ref519a3 r2a17f0a  
    13631363function pushEvent(slug, event) {
    13641364  try { Push.notifySite(slug, event).catch(() => {}); } catch { /* never throw */ }
     1365  wakeNews(slug);   // long-poll waiters (Robins verzoek, 31-7): same moments as push
     1366}
     1367
     1368// ── Long-poll on news (Robins verzoek, 31-7) ─────────────────────
     1369// The app holds GET /ap/users/:slug/inbox/wait open; the moment anything
     1370// push-worthy lands for that account (a message, a reply, a wave, a help
     1371// request) every waiter is woken and the app re-reads its feed. In-process
     1372// on purpose: one Klonkt is one process, and a waiter is one callback.
     1373const _newsWaiters = new Map();   // slug -> Set<cb>
     1374export function onNews(slug, cb) {
     1375  let set = _newsWaiters.get(slug);
     1376  if (!set) { set = new Set(); _newsWaiters.set(slug, set); }
     1377  set.add(cb);
     1378  return () => { set.delete(cb); if (!set.size) _newsWaiters.delete(slug); };
     1379}
     1380export function wakeNews(slug) {
     1381  const set = _newsWaiters.get(slug);
     1382  if (!set || !set.size) return;
     1383  const cbs = [...set];
     1384  set.clear();
     1385  _newsWaiters.delete(slug);
     1386  for (const cb of cbs) { try { cb(); } catch { /* a waiter must never break the rest */ } }
    13651387}
    13661388// Hub-aware path prefix for a site's pages ('' in solo).
     
    42504272  linkifyBody, bakePostContent, bakePostContentWithMentions, listFollowers, removeFollower, listConnections,
    42514273  noteVisibility, belongsInTimeline, playerUrlFor, isRejectedObject, rejectInteraction, interactionReportTarget,
    4252   getMessages, notificationsSeenAt, ingestOutboxActivity, c2sVisibility, actorDisplay, buildActorRef, prefersEnriched, selfAuthor, getReplyMessages,
     4274  getMessages, notificationsSeenAt, ingestOutboxActivity, c2sVisibility, actorDisplay, buildActorRef, prefersEnriched, selfAuthor, getReplyMessages, onNews, wakeNews,
    42534275};
Note: See TracChangeset for help on using the changeset viewer.