Improve LNC realiability by being nicer (#1658)
* be nicer to lnc * decrease timeout to 4 seconds
This commit is contained in:
parent
6630899e79
commit
e05989d371
|
@ -3,18 +3,47 @@ import { bolt11Tags } from '@/lib/bolt11'
|
|||
import { Mutex } from 'async-mutex'
|
||||
export * from '@/wallets/lnc'
|
||||
|
||||
async function disconnect (lnc, logger) {
|
||||
if (lnc) {
|
||||
const mutex = new Mutex()
|
||||
const serverHost = 'mailbox.terminal.lightning.today:443'
|
||||
|
||||
export async function testSendPayment (credentials, { logger }) {
|
||||
const lnc = await getLNC(credentials, { logger })
|
||||
logger?.info('validating permissions ...')
|
||||
await validateNarrowPerms(lnc)
|
||||
logger?.info('permissions ok')
|
||||
return lnc.credentials.credentials
|
||||
}
|
||||
|
||||
export async function sendPayment (bolt11, credentials, { logger }) {
|
||||
const hash = bolt11Tags(bolt11).payment_hash
|
||||
return await mutex.runExclusive(async () => {
|
||||
try {
|
||||
const lnc = await getLNC(credentials, { logger })
|
||||
const { paymentError, paymentPreimage: preimage } = await lnc.lnd.lightning.sendPaymentSync({ payment_request: bolt11 })
|
||||
if (paymentError) throw new Error(paymentError)
|
||||
if (!preimage) throw new Error('No preimage in response')
|
||||
return preimage
|
||||
} catch (err) {
|
||||
const msg = err.message || err.toString?.()
|
||||
if (msg.includes('invoice expired')) throw new InvoiceExpiredError(hash)
|
||||
if (msg.includes('canceled')) throw new InvoiceCanceledError(hash)
|
||||
throw err
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function disconnectLNC (lnc, { logger } = {}) {
|
||||
try {
|
||||
if (!lnc?.isConnected) return
|
||||
lnc.disconnect()
|
||||
logger.info('disconnecting...')
|
||||
// wait for lnc to disconnect before releasing the mutex
|
||||
logger?.info('disconnecting...')
|
||||
// wait for lnc to disconnect
|
||||
await new Promise((resolve, reject) => {
|
||||
let counter = 0
|
||||
const interval = setInterval(() => {
|
||||
if (lnc?.isConnected) {
|
||||
if (counter++ > 100) {
|
||||
logger.error('failed to disconnect from lnc')
|
||||
logger?.error('failed to disconnect from lnc')
|
||||
clearInterval(interval)
|
||||
reject(new Error('failed to disconnect from lnc'))
|
||||
}
|
||||
|
@ -24,85 +53,59 @@ async function disconnect (lnc, logger) {
|
|||
resolve()
|
||||
})
|
||||
}, 50)
|
||||
logger.info('disconnected')
|
||||
logger?.info('disconnected')
|
||||
} catch (err) {
|
||||
logger.error('failed to disconnect from lnc: ' + err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function testSendPayment (credentials, { logger }) {
|
||||
let lnc
|
||||
try {
|
||||
lnc = await getLNC(credentials)
|
||||
|
||||
logger.info('connecting ...')
|
||||
await lnc.connect()
|
||||
logger.info('connected')
|
||||
|
||||
logger.info('validating permissions ...')
|
||||
await validateNarrowPerms(lnc)
|
||||
logger.info('permissions ok')
|
||||
|
||||
return lnc.credentials.credentials
|
||||
} finally {
|
||||
await disconnect(lnc, logger)
|
||||
logger?.error('failed to disconnect from lnc: ' + err)
|
||||
}
|
||||
}
|
||||
|
||||
const mutex = new Mutex()
|
||||
async function getLNC (credentials = {}, { logger } = {}) {
|
||||
if (window.snLncKillerTimeout) clearTimeout(window.snLncKillerTimeout)
|
||||
|
||||
export async function sendPayment (bolt11, credentials, { logger }) {
|
||||
const hash = bolt11Tags(bolt11).payment_hash
|
||||
|
||||
return await mutex.runExclusive(async () => {
|
||||
let lnc
|
||||
try {
|
||||
lnc = await getLNC(credentials)
|
||||
|
||||
await lnc.connect()
|
||||
const { paymentError, paymentPreimage: preimage } =
|
||||
await lnc.lnd.lightning.sendPaymentSync({ payment_request: bolt11 })
|
||||
|
||||
if (paymentError) throw new Error(paymentError)
|
||||
if (!preimage) throw new Error('No preimage in response')
|
||||
|
||||
return preimage
|
||||
} catch (err) {
|
||||
const msg = err.message || err.toString?.()
|
||||
if (msg.includes('invoice expired')) {
|
||||
throw new InvoiceExpiredError(hash)
|
||||
}
|
||||
if (msg.includes('canceled')) {
|
||||
throw new InvoiceCanceledError(hash)
|
||||
}
|
||||
throw err
|
||||
} finally {
|
||||
await disconnect(lnc, logger)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function getLNC (credentials = {}) {
|
||||
const serverHost = 'mailbox.terminal.lightning.today:443'
|
||||
// XXX we MUST reuse the same instance of LNC because it references a global Go object
|
||||
// that holds closures to the first LNC instance it's created with
|
||||
if (window.lnc) {
|
||||
window.lnc.credentials.credentials = {
|
||||
...window.lnc.credentials.credentials,
|
||||
...credentials,
|
||||
serverHost
|
||||
}
|
||||
return window.lnc
|
||||
}
|
||||
if (!window.snLnc) { // create new instance
|
||||
const { default: LNC } = await import('@lightninglabs/lnc-web')
|
||||
window.lnc = new LNC({
|
||||
window.snLnc = new LNC({
|
||||
credentialStore: new LncCredentialStore({
|
||||
...credentials,
|
||||
serverHost
|
||||
})
|
||||
})
|
||||
return window.lnc
|
||||
|
||||
window.addEventListener('beforeunload', () => {
|
||||
// try to disconnect gracefully when the page is closed
|
||||
disconnectLNC(window.snLnc, { logger })
|
||||
})
|
||||
} else if (JSON.stringify(window.snLncCredentials ?? {}) !== JSON.stringify(credentials)) {
|
||||
console.log('LNC instance has new credentials')
|
||||
// disconnect and update credentials if they've changed
|
||||
await disconnectLNC(window.snLnc, { logger })
|
||||
// XXX we MUST reuse the same instance of LNC because it references a global Go object
|
||||
// that holds closures to the first LNC instance it's created with
|
||||
window.snLnc.credentials.credentials = {
|
||||
...window.snLnc.credentials.credentials,
|
||||
...credentials,
|
||||
serverHost
|
||||
}
|
||||
}
|
||||
|
||||
if (!window.snLnc.isConnected) {
|
||||
logger?.info('connecting ...')
|
||||
await window.snLnc.connect()
|
||||
logger?.info('connected')
|
||||
}
|
||||
|
||||
window.snLncCredentials = {
|
||||
...credentials
|
||||
}
|
||||
|
||||
window.snLncKillerTimeout = setTimeout(() => {
|
||||
logger?.info('disconnecting from lnc due to inactivity ...')
|
||||
mutex.runExclusive(async () => {
|
||||
await disconnectLNC(window.snLnc, { logger })
|
||||
})
|
||||
}, 4000)
|
||||
|
||||
return window.snLnc
|
||||
}
|
||||
|
||||
function validateNarrowPerms (lnc) {
|
||||
|
|
Loading…
Reference in New Issue