sender helper

This commit is contained in:
boufni95 2025-12-17 16:53:47 +00:00
parent ecf805c885
commit 991f49fe69
18 changed files with 96 additions and 125 deletions

View file

@ -7,6 +7,7 @@ import { getLogger } from './services/helpers/logger.js';
import { initMainHandler, initSettings } from './services/main/init.js'; import { initMainHandler, initSettings } from './services/main/init.js';
import { nip19 } from 'nostr-tools' import { nip19 } from 'nostr-tools'
import { LoadStorageSettingsFromEnv } from './services/storage/index.js'; import { LoadStorageSettingsFromEnv } from './services/storage/index.js';
import { AppInfo } from './services/nostr/nostrPool.js';
//@ts-ignore //@ts-ignore
const { nprofileEncode } = nip19 const { nprofileEncode } = nip19
@ -20,14 +21,28 @@ const start = async () => {
return return
} }
const { apps, mainHandler, liquidityProviderInfo, wizard, adminManager } = keepOn const { mainHandler, liquidityProviderInfo, wizard, adminManager } = keepOn
const serverMethods = GetServerMethods(mainHandler) const serverMethods = GetServerMethods(mainHandler)
const nostrSettings = settingsManager.getSettings().nostrRelaySettings const nostrSettings = settingsManager.getSettings().nostrRelaySettings
log("initializing nostr middleware") log("initializing nostr middleware")
const relays = settingsManager.getSettings().nostrRelaySettings.relays
const maxEventContentLength = settingsManager.getSettings().nostrRelaySettings.maxEventContentLength
const apps: AppInfo[] = keepOn.apps.map(app => {
return {
appId: app.appId,
privateKey: app.privateKey,
publicKey: app.publicKey,
name: app.name,
provider: app.publicKey === liquidityProviderInfo.publicKey ? {
clientId: liquidityProviderInfo.clientId,
pubDestination: settingsManager.getSettings().liquiditySettings.liquidityProviderPub,
relayUrl: settingsManager.getSettings().liquiditySettings.providerRelayUrl || relays[0]
} : undefined
}
})
const { Send } = nostrMiddleware(serverMethods, mainHandler, const { Send } = nostrMiddleware(serverMethods, mainHandler,
{ {
...nostrSettings, apps, clients: [liquidityProviderInfo], relays, maxEventContentLength, apps
providerDestinationPub: settingsManager.getSettings().liquiditySettings.liquidityProviderPub
}, },
(e, p) => mainHandler.liquidityProvider.onEvent(e, p) (e, p) => mainHandler.liquidityProvider.onEvent(e, p)
) )

View file

@ -43,8 +43,7 @@ const start = async () => {
}) })
const { Send, Stop, Ping, Reset } = nostrMiddleware(serverMethods, mainHandler, const { Send, Stop, Ping, Reset } = nostrMiddleware(serverMethods, mainHandler,
{ {
relays, maxEventContentLength, apps, /* clients: [liquidityProviderInfo], */ relays, maxEventContentLength, apps
/* providerDestinationPub: settingsManager.getSettings().liquiditySettings.liquidityProviderPub */
}, },
(e, p) => mainHandler.liquidityProvider.onEvent(e, p) (e, p) => mainHandler.liquidityProvider.onEvent(e, p)
) )

View file

@ -1,7 +1,7 @@
import { StateBundler } from "../storage/tlv/stateBundler.js"; import { StateBundler } from "../storage/tlv/stateBundler.js";
import { TlvStorageFactory } from "../storage/tlv/tlvFilesStorageFactory.js"; import { TlvStorageFactory } from "../storage/tlv/tlvFilesStorageFactory.js";
import { NostrSend } from "../nostr/nostrPool.js";
import { ProcessMetricsCollector } from "../storage/tlv/processMetricsCollector.js"; import { ProcessMetricsCollector } from "../storage/tlv/processMetricsCollector.js";
import { NostrSender } from "../nostr/sender.js";
type UtilsSettings = { type UtilsSettings = {
noCollector?: boolean noCollector?: boolean
dataDir: string, dataDir: string,
@ -10,9 +10,11 @@ type UtilsSettings = {
export class Utils { export class Utils {
tlvStorageFactory: TlvStorageFactory tlvStorageFactory: TlvStorageFactory
stateBundler: StateBundler stateBundler: StateBundler
_nostrSend: NostrSend = () => { throw new Error('nostr send not initialized yet') } nostrSender: NostrSender
constructor({ noCollector, dataDir, allowResetMetricsStorages }: UtilsSettings) {
this.tlvStorageFactory = new TlvStorageFactory(allowResetMetricsStorages) constructor({ noCollector, dataDir, allowResetMetricsStorages }: UtilsSettings, nostrSender: NostrSender) {
this.nostrSender = nostrSender
this.tlvStorageFactory = new TlvStorageFactory(allowResetMetricsStorages, nostrSender)
this.stateBundler = new StateBundler(dataDir, this.tlvStorageFactory) this.stateBundler = new StateBundler(dataDir, this.tlvStorageFactory)
if (!noCollector) { if (!noCollector) {
new ProcessMetricsCollector((metrics) => { new ProcessMetricsCollector((metrics) => {
@ -21,11 +23,6 @@ export class Utils {
} }
} }
attachNostrSend(f: NostrSend) {
this._nostrSend = f
this.tlvStorageFactory.attachNostrSend(f)
}
Stop() { Stop() {
this.stateBundler.Stop() this.stateBundler.Stop()
this.tlvStorageFactory.disconnect() this.tlvStorageFactory.disconnect()

View file

@ -10,7 +10,6 @@ import { Application } from '../storage/entity/Application.js'
import { ZapInfo } from '../storage/entity/UserReceivingInvoice.js' import { ZapInfo } from '../storage/entity/UserReceivingInvoice.js'
import { nofferEncode, ndebitEncode, OfferPriceType, nmanageEncode } from '@shocknet/clink-sdk' import { nofferEncode, ndebitEncode, OfferPriceType, nmanageEncode } from '@shocknet/clink-sdk'
import SettingsManager from './settingsManager.js' import SettingsManager from './settingsManager.js'
import { NostrSend, SendData, SendInitiator } from '../nostr/handler.js'
const TOKEN_EXPIRY_TIME = 2 * 60 * 1000 // 2 minutes, in milliseconds const TOKEN_EXPIRY_TIME = 2 * 60 * 1000 // 2 minutes, in milliseconds
type NsecLinkingData = { type NsecLinkingData = {
@ -18,7 +17,6 @@ type NsecLinkingData = {
expiry: number expiry: number
} }
export default class { export default class {
_nostrSend: NostrSend | null = null
storage: Storage storage: Storage
settings: SettingsManager settings: SettingsManager
paymentManager: PaymentManager paymentManager: PaymentManager
@ -34,17 +32,6 @@ export default class {
this.StartLinkingTokenInterval() this.StartLinkingTokenInterval()
} }
attachNostrSend = (nostrSend: NostrSend) => {
this._nostrSend = nostrSend
}
nostrSend: NostrSend = (initiator: SendInitiator, data: SendData, relays?: string[] | undefined) => {
if (!this._nostrSend) {
throw new Error("No nostrSend attached")
}
this._nostrSend(initiator, data, relays)
}
StartLinkingTokenInterval() { StartLinkingTokenInterval() {
this.linkingTokenInterval = setInterval(() => { this.linkingTokenInterval = setInterval(() => {
const now = Date.now(); const now = Date.now();
@ -259,7 +246,7 @@ export default class {
const message: Types.LiveUserOperation & { requestId: string, status: 'OK' } = const message: Types.LiveUserOperation & { requestId: string, status: 'OK' } =
{ operation: op, requestId: "GetLiveUserOperations", status: 'OK', latest_balance: balance } { operation: op, requestId: "GetLiveUserOperations", status: 'OK', latest_balance: balance }
if (appUser.nostr_public_key) { // TODO - fix before support for http streams if (appUser.nostr_public_key) { // TODO - fix before support for http streams
this.nostrSend({ type: 'app', appId: appUser.application.app_id }, { type: 'content', content: JSON.stringify(message), pub: appUser.nostr_public_key }) this.storage.NostrSender().Send({ type: 'app', appId: appUser.application.app_id }, { type: 'content', content: JSON.stringify(message), pub: appUser.nostr_public_key })
} }
} }

View file

@ -6,8 +6,7 @@ import { ERROR, getLogger } from "../helpers/logger.js";
import { DebitAccess, DebitAccessRules } from '../storage/entity/DebitAccess.js'; import { DebitAccess, DebitAccessRules } from '../storage/entity/DebitAccess.js';
import { Application } from '../storage/entity/Application.js'; import { Application } from '../storage/entity/Application.js';
import { ApplicationUser } from '../storage/entity/ApplicationUser.js'; import { ApplicationUser } from '../storage/entity/ApplicationUser.js';
import { NostrEvent, NostrSend, SendData, SendInitiator } from '../nostr/handler.js'; import { NostrEvent } from '../nostr/nostrPool.js';
import { UnsignedEvent } from 'nostr-tools';
import { Ndebit, NdebitData, NdebitFailure, NdebitSuccess, RecurringDebitTimeUnit } from "@shocknet/clink-sdk"; import { Ndebit, NdebitData, NdebitFailure, NdebitSuccess, RecurringDebitTimeUnit } from "@shocknet/clink-sdk";
import { import {
debitAccessRulesToDebitRules, newNdebitResponse, debitRulesToDebitAccessRules, debitAccessRulesToDebitRules, newNdebitResponse, debitRulesToDebitAccessRules,
@ -16,12 +15,7 @@ import {
} from "./debitTypes.js"; } from "./debitTypes.js";
export class DebitManager { export class DebitManager {
_nostrSend: NostrSend | null = null
applicationManager: ApplicationManager applicationManager: ApplicationManager
storage: Storage storage: Storage
lnd: LND lnd: LND
logger = getLogger({ component: 'DebitManager' }) logger = getLogger({ component: 'DebitManager' })
@ -31,17 +25,6 @@ export class DebitManager {
this.applicationManager = applicationManager this.applicationManager = applicationManager
} }
attachNostrSend = (nostrSend: NostrSend) => {
this._nostrSend = nostrSend
}
nostrSend: NostrSend = (initiator: SendInitiator, data: SendData, relays?: string[] | undefined) => {
if (!this._nostrSend) {
throw new Error("No nostrSend attached")
}
this._nostrSend(initiator, data, relays)
}
GetDebitAuthorizations = async (ctx: Types.UserContext): Promise<Types.DebitAuthorizations> => { GetDebitAuthorizations = async (ctx: Types.UserContext): Promise<Types.DebitAuthorizations> => {
const allDebitsAccesses = await this.storage.debitStorage.GetAllUserDebitAccess(ctx.app_user_id) const allDebitsAccesses = await this.storage.debitStorage.GetAllUserDebitAccess(ctx.app_user_id)
const debits: Types.DebitAuthorization[] = allDebitsAccesses.map(access => ({ const debits: Types.DebitAuthorization[] = allDebitsAccesses.map(access => ({
@ -135,8 +118,8 @@ export class DebitManager {
} }
handleNip68Debit = async (pointerdata: NdebitData, event: NostrEvent) => { handleNip68Debit = async (pointerdata: NdebitData, event: NostrEvent) => {
if (!this._nostrSend) { if (!this.storage.NostrSender().IsReady()) {
throw new Error("No nostrSend attached") throw new Error("Nostr sender not ready")
} }
this.logger("📥 [DEBIT REQUEST] Received debit request", { this.logger("📥 [DEBIT REQUEST] Received debit request", {
fromPub: event.pub, fromPub: event.pub,
@ -148,7 +131,7 @@ export class DebitManager {
this.logger("🔍 [DEBIT REQUEST] Sending ", res.status, " response") this.logger("🔍 [DEBIT REQUEST] Sending ", res.status, " response")
if (res.status === 'fail' || res.status === 'authOk') { if (res.status === 'fail' || res.status === 'authOk') {
const e = newNdebitResponse(JSON.stringify(res.debitRes), event) const e = newNdebitResponse(JSON.stringify(res.debitRes), event)
this.nostrSend({ type: 'app', appId: event.appId }, { type: 'event', event: e, encrypt: { toPub: event.pub } }) this.storage.NostrSender().Send({ type: 'app', appId: event.appId }, { type: 'event', event: e, encrypt: { toPub: event.pub } })
return return
} }
const { appUser } = res const { appUser } = res
@ -166,7 +149,7 @@ export class DebitManager {
return return
} }
const message: Types.LiveDebitRequest & { requestId: string, status: 'OK' } = { ...res.liveDebitReq, requestId: "GetLiveDebitRequests", status: 'OK' } const message: Types.LiveDebitRequest & { requestId: string, status: 'OK' } = { ...res.liveDebitReq, requestId: "GetLiveDebitRequests", status: 'OK' }
this.nostrSend({ type: 'app', appId: event.appId }, { type: 'content', content: JSON.stringify(message), pub: res.appUser.nostr_public_key }) this.storage.NostrSender().Send({ type: 'app', appId: event.appId }, { type: 'content', content: JSON.stringify(message), pub: res.appUser.nostr_public_key })
} }
notifyPaymentSuccess = (debitRes: NdebitSuccess, event: { pub: string, id: string, appId: string }) => { notifyPaymentSuccess = (debitRes: NdebitSuccess, event: { pub: string, id: string, appId: string }) => {
@ -175,7 +158,8 @@ export class DebitManager {
sendDebitResponse = (debitRes: NdebitFailure | NdebitSuccess, event: { pub: string, id: string, appId: string }) => { sendDebitResponse = (debitRes: NdebitFailure | NdebitSuccess, event: { pub: string, id: string, appId: string }) => {
const e = newNdebitResponse(JSON.stringify(debitRes), event) const e = newNdebitResponse(JSON.stringify(debitRes), event)
this.nostrSend({ type: 'app', appId: event.appId }, { type: 'event', event: e, encrypt: { toPub: event.pub } }) this.storage.NostrSender().Send({ type: 'app', appId: event.appId }, { type: 'event', event: e, encrypt: { toPub: event.pub } })
} }
payNdebitInvoice = async (event: NostrEvent, pointerdata: NdebitData): Promise<HandleNdebitRes> => { payNdebitInvoice = async (event: NostrEvent, pointerdata: NdebitData): Promise<HandleNdebitRes> => {

View file

@ -62,8 +62,6 @@ export default class {
rugPullTracker: RugPullTracker rugPullTracker: RugPullTracker
unlocker: Unlocker unlocker: Unlocker
notificationsManager: NotificationsManager notificationsManager: NotificationsManager
//webRTC: webRTC
nostrSend: NostrSend = () => { getLogger({})("nostr send not initialized yet") }
nostrProcessPing: (() => Promise<void>) | null = null nostrProcessPing: (() => Promise<void>) | null = null
nostrReset: (settings: NostrSettings) => void = () => { getLogger({})("nostr reset not initialized yet") } nostrReset: (settings: NostrSettings) => void = () => { getLogger({})("nostr reset not initialized yet") }
constructor(settings: SettingsManager, storage: Storage, adminManager: AdminManager, utils: Utils, unlocker: Unlocker) { constructor(settings: SettingsManager, storage: Storage, adminManager: AdminManager, utils: Utils, unlocker: Unlocker) {
@ -109,14 +107,7 @@ export default class {
} }
attachNostrSend(f: NostrSend) { attachNostrSend(f: NostrSend) {
this.nostrSend = f this.utils.nostrSender.AttachNostrSend(f)
this.liquidityProvider.attachNostrSend(f)
this.debitManager.attachNostrSend(f)
this.offerManager.attachNostrSend(f)
this.managementManager.attachNostrSend(f)
this.utils.attachNostrSend(f)
this.applicationManager.attachNostrSend(f)
//this.webRTC.attachNostrSend(f)
} }
attachNostrProcessPing(f: () => Promise<void>) { attachNostrProcessPing(f: () => Promise<void>) {
@ -379,7 +370,7 @@ export default class {
const message: Types.LiveUserOperation & { requestId: string, status: 'OK' } = const message: Types.LiveUserOperation & { requestId: string, status: 'OK' } =
{ operation: op, requestId: "GetLiveUserOperations", status: 'OK', latest_balance: balance } { operation: op, requestId: "GetLiveUserOperations", status: 'OK', latest_balance: balance }
const j = JSON.stringify(message) const j = JSON.stringify(message)
this.nostrSend({ type: 'app', appId: app.app_id }, { type: 'content', content: j, pub: user.nostr_public_key }) this.utils.nostrSender.Send({ type: 'app', appId: app.app_id }, { type: 'content', content: j, pub: user.nostr_public_key })
this.SendEncryptedNotification(app, user, op) this.SendEncryptedNotification(app, user, op)
} }
@ -412,7 +403,7 @@ export default class {
pubkey: app.nostr_public_key, pubkey: app.nostr_public_key,
tags, tags,
} }
this.nostrSend({ type: 'app', appId: app.app_id }, { type: 'event', event }) this.utils.nostrSender.Send({ type: 'app', appId: app.app_id }, { type: 'event', event })
} }
async createZapReceipt(log: PubLogger, invoice: UserReceivingInvoice) { async createZapReceipt(log: PubLogger, invoice: UserReceivingInvoice) {
@ -432,7 +423,7 @@ export default class {
tags, tags,
} }
log({ unsigned: event }) log({ unsigned: event })
this.nostrSend({ type: 'app', appId: invoice.linkedApplication.app_id }, { type: 'event', event }, zapInfo.relays || undefined) this.utils.nostrSender.Send({ type: 'app', appId: invoice.linkedApplication.app_id }, { type: 'event', event }, zapInfo.relays || undefined)
} }
async ResetNostr() { async ResetNostr() {

View file

@ -10,6 +10,7 @@ import { Wizard } from "../wizard/index.js"
import { AdminManager } from "./adminManager.js" import { AdminManager } from "./adminManager.js"
import SettingsManager from "./settingsManager.js" import SettingsManager from "./settingsManager.js"
import { LoadStorageSettingsFromEnv } from "../storage/index.js" import { LoadStorageSettingsFromEnv } from "../storage/index.js"
import { NostrSender } from "../nostr/sender.js"
export type AppData = { export type AppData = {
privateKey: string; privateKey: string;
publicKey: string; publicKey: string;
@ -18,7 +19,8 @@ export type AppData = {
} }
export const initSettings = async (log: PubLogger, storageSettings: StorageSettings): Promise<SettingsManager> => { export const initSettings = async (log: PubLogger, storageSettings: StorageSettings): Promise<SettingsManager> => {
const utils = new Utils({ dataDir: storageSettings.dataDir, allowResetMetricsStorages: storageSettings.allowResetMetricsStorages }) const nostrSender = new NostrSender()
const utils = new Utils({ dataDir: storageSettings.dataDir, allowResetMetricsStorages: storageSettings.allowResetMetricsStorages }, nostrSender)
const storageManager = new Storage(storageSettings, utils) const storageManager = new Storage(storageSettings, utils)
await storageManager.Connect(log) await storageManager.Connect(log)
const settingsManager = new SettingsManager(storageManager) const settingsManager = new SettingsManager(storageManager)

View file

@ -3,7 +3,6 @@ import { NostrRequest } from '../../../proto/autogenerated/ts/nostr_transport.js
import * as Types from '../../../proto/autogenerated/ts/types.js' import * as Types from '../../../proto/autogenerated/ts/types.js'
import { ERROR, getLogger } from '../helpers/logger.js' import { ERROR, getLogger } from '../helpers/logger.js'
import { Utils } from '../helpers/utilsWrapper.js' import { Utils } from '../helpers/utilsWrapper.js'
import { NostrSend } from '../nostr/nostrPool.js'
import { InvoicePaidCb } from '../lnd/settings.js' import { InvoicePaidCb } from '../lnd/settings.js'
import Storage from '../storage/index.js' import Storage from '../storage/index.js'
import SettingsManager from './settingsManager.js' import SettingsManager from './settingsManager.js'
@ -16,7 +15,7 @@ export class LiquidityProvider {
clientId: string = "" clientId: string = ""
myPub: string = "" myPub: string = ""
log = getLogger({ component: 'liquidityProvider' }) log = getLogger({ component: 'liquidityProvider' })
nostrSend: NostrSend | null = null // nostrSend: NostrSend | null = null
configured = false configured = false
pubDestination: string pubDestination: string
ready: boolean ready: boolean
@ -287,15 +286,8 @@ export class LiquidityProvider {
} }
attachNostrSend(f: NostrSend) {
this.log("attaching nostrSend action")
this.nostrSend = f
this.setSetIfConfigured()
}
setSetIfConfigured = () => { setSetIfConfigured = () => {
if (this.nostrSend && !!this.pubDestination && !!this.clientId && !!this.myPub) { if (this.utils.nostrSender.IsReady() && !!this.pubDestination && !!this.clientId && !!this.myPub) {
this.configured = true this.configured = true
this.log("configured to send to ") this.log("configured to send to ")
} }
@ -339,7 +331,7 @@ export class LiquidityProvider {
} }
clientSend = (to: string, message: NostrRequest): Promise<any> => { clientSend = (to: string, message: NostrRequest): Promise<any> => {
if (!this.configured || !this.nostrSend) { if (!this.configured || !this.utils.nostrSender.IsReady()) {
throw new Error("liquidity provider not initialized") throw new Error("liquidity provider not initialized")
} }
if (!message.requestId) { if (!message.requestId) {
@ -349,7 +341,7 @@ export class LiquidityProvider {
if (this.clientCbs[reqId]) { if (this.clientCbs[reqId]) {
throw new Error("request was already sent") throw new Error("request was already sent")
} }
this.nostrSend({ type: 'client', clientId: this.clientId }, { this.utils.nostrSender.Send({ type: 'client', clientId: this.clientId }, {
type: 'content', type: 'content',
pub: to, pub: to,
content: JSON.stringify(message) content: JSON.stringify(message)
@ -368,7 +360,7 @@ export class LiquidityProvider {
} }
clientSub = (to: string, message: NostrRequest, cb: (res: any) => void): void => { clientSub = (to: string, message: NostrRequest, cb: (res: any) => void): void => {
if (!this.configured || !this.nostrSend) { if (!this.configured || !this.utils.nostrSender.IsReady()) {
throw new Error("liquidity provider not initialized") throw new Error("liquidity provider not initialized")
} }
if (!message.requestId) { if (!message.requestId) {
@ -387,7 +379,7 @@ export class LiquidityProvider {
this.log("sub for", reqId, "was already registered, overriding") this.log("sub for", reqId, "was already registered, overriding")
return return
} }
this.nostrSend({ type: 'client', clientId: this.clientId }, { this.utils.nostrSender.Send({ type: 'client', clientId: this.clientId }, {
type: 'content', type: 'content',
pub: to, pub: to,
content: JSON.stringify(message) content: JSON.stringify(message)

View file

@ -2,7 +2,7 @@ import { getRepository } from "typeorm";
import { User } from "../storage/entity/User.js"; import { User } from "../storage/entity/User.js";
import { UserOffer } from "../storage/entity/UserOffer.js"; import { UserOffer } from "../storage/entity/UserOffer.js";
import { ManagementGrant } from "../storage/entity/ManagementGrant.js"; import { ManagementGrant } from "../storage/entity/ManagementGrant.js";
import { NostrEvent, NostrSend } from "../nostr/handler.js"; import { NostrEvent } from "../nostr/nostrPool.js";
import Storage from "../storage/index.js"; import Storage from "../storage/index.js";
import { OfferManager } from "./offerManager.js"; import { OfferManager } from "./offerManager.js";
import * as Types from "../../../proto/autogenerated/ts/types.js"; import * as Types from "../../../proto/autogenerated/ts/types.js";
@ -13,7 +13,6 @@ import SettingsManager from "./settingsManager.js";
type Result<T> = { state: 'success', result: T } | { state: 'error', err: NmanageFailure } | { state: 'authRequired' } type Result<T> = { state: 'success', result: T } | { state: 'error', err: NmanageFailure } | { state: 'authRequired' }
export class ManagementManager { export class ManagementManager {
private nostrSend: NostrSend;
private storage: Storage; private storage: Storage;
private settings: SettingsManager; private settings: SettingsManager;
private awaitingRequests: Record<string, { request: NmanageRequest, event: NostrEvent }> = {} private awaitingRequests: Record<string, { request: NmanageRequest, event: NostrEvent }> = {}
@ -24,10 +23,6 @@ export class ManagementManager {
this.logger = getLogger({ component: 'ManagementManager' }) this.logger = getLogger({ component: 'ManagementManager' })
} }
attachNostrSend(f: NostrSend) {
this.nostrSend = f
}
ResetManage = async (ctx: Types.UserContext, req: Types.ManageOperation): Promise<void> => { ResetManage = async (ctx: Types.UserContext, req: Types.ManageOperation): Promise<void> => {
await this.storage.managementStorage.removeGrant(ctx.app_user_id, req.npub) await this.storage.managementStorage.removeGrant(ctx.app_user_id, req.npub)
} }
@ -62,12 +57,12 @@ export class ManagementManager {
private sendManageAuthorizationRequest = (appId: string, userPub: string, { requestId, npub }: { requestId: string, npub: string }) => { private sendManageAuthorizationRequest = (appId: string, userPub: string, { requestId, npub }: { requestId: string, npub: string }) => {
const message: Types.LiveManageRequest & { requestId: string, status: 'OK' } = { requestId: "GetLiveManageRequests", status: 'OK', npub: npub, request_id: requestId } const message: Types.LiveManageRequest & { requestId: string, status: 'OK' } = { requestId: "GetLiveManageRequests", status: 'OK', npub: npub, request_id: requestId }
this.logger("Sending manage authorization request to", npub, "for app", appId) this.logger("Sending manage authorization request to", npub, "for app", appId)
this.nostrSend({ type: 'app', appId: appId }, { type: 'content', content: JSON.stringify(message), pub: userPub }) this.storage.NostrSender().Send({ type: 'app', appId: appId }, { type: 'content', content: JSON.stringify(message), pub: userPub })
} }
private sendError(event: NostrEvent, err: NmanageFailure) { private sendError(event: NostrEvent, err: NmanageFailure) {
const e = newNmanageResponse(JSON.stringify(err), event) const e = newNmanageResponse(JSON.stringify(err), event)
this.nostrSend({ type: 'app', appId: event.appId }, { type: 'event', event: e, encrypt: { toPub: event.pub } }) this.storage.NostrSender().Send({ type: 'app', appId: event.appId }, { type: 'event', event: e, encrypt: { toPub: event.pub } })
} }
private async handleAuthRequired(nmanageReq: NmanageRequest, event: NostrEvent) { private async handleAuthRequired(nmanageReq: NmanageRequest, event: NostrEvent) {
@ -107,7 +102,7 @@ export class ManagementManager {
return return
} }
const e = newNmanageResponse(JSON.stringify(r.result), event) const e = newNmanageResponse(JSON.stringify(r.result), event)
this.nostrSend({ type: 'app', appId: event.appId }, { type: 'event', event: e, encrypt: { toPub: event.pub } }) this.storage.NostrSender().Send({ type: 'app', appId: event.appId }, { type: 'event', event: e, encrypt: { toPub: event.pub } })
} catch (err: any) { } catch (err: any) {
this.logger(ERROR, err.message || err) this.logger(ERROR, err.message || err)
this.sendError(event, { res: 'GFY', code: 2, error: 'Temporary Failure' }) this.sendError(event, { res: 'GFY', code: 2, error: 'Temporary Failure' })

View file

@ -4,7 +4,7 @@ import ProductManager from "./productManager.js";
import Storage from '../storage/index.js' import Storage from '../storage/index.js'
import LND from "../lnd/lnd.js" import LND from "../lnd/lnd.js"
import { ERROR, getLogger } from "../helpers/logger.js"; import { ERROR, getLogger } from "../helpers/logger.js";
import { NostrEvent, NostrSend, SendData, SendInitiator } from '../nostr/handler.js'; import { NostrEvent } from '../nostr/nostrPool.js';
import { UnsignedEvent } from 'nostr-tools'; import { UnsignedEvent } from 'nostr-tools';
import { UserOffer } from '../storage/entity/UserOffer.js'; import { UserOffer } from '../storage/entity/UserOffer.js';
import { LiquidityManager } from "./liquidityManager.js" import { LiquidityManager } from "./liquidityManager.js"
@ -31,9 +31,6 @@ const mapToOfferConfig = (appUserId: string, offer: UserOffer, { pubkey, relay }
} }
} }
export class OfferManager { export class OfferManager {
_nostrSend: NostrSend | null = null
settings: SettingsManager settings: SettingsManager
applicationManager: ApplicationManager applicationManager: ApplicationManager
productManager: ProductManager productManager: ProductManager
@ -50,16 +47,6 @@ export class OfferManager {
this.liquidityManager = liquidityManager this.liquidityManager = liquidityManager
} }
attachNostrSend = (nostrSend: NostrSend) => {
this._nostrSend = nostrSend
}
nostrSend: NostrSend = (initiator: SendInitiator, data: SendData, relays?: string[] | undefined) => {
if (!this._nostrSend) {
throw new Error("No nostrSend attached")
}
this._nostrSend(initiator, data, relays)
}
async AddUserOffer(ctx: Types.UserContext, req: Types.OfferConfig): Promise<Types.OfferId> { async AddUserOffer(ctx: Types.UserContext, req: Types.OfferConfig): Promise<Types.OfferId> {
const newOffer = await this.storage.offerStorage.AddUserOffer(ctx.app_user_id, { const newOffer = await this.storage.offerStorage.AddUserOffer(ctx.app_user_id, {
payer_data: req.payer_data, payer_data: req.payer_data,
@ -176,7 +163,7 @@ export class OfferManager {
max: offerInvoice.max max: offerInvoice.max
}) })
const e = newNofferResponse(JSON.stringify({ code, error: codeToMessage(code), range: { min: 10, max: offerInvoice.max } }), event) const e = newNofferResponse(JSON.stringify({ code, error: codeToMessage(code), range: { min: 10, max: offerInvoice.max } }), event)
this.nostrSend({ type: 'app', appId: event.appId }, { type: 'event', event: e, encrypt: { toPub: event.pub } }) this.storage.NostrSender().Send({ type: 'app', appId: event.appId }, { type: 'event', event: e, encrypt: { toPub: event.pub } })
return return
} }
@ -188,7 +175,7 @@ export class OfferManager {
}) })
const e = newNofferResponse(JSON.stringify({ bolt11: offerInvoice.invoice }), event) const e = newNofferResponse(JSON.stringify({ bolt11: offerInvoice.invoice }), event)
this.nostrSend({ type: 'app', appId: event.appId }, { type: 'event', event: e, encrypt: { toPub: event.pub } }) this.storage.NostrSender().Send({ type: 'app', appId: event.appId }, { type: 'event', event: e, encrypt: { toPub: event.pub } })
this.logger("📤 [OFFER RESPONSE] Sent offer response", { this.logger("📤 [OFFER RESPONSE] Sent offer response", {
toPub: event.pub, toPub: event.pub,

View file

@ -0,0 +1,18 @@
import { NostrSend, SendData, SendInitiator } from "./nostrPool.js"
export class NostrSender {
private _nostrSend: NostrSend = () => { throw new Error('nostr send not initialized yet') }
private isReady: boolean = false
AttachNostrSend(nostrSend: NostrSend) {
this._nostrSend = nostrSend
this.isReady = true
}
Send(initiator: SendInitiator, data: SendData, relays?: string[] | undefined) {
if (!this._nostrSend) {
throw new Error("No nostrSend attached")
}
this._nostrSend(initiator, data, relays)
}
IsReady() {
return this.isReady
}
}

View file

@ -118,6 +118,10 @@ export default class {
} */ } */
} }
NostrSender() {
return this.utils.nostrSender
}
getStorageSettings(): StorageSettings { getStorageSettings(): StorageSettings {
return this.settings return this.settings
} }

View file

@ -2,11 +2,12 @@ import { ChildProcess, fork } from 'child_process';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { AddTlvOperation, ITlvStorageOperation, SuccessTlvOperationResponse, LoadLatestTlvOperation, LoadTlvFileOperation, NewTlvStorageOperation, SerializableLatestData, SerializableTlvFile, TlvOperationResponse, TlvStorageSettings, WebRtcMessageOperation, ProcessMetricsTlvOperation, ZipStoragesOperation, ResetTlvStorageOperation, PingTlvOperation } from './tlvFilesStorageProcessor'; import { AddTlvOperation, ITlvStorageOperation, SuccessTlvOperationResponse, LoadLatestTlvOperation, LoadTlvFileOperation, NewTlvStorageOperation, SerializableLatestData, SerializableTlvFile, TlvOperationResponse, TlvStorageSettings, WebRtcMessageOperation, ProcessMetricsTlvOperation, ZipStoragesOperation, ResetTlvStorageOperation, PingTlvOperation } from './tlvFilesStorageProcessor';
import { LatestData, TlvFile } from './tlvFilesStorage'; import { LatestData, TlvFile } from './tlvFilesStorage';
import { NostrSend, SendData, SendInitiator } from '../../nostr/handler'; import { SendData, SendInitiator } from '../../nostr/nostrPool.js';
import { WebRtcUserInfo } from '../../webRTC'; import { WebRtcUserInfo } from '../../webRTC';
import * as Types from '../../../../proto/autogenerated/ts/types.js' import * as Types from '../../../../proto/autogenerated/ts/types.js'
import { ProcessMetrics } from './processMetricsCollector'; import { ProcessMetrics } from './processMetricsCollector';
import { getLogger, ERROR } from '../../helpers/logger.js'; import { getLogger, ERROR } from '../../helpers/logger.js';
import { NostrSender } from '../../nostr/sender';
export type TlvStorageInterface = { export type TlvStorageInterface = {
AddTlv: (appId: string, dataName: string, tlv: Uint8Array) => Promise<number> AddTlv: (appId: string, dataName: string, tlv: Uint8Array) => Promise<number>
LoadLatest: (limit?: number) => Promise<LatestData> LoadLatest: (limit?: number) => Promise<LatestData>
@ -17,12 +18,14 @@ export class TlvStorageFactory extends EventEmitter {
private process: ChildProcess; private process: ChildProcess;
private isConnected: boolean = false; private isConnected: boolean = false;
private debug: boolean = false; private debug: boolean = false;
private _nostrSend: NostrSend = () => { throw new Error('nostr send not initialized yet') } // private _nostrSend: NostrSend = () => { throw new Error('nostr send not initialized yet') }
private nostrSender: NostrSender
private allowResetMetricsStorages: boolean private allowResetMetricsStorages: boolean
log = getLogger({ component: 'TlvStorageFactory' }) log = getLogger({ component: 'TlvStorageFactory' })
constructor(allowResetMetricsStorages: boolean) { constructor(allowResetMetricsStorages: boolean, nostrSender: NostrSender) {
super(); super();
this.allowResetMetricsStorages = allowResetMetricsStorages this.allowResetMetricsStorages = allowResetMetricsStorages
this.nostrSender = nostrSender
this.initializeSubprocess(); this.initializeSubprocess();
} }
@ -30,15 +33,8 @@ export class TlvStorageFactory extends EventEmitter {
this.debug = debug; this.debug = debug;
} }
attachNostrSend(f: NostrSend) {
this._nostrSend = f
}
private nostrSend = (opResponse: SuccessTlvOperationResponse<{ initiator: SendInitiator, data: SendData, relays?: string[] }>) => { private nostrSend = (opResponse: SuccessTlvOperationResponse<{ initiator: SendInitiator, data: SendData, relays?: string[] }>) => {
if (!this._nostrSend) { this.nostrSender.Send(opResponse.data.initiator, opResponse.data.data, opResponse.data.relays)
throw new Error("No nostrSend attached")
}
this._nostrSend(opResponse.data.initiator, opResponse.data.data, opResponse.data.relays)
} }
private initializeSubprocess() { private initializeSubprocess() {

View file

@ -2,8 +2,8 @@ import { PubLogger, getLogger } from '../../helpers/logger.js';
import webRTC, { WebRtcUserInfo } from '../../webRTC/index.js'; import webRTC, { WebRtcUserInfo } from '../../webRTC/index.js';
import { TlvFilesStorage } from './tlvFilesStorage.js'; import { TlvFilesStorage } from './tlvFilesStorage.js';
import * as Types from '../../../../proto/autogenerated/ts/types.js' import * as Types from '../../../../proto/autogenerated/ts/types.js'
import { SendData } from '../../nostr/handler.js'; import { SendData } from '../../nostr/nostrPool.js';
import { SendInitiator } from '../../nostr/handler.js'; import { SendInitiator } from '../../nostr/nostrPool.js';
import { ProcessMetrics, ProcessMetricsCollector } from './processMetricsCollector.js'; import { ProcessMetrics, ProcessMetricsCollector } from './processMetricsCollector.js';
import { integerToUint8Array } from '../../helpers/tlv.js'; import { integerToUint8Array } from '../../helpers/tlv.js';
import { zip } from 'zip-a-folder' import { zip } from 'zip-a-folder'

View file

@ -3,7 +3,7 @@ import wrtc from 'wrtc'
import Storage from '../storage/index.js' import Storage from '../storage/index.js'
import { ERROR, getLogger } from "../helpers/logger.js" import { ERROR, getLogger } from "../helpers/logger.js"
import * as Types from '../../../proto/autogenerated/ts/types.js' import * as Types from '../../../proto/autogenerated/ts/types.js'
import { NostrSend, SendData, SendInitiator } from "../nostr/handler.js" import { NostrSend, SendData, SendInitiator } from "../nostr/nostrPool.js"
import { encodeTLbV, encodeTLV, encodeTLVDataPacket } from '../helpers/tlv.js' import { encodeTLbV, encodeTLV, encodeTLVDataPacket } from '../helpers/tlv.js'
import { Utils } from '../helpers/utilsWrapper.js' import { Utils } from '../helpers/utilsWrapper.js'
import { TlvFilesStorage } from '../storage/tlv/tlvFilesStorage.js' import { TlvFilesStorage } from '../storage/tlv/tlvFilesStorage.js'
@ -111,7 +111,7 @@ export default class webRTC {
const packet = packets[i] const packet = packets[i]
const tlv = encodeTLVDataPacket({ dataId: id, packetNum: i + 1, totalPackets: packets.length, data: packet }) const tlv = encodeTLVDataPacket({ dataId: id, packetNum: i + 1, totalPackets: packets.length, data: packet })
const bytes = encodeTLbV(tlv) const bytes = encodeTLbV(tlv)
channel.send(bytes) channel.send(new Uint8Array(bytes))
} }
} catch (e: any) { } catch (e: any) {
this.log(ERROR, 'ondatachannel', e.message || e) this.log(ERROR, 'ondatachannel', e.message || e)

View file

@ -8,6 +8,7 @@ import LND from '../services/lnd/lnd.js'
import { LiquidityProvider } from "../services/main/liquidityProvider.js" import { LiquidityProvider } from "../services/main/liquidityProvider.js"
import { Utils } from "../services/helpers/utilsWrapper.js" import { Utils } from "../services/helpers/utilsWrapper.js"
import { LoadStorageSettingsFromEnv } from "../services/storage/index.js" import { LoadStorageSettingsFromEnv } from "../services/storage/index.js"
import { NostrSender } from "../services/nostr/sender.js"
export type ChainTools = { export type ChainTools = {
mine: (amount: number) => Promise<void> mine: (amount: number) => Promise<void>
@ -15,7 +16,8 @@ export type ChainTools = {
export const setupNetwork = async (): Promise<ChainTools> => { export const setupNetwork = async (): Promise<ChainTools> => {
const storageSettings = GetTestStorageSettings(LoadStorageSettingsFromEnv()) const storageSettings = GetTestStorageSettings(LoadStorageSettingsFromEnv())
const setupUtils = new Utils({ dataDir: storageSettings.dataDir, allowResetMetricsStorages: storageSettings.allowResetMetricsStorages }) const nostrSender = new NostrSender()
const setupUtils = new Utils({ dataDir: storageSettings.dataDir, allowResetMetricsStorages: storageSettings.allowResetMetricsStorages }, nostrSender)
//const settingsManager = new SettingsManager(storageSettings) //const settingsManager = new SettingsManager(storageSettings)
const core = new BitcoinCoreWrapper(LoadBitcoinCoreSettingsFromEnv()) const core = new BitcoinCoreWrapper(LoadBitcoinCoreSettingsFromEnv())
await core.InitAddress() await core.InitAddress()
@ -23,7 +25,7 @@ export const setupNetwork = async (): Promise<ChainTools> => {
const lndSettings = LoadLndSettingsFromEnv({}) const lndSettings = LoadLndSettingsFromEnv({})
const lndNodeSettings = LoadLndNodeSettingsFromEnv({}) const lndNodeSettings = LoadLndNodeSettingsFromEnv({})
const secondLndNodeSettings = LoadSecondLndSettingsFromEnv() const secondLndNodeSettings = LoadSecondLndSettingsFromEnv()
const liquiditySettings: LiquiditySettings = { disableLiquidityProvider: true, liquidityProviderPub: "", useOnlyLiquidityProvider: false } const liquiditySettings: LiquiditySettings = { disableLiquidityProvider: true, liquidityProviderPub: "", useOnlyLiquidityProvider: false, providerRelayUrl: "" }
const alice = new LND(() => ({ lndSettings, lndNodeSettings }), new LiquidityProvider(() => liquiditySettings, setupUtils, async () => { }, async () => { }), async () => { }, setupUtils, async () => { }, async () => { }, () => { }, () => { }, () => { }) const alice = new LND(() => ({ lndSettings, lndNodeSettings }), new LiquidityProvider(() => liquiditySettings, setupUtils, async () => { }, async () => { }), async () => { }, setupUtils, async () => { }, async () => { }, () => { }, () => { }, () => { })
const bob = new LND(() => ({ lndSettings, lndNodeSettings: secondLndNodeSettings }), new LiquidityProvider(() => liquiditySettings, setupUtils, async () => { }, async () => { }), async () => { }, setupUtils, async () => { }, async () => { }, () => { }, () => { }, () => { }) const bob = new LND(() => ({ lndSettings, lndNodeSettings: secondLndNodeSettings }), new LiquidityProvider(() => liquiditySettings, setupUtils, async () => { }, async () => { }), async () => { }, setupUtils, async () => { }, async () => { }, () => { }, () => { }, () => { })
await tryUntil<void>(async i => { await tryUntil<void>(async i => {

View file

@ -32,7 +32,7 @@ export const initBootstrappedInstance = async (T: TestBase) => {
console.log("sending new operation to provider") console.log("sending new operation to provider")
bootstrapped.liquidityProvider.onEvent(j, T.app.publicKey) bootstrapped.liquidityProvider.onEvent(j, T.app.publicKey)
}) })
bootstrapped.liquidityProvider.attachNostrSend(async (_, data, r) => { bootstrapped.attachNostrSend(async (_, data, r) => {
const res = await handleSend(T, data) const res = await handleSend(T, data)
if (data.type === 'event') { if (data.type === 'event') {
throw new Error("unsupported event type") throw new Error("unsupported event type")

View file

@ -15,6 +15,7 @@ import { AdminManager } from '../services/main/adminManager.js'
import { TlvStorageFactory } from '../services/storage/tlv/tlvFilesStorageFactory.js' import { TlvStorageFactory } from '../services/storage/tlv/tlvFilesStorageFactory.js'
import { ChainTools } from './networkSetup.js' import { ChainTools } from './networkSetup.js'
import { LiquiditySettings, LoadLndSettingsFromEnv, LoadSecondLndSettingsFromEnv, LoadThirdLndSettingsFromEnv } from '../services/main/settings.js' import { LiquiditySettings, LoadLndSettingsFromEnv, LoadSecondLndSettingsFromEnv, LoadThirdLndSettingsFromEnv } from '../services/main/settings.js'
import { NostrSender } from '../services/nostr/sender.js'
chai.use(chaiString) chai.use(chaiString)
export const expect = chai.expect export const expect = chai.expect
export type Describe = (message: string, failure?: boolean) => void export type Describe = (message: string, failure?: boolean) => void
@ -46,7 +47,8 @@ export type StorageTestBase = {
export const setupStorageTest = async (d: Describe): Promise<StorageTestBase> => { export const setupStorageTest = async (d: Describe): Promise<StorageTestBase> => {
const settings = GetTestStorageSettings(LoadStorageSettingsFromEnv()) const settings = GetTestStorageSettings(LoadStorageSettingsFromEnv())
const utils = new Utils({ dataDir: settings.dataDir, allowResetMetricsStorages: true }) const nostrSender = new NostrSender()
const utils = new Utils({ dataDir: settings.dataDir, allowResetMetricsStorages: true }, nostrSender)
const storageManager = new Storage(settings, utils) const storageManager = new Storage(settings, utils)
await storageManager.Connect(console.log) await storageManager.Connect(console.log)
return { return {
@ -79,8 +81,8 @@ export const SetupTest = async (d: Describe, chainTools: ChainTools): Promise<Te
const u2 = await main.applicationManager.AddAppUser(app.appId, { identifier: "user2", balance: 0, fail_if_exists: true }) const u2 = await main.applicationManager.AddAppUser(app.appId, { identifier: "user2", balance: 0, fail_if_exists: true })
const user1 = { userId: u1.info.userId, appUserIdentifier: u1.identifier, appId: app.appId } const user1 = { userId: u1.info.userId, appUserIdentifier: u1.identifier, appId: app.appId }
const user2 = { userId: u2.info.userId, appUserIdentifier: u2.identifier, appId: app.appId } const user2 = { userId: u2.info.userId, appUserIdentifier: u2.identifier, appId: app.appId }
const nostrSender = new NostrSender()
const extermnalUtils = new Utils({ dataDir: storageSettings.dataDir, allowResetMetricsStorages: storageSettings.allowResetMetricsStorages }) const extermnalUtils = new Utils({ dataDir: storageSettings.dataDir, allowResetMetricsStorages: storageSettings.allowResetMetricsStorages }, nostrSender)
/* const externalAccessToMainLnd = new LND(settings.lndSettings, new LiquidityProvider("", extermnalUtils, async () => { }, async () => { }), extermnalUtils, async () => { }, async () => { }, () => { }, () => { }) /* const externalAccessToMainLnd = new LND(settings.lndSettings, new LiquidityProvider("", extermnalUtils, async () => { }, async () => { }), extermnalUtils, async () => { }, async () => { }, () => { }, () => { })
await externalAccessToMainLnd.Warmup() */ await externalAccessToMainLnd.Warmup() */
const liquiditySettings: LiquiditySettings = { disableLiquidityProvider: true, liquidityProviderPub: "", useOnlyLiquidityProvider: false, providerRelayUrl: "" } const liquiditySettings: LiquiditySettings = { disableLiquidityProvider: true, liquidityProviderPub: "", useOnlyLiquidityProvider: false, providerRelayUrl: "" }