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 BigNumber = require('bignumber.js')
|
||||||
const logger = require('./logger')
|
const logger = require('./logger')
|
||||||
const configManager = require('./config-manager')
|
const configManager = require('./config-manager')
|
||||||
|
const db = require('./db')
|
||||||
|
|
||||||
let mock = false
|
let mock = false
|
||||||
|
|
||||||
|
|
@ -121,16 +122,15 @@ function poll (req, res) {
|
||||||
.catch(logger.error)
|
.catch(logger.error)
|
||||||
}
|
}
|
||||||
|
|
||||||
function trade (req, res) {
|
function trade (req, res, next) {
|
||||||
const tx = req.body
|
const tx = req.body
|
||||||
tx.cryptoAtoms = new BigNumber(tx.cryptoAtoms)
|
tx.cryptoAtoms = new BigNumber(tx.cryptoAtoms)
|
||||||
|
|
||||||
plugins.trade(getDeviceId(req), tx)
|
plugins.trade(getDeviceId(req), tx)
|
||||||
.then(() => res.status(201).json({}))
|
.then(() => {
|
||||||
.catch(err => {
|
updateCachedAction(req, {}, 201)
|
||||||
logger.error(err)
|
res.status(201).json({})
|
||||||
res.status(500).json({err})
|
})
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function stateChange (req, res) {
|
function stateChange (req, res) {
|
||||||
|
|
@ -147,20 +147,11 @@ function send (req, res) {
|
||||||
tx.cryptoAtoms = new BigNumber(tx.cryptoAtoms)
|
tx.cryptoAtoms = new BigNumber(tx.cryptoAtoms)
|
||||||
|
|
||||||
return plugins.sendCoins(getDeviceId(req), tx)
|
return plugins.sendCoins(getDeviceId(req), tx)
|
||||||
.then(status => {
|
.then(status => {
|
||||||
res.json({
|
const body = {txId: status && status.txId}
|
||||||
txHash: status && status.txHash,
|
updateCachedAction(req, body, 200)
|
||||||
txId: status && status.txId
|
.then(() => res.json(body))
|
||||||
})
|
})
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.log('DEBUG15: %s', err)
|
|
||||||
logger.error(err)
|
|
||||||
res.json({
|
|
||||||
err: err.message,
|
|
||||||
errType: err.name
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function cashOut (req, res) {
|
function cashOut (req, res) {
|
||||||
|
|
@ -232,8 +223,14 @@ function pair (req, res) {
|
||||||
|
|
||||||
return pair.pair(token, deviceId)
|
return pair.pair(token, deviceId)
|
||||||
.then(valid => {
|
.then(valid => {
|
||||||
if (valid) return res.status(200).end()
|
updateCachedAction(req, {})
|
||||||
return res.status(408).end()
|
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))
|
.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) {
|
function init (opts) {
|
||||||
plugins = opts.plugins
|
plugins = opts.plugins
|
||||||
mock = opts.mock
|
mock = opts.mock
|
||||||
|
|
@ -341,6 +376,8 @@ function init (opts) {
|
||||||
const app = opts.app
|
const app = opts.app
|
||||||
const localApp = opts.localApp
|
const localApp = opts.localApp
|
||||||
|
|
||||||
|
app.post('*', cacheAction)
|
||||||
|
|
||||||
app.post('/pair', pair)
|
app.post('/pair', pair)
|
||||||
app.get('/ca', ca)
|
app.get('/ca', ca)
|
||||||
|
|
||||||
|
|
@ -363,6 +400,8 @@ function init (opts) {
|
||||||
app.get('/await_dispense/:txId', authMiddleware, waitForDispense)
|
app.get('/await_dispense/:txId', authMiddleware, waitForDispense)
|
||||||
app.post('/dispense', authMiddleware, dispense)
|
app.post('/dispense', authMiddleware, dispense)
|
||||||
|
|
||||||
|
app.post('*', updateCachedAction)
|
||||||
|
|
||||||
localApp.get('/pid', (req, res) => {
|
localApp.get('/pid', (req, res) => {
|
||||||
const deviceId = req.query.device_id
|
const deviceId = req.query.device_id
|
||||||
const pidRec = pids[deviceId]
|
const pidRec = pids[deviceId]
|
||||||
|
|
@ -403,11 +442,3 @@ function getDeviceId (req) {
|
||||||
req.connection.getPeerCertificate().fingerprint) || 'unknown'
|
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",
|
"bunyan": "^1.8.1",
|
||||||
"chalk": "^1.1.3",
|
"chalk": "^1.1.3",
|
||||||
"express": "^4.13.4",
|
"express": "^4.13.4",
|
||||||
|
"express-limiter": "^1.6.0",
|
||||||
"helmet": "^2.3.0",
|
"helmet": "^2.3.0",
|
||||||
"inquirer": "^1.0.0",
|
"inquirer": "^1.0.0",
|
||||||
"lamassu-bitcoinaverage": "~1.0.0",
|
"lamassu-bitcoinaverage": "~1.0.0",
|
||||||
|
|
@ -36,6 +37,7 @@
|
||||||
"node-hkdf-sync": "^1.0.0",
|
"node-hkdf-sync": "^1.0.0",
|
||||||
"node-uuid": "^1.4.2",
|
"node-uuid": "^1.4.2",
|
||||||
"numeral": "^1.5.3",
|
"numeral": "^1.5.3",
|
||||||
|
"on-finished": "^2.3.0",
|
||||||
"pg": "^4.5.5",
|
"pg": "^4.5.5",
|
||||||
"pg-promise": "^4.3.3",
|
"pg-promise": "^4.3.3",
|
||||||
"pify": "^2.3.0",
|
"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
|
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