This commit is contained in:
Josh Harvey 2016-10-26 04:10:23 +03:00
parent 22e58844c9
commit 9c57b1de87
4 changed files with 88 additions and 30 deletions

View file

@ -3,6 +3,7 @@
const BigNumber = require('bignumber.js')
const logger = require('./logger')
const configManager = require('./config-manager')
const db = require('./db')
let mock = false
@ -121,15 +122,14 @@ function poll (req, res) {
.catch(logger.error)
}
function trade (req, res) {
function trade (req, res, next) {
const tx = req.body
tx.cryptoAtoms = new BigNumber(tx.cryptoAtoms)
plugins.trade(getDeviceId(req), tx)
.then(() => res.status(201).json({}))
.catch(err => {
logger.error(err)
res.status(500).json({err})
.then(() => {
updateCachedAction(req, {}, 201)
res.status(201).json({})
})
}
@ -148,18 +148,9 @@ function send (req, res) {
return plugins.sendCoins(getDeviceId(req), tx)
.then(status => {
res.json({
txHash: status && status.txHash,
txId: status && status.txId
})
})
.catch(err => {
console.log('DEBUG15: %s', err)
logger.error(err)
res.json({
err: err.message,
errType: err.name
})
const body = {txId: status && status.txId}
updateCachedAction(req, body, 200)
.then(() => res.json(body))
})
}
@ -232,8 +223,14 @@ function pair (req, res) {
return pair.pair(token, deviceId)
.then(valid => {
if (valid) return res.status(200).end()
return res.status(408).end()
updateCachedAction(req, {})
if (valid) {
updateCachedAction(req, {}, 200)
return res.json({})
}
updateCachedAction(req, {}, 408)
return res.status(408).json({})
})
}
@ -333,6 +330,44 @@ function dispense (req, res) {
.catch(err => logger.error(err))
}
function isUniqueViolation (err) {
return err.code === '23505'
}
function cacheAction (req, res, next) {
const sql = `insert into idempotents (request_id, device_id, body, status, pending)
values ($1, $2, $3, $4, $5)`
const requestId = req.headers['request-id']
const deviceId = getDeviceId(req)
db.none(sql, [requestId, deviceId, {}, 204, true])
.then(() => next())
.catch(err => {
if (!isUniqueViolation(err)) throw err
const sql2 = 'select body, status, pending from idempotents where request_id=$1'
return db.one(sql2, [requestId])
.then(row => {
if (row.pending) return res.status(204).end()
return res.status(row.status).json(row.body)
})
})
}
function cachedActionError (req, err, status) {
return updateCachedAction(req, {error: err}, status || 500)
}
function updateCachedAction (req, body, status) {
const sql = 'update idempotents set body=$1, status=$2, pending=$3 where request_id=$4 and device_id=$5'
const requestId = req.headers['request-id']
const deviceId = getDeviceId(req)
return db.none(sql, [body, status, false, requestId, deviceId])
}
function init (opts) {
plugins = opts.plugins
mock = opts.mock
@ -341,6 +376,8 @@ function init (opts) {
const app = opts.app
const localApp = opts.localApp
app.post('*', cacheAction)
app.post('/pair', pair)
app.get('/ca', ca)
@ -363,6 +400,8 @@ function init (opts) {
app.get('/await_dispense/:txId', authMiddleware, waitForDispense)
app.post('/dispense', authMiddleware, dispense)
app.post('*', updateCachedAction)
localApp.get('/pid', (req, res) => {
const deviceId = req.query.device_id
const pidRec = pids[deviceId]
@ -403,11 +442,3 @@ function getDeviceId (req) {
req.connection.getPeerCertificate().fingerprint) || 'unknown'
}
function cachedResponse (deviceId, txId, req) {
return plugins.cachedResponse(deviceId, txId, req.path, req.method)
.then(r => r.body)
}
function cacheResponse (deviceId, txId, req, body) {
return plugins.cacheResponse(deviceId, txId, req.path, req.method, body)
}

View file

@ -0,0 +1,20 @@
var db = require('./db')
exports.up = function (next) {
var sql = [
'drop table if exists cached_responses',
`create table idempotents (
request_id text PRIMARY KEY,
device_id text NOT NULL,
body json NOT NULL,
status integer NOT NULL,
pending boolean NOT NULL,
created timestamptz NOT NULL default now()
)`
]
db.multi(sql, next)
}
exports.down = function (next) {
next()
}

View file

@ -15,6 +15,7 @@
"bunyan": "^1.8.1",
"chalk": "^1.1.3",
"express": "^4.13.4",
"express-limiter": "^1.6.0",
"helmet": "^2.3.0",
"inquirer": "^1.0.0",
"lamassu-bitcoinaverage": "~1.0.0",
@ -36,6 +37,7 @@
"node-hkdf-sync": "^1.0.0",
"node-uuid": "^1.4.2",
"numeral": "^1.5.3",
"on-finished": "^2.3.0",
"pg": "^4.5.5",
"pg-promise": "^4.3.3",
"pify": "^2.3.0",

View file

@ -109,3 +109,8 @@ options: configure per machine; configure per crypto/fiat
v need to create CA: http://stackoverflow.com/questions/19665863/how-do-i-use-a-self-signed-certificate-for-a-https-node-js-server
--------------------------------
- consistent error handling
- usage of http status codes (good for got)
- finish idempotency for all calls