Changeset 2a17f0a in Klonkt
- Timestamp:
- 07/30/2026 11:54:08 PM (6 weeks ago)
- Branches:
- main
- Children:
- 0f48411
- Parents:
- ef519a3
- Files:
-
- 1 added
- 2 edited
-
src/routes/activitypub.js (modified) (1 diff)
-
src/services/ActivityPubService.js (modified) (2 diffs)
-
test/long-poll.test.js (added)
Legend:
- Unmodified
- Added
- Removed
-
src/routes/activitypub.js
ref519a3 r2a17f0a 174 174 <p class="small">No Shaer? Any fediverse app can follow ${esc(handle)}.</p> 175 175 </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. 182 router.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)); 176 196 }); 177 197 -
src/services/ActivityPubService.js
ref519a3 r2a17f0a 1363 1363 function pushEvent(slug, event) { 1364 1364 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. 1373 const _newsWaiters = new Map(); // slug -> Set<cb> 1374 export 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 } 1380 export 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 */ } } 1365 1387 } 1366 1388 // Hub-aware path prefix for a site's pages ('' in solo). … … 4250 4272 linkifyBody, bakePostContent, bakePostContentWithMentions, listFollowers, removeFollower, listConnections, 4251 4273 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, 4253 4275 };
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)