chore: server code formatting
This commit is contained in:
parent
aedabcbdee
commit
68517170e2
234 changed files with 9824 additions and 6195 deletions
|
|
@ -13,170 +13,208 @@ const toObj = helper.toObj
|
|||
|
||||
module.exports = { atomic }
|
||||
|
||||
function atomic (tx, pi, fromClient) {
|
||||
function atomic(tx, pi, fromClient) {
|
||||
const TransactionMode = pgp.txMode.TransactionMode
|
||||
const isolationLevel = pgp.txMode.isolationLevel
|
||||
const mode = new TransactionMode({ tiLevel: isolationLevel.serializable })
|
||||
function transaction (t) {
|
||||
function transaction(t) {
|
||||
const sql = 'SELECT * FROM cash_out_txs WHERE id=$1 FOR UPDATE'
|
||||
|
||||
return t.oneOrNone(sql, [tx.id])
|
||||
return t
|
||||
.oneOrNone(sql, [tx.id])
|
||||
.then(toObj)
|
||||
.then(oldTx => {
|
||||
const isStale = fromClient && oldTx && (oldTx.txVersion >= tx.txVersion)
|
||||
const isStale = fromClient && oldTx && oldTx.txVersion >= tx.txVersion
|
||||
if (isStale) throw new E.StaleTxError({ txId: tx.id })
|
||||
|
||||
// Server doesn't bump version, so we just prevent from version being older.
|
||||
const isStaleFromServer = !fromClient && oldTx && (oldTx.txVersion > tx.txVersion)
|
||||
if (isStaleFromServer) throw new Error('Stale Error: server triggered', tx.id)
|
||||
const isStaleFromServer =
|
||||
!fromClient && oldTx && oldTx.txVersion > tx.txVersion
|
||||
if (isStaleFromServer)
|
||||
throw new Error('Stale Error: server triggered', tx.id)
|
||||
|
||||
return preProcess(t, oldTx, tx, pi)
|
||||
.then(preProcessedTx => cashOutLow.upsert(t, oldTx, preProcessedTx))
|
||||
return preProcess(t, oldTx, tx, pi).then(preProcessedTx =>
|
||||
cashOutLow.upsert(t, oldTx, preProcessedTx),
|
||||
)
|
||||
})
|
||||
}
|
||||
return db.tx({ mode }, transaction)
|
||||
}
|
||||
|
||||
function preProcess (t, oldTx, newTx, pi) {
|
||||
function preProcess(t, oldTx, newTx, pi) {
|
||||
if (!oldTx) {
|
||||
return pi.isHd(newTx)
|
||||
return pi
|
||||
.isHd(newTx)
|
||||
.then(isHd => nextHd(t, isHd, newTx))
|
||||
.then(newTxHd => {
|
||||
return pi.newAddress(newTxHd)
|
||||
.then(_.merge(newTxHd))
|
||||
return pi.newAddress(newTxHd).then(_.merge(newTxHd))
|
||||
})
|
||||
.then(addressedTx => {
|
||||
const rec = {
|
||||
to_address: addressedTx.toAddress,
|
||||
layer_2_address: addressedTx.layer2Address
|
||||
layer_2_address: addressedTx.layer2Address,
|
||||
}
|
||||
|
||||
return cashOutActions.logAction(t, 'provisionAddress', rec, addressedTx)
|
||||
})
|
||||
.catch(err => {
|
||||
pi.notifyOperator(newTx, { isRedemption: false, error: 'Error while provisioning address' })
|
||||
.catch((err) => logger.error('Failure sending transaction notification', err))
|
||||
return cashOutActions.logError(t, 'provisionAddress', err, newTx)
|
||||
.then(() => { throw err })
|
||||
pi.notifyOperator(newTx, {
|
||||
isRedemption: false,
|
||||
error: 'Error while provisioning address',
|
||||
}).catch(err =>
|
||||
logger.error('Failure sending transaction notification', err),
|
||||
)
|
||||
return cashOutActions
|
||||
.logError(t, 'provisionAddress', err, newTx)
|
||||
.then(() => {
|
||||
throw err
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
return Promise.resolve(updateStatus(oldTx, newTx))
|
||||
.then(updatedTx => {
|
||||
if (updatedTx.status !== oldTx.status) {
|
||||
const isZeroConf = pi.isZeroConf(updatedTx)
|
||||
updatedTx.justAuthorized = wasJustAuthorized(oldTx, updatedTx, isZeroConf)
|
||||
return Promise.resolve(updateStatus(oldTx, newTx)).then(updatedTx => {
|
||||
if (updatedTx.status !== oldTx.status) {
|
||||
const isZeroConf = pi.isZeroConf(updatedTx)
|
||||
updatedTx.justAuthorized = wasJustAuthorized(oldTx, updatedTx, isZeroConf)
|
||||
|
||||
const rec = {
|
||||
to_address: updatedTx.toAddress,
|
||||
tx_hash: updatedTx.txHash
|
||||
}
|
||||
|
||||
return cashOutActions.logAction(t, updatedTx.status, rec, updatedTx)
|
||||
const rec = {
|
||||
to_address: updatedTx.toAddress,
|
||||
tx_hash: updatedTx.txHash,
|
||||
}
|
||||
|
||||
const hasError = !oldTx.error && newTx.error
|
||||
const hasDispenseOccurred = !oldTx.dispenseConfirmed && dispenseOccurred(newTx.bills)
|
||||
return cashOutActions.logAction(t, updatedTx.status, rec, updatedTx)
|
||||
}
|
||||
|
||||
if (hasError || hasDispenseOccurred) {
|
||||
return cashOutActions.logDispense(t, updatedTx)
|
||||
.then(it => updateCassettes(t, updatedTx).then(() => it) )
|
||||
.then((t) => {
|
||||
pi.notifyOperator(updatedTx, { isRedemption: true })
|
||||
.catch((err) => logger.error('Failure sending transaction notification', err))
|
||||
return t
|
||||
})
|
||||
}
|
||||
const hasError = !oldTx.error && newTx.error
|
||||
const hasDispenseOccurred =
|
||||
!oldTx.dispenseConfirmed && dispenseOccurred(newTx.bills)
|
||||
|
||||
if (!oldTx.phone && newTx.phone) {
|
||||
return cashOutActions.logAction(t, 'addPhone', {}, updatedTx)
|
||||
}
|
||||
if (hasError || hasDispenseOccurred) {
|
||||
return cashOutActions
|
||||
.logDispense(t, updatedTx)
|
||||
.then(it => updateCassettes(t, updatedTx).then(() => it))
|
||||
.then(t => {
|
||||
pi.notifyOperator(updatedTx, { isRedemption: true }).catch(err =>
|
||||
logger.error('Failure sending transaction notification', err),
|
||||
)
|
||||
return t
|
||||
})
|
||||
}
|
||||
|
||||
if (!oldTx.redeem && newTx.redeem) {
|
||||
return cashOutActions.logAction(t, 'redeemLater', {}, updatedTx)
|
||||
}
|
||||
if (!oldTx.phone && newTx.phone) {
|
||||
return cashOutActions.logAction(t, 'addPhone', {}, updatedTx)
|
||||
}
|
||||
|
||||
return updatedTx
|
||||
})
|
||||
if (!oldTx.redeem && newTx.redeem) {
|
||||
return cashOutActions.logAction(t, 'redeemLater', {}, updatedTx)
|
||||
}
|
||||
|
||||
return updatedTx
|
||||
})
|
||||
}
|
||||
|
||||
function nextHd (t, isHd, tx) {
|
||||
function nextHd(t, isHd, tx) {
|
||||
if (!isHd) return Promise.resolve(tx)
|
||||
|
||||
return t.one("select nextval('hd_indices_seq') as hd_index")
|
||||
return t
|
||||
.one("select nextval('hd_indices_seq') as hd_index")
|
||||
.then(row => _.set('hdIndex', row.hd_index, tx))
|
||||
}
|
||||
|
||||
function updateCassettes (t, tx) {
|
||||
function updateCassettes(t, tx) {
|
||||
if (!dispenseOccurred(tx.bills)) return Promise.resolve()
|
||||
|
||||
const billsStmt = _.join(', ')(_.map(it => `${tx.bills[it].name} = ${tx.bills[it].name} - $${it + 1}`)(_.range(0, _.size(tx.bills))))
|
||||
const billsStmt = _.join(', ')(
|
||||
_.map(it => `${tx.bills[it].name} = ${tx.bills[it].name} - $${it + 1}`)(
|
||||
_.range(0, _.size(tx.bills)),
|
||||
),
|
||||
)
|
||||
const returnStmt = _.join(', ')(_.map(bill => `${bill.name}`)(tx.bills))
|
||||
|
||||
const sql = `UPDATE devices SET ${billsStmt} WHERE device_id = $${_.size(tx.bills) + 1} RETURNING ${returnStmt}`
|
||||
|
||||
const values = []
|
||||
|
||||
_.forEach(it => values.push(
|
||||
tx.bills[it].dispensed + tx.bills[it].rejected
|
||||
), _.times(_.identity(), _.size(tx.bills)))
|
||||
_.forEach(
|
||||
it => values.push(tx.bills[it].dispensed + tx.bills[it].rejected),
|
||||
_.times(_.identity(), _.size(tx.bills)),
|
||||
)
|
||||
|
||||
values.push(tx.deviceId)
|
||||
|
||||
return t.one(sql, values)
|
||||
}
|
||||
|
||||
function wasJustAuthorized (oldTx, newTx, isZeroConf) {
|
||||
const isAuthorized = () => _.includes(oldTx.status, ['notSeen', 'published', 'rejected']) &&
|
||||
function wasJustAuthorized(oldTx, newTx, isZeroConf) {
|
||||
const isAuthorized = () =>
|
||||
_.includes(oldTx.status, ['notSeen', 'published', 'rejected']) &&
|
||||
_.includes(newTx.status, ['authorized', 'instant', 'confirmed'])
|
||||
|
||||
const isConfirmed = () => _.includes(oldTx.status, ['notSeen', 'published', 'authorized', 'rejected']) &&
|
||||
_.includes(newTx.status, ['instant', 'confirmed'])
|
||||
const isConfirmed = () =>
|
||||
_.includes(oldTx.status, [
|
||||
'notSeen',
|
||||
'published',
|
||||
'authorized',
|
||||
'rejected',
|
||||
]) && _.includes(newTx.status, ['instant', 'confirmed'])
|
||||
|
||||
return isZeroConf ? isAuthorized() : isConfirmed()
|
||||
}
|
||||
|
||||
function isPublished (status) {
|
||||
return _.includes(status, ['published', 'rejected', 'authorized', 'instant', 'confirmed'])
|
||||
function isPublished(status) {
|
||||
return _.includes(status, [
|
||||
'published',
|
||||
'rejected',
|
||||
'authorized',
|
||||
'instant',
|
||||
'confirmed',
|
||||
])
|
||||
}
|
||||
|
||||
function isConfirmed (status) {
|
||||
function isConfirmed(status) {
|
||||
return status === 'confirmed'
|
||||
}
|
||||
|
||||
function updateStatus (oldTx, newTx) {
|
||||
function updateStatus(oldTx, newTx) {
|
||||
const oldStatus = oldTx.status
|
||||
const newStatus = ratchetStatus(oldStatus, newTx.status)
|
||||
|
||||
const publishedAt = !oldTx.publishedAt && isPublished(newStatus)
|
||||
? 'now()^'
|
||||
: undefined
|
||||
const publishedAt =
|
||||
!oldTx.publishedAt && isPublished(newStatus) ? 'now()^' : undefined
|
||||
|
||||
const confirmedAt = !oldTx.confirmedAt && isConfirmed(newStatus)
|
||||
? 'now()^'
|
||||
: undefined
|
||||
const confirmedAt =
|
||||
!oldTx.confirmedAt && isConfirmed(newStatus) ? 'now()^' : undefined
|
||||
|
||||
const updateRec = {
|
||||
publishedAt,
|
||||
confirmedAt,
|
||||
status: newStatus
|
||||
status: newStatus,
|
||||
}
|
||||
|
||||
return _.merge(newTx, updateRec)
|
||||
}
|
||||
|
||||
function ratchetStatus (oldStatus, newStatus) {
|
||||
const statusOrder = ['notSeen', 'published', 'rejected',
|
||||
'authorized', 'instant', 'confirmed']
|
||||
function ratchetStatus(oldStatus, newStatus) {
|
||||
const statusOrder = [
|
||||
'notSeen',
|
||||
'published',
|
||||
'rejected',
|
||||
'authorized',
|
||||
'instant',
|
||||
'confirmed',
|
||||
]
|
||||
|
||||
if (oldStatus === newStatus) return oldStatus
|
||||
if (newStatus === 'insufficientFunds') return newStatus
|
||||
|
||||
const idx = Math.max(statusOrder.indexOf(oldStatus), statusOrder.indexOf(newStatus))
|
||||
const idx = Math.max(
|
||||
statusOrder.indexOf(oldStatus),
|
||||
statusOrder.indexOf(newStatus),
|
||||
)
|
||||
return statusOrder[idx]
|
||||
}
|
||||
|
||||
function dispenseOccurred (bills) {
|
||||
function dispenseOccurred(bills) {
|
||||
if (_.isEmpty(bills)) return false
|
||||
return _.every(_.overEvery([_.has('dispensed'), _.has('rejected')]), bills)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue