UNPKG

@jsonjoy.com/reactive-rpc

Version:

Reactive-RPC is a library for building reactive APIs over WebSocket, HTTP, and other RPCs.

110 lines 3.72 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PresenceService = void 0; const rxjs_1 = require("rxjs"); class PresenceService { constructor() { this.rooms = new Map(); this.observers = new Map(); } async update(roomId, entryId, ttl, data) { const now = Date.now(); const room = this.getRoom(roomId); if (!data || typeof data !== 'object') throw new Error('ROOM_ENTRY_MUST_BE_OBJECT'); const entry = room.get(entryId) ?? { id: entryId, lastSeen: now, validUntil: now + ttl, data: {}, }; entry.lastSeen = now; entry.validUntil = now + ttl; Object.assign(entry.data, data); room.set(entryId, entry); this.cleanUpRoom(roomId); await new Promise((resolve) => setImmediate(resolve)); const observers = this.observers.get(roomId); if (observers) for (const observer of observers) observer.next([entry]); return entry; } async remove(roomId, entryId) { const room = this.getRoom(roomId); room.delete(entryId); if (!room.size) this.rooms.delete(roomId); await new Promise((resolve) => setImmediate(resolve)); const observers = this.observers.get(roomId); if (observers) for (const observer of observers) observer.next([ { id: entryId, lastSeen: Date.now(), validUntil: 0, data: {}, }, ]); } listen$(roomId) { return new rxjs_1.Observable((observer) => { this.cleanUpRoom(roomId); if (!this.observers.has(roomId)) this.observers.set(roomId, []); this.observers.get(roomId).push(observer); const room = this.getRoom(roomId); const entries = []; for (const entry of room.values()) { entries.push(entry); if (entries.length === 100) break; } if (entries.length) observer.next(entries); return () => { const observers = this.observers.get(roomId); if (!observers) { this.cleanUpRoom(roomId); return; } const index = observers.findIndex((o) => o === observer); if (index > -1) observers.splice(index, 1); if (!observers.length) { this.observers.delete(roomId); } }; }); } getRoom(roomId) { const room = this.rooms.get(roomId); if (room) return room; const newRoom = new Map(); this.rooms.set(roomId, newRoom); return newRoom; } cleanUpRoom(roomId) { const room = this.rooms.get(roomId); if (!room) return; const now = Date.now(); for (const [entry, presence] of room.entries()) { if (presence.validUntil < now) room.delete(entry); } if (!room.size) this.rooms.delete(roomId); } stats() { return { rooms: this.rooms.size, entries: [...this.rooms.values()].reduce((acc, v) => acc + v.size, 0), observers: [...this.observers.values()].reduce((acc, v) => acc + v.length, 0), }; } } exports.PresenceService = PresenceService; //# sourceMappingURL=PresenceService.js.map