import { type WalletInterface, type WalletNotification, type NotificationHolderInterface, } from './generated/bark'; type Unsubscribe = () => void; /** * Wraps the pull-based {@link NotificationHolderInterface} into a subscribe/unsubscribe API. * * The internal polling loop starts when the first listener subscribes and stops when the * last listener unsubscribes. Re-subscribing after all listeners have been removed creates * a fresh {@link NotificationHolderInterface} and restarts the loop. * * @example * ```ts * const notifications = new WalletNotifications(wallet); * * const unsubscribe = notifications.subscribe((event) => { * switch (event.tag) { * case WalletNotification_Tags.MovementCreated: * console.log('movement created', event.inner.movement); * break; * case WalletNotification_Tags.MovementUpdated: * console.log('movement updated', event.inner.movement); * break; * case WalletNotification_Tags.ChannelLagging: * console.log('channel lagging'); * break; * } * }); * * // later… * unsubscribe(); * ``` */ export class WalletNotifications { private holder: NotificationHolderInterface | null = null; private readonly listeners = new Set<(event: WalletNotification) => void>(); constructor(private readonly wallet: WalletInterface) {} subscribe(listener: (event: WalletNotification) => void): Unsubscribe { this.listeners.add(listener); if (this.listeners.size === 1) { this.startLoop(); } return () => { this.listeners.delete(listener); if (this.listeners.size === 0) { this.holder?.cancelNextNotificationWait(); this.holder = null; } }; } private startLoop(): void { const localHolder = this.wallet.notifications(); this.holder = localHolder; (async () => { try { while (true) { const event = await localHolder.nextNotification(); if (event == null) break; for (const listener of this.listeners) { try { listener(event); } catch (err) { console.error('Wallet notification listener failed', err); } } } } catch (err) { console.error('Wallet notification loop failed', err); } finally { if (this.holder === localHolder) { this.holder = null; } } })(); } }