commit
ecf805c885
13 changed files with 550 additions and 46 deletions
|
|
@ -18,6 +18,7 @@
|
||||||
# LIQUIDITY_PROVIDER_PUB=null
|
# LIQUIDITY_PROVIDER_PUB=null
|
||||||
# DISABLE_LIQUIDITY_PROVIDER=false
|
# DISABLE_LIQUIDITY_PROVIDER=false
|
||||||
# USE_ONLY_LIQUIDITY_PROVIDER=false
|
# USE_ONLY_LIQUIDITY_PROVIDER=false
|
||||||
|
PROVIDER_RELAY_URL=
|
||||||
|
|
||||||
#SWAPS
|
#SWAPS
|
||||||
# BOLTZ_HTTP_URL=
|
# BOLTZ_HTTP_URL=
|
||||||
|
|
|
||||||
20
src/index.ts
20
src/index.ts
|
|
@ -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
|
||||||
|
|
||||||
|
|
@ -22,15 +23,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)
|
||||||
log("initializing nostr middleware")
|
log("initializing nostr middleware")
|
||||||
const relays = settingsManager.getSettings().nostrRelaySettings.relays
|
const relays = settingsManager.getSettings().nostrRelaySettings.relays
|
||||||
const maxEventContentLength = settingsManager.getSettings().nostrRelaySettings.maxEventContentLength
|
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, Stop, Ping, Reset } = nostrMiddleware(serverMethods, mainHandler,
|
const { Send, Stop, Ping, Reset } = nostrMiddleware(serverMethods, mainHandler,
|
||||||
{
|
{
|
||||||
relays, maxEventContentLength, apps, clients: [liquidityProviderInfo],
|
relays, maxEventContentLength, apps, /* clients: [liquidityProviderInfo], */
|
||||||
providerDestinationPub: settingsManager.getSettings().liquiditySettings.liquidityProviderPub
|
/* providerDestinationPub: settingsManager.getSettings().liquiditySettings.liquidityProviderPub */
|
||||||
},
|
},
|
||||||
(e, p) => mainHandler.liquidityProvider.onEvent(e, p)
|
(e, p) => mainHandler.liquidityProvider.onEvent(e, p)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import Main from "./services/main/index.js"
|
import Main from "./services/main/index.js"
|
||||||
import Nostr from "./services/nostr/index.js"
|
import Nostr from "./services/nostr/index.js"
|
||||||
import { NostrEvent, NostrSend, NostrSettings } from "./services/nostr/handler.js"
|
import { NostrEvent, NostrSend, NostrSettings } from "./services/nostr/nostrPool.js"
|
||||||
import * as Types from '../proto/autogenerated/ts/types.js'
|
import * as Types from '../proto/autogenerated/ts/types.js'
|
||||||
import NewNostrTransport, { NostrRequest } from '../proto/autogenerated/ts/nostr_transport.js';
|
import NewNostrTransport, { NostrRequest } from '../proto/autogenerated/ts/nostr_transport.js';
|
||||||
import { ERROR, getLogger } from "./services/helpers/logger.js";
|
import { ERROR, getLogger } from "./services/helpers/logger.js";
|
||||||
|
|
@ -50,6 +50,10 @@ export default (serverMethods: Types.ServerMethods, mainHandler: Main, nostrSett
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (event.kind === 21001) {
|
if (event.kind === 21001) {
|
||||||
|
if (event.relayConstraint === 'provider') {
|
||||||
|
log("got noffer request on provider only relay, ignoring")
|
||||||
|
return
|
||||||
|
}
|
||||||
const offerReq = j as NofferData
|
const offerReq = j as NofferData
|
||||||
log("🎯 [NOSTR EVENT] Received offer request (kind 21001)", {
|
log("🎯 [NOSTR EVENT] Received offer request (kind 21001)", {
|
||||||
fromPub: event.pub,
|
fromPub: event.pub,
|
||||||
|
|
@ -60,18 +64,33 @@ export default (serverMethods: Types.ServerMethods, mainHandler: Main, nostrSett
|
||||||
mainHandler.offerManager.handleClinkOffer(offerReq, event)
|
mainHandler.offerManager.handleClinkOffer(offerReq, event)
|
||||||
return
|
return
|
||||||
} else if (event.kind === 21002) {
|
} else if (event.kind === 21002) {
|
||||||
|
if (event.relayConstraint === 'provider') {
|
||||||
|
log("got debit request on provider only relay, ignoring")
|
||||||
|
return
|
||||||
|
}
|
||||||
const debitReq = j as NdebitData
|
const debitReq = j as NdebitData
|
||||||
mainHandler.debitManager.handleNip68Debit(debitReq, event)
|
mainHandler.debitManager.handleNip68Debit(debitReq, event)
|
||||||
return
|
return
|
||||||
} else if (event.kind === 21003) {
|
} else if (event.kind === 21003) {
|
||||||
|
if (event.relayConstraint === 'provider') {
|
||||||
|
log("got management request on provider only relay, ignoring")
|
||||||
|
return
|
||||||
|
}
|
||||||
const nmanageReq = j as NmanageRequest
|
const nmanageReq = j as NmanageRequest
|
||||||
mainHandler.managementManager.handleRequest(nmanageReq, event);
|
mainHandler.managementManager.handleRequest(nmanageReq, event);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!j.rpcName) {
|
if (!j.rpcName) {
|
||||||
|
if (event.relayConstraint === 'service') {
|
||||||
|
log("got relay response on service only relay, ignoring")
|
||||||
|
}
|
||||||
onClientEvent(j as { requestId: string }, event.pub)
|
onClientEvent(j as { requestId: string }, event.pub)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if (event.relayConstraint === 'provider') {
|
||||||
|
log("got service request on provider only relay, ignoring")
|
||||||
|
return
|
||||||
|
}
|
||||||
if (j.authIdentifier !== event.pub) {
|
if (j.authIdentifier !== event.pub) {
|
||||||
log(ERROR, "authIdentifier does not match", j.authIdentifier || "--", event.pub)
|
log(ERROR, "authIdentifier does not match", j.authIdentifier || "--", event.pub)
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
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/handler.js";
|
import { NostrSend } from "../nostr/nostrPool.js";
|
||||||
import { ProcessMetricsCollector } from "../storage/tlv/processMetricsCollector.js";
|
import { ProcessMetricsCollector } from "../storage/tlv/processMetricsCollector.js";
|
||||||
type UtilsSettings = {
|
type UtilsSettings = {
|
||||||
noCollector?: boolean
|
noCollector?: boolean
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import AppUserManager from "./appUserManager.js"
|
||||||
import { Application } from '../storage/entity/Application.js'
|
import { Application } from '../storage/entity/Application.js'
|
||||||
import { UserReceivingInvoice, ZapInfo } from '../storage/entity/UserReceivingInvoice.js'
|
import { UserReceivingInvoice, ZapInfo } from '../storage/entity/UserReceivingInvoice.js'
|
||||||
import { UnsignedEvent } from 'nostr-tools'
|
import { UnsignedEvent } from 'nostr-tools'
|
||||||
import { NostrEvent, NostrSend } from '../nostr/handler.js'
|
import { NostrSend } from '../nostr/nostrPool.js'
|
||||||
import MetricsManager from '../metrics/index.js'
|
import MetricsManager from '../metrics/index.js'
|
||||||
import { LoggedEvent } from '../storage/eventsLog.js'
|
import { LoggedEvent } from '../storage/eventsLog.js'
|
||||||
import { LiquidityProvider } from "./liquidityProvider.js"
|
import { LiquidityProvider } from "./liquidityProvider.js"
|
||||||
|
|
@ -31,7 +31,7 @@ import { Agent } from "https"
|
||||||
import { NotificationsManager } from "./notificationsManager.js"
|
import { NotificationsManager } from "./notificationsManager.js"
|
||||||
import { ApplicationUser } from '../storage/entity/ApplicationUser.js'
|
import { ApplicationUser } from '../storage/entity/ApplicationUser.js'
|
||||||
import SettingsManager from './settingsManager.js'
|
import SettingsManager from './settingsManager.js'
|
||||||
import { NostrSettings } from '../nostr/handler.js'
|
import { NostrSettings, AppInfo } from '../nostr/nostrPool.js'
|
||||||
type UserOperationsSub = {
|
type UserOperationsSub = {
|
||||||
id: string
|
id: string
|
||||||
newIncomingInvoice: (operation: Types.UserOperation) => void
|
newIncomingInvoice: (operation: Types.UserOperation) => void
|
||||||
|
|
@ -453,12 +453,26 @@ export default class {
|
||||||
publicKey: liquidityProviderApp.nostr_public_key || "",
|
publicKey: liquidityProviderApp.nostr_public_key || "",
|
||||||
name: "liquidity_provider", clientId: `client_${liquidityProviderApp.app_id}`
|
name: "liquidity_provider", clientId: `client_${liquidityProviderApp.app_id}`
|
||||||
}
|
}
|
||||||
|
const relays = this.settings.getSettings().nostrRelaySettings.relays
|
||||||
|
const appsInfo: AppInfo[] = apps.map(app => {
|
||||||
|
return {
|
||||||
|
appId: app.app_id,
|
||||||
|
privateKey: app.nostr_private_key || "",
|
||||||
|
publicKey: app.nostr_public_key || "",
|
||||||
|
name: app.name,
|
||||||
|
provider: app.nostr_public_key === liquidityProviderInfo.publicKey ? {
|
||||||
|
clientId: liquidityProviderInfo.clientId,
|
||||||
|
pubDestination: this.settings.getSettings().liquiditySettings.liquidityProviderPub,
|
||||||
|
relayUrl: this.settings.getSettings().liquiditySettings.providerRelayUrl || relays[0]
|
||||||
|
} : undefined
|
||||||
|
}
|
||||||
|
})
|
||||||
const s: NostrSettings = {
|
const s: NostrSettings = {
|
||||||
apps: apps.map(a => ({ appId: a.app_id, name: a.name, privateKey: a.nostr_private_key || "", publicKey: a.nostr_public_key || "" })),
|
apps: appsInfo,
|
||||||
relays: this.settings.getSettings().nostrRelaySettings.relays,
|
relays,
|
||||||
maxEventContentLength: this.settings.getSettings().nostrRelaySettings.maxEventContentLength,
|
maxEventContentLength: this.settings.getSettings().nostrRelaySettings.maxEventContentLength,
|
||||||
clients: [liquidityProviderInfo],
|
/* clients: [liquidityProviderInfo],
|
||||||
providerDestinationPub: this.settings.getSettings().liquiditySettings.liquidityProviderPub
|
providerDestinationPub: this.settings.getSettings().liquiditySettings.liquidityProviderPub */
|
||||||
}
|
}
|
||||||
this.nostrReset(s)
|
this.nostrReset(s)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ 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 { NostrEvent, NostrSend } from '../nostr/handler.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'
|
||||||
|
|
|
||||||
|
|
@ -168,13 +168,15 @@ export type LiquiditySettings = {
|
||||||
liquidityProviderPub: string // cold setting
|
liquidityProviderPub: string // cold setting
|
||||||
useOnlyLiquidityProvider: boolean // hot setting
|
useOnlyLiquidityProvider: boolean // hot setting
|
||||||
disableLiquidityProvider: boolean // hot setting
|
disableLiquidityProvider: boolean // hot setting
|
||||||
|
providerRelayUrl: string
|
||||||
}
|
}
|
||||||
export const LoadLiquiditySettingsFromEnv = (dbEnv: Record<string, string | undefined>, addToDb?: EnvCacher): LiquiditySettings => {
|
export const LoadLiquiditySettingsFromEnv = (dbEnv: Record<string, string | undefined>, addToDb?: EnvCacher): LiquiditySettings => {
|
||||||
//const liquidityProviderPub = process.env.LIQUIDITY_PROVIDER_PUB === "null" ? "" : (process.env.LIQUIDITY_PROVIDER_PUB || "76ed45f00cea7bac59d8d0b7d204848f5319d7b96c140ffb6fcbaaab0a13d44e")
|
//const liquidityProviderPub = process.env.LIQUIDITY_PROVIDER_PUB === "null" ? "" : (process.env.LIQUIDITY_PROVIDER_PUB || "76ed45f00cea7bac59d8d0b7d204848f5319d7b96c140ffb6fcbaaab0a13d44e")
|
||||||
const liquidityProviderPub = chooseEnv("LIQUIDITY_PROVIDER_PUB", dbEnv, "76ed45f00cea7bac59d8d0b7d204848f5319d7b96c140ffb6fcbaaab0a13d44e", addToDb)
|
const liquidityProviderPub = chooseEnv("LIQUIDITY_PROVIDER_PUB", dbEnv, "76ed45f00cea7bac59d8d0b7d204848f5319d7b96c140ffb6fcbaaab0a13d44e", addToDb)
|
||||||
const disableLiquidityProvider = chooseEnvBool("DISABLE_LIQUIDITY_PROVIDER", dbEnv, false, addToDb) || liquidityProviderPub === "null"
|
const disableLiquidityProvider = chooseEnvBool("DISABLE_LIQUIDITY_PROVIDER", dbEnv, false, addToDb) || liquidityProviderPub === "null"
|
||||||
const useOnlyLiquidityProvider = chooseEnvBool("USE_ONLY_LIQUIDITY_PROVIDER", dbEnv, false, addToDb)
|
const useOnlyLiquidityProvider = chooseEnvBool("USE_ONLY_LIQUIDITY_PROVIDER", dbEnv, false, addToDb)
|
||||||
return { liquidityProviderPub, useOnlyLiquidityProvider, disableLiquidityProvider }
|
const providerRelayUrl = chooseEnv("PROVIDER_RELAY_URL", dbEnv, "", addToDb)
|
||||||
|
return { liquidityProviderPub, useOnlyLiquidityProvider, disableLiquidityProvider, providerRelayUrl }
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SwapsSettings = {
|
export type SwapsSettings = {
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,37 @@
|
||||||
//import { SimplePool, Sub, Event, UnsignedEvent, getEventHash, signEvent } from 'nostr-tools'
|
//import { SimplePool, Sub, Event, UnsignedEvent, getEventHash, signEvent } from 'nostr-tools'
|
||||||
import WebSocket from 'ws'
|
/* import WebSocket from 'ws'
|
||||||
Object.assign(global, { WebSocket: WebSocket });
|
Object.assign(global, { WebSocket: WebSocket }); */
|
||||||
import crypto from 'crypto'
|
/* import crypto from 'crypto'
|
||||||
import { SimplePool, Event, UnsignedEvent, finalizeEvent, Relay, nip44, Filter } from 'nostr-tools'
|
import { SimplePool, Event, UnsignedEvent, finalizeEvent, Relay, nip44, Filter } from 'nostr-tools' */
|
||||||
import { ERROR, getLogger } from '../helpers/logger.js'
|
import { ERROR, getLogger } from '../helpers/logger.js'
|
||||||
import { nip19 } from 'nostr-tools'
|
/* import { nip19 } from 'nostr-tools'
|
||||||
import { encrypt as encryptV1, decrypt as decryptV1, getSharedSecret as getConversationKeyV1 } from './nip44v1.js'
|
import { encrypt as encryptV1, decrypt as decryptV1, getSharedSecret as getConversationKeyV1 } from './nip44v1.js' */
|
||||||
import { ProcessMetrics, ProcessMetricsCollector } from '../storage/tlv/processMetricsCollector.js'
|
import { ProcessMetrics, ProcessMetricsCollector } from '../storage/tlv/processMetricsCollector.js'
|
||||||
import { Subscription } from 'nostr-tools/lib/types/abstract-relay.js';
|
/* import { Subscription } from 'nostr-tools/lib/types/abstract-relay.js';
|
||||||
const { nprofileEncode } = nip19
|
const { nprofileEncode } = nip19
|
||||||
const { v2 } = nip44
|
const { v2 } = nip44
|
||||||
const { encrypt: encryptV2, decrypt: decryptV2, utils } = v2
|
const { encrypt: encryptV2, decrypt: decryptV2, utils } = v2
|
||||||
const { getConversationKey: getConversationKeyV2 } = utils
|
const { getConversationKey: getConversationKeyV2 } = utils */
|
||||||
const handledEvents: string[] = [] // TODO: - big memory leak here, add TTL
|
/* const handledEvents: string[] = [] // TODO: - big memory leak here, add TTL
|
||||||
type AppInfo = { appId: string, publicKey: string, privateKey: string, name: string }
|
type AppInfo = { appId: string, publicKey: string, privateKey: string, name: string }
|
||||||
type ClientInfo = { clientId: string, publicKey: string, privateKey: string, name: string }
|
type ClientInfo = { clientId: string, publicKey: string, privateKey: string, name: string }
|
||||||
type SendDataContent = { type: "content", content: string, pub: string }
|
type SendDataContent = { type: "content", content: string, pub: string }
|
||||||
type SendDataEvent = { type: "event", event: UnsignedEvent, encrypt?: { toPub: string } }
|
type SendDataEvent = { type: "event", event: UnsignedEvent, encrypt?: { toPub: string } }
|
||||||
export type SendData = SendDataContent | SendDataEvent
|
export type SendData = SendDataContent | SendDataEvent
|
||||||
export type SendInitiator = { type: 'app', appId: string } | { type: 'client', clientId: string }
|
export type SendInitiator = { type: 'app', appId: string } | { type: 'client', clientId: string }
|
||||||
export type NostrSend = (initiator: SendInitiator, data: SendData, relays?: string[] | undefined) => void
|
export type NostrSend = (initiator: SendInitiator, data: SendData, relays?: string[] | undefined) => void */
|
||||||
|
import { NostrPool } from './nostrPool.js'
|
||||||
|
import { NostrSettings, SendInitiator, SendData, NostrEvent, NostrSend } from './nostrPool.js'
|
||||||
|
|
||||||
export type NostrSettings = {
|
/* export type NostrSettings = {
|
||||||
apps: AppInfo[]
|
apps: AppInfo[]
|
||||||
relays: string[]
|
relays: string[]
|
||||||
clients: ClientInfo[]
|
clients: ClientInfo[]
|
||||||
maxEventContentLength: number
|
maxEventContentLength: number
|
||||||
providerDestinationPub: string
|
providerDestinationPub: string
|
||||||
}
|
} */
|
||||||
|
|
||||||
export type NostrEvent = {
|
/* export type NostrEvent = {
|
||||||
id: string
|
id: string
|
||||||
pub: string
|
pub: string
|
||||||
content: string
|
content: string
|
||||||
|
|
@ -37,7 +39,8 @@ export type NostrEvent = {
|
||||||
startAtNano: string
|
startAtNano: string
|
||||||
startAtMs: number
|
startAtMs: number
|
||||||
kind: number
|
kind: number
|
||||||
}
|
relayConstraint?: 'service' | 'provider'
|
||||||
|
} */
|
||||||
|
|
||||||
type SettingsRequest = {
|
type SettingsRequest = {
|
||||||
type: 'settings'
|
type: 'settings'
|
||||||
|
|
@ -88,7 +91,7 @@ const send = (message: ChildProcessResponse) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let subProcessHandler: Handler | undefined
|
let subProcessHandler: NostrPool | undefined
|
||||||
process.on("message", (message: ChildProcessRequest) => {
|
process.on("message", (message: ChildProcessRequest) => {
|
||||||
switch (message.type) {
|
switch (message.type) {
|
||||||
case 'settings':
|
case 'settings':
|
||||||
|
|
@ -108,11 +111,15 @@ process.on("message", (message: ChildProcessRequest) => {
|
||||||
const handleNostrSettings = (settings: NostrSettings) => {
|
const handleNostrSettings = (settings: NostrSettings) => {
|
||||||
if (subProcessHandler) {
|
if (subProcessHandler) {
|
||||||
getLogger({ component: "nostrMiddleware" })("got new nostr setting, resetting nostr handler")
|
getLogger({ component: "nostrMiddleware" })("got new nostr setting, resetting nostr handler")
|
||||||
subProcessHandler.Stop()
|
subProcessHandler.UpdateSettings(settings)
|
||||||
initNostrHandler(settings)
|
// initNostrHandler(settings)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
initNostrHandler(settings)
|
subProcessHandler = new NostrPool(event => {
|
||||||
|
send(event)
|
||||||
|
})
|
||||||
|
subProcessHandler.UpdateSettings(settings)
|
||||||
|
// initNostrHandler(settings)
|
||||||
new ProcessMetricsCollector((metrics) => {
|
new ProcessMetricsCollector((metrics) => {
|
||||||
send({
|
send({
|
||||||
type: 'processMetrics',
|
type: 'processMetrics',
|
||||||
|
|
@ -120,14 +127,11 @@ const handleNostrSettings = (settings: NostrSettings) => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const initNostrHandler = (settings: NostrSettings) => {
|
/* const initNostrHandler = (settings: NostrSettings) => {
|
||||||
subProcessHandler = new Handler(settings, event => {
|
subProcessHandler = new NostrPool(event => {
|
||||||
send({
|
send(event)
|
||||||
type: 'event',
|
|
||||||
event: event
|
|
||||||
})
|
})
|
||||||
})
|
} */
|
||||||
}
|
|
||||||
const sendToNostr: NostrSend = (initiator, data, relays) => {
|
const sendToNostr: NostrSend = (initiator, data, relays) => {
|
||||||
if (!subProcessHandler) {
|
if (!subProcessHandler) {
|
||||||
getLogger({ component: "nostrMiddleware" })(ERROR, "nostr was not initialized")
|
getLogger({ component: "nostrMiddleware" })(ERROR, "nostr was not initialized")
|
||||||
|
|
@ -137,7 +141,7 @@ const sendToNostr: NostrSend = (initiator, data, relays) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
send({ type: 'ready' })
|
send({ type: 'ready' })
|
||||||
const supportedKinds = [21000, 21001, 21002, 21003]
|
/* const supportedKinds = [21000, 21001, 21002, 21003]
|
||||||
export default class Handler {
|
export default class Handler {
|
||||||
pool = new SimplePool()
|
pool = new SimplePool()
|
||||||
settings: NostrSettings
|
settings: NostrSettings
|
||||||
|
|
@ -382,4 +386,4 @@ const splitContent = (content: string, maxLength: number) => {
|
||||||
parts.push(content.slice(i, i + maxLength))
|
parts.push(content.slice(i, i + maxLength))
|
||||||
}
|
}
|
||||||
return parts
|
return parts
|
||||||
}
|
} */
|
||||||
|
|
@ -1,13 +1,11 @@
|
||||||
import { ChildProcess, fork } from 'child_process'
|
import { ChildProcess, fork } from 'child_process'
|
||||||
import { NostrSettings, NostrEvent, ChildProcessRequest, ChildProcessResponse, SendData, SendInitiator } from "./handler.js"
|
import { NostrSettings, NostrEvent, SendData, SendInitiator } from "./nostrPool.js"
|
||||||
|
import { ChildProcessRequest, ChildProcessResponse } from "./handler.js"
|
||||||
import { Utils } from '../helpers/utilsWrapper.js'
|
import { Utils } from '../helpers/utilsWrapper.js'
|
||||||
import { getLogger, ERROR } from '../helpers/logger.js'
|
import { getLogger, ERROR } from '../helpers/logger.js'
|
||||||
type EventCallback = (event: NostrEvent) => void
|
type EventCallback = (event: NostrEvent) => void
|
||||||
type BeaconCallback = (beacon: { content: string, pub: string }) => void
|
type BeaconCallback = (beacon: { content: string, pub: string }) => void
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export default class NostrSubprocess {
|
export default class NostrSubprocess {
|
||||||
childProcess: ChildProcess
|
childProcess: ChildProcess
|
||||||
utils: Utils
|
utils: Utils
|
||||||
|
|
|
||||||
300
src/services/nostr/nostrPool.ts
Normal file
300
src/services/nostr/nostrPool.ts
Normal file
|
|
@ -0,0 +1,300 @@
|
||||||
|
import WebSocket from 'ws'
|
||||||
|
Object.assign(global, { WebSocket: WebSocket });
|
||||||
|
import crypto from 'crypto'
|
||||||
|
import { SimplePool, Event, UnsignedEvent, finalizeEvent, Relay, nip44, Filter } from 'nostr-tools'
|
||||||
|
import { ERROR, getLogger, PubLogger } from '../helpers/logger.js'
|
||||||
|
import { nip19 } from 'nostr-tools'
|
||||||
|
import { encrypt as encryptV1, decrypt as decryptV1, getSharedSecret as getConversationKeyV1 } from './nip44v1.js'
|
||||||
|
import { Subscription } from 'nostr-tools/lib/types/abstract-relay.js';
|
||||||
|
import { RelayConnection, RelaySettings } from './nostrRelayConnection.js'
|
||||||
|
const { nprofileEncode } = nip19
|
||||||
|
const { v2 } = nip44
|
||||||
|
const { encrypt: encryptV2, decrypt: decryptV2, utils } = v2
|
||||||
|
const { getConversationKey: getConversationKeyV2 } = utils
|
||||||
|
// const handledEvents: string[] = [] // TODO: - big memory leak here, add TTL
|
||||||
|
export type SendDataContent = { type: "content", content: string, pub: string }
|
||||||
|
export type SendDataEvent = { type: "event", event: UnsignedEvent, encrypt?: { toPub: string } }
|
||||||
|
export type SendData = SendDataContent | SendDataEvent
|
||||||
|
export type SendInitiator = { type: 'app', appId: string } | { type: 'client', clientId: string }
|
||||||
|
export type NostrSend = (initiator: SendInitiator, data: SendData, relays?: string[] | undefined) => void
|
||||||
|
|
||||||
|
export type LinkedProviderInfo = { pubDestination: string, clientId: string, relayUrl: string }
|
||||||
|
export type AppInfo = { appId: string, publicKey: string, privateKey: string, name: string, provider?: LinkedProviderInfo }
|
||||||
|
// export type ClientInfo = { clientId: string, publicKey: string, privateKey: string, name: string }
|
||||||
|
export type NostrSettings = {
|
||||||
|
apps: AppInfo[]
|
||||||
|
relays: string[]
|
||||||
|
// clients: ClientInfo[]
|
||||||
|
maxEventContentLength: number
|
||||||
|
// providerDestinationPub: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NostrEvent = {
|
||||||
|
id: string
|
||||||
|
pub: string
|
||||||
|
content: string
|
||||||
|
appId: string
|
||||||
|
startAtNano: string
|
||||||
|
startAtMs: number
|
||||||
|
kind: number
|
||||||
|
relayConstraint?: 'service' | 'provider'
|
||||||
|
}
|
||||||
|
type RelayEvent = { type: 'event', event: NostrEvent } | { type: 'beacon', content: string, pub: string }
|
||||||
|
type RelayEventCallback = (event: RelayEvent) => void
|
||||||
|
const splitContent = (content: string, maxLength: number) => {
|
||||||
|
const parts = []
|
||||||
|
for (let i = 0; i < content.length; i += maxLength) {
|
||||||
|
parts.push(content.slice(i, i + maxLength))
|
||||||
|
}
|
||||||
|
return parts
|
||||||
|
}
|
||||||
|
const actionKinds = [21000, 21001, 21002, 21003]
|
||||||
|
const beaconKind = 30078
|
||||||
|
const appTag = "Lightning.Pub"
|
||||||
|
export class NostrPool {
|
||||||
|
relays: Record<string, RelayConnection> = {}
|
||||||
|
apps: Record<string /* app pubKey */, AppInfo> = {}
|
||||||
|
maxEventContentLength: number
|
||||||
|
// providerDestinationPub: string | undefined
|
||||||
|
eventCallback: RelayEventCallback
|
||||||
|
log = getLogger({ component: "nostrMiddleware" })
|
||||||
|
handledEvents: Map<string, { handledAt: number }> = new Map() // add expiration handler
|
||||||
|
providerInfo: (LinkedProviderInfo & { appPub: string }) | undefined = undefined
|
||||||
|
cleanupInterval: NodeJS.Timeout | undefined = undefined
|
||||||
|
constructor(eventCallback: RelayEventCallback) {
|
||||||
|
this.eventCallback = eventCallback
|
||||||
|
}
|
||||||
|
|
||||||
|
StartCleanupInterval() {
|
||||||
|
this.cleanupInterval = setInterval(() => {
|
||||||
|
this.handledEvents.forEach((value, key) => {
|
||||||
|
if (Date.now() - value.handledAt > 1000 * 60 * 60 * 2) {
|
||||||
|
this.handledEvents.delete(key)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, 1000 * 60 * 60 * 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateSettings(settings: NostrSettings) {
|
||||||
|
Object.values(this.relays).forEach(relay => relay.Stop())
|
||||||
|
settings.apps.forEach(app => {
|
||||||
|
this.log("appId:", app.appId, "pubkey:", app.publicKey, "nprofile:", nprofileEncode({ pubkey: app.publicKey, relays: settings.relays }))
|
||||||
|
})
|
||||||
|
this.maxEventContentLength = settings.maxEventContentLength
|
||||||
|
const { apps, rSettings, providerInfo } = processApps(settings)
|
||||||
|
this.providerInfo = providerInfo
|
||||||
|
this.apps = apps
|
||||||
|
this.relays = {}
|
||||||
|
for (const r of rSettings) {
|
||||||
|
this.relays[r.relayUrl] = new RelayConnection(r, (e, r) => this.onEvent(e, r))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private onEvent = (e: Event, relay: RelayConnection) => {
|
||||||
|
const validated = this.validateEvent(e, relay)
|
||||||
|
if (!validated || this.handledEvents.has(e.id)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.handledEvents.set(e.id, { handledAt: Date.now() })
|
||||||
|
if (validated.type === 'beacon') {
|
||||||
|
this.eventCallback({ type: 'beacon', content: e.content, pub: validated.pub })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const { app } = validated
|
||||||
|
|
||||||
|
const startAtMs = Date.now()
|
||||||
|
const startAtNano = process.hrtime.bigint().toString()
|
||||||
|
let content = ""
|
||||||
|
try {
|
||||||
|
if (e.kind === 21000) {
|
||||||
|
content = decryptV1(e.content, getConversationKeyV1(app.privateKey, e.pubkey))
|
||||||
|
} else {
|
||||||
|
content = decryptV2(e.content, getConversationKeyV2(Buffer.from(app.privateKey, 'hex'), e.pubkey))
|
||||||
|
}
|
||||||
|
} catch (e: any) {
|
||||||
|
this.log(ERROR, "failed to decrypt event", e.message, e.content)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const relayConstraint = relay.getConstraint()
|
||||||
|
const nostrEvent: NostrEvent = { id: e.id, content, pub: e.pubkey, appId: app.appId, startAtNano, startAtMs, kind: e.kind, relayConstraint }
|
||||||
|
this.eventCallback({ type: 'event', event: nostrEvent })
|
||||||
|
}
|
||||||
|
|
||||||
|
private validateEvent(e: Event, relay: RelayConnection): { type: 'event', pub: string, app: AppInfo } | { type: 'beacon', content: string, pub: string } | null {
|
||||||
|
if (e.kind === 30078 && this.providerInfo && relay.isProviderRelay() && e.pubkey === this.providerInfo.pubDestination) {
|
||||||
|
return { type: 'beacon', content: e.content, pub: e.pubkey }
|
||||||
|
}
|
||||||
|
if (!actionKinds.includes(e.kind) || !e.pubkey) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
const pubTags = e.tags.find(tags => tags && tags.length > 1 && tags[0] === 'p')
|
||||||
|
if (!pubTags) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
const app = this.apps[pubTags[1]]
|
||||||
|
if (!app) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return { type: 'event', pub: e.pubkey, app }
|
||||||
|
}
|
||||||
|
|
||||||
|
async Send(initiator: SendInitiator, data: SendData, relays?: string[]) {
|
||||||
|
try {
|
||||||
|
const keys = this.getSendKeys(initiator)
|
||||||
|
const privateKey = Buffer.from(keys.privateKey, 'hex')
|
||||||
|
const toSign = await this.handleSend(data, keys)
|
||||||
|
await Promise.all(toSign.map(ue => this.sendEvent(ue, keys, relays)))
|
||||||
|
} catch (e: any) {
|
||||||
|
this.log(ERROR, "failed to send event", e.message || e)
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private async handleSend(data: SendData, keys: { name: string, privateKey: string, publicKey: string }): Promise<UnsignedEvent[]> {
|
||||||
|
if (data.type === 'content') {
|
||||||
|
const parts = splitContent(data.content, this.maxEventContentLength)
|
||||||
|
if (parts.length > 1) {
|
||||||
|
const shardsId = crypto.randomBytes(16).toString('hex')
|
||||||
|
const totalShards = parts.length
|
||||||
|
const ues = await Promise.all(parts.map((part, index) => this.handleSendDataContent({ ...data, content: JSON.stringify({ part, index, totalShards, shardsId }) }, keys)))
|
||||||
|
return ues
|
||||||
|
}
|
||||||
|
return [await this.handleSendDataContent(data, keys)]
|
||||||
|
}
|
||||||
|
const ue = await this.handleSendDataEvent(data, keys)
|
||||||
|
return [ue]
|
||||||
|
}
|
||||||
|
|
||||||
|
private async handleSendDataContent(data: SendDataContent, keys: { name: string, privateKey: string, publicKey: string }): Promise<UnsignedEvent> {
|
||||||
|
let content = encryptV1(data.content, getConversationKeyV1(keys.privateKey, data.pub))
|
||||||
|
return {
|
||||||
|
content,
|
||||||
|
created_at: Math.floor(Date.now() / 1000),
|
||||||
|
kind: 21000,
|
||||||
|
pubkey: keys.publicKey,
|
||||||
|
tags: [['p', data.pub]],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async handleSendDataEvent(data: SendDataEvent, keys: { name: string, privateKey: string, publicKey: string }): Promise<UnsignedEvent> {
|
||||||
|
const toSign = data.event
|
||||||
|
if (data.encrypt) {
|
||||||
|
toSign.content = encryptV2(data.event.content, getConversationKeyV2(Buffer.from(keys.privateKey, 'hex'), data.encrypt.toPub))
|
||||||
|
}
|
||||||
|
if (!toSign.pubkey) {
|
||||||
|
toSign.pubkey = keys.publicKey
|
||||||
|
}
|
||||||
|
return toSign
|
||||||
|
}
|
||||||
|
private getServiceRelays() {
|
||||||
|
return Object.values(this.relays).filter(r => r.isServiceRelay()).map(r => r.GetUrl())
|
||||||
|
}
|
||||||
|
|
||||||
|
private async sendEvent(event: UnsignedEvent, keys: { name: string, privateKey: string }, relays?: string[]) {
|
||||||
|
const signed = finalizeEvent(event, Buffer.from(keys.privateKey, 'hex'))
|
||||||
|
let sent = false
|
||||||
|
const log = getLogger({ appName: keys.name })
|
||||||
|
const r = relays ? relays : this.getServiceRelays()
|
||||||
|
const pool = new SimplePool()
|
||||||
|
await Promise.all(pool.publish(r, signed).map(async p => {
|
||||||
|
try {
|
||||||
|
await p
|
||||||
|
sent = true
|
||||||
|
} catch (e: any) {
|
||||||
|
console.log(e)
|
||||||
|
log(e)
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
if (!sent) {
|
||||||
|
log("failed to send event")
|
||||||
|
} else {
|
||||||
|
//log("sent event")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private getSendKeys(initiator: SendInitiator) {
|
||||||
|
if (initiator.type === 'app') {
|
||||||
|
const { appId } = initiator
|
||||||
|
const found = Object.values(this.apps).find((info: AppInfo) => info.appId === appId)
|
||||||
|
if (!found) {
|
||||||
|
throw new Error("unkown app")
|
||||||
|
}
|
||||||
|
return { name: found.name, publicKey: found.publicKey, privateKey: found.privateKey }
|
||||||
|
} else if (initiator.type === 'client') {
|
||||||
|
const { clientId } = initiator
|
||||||
|
const providerApp = this.apps[this.providerInfo?.appPub || ""]
|
||||||
|
if (this.providerInfo && this.providerInfo.clientId === clientId && providerApp) {
|
||||||
|
return { name: providerApp.name, publicKey: providerApp.publicKey, privateKey: providerApp.privateKey }
|
||||||
|
}
|
||||||
|
throw new Error("unkown client")
|
||||||
|
}
|
||||||
|
throw new Error("unkown initiator type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const processApps = (settings: NostrSettings) => {
|
||||||
|
const apps: Record<string, AppInfo> = {}
|
||||||
|
let providerInfo: (LinkedProviderInfo & { appPub: string }) | undefined = undefined
|
||||||
|
for (const app of settings.apps) {
|
||||||
|
apps[app.publicKey] = app
|
||||||
|
if (app.provider) {
|
||||||
|
if (providerInfo) {
|
||||||
|
throw new Error("found more than one provider")
|
||||||
|
}
|
||||||
|
providerInfo = { ...app.provider, appPub: app.publicKey }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let providerAssigned = false
|
||||||
|
const rSettings: RelaySettings[] = []
|
||||||
|
new Set(settings.relays).forEach(r => {
|
||||||
|
const filters = [getServiceFilter(apps)]
|
||||||
|
if (providerInfo && providerInfo.relayUrl === r) {
|
||||||
|
providerAssigned = true
|
||||||
|
filters.push(getBeaconFilter(providerInfo.pubDestination))
|
||||||
|
}
|
||||||
|
rSettings.push({
|
||||||
|
relayUrl: r,
|
||||||
|
serviceRelay: true,
|
||||||
|
providerRelay: r === providerInfo?.relayUrl,
|
||||||
|
filters: filters,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
if (!providerAssigned && providerInfo) {
|
||||||
|
rSettings.push({
|
||||||
|
relayUrl: providerInfo.relayUrl,
|
||||||
|
providerRelay: true,
|
||||||
|
serviceRelay: false,
|
||||||
|
filters: [
|
||||||
|
getProviderFilter(providerInfo.appPub, providerInfo.pubDestination),
|
||||||
|
getBeaconFilter(providerInfo.pubDestination),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return { apps, rSettings, providerInfo }
|
||||||
|
}
|
||||||
|
|
||||||
|
const getServiceFilter = (apps: Record<string, AppInfo>): Filter => {
|
||||||
|
return {
|
||||||
|
since: Math.ceil(Date.now() / 1000),
|
||||||
|
kinds: actionKinds,
|
||||||
|
'#p': Object.keys(apps),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getProviderFilter = (appPub: string, providerPub: string): Filter => {
|
||||||
|
return {
|
||||||
|
since: Math.ceil(Date.now() / 1000),
|
||||||
|
kinds: actionKinds,
|
||||||
|
'#p': [appPub],
|
||||||
|
authors: [providerPub]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getBeaconFilter = (providerPub: string): Filter => {
|
||||||
|
return {
|
||||||
|
kinds: [beaconKind], '#d': [appTag],
|
||||||
|
authors: [providerPub]
|
||||||
|
}
|
||||||
|
}
|
||||||
152
src/services/nostr/nostrRelayConnection.ts
Normal file
152
src/services/nostr/nostrRelayConnection.ts
Normal file
|
|
@ -0,0 +1,152 @@
|
||||||
|
import WebSocket from 'ws'
|
||||||
|
Object.assign(global, { WebSocket: WebSocket });
|
||||||
|
import { Event, UnsignedEvent, Relay, Filter } from 'nostr-tools'
|
||||||
|
import { ERROR, getLogger, PubLogger } from '../helpers/logger.js'
|
||||||
|
import { Subscription } from 'nostr-tools/lib/types/abstract-relay.js';
|
||||||
|
// const handledEvents: string[] = [] // TODO: - big memory leak here, add TTL
|
||||||
|
/* export type SendDataContent = { type: "content", content: string, pub: string }
|
||||||
|
export type SendDataEvent = { type: "event", event: UnsignedEvent, encrypt?: { toPub: string } }
|
||||||
|
export type SendData = SendDataContent | SendDataEvent
|
||||||
|
export type SendInitiator = { type: 'app', appId: string } | { type: 'client', clientId: string }
|
||||||
|
export type NostrSend = (initiator: SendInitiator, data: SendData, relays?: string[] | undefined) => void */
|
||||||
|
|
||||||
|
/* export type LinkedProviderInfo = { pubDestination: string, clientId: string, relayUrl: string }
|
||||||
|
export type AppInfo = { appId: string, publicKey: string, privateKey: string, name: string, provider?: LinkedProviderInfo } */
|
||||||
|
// export type ClientInfo = { clientId: string, publicKey: string, privateKey: string, name: string }
|
||||||
|
/* export type NostrSettings = {
|
||||||
|
apps: AppInfo[]
|
||||||
|
relays: string[]
|
||||||
|
// clients: ClientInfo[]
|
||||||
|
maxEventContentLength: number
|
||||||
|
// providerDestinationPub: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NostrEvent = {
|
||||||
|
id: string
|
||||||
|
pub: string
|
||||||
|
content: string
|
||||||
|
appId: string
|
||||||
|
startAtNano: string
|
||||||
|
startAtMs: number
|
||||||
|
kind: number
|
||||||
|
relayConstraint?: 'service' | 'provider'
|
||||||
|
} */
|
||||||
|
|
||||||
|
type RelayCallback = (event: Event, relay: RelayConnection) => void
|
||||||
|
export type RelaySettings = { relayUrl: string, filters: Filter[], serviceRelay: boolean, providerRelay: boolean }
|
||||||
|
|
||||||
|
|
||||||
|
export class RelayConnection {
|
||||||
|
eventCallback: RelayCallback
|
||||||
|
log: PubLogger
|
||||||
|
relay: Relay | null = null
|
||||||
|
sub: Subscription | null = null
|
||||||
|
// relayUrl: string
|
||||||
|
stopped = false
|
||||||
|
// filters: Filter[]
|
||||||
|
settings: RelaySettings
|
||||||
|
constructor(settings: RelaySettings, eventCallback: RelayCallback, autoconnect = true) {
|
||||||
|
this.log = getLogger({ component: "relay:" + settings.relayUrl })
|
||||||
|
// this.relayUrl = relayUrl
|
||||||
|
// this.filters = filters
|
||||||
|
this.settings = settings
|
||||||
|
this.eventCallback = eventCallback
|
||||||
|
if (autoconnect) {
|
||||||
|
this.ConnectLoop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GetUrl() {
|
||||||
|
return this.settings.relayUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
Stop() {
|
||||||
|
this.stopped = true
|
||||||
|
this.sub?.close()
|
||||||
|
this.relay?.close()
|
||||||
|
this.relay = null
|
||||||
|
this.sub = null
|
||||||
|
}
|
||||||
|
|
||||||
|
isServiceRelay() {
|
||||||
|
return this.settings.serviceRelay
|
||||||
|
}
|
||||||
|
isProviderRelay() {
|
||||||
|
return this.settings.providerRelay
|
||||||
|
}
|
||||||
|
|
||||||
|
getConstraint(): 'service' | 'provider' | undefined {
|
||||||
|
if (this.isProviderRelay() && !this.isServiceRelay()) {
|
||||||
|
return 'provider'
|
||||||
|
}
|
||||||
|
if (this.isServiceRelay() && !this.isProviderRelay()) {
|
||||||
|
return 'service'
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
async ConnectLoop() {
|
||||||
|
let failures = 0
|
||||||
|
while (!this.stopped) {
|
||||||
|
await this.ConnectPromise()
|
||||||
|
const pow = Math.pow(2, failures)
|
||||||
|
const delay = Math.min(pow, 900)
|
||||||
|
this.log("connection failed, will try again in", delay, "seconds (failures:", failures, ")")
|
||||||
|
await new Promise(resolve => setTimeout(resolve, delay * 1000))
|
||||||
|
failures++
|
||||||
|
}
|
||||||
|
this.log("nostr handler stopped")
|
||||||
|
}
|
||||||
|
|
||||||
|
async ConnectPromise() {
|
||||||
|
return new Promise<void>(async (res) => {
|
||||||
|
this.relay = await this.GetRelay()
|
||||||
|
if (!this.relay) {
|
||||||
|
res()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.sub = this.Subscribe(this.relay)
|
||||||
|
this.relay.onclose = (() => {
|
||||||
|
this.log("disconnected")
|
||||||
|
this.sub?.close()
|
||||||
|
if (this.relay) {
|
||||||
|
this.relay.onclose = null
|
||||||
|
this.relay.close()
|
||||||
|
this.relay = null
|
||||||
|
}
|
||||||
|
this.sub = null
|
||||||
|
res()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async GetRelay(): Promise<Relay | null> {
|
||||||
|
try {
|
||||||
|
const relay = await Relay.connect(this.settings.relayUrl)
|
||||||
|
if (!relay.connected) {
|
||||||
|
throw new Error("failed to connect to relay")
|
||||||
|
}
|
||||||
|
return relay
|
||||||
|
} catch (err: any) {
|
||||||
|
this.log("failed to connect to relay", err.message || err)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Subscribe(relay: Relay) {
|
||||||
|
this.log("🔍 subscribing...")
|
||||||
|
return relay.subscribe(this.settings.filters, {
|
||||||
|
oneose: () => this.log("is ready"),
|
||||||
|
onevent: (e) => this.eventCallback(e, this)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
Send(e: Event) {
|
||||||
|
if (!this.relay) {
|
||||||
|
throw new Error("relay not connected")
|
||||||
|
}
|
||||||
|
return this.relay.publish(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { getLogger } from '../services/helpers/logger.js'
|
import { getLogger } from '../services/helpers/logger.js'
|
||||||
import { initMainHandler, initSettings } from '../services/main/init.js'
|
import { initMainHandler, initSettings } from '../services/main/init.js'
|
||||||
import { SendData } from '../services/nostr/handler.js'
|
import { SendData } from '../services/nostr/nostrPool.js'
|
||||||
import { TestBase, TestUserData } from './testBase.js'
|
import { TestBase, TestUserData } from './testBase.js'
|
||||||
import * as Types from '../../proto/autogenerated/ts/types.js'
|
import * as Types from '../../proto/autogenerated/ts/types.js'
|
||||||
import { GetTestStorageSettings, LoadStorageSettingsFromEnv } from '../services/storage/index.js'
|
import { GetTestStorageSettings, LoadStorageSettingsFromEnv } from '../services/storage/index.js'
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ export const SetupTest = async (d: Describe, chainTools: ChainTools): Promise<Te
|
||||||
const extermnalUtils = new Utils({ dataDir: storageSettings.dataDir, allowResetMetricsStorages: storageSettings.allowResetMetricsStorages })
|
const extermnalUtils = new Utils({ dataDir: storageSettings.dataDir, allowResetMetricsStorages: storageSettings.allowResetMetricsStorages })
|
||||||
/* 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 }
|
const liquiditySettings: LiquiditySettings = { disableLiquidityProvider: true, liquidityProviderPub: "", useOnlyLiquidityProvider: false, providerRelayUrl: "" }
|
||||||
const lndSettings = LoadLndSettingsFromEnv({})
|
const lndSettings = LoadLndSettingsFromEnv({})
|
||||||
const secondLndNodeSettings = LoadSecondLndSettingsFromEnv()
|
const secondLndNodeSettings = LoadSecondLndSettingsFromEnv()
|
||||||
const otherLndSetting = () => ({ lndSettings, lndNodeSettings: secondLndNodeSettings })
|
const otherLndSetting = () => ({ lndSettings, lndNodeSettings: secondLndNodeSettings })
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue