Merge pull request #49 from shocknet/spont-pay-fail-fast

Spont pay fail fast
This commit is contained in:
Daniel Lugo 2020-03-24 15:05:39 -04:00 committed by GitHub
commit 71cde7d2f1
3 changed files with 98 additions and 33 deletions

View file

@ -14,7 +14,7 @@ const Getters = require('./getters')
const Key = require('./key') const Key = require('./key')
const Utils = require('./utils') const Utils = require('./utils')
// const { promisifyGunNode: p } = Utils // const { promisifyGunNode: p } = Utils
const { isHandshakeRequest } = require('./schema') const { isHandshakeRequest, isOrderResponse } = require('./schema')
/** /**
* @typedef {import('./SimpleGUN').GUNNode} GUNNode * @typedef {import('./SimpleGUN').GUNNode} GUNNode
* @typedef {import('./SimpleGUN').ISEA} ISEA * @typedef {import('./SimpleGUN').ISEA} ISEA
@ -977,7 +977,10 @@ const sendPayment = async (to, amount, memo) => {
v => typeof v === 'undefined' v => typeof v === 'undefined'
) )
const invoice = await Promise.race([ /**
* @type {import('./schema').OrderResponse}
*/
const encryptedOrderRes = await Promise.race([
Promise.race([onMethod, freshGunMethod]).then(v => { Promise.race([onMethod, freshGunMethod]).then(v => {
clearTimeout(timeoutID) clearTimeout(timeoutID)
return v return v
@ -990,16 +993,24 @@ const sendPayment = async (to, amount, memo) => {
}) })
]) ])
if (typeof invoice !== 'string') { if (!isOrderResponse(encryptedOrderRes)) {
throw new Error( throw new Error(
'received invoice not an string, isntead got: ' + 'received response not an OrderResponse, instead got: ' +
JSON.stringify(invoice) JSON.stringify(encryptedOrderRes)
) )
} }
const decInvoice = await SEA.decrypt(invoice, ourSecret) /** @type {import('./schema').OrderResponse} */
const orderResponse = {
response: await SEA.decrypt(encryptedOrderRes.response, ourSecret),
type: encryptedOrderRes.type
}
logger.info('decoded invoice: ' + decInvoice) logger.info('decoded orderResponse: ' + JSON.stringify(orderResponse))
if (orderResponse.type === 'err') {
throw new Error(orderResponse.response)
}
const { const {
services: { lightning } services: { lightning }
@ -1020,37 +1031,40 @@ const sendPayment = async (to, amount, memo) => {
logger.info('Will now send payment through lightning') logger.info('Will now send payment through lightning')
const sendPaymentSyncArgs = {
/** @type {string} */
payment_request: orderResponse.response
}
await new Promise((resolve, rej) => { await new Promise((resolve, rej) => {
lightning.sendPaymentSync( lightning.sendPaymentSync(sendPaymentSyncArgs, (
{ /** @type {SendErr=} */ err,
payment_request: decInvoice /** @type {SendResponse} */ res
}, ) => {
(/** @type {SendErr=} */ err, /** @type {SendResponse} */ res) => { if (err) {
if (err) { rej(new Error(err.details))
rej(new Error(err.details)) } else if (res) {
} else if (res) { if (res.payment_error) {
if (res.payment_error) { rej(
rej( new Error(
new Error( `sendPaymentSync error response: ${JSON.stringify(res)}`
`sendPaymentSync error response: ${JSON.stringify(res)}`
)
) )
} else if (!res.payment_route) { )
rej( } else if (!res.payment_route) {
new Error( rej(
`sendPaymentSync no payment route response: ${JSON.stringify( new Error(
res `sendPaymentSync no payment route response: ${JSON.stringify(
)}` res
) )}`
) )
} else { )
resolve()
}
} else { } else {
rej(new Error('no error or response received from sendPaymentSync')) resolve()
} }
} else {
rej(new Error('no error or response received from sendPaymentSync'))
} }
) })
}) })
} catch (e) { } catch (e) {
logger.error('Error inside sendPayment()') logger.error('Error inside sendPayment()')

View file

@ -127,11 +127,17 @@ const listenerForAddr = (addr, SEA) => async (order, orderID) => {
`onOrders() -> Will now place the encrypted invoice in order to response usergraph: ${addr}` `onOrders() -> Will now place the encrypted invoice in order to response usergraph: ${addr}`
) )
/** @type {Schema.OrderResponse} */
const orderResponse = {
response: encInvoice,
type: 'invoice'
}
await new Promise((res, rej) => { await new Promise((res, rej) => {
getUser() getUser()
.get(Key.ORDER_TO_RESPONSE) .get(Key.ORDER_TO_RESPONSE)
.get(orderID) .get(orderID)
.put(encInvoice, ack => { .put(orderResponse, ack => {
if (ack.err) { if (ack.err) {
rej( rej(
new Error( new Error(
@ -150,6 +156,23 @@ const listenerForAddr = (addr, SEA) => async (order, orderID) => {
)}` )}`
) )
logger.error(err) logger.error(err)
/** @type {Schema.OrderResponse} */
const orderResponse = {
response: err.message,
type: 'err'
}
getUser()
.get(Key.ORDER_TO_RESPONSE)
.get(orderID)
.put(orderResponse, ack => {
if (ack.err) {
logger.error(
`Error saving encrypted invoice to order to response usergraph: ${ack}`
)
}
})
} }
} }

View file

@ -382,3 +382,31 @@ exports.isOrder = item => {
return typeof obj.timestamp === 'number' return typeof obj.timestamp === 'number'
} }
/**
* @typedef {object} OrderResponse
* @prop {'err'|'invoice'} type
* @prop {string} response
*/
/**
* @param {*} o
* @returns {o is OrderResponse}
*/
exports.isOrderResponse = o => {
if (typeof o !== 'object') {
return false
}
if (o === null) {
return false
}
const obj = /** @type {OrderResponse} */ (o)
if (typeof obj.response !== 'string') {
return false
}
return obj.type === 'err' || obj.type === 'invoice'
}