diff --git a/src/index.ts b/src/index.ts index 231d573a7..41cbb3cc4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -21,6 +21,7 @@ const start = async () => { const nostrSettings = LoadNosrtSettingsFromEnv() const { Send } = nostrMiddleware(serverMethods, mainHandler, { ...nostrSettings, apps }) mainHandler.attachNostrSend(Send) + mainHandler.StartBeacons() const Server = NewServer(serverMethods, serverOptions(mainHandler)) Server.Listen(mainSettings.servicePort) } diff --git a/src/services/main/applicationManager.ts b/src/services/main/applicationManager.ts index 0f2f6c82c..15498d08a 100644 --- a/src/services/main/applicationManager.ts +++ b/src/services/main/applicationManager.ts @@ -5,8 +5,9 @@ import { MainSettings } from './settings.js' import PaymentManager from './paymentManager.js' import { InboundOptionals, defaultInvoiceExpiry } from '../storage/paymentStorage.js' import { ApplicationUser } from '../storage/entity/ApplicationUser.js' -import { getLogger } from '../helpers/logger.js' +import { PubLogger, getLogger } from '../helpers/logger.js' import crypto from 'crypto' +import { Application } from '../storage/entity/Application.js' const TOKEN_EXPIRY_TIME = 2 * 60 * 1000 // 2 minutes, in milliseconds @@ -19,11 +20,18 @@ export default class { settings: MainSettings paymentManager: PaymentManager nPubLinkingTokens = new Map(); - linkingTokenInterval: NodeJS.Timeout + linkingTokenInterval: NodeJS.Timeout | null = null + serviceBeaconInterval: NodeJS.Timeout | null = null + log: PubLogger constructor(storage: Storage, settings: MainSettings, paymentManager: PaymentManager) { + this.log = getLogger({ component: "ApplicationManager" }) this.storage = storage this.settings = settings this.paymentManager = paymentManager + this.StartLinkingTokenInterval() + } + + StartLinkingTokenInterval() { this.linkingTokenInterval = setInterval(() => { const now = Date.now(); for (let [token, data] of this.nPubLinkingTokens) { @@ -36,8 +44,27 @@ export default class { } }, 60 * 1000); // 1 minute } + + async StartAppsServiceBeacon(publishBeacon: (app: Application) => void) { + this.serviceBeaconInterval = setInterval(async () => { + try { + const apps = await this.storage.applicationStorage.GetApplications() + apps.forEach(app => { + publishBeacon(app) + }) + } catch (e) { + this.log("error in beacon", (e as any).message) + } + }, 60 * 1000) + } + Stop() { - clearInterval(this.linkingTokenInterval) + if (this.linkingTokenInterval) { + clearInterval(this.linkingTokenInterval) + } + if (this.serviceBeaconInterval) { + clearInterval(this.serviceBeaconInterval) + } } SignAppToken(appId: string): string { return jwt.sign({ appId }, this.settings.jwtSecret); diff --git a/src/services/main/index.ts b/src/services/main/index.ts index 7b486394f..96e456c63 100644 --- a/src/services/main/index.ts +++ b/src/services/main/index.ts @@ -23,7 +23,7 @@ type UserOperationsSub = { newIncomingTx: (operation: Types.UserOperation) => void newOutgoingTx: (operation: Types.UserOperation) => void } - +const appTag = "Lightning.Pub" export default class { storage: Storage lnd: LND @@ -36,7 +36,6 @@ export default class { paymentSubs: Record void) | null> = {} metricsManager: MetricsManager nostrSend: NostrSend = () => { getLogger({})("nostr send not initialized yet") } - constructor(settings: MainSettings, storage: Storage) { this.settings = settings this.storage = storage @@ -56,6 +55,12 @@ export default class { this.paymentManager.Stop() } + StartBeacons() { + this.applicationManager.StartAppsServiceBeacon(app => { + this.UpdateBeacon(app, { type: 'service', name: app.name }) + }) + } + attachNostrSend(f: NostrSend) { this.nostrSend = f } @@ -206,6 +211,22 @@ export default class { this.nostrSend(app.app_id, { type: 'content', content: JSON.stringify(message), pub: user.nostr_public_key }) } + async UpdateBeacon(app: Application, content: { type: 'service', name: string }) { + if (!app.nostr_public_key) { + getLogger({ appName: app.name })("cannot update beacon, public key not set") + return + } + const tags = [["d", appTag]] + const event: UnsignedEvent = { + content: JSON.stringify(content), + created_at: Math.floor(Date.now() / 1000), + kind: 30078, + pubkey: app.nostr_public_key, + tags, + } + this.nostrSend(app.app_id, { type: 'event', event }) + } + async createZapReceipt(log: PubLogger, invoice: UserReceivingInvoice) { const zapInfo = invoice.zap_info if (!zapInfo || !invoice.linkedApplication || !invoice.linkedApplication.nostr_public_key) {