From 3b4945f0186e059fe722ac05bbf26285de9adaa9 Mon Sep 17 00:00:00 2001 From: Daniel Salazar Date: Wed, 28 Oct 2026 00:53:28 -0700 Subject: [PATCH] feat(events): isOnline presence check for a user and app --- .../services/events/EventForwardService.ts | 11 +++++++++++ src/backend/services/events/forwarding.test.ts | 15 +++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/backend/services/events/EventForwardService.ts b/src/backend/services/events/EventForwardService.ts index f40c8eef2..3ca50b16b 100644 --- a/src/backend/services/events/EventForwardService.ts +++ b/src/backend/services/events/EventForwardService.ts @@ -403,6 +403,17 @@ export class EventForwardService extends PuterService { } } + /** + * Whether the pair holds a socket anywhere: this node, this region or a + * peer region. Only this node's sockets count where presence is not kept. + */ + async isOnline(userId: number, appUid: string | null): Promise { + if (this.services.socket.has(forwardTarget(userId, appUid))) return true; + if (!this.active) return false; + if (await this.heldInRegion(userId, appUid)) return true; + return (await this.regionsFor(userId, appUid)).length > 0; + } + /** Send one `single` to a named region, carrying what settles it. */ handOff(region: string, delivery: ForwardableDelivery): void { this.#send(region, delivery); diff --git a/src/backend/services/events/forwarding.test.ts b/src/backend/services/events/forwarding.test.ts index 04243ef29..e326ca8af 100644 --- a/src/backend/services/events/forwarding.test.ts +++ b/src/backend/services/events/forwarding.test.ts @@ -1647,6 +1647,21 @@ describe('presence moving in another region', () => { }); }); +describe('isOnline', () => { + it('is true for a socket on this node, in this region or in a peer region', async () => { + const west = makeRegion('west', ['east']); + const east = makeRegion('east', ['west']); + await register(west); + expect(await west.forward.isOnline(userId, null)).toBe(false); + + east.rooms.add(String(userId)); + await east.forward.noteConnect(actorFor(), 'tab-1'); + expect(await east.forward.isOnline(userId, null)).toBe(true); + expect(await west.forward.isOnline(userId, null)).toBe(true); + expect(await west.forward.isOnline(userId, 'app-other')).toBe(false); + }); +}); + // -- Decommissioned regions -------------------------------------------- describe('a row naming a region that is not a peer', () => {