WIP
This commit is contained in:
parent
22e58844c9
commit
9c57b1de87
4 changed files with 88 additions and 30 deletions
|
|
@ -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,16 +122,15 @@ 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({})
|
||||
})
|
||||
}
|
||||
|
||||
function stateChange (req, res) {
|
||||
|
|
@ -147,20 +147,11 @@ function send (req, res) {
|
|||
tx.cryptoAtoms = new BigNumber(tx.cryptoAtoms)
|
||||
|
||||
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
|
||||
})
|
||||
})
|
||||
.then(status => {
|
||||
const body = {txId: status && status.txId}
|
||||
updateCachedAction(req, body, 200)
|
||||
.then(() => res.json(body))
|
||||
})
|
||||
}
|
||||
|
||||
function cashOut (req, res) {
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
20
migrations/016-new_cached_requests_table.js
Normal file
20
migrations/016-new_cached_requests_table.js
Normal 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()
|
||||
}
|
||||
|
|
@ -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",
|
||||
|
|
|
|||
5
todo.txt
5
todo.txt
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue