This commit is contained in:
Josh Harvey 2016-07-27 17:18:42 +03:00
parent b62cd590ef
commit 5312086622
3 changed files with 127 additions and 131 deletions

View file

@ -243,9 +243,7 @@ exports.getConfig = function getConfig () {
return cachedConfig
}
exports.logEvent = function event (session, rawEvent) {
return db.recordDeviceEvent(session, rawEvent)
}
exports.logEvent = db.recordDeviceEvent
function buildCartridges (cartridges, virtualCartridges, rec) {
return {
@ -264,12 +262,12 @@ function buildCartridges (cartridges, virtualCartridges, rec) {
}
}
exports.pollQueries = function pollQueries (session) {
exports.pollQueries = function pollQueries (deviceId) {
const cartridges = cachedConfig.exchanges.settings.cartridges
if (!cartridges) return Promise.resolve({})
const virtualCartridges = cachedConfig.exchanges.settings.virtualCartridges
return db.cartridgeCounts(session)
return db.cartridgeCounts(deviceId)
.then(result => ({
cartridges: buildCartridges(cartridges, virtualCartridges, result)
}))
@ -298,8 +296,8 @@ function _sendCoinsCb (toAddress, cryptoAtoms, cryptoCode, cb) {
// NOTE: This will fail if we have already sent coins because there will be
// a db unique db record in the table already.
function executeTx (fingerprint, tx) {
return db.addOutgoingTx(fingerprint, tx)
function executeTx (deviceId, tx) {
return db.addOutgoingTx(deviceId, tx)
.then(() => _sendCoins(tx.toAddress, tx.cryptoAtoms, tx.cryptoCode))
.then(txHash => {
const fee = null // Need to fill this out in plugins
@ -316,7 +314,7 @@ function executeTx (fingerprint, tx) {
}
// TODO: Run these in parallel and return success
exports.trade = function trade (session, rawTrade) {
exports.trade = function trade (deviceId, rawTrade) {
// TODO: move this to DB, too
// add bill to trader queue (if trader is enabled)
const cryptoCode = rawTrade.cryptoCode || 'BTC'
@ -332,41 +330,41 @@ exports.trade = function trade (session, rawTrade) {
})
}
return db.recordBill(session, rawTrade)
return db.recordBill(deviceId, rawTrade)
}
exports.stateChange = function stateChange (session, rec, cb) {
exports.stateChange = function stateChange (deviceId, deviceTime, rec, cb) {
const event = {
id: rec.uuid,
fingerprint: session.fingerprint,
fingerprint: deviceId,
eventType: 'stateChange',
note: JSON.stringify({state: rec.state, isIdle: rec.isIdle, sessionId: session.id}),
deviceTime: session.deviceTime
note: JSON.stringify({state: rec.state, isIdle: rec.isIdle, txId: rec.txId}),
deviceTime: deviceTime
}
return db.machineEvent(event)
}
exports.recordPing = function recordPing (session, rec, cb) {
exports.recordPing = function recordPing (deviceId, deviceTime, rec, cb) {
const event = {
id: uuid.v4(),
fingerprint: session.fingerprint,
fingerprint: deviceId,
eventType: 'ping',
note: JSON.stringify({state: rec.state, isIdle: rec.idle === 'true', sessionId: session.id}),
deviceTime: session.deviceTime
note: JSON.stringify({state: rec.state, isIdle: rec.idle === 'true', txId: rec.txId}),
deviceTime: deviceTime
}
return db.machineEvent(event)
}
exports.sendCoins = function sendCoins (session, rawTx) {
return executeTx(session.fingerprint, rawTx)
exports.sendCoins = function sendCoins (rawTx) {
return executeTx(rawTx)
}
exports.cashOut = function cashOut (session, tx) {
exports.cashOut = function cashOut (tx) {
const cryptoCode = tx.cryptoCode || 'BTC'
const walletPlugin = walletPlugins[cryptoCode]
const serialPromise = walletPlugin.supportsHD
? db.nextCashOutSerialHD(tx.sessionId, cryptoCode)
? db.nextCashOutSerialHD(tx.id, cryptoCode)
: Promise.resolve()
return serialPromise
@ -381,15 +379,13 @@ exports.cashOut = function cashOut (session, tx) {
if (err) return reject(err)
const newTx = R.assoc('toAddress', address, tx)
return db.addInitialIncoming(session, newTx, address)
return db.addInitialIncoming(newTx, address)
.then(() => resolve(address))
})
}))
}
exports.dispenseAck = function dispenseAck (session, rec) {
return db.addDispense(session, rec.tx, rec.cartridges)
}
exports.dispenseAck = db.addDispense
exports.fiatBalance = function fiatBalance (cryptoCode) {
const deviceRate = exports.getDeviceRate(cryptoCode)
@ -765,13 +761,8 @@ exports.getPhoneCode = function getPhoneCode (phone) {
.then(() => code)
}
exports.updatePhone = function updatePhone (session, tx, notified) {
return db.addIncomingPhone(session, tx, notified)
}
exports.registerRedeem = function registerRedeem (session) {
return db.updateRedeem(session)
}
exports.updatePhone = db.addIncomingPhone
exports.registerRedeem = db.updateRedeem
exports.fetchPhoneTx = function fetchPhoneTx (phone) {
return db.fetchPhoneTxs(phone, TRANSACTION_EXPIRATION)
@ -798,9 +789,9 @@ exports.requestDispense = function requestDispense (tx) {
return db.addDispenseRequest(tx)
}
exports.cachedResponse = (session, path, method) => db.cachedResponse(session, path, method)
exports.cachedResponse = db.cachedResponse
exports.cacheResponse = (session, path, method, body) => db.cacheResponse(session, path, method, body)
exports.cacheResponse = db.cacheResponse
function sweepHD (row) {
const cryptoCode = row.crypto_code

View file

@ -41,14 +41,14 @@ exports.init = function init (conString) {
}
// logs inputted bill and overall tx status (if available)
exports.recordBill = function recordBill (session, rec) {
exports.recordBill = function recordBill (deviceId, rec) {
const fields = [
'id',
'device_fingerprint',
'currency_code',
'crypto_code',
'to_address',
'session_id',
'tx_id',
'device_time',
'satoshis',
'denomination'
@ -56,11 +56,11 @@ exports.recordBill = function recordBill (session, rec) {
const values = [
rec.uuid,
session.fingerprint,
deviceId,
rec.currency,
rec.cryptoCode,
rec.toAddress,
session.id,
rec.txId,
rec.deviceTime,
rec.cryptoAtoms.toString(),
rec.fiat
@ -73,10 +73,10 @@ exports.recordBill = function recordBill (session, rec) {
})
}
exports.recordDeviceEvent = function recordDeviceEvent (session, event) {
const sql = 'INSERT INTO device_events (device_fingerprint, event_type, ' +
exports.recordDeviceEvent = function recordDeviceEvent (deviceId, event) {
const sql = 'INSERT INTO device_events (device_id, event_type, ' +
'note, device_time) VALUES ($1, $2, $3, $4)'
const values = [session.fingerprint, event.eventType, event.note,
const values = [deviceId, event.eventType, event.note,
event.deviceTime]
return db.none(sql, values)
}
@ -158,11 +158,11 @@ function insertDispense (session, tx, cartridges) {
return db.none(sql, values)
}
exports.addIncomingPhone = function addIncomingPhone (session, tx, notified) {
exports.addIncomingPhone = function addIncomingPhone (tx, notified) {
const sql = `UPDATE cash_out_txs SET phone=$1, notified=$2
WHERE session_id=$3
WHERE tx_id=$3
AND phone IS NULL`
const values = [tx.phone, notified, tx.sessionId]
const values = [tx.phone, notified, tx.id]
return db.result(sql, values)
.then(results => {
@ -171,7 +171,7 @@ exports.addIncomingPhone = function addIncomingPhone (session, tx, notified) {
if (noPhone) return {noPhone: noPhone}
return db.none(sql2, [tx.sessionId, 'addedPhone'])
return db.none(sql2, [tx.txId, 'addedPhone'])
.then(() => ({noPhone: noPhone}))
})
}
@ -244,11 +244,11 @@ exports.addDispense = function addDispense (session, tx, cartridges) {
})
}
exports.cartridgeCounts = function cartridgeCounts (session) {
exports.cartridgeCounts = function cartridgeCounts (deviceId) {
const sql = 'SELECT id, count1, count2 FROM dispenses ' +
'WHERE device_fingerprint=$1 AND refill=$2 ' +
'ORDER BY id DESC LIMIT 1'
return db.oneOrNone(sql, [session.fingerprint, true])
return db.oneOrNone(sql, [deviceId, true])
.then(row => {
const counts = row ? [row.count1, row.count2] : [0, 0]
return {id: row.id, counts: counts}
@ -360,14 +360,14 @@ exports.updateTxStatus = function updateTxStatus (tx, status) {
})
}
exports.updateRedeem = function updateRedeem (session) {
const sql = 'UPDATE cash_out_txs SET redeem=$1 WHERE session_id=$2'
const values = [true, session.id]
exports.updateRedeem = function updateRedeem (txId) {
const sql = 'UPDATE cash_out_txs SET redeem=$1 WHERE txId=$2'
const values = [true, txId]
return db.none(sql, values)
.then(() => {
const sql2 = 'insert into cash_out_actions (session_id, action) values ($1, $2)'
return db.none(sql2, [session.id, 'redeem'])
return db.none(sql2, [txId, 'redeem'])
})
}
@ -382,29 +382,29 @@ exports.updateNotify = function updateNotify (tx) {
})
}
function insertCachedRequest (session, path, method, body) {
function insertCachedRequest (deviceId, txId, path, method, body) {
const fields = [
'device_fingerprint',
'session_id',
'device_id',
'tx_id',
'path',
'method',
'body'
]
const sql = getInsertQuery('cached_responses', fields)
return db.none(sql, [session.fingerprint, session.id, path, method, body])
return db.none(sql, [deviceId, txId, path, method, body])
}
exports.cachedResponse = function (session, path, method) {
exports.cachedResponse = function (deviceId, txId, path, method) {
const sql = `select body from cached_responses
where device_fingerprint=$1
and session_id=$2
where device_id=$1
and tx_id=$2
and path=$3
and method=$4`
const values = [session.fingerprint, session.id, path, method]
const values = [deviceId, txId, path, method]
return insertCachedRequest(session, path, method, {pendingRequest: true})
return insertCachedRequest(deviceId, txId, path, method, {pendingRequest: true})
.then(() => ({}))
.catch(err => {
if (!isUniqueViolation(err)) throw err
@ -422,15 +422,15 @@ function pruneCachedResponses () {
return db.none(sql, values)
}
exports.cacheResponse = function (session, path, method, body) {
exports.cacheResponse = function (deviceId, txId, path, method, body) {
const sql = `update cached_responses
set body=$1
where device_fingerprint=$2
and session_id=$3
where device_id=$2
and tx_id=$3
and path=$4
and method=$5`
const values = [body, session.fingerprint, session.id, path, method]
const values = [body, deviceId, txId, path, method]
return db.none(sql, values)
}

View file

@ -10,7 +10,7 @@ let lamassuConfig
module.exports = {
init,
getFingerprint
getDeviceId
}
const STALE_TICKER = 3 * 60 * 1000
@ -57,12 +57,13 @@ function buildBalances () {
}
function poll (req, res) {
const fingerprint = getFingerprint(req)
const deviceId = getDeviceId(req)
const deviceTime = getDeviceTime(req)
const pid = req.query.pid
pids[fingerprint] = {pid, ts: Date.now()}
pids[deviceId] = {pid, ts: Date.now()}
logger.debug('poll request from: %s', fingerprint)
logger.debug('poll request from: %s', deviceId)
let rates = {}
let balances = {}
@ -74,11 +75,11 @@ function poll (req, res) {
const settings = config.exchanges.settings
const complianceSettings = settings.compliance
plugins.pollQueries(session(req))
plugins.pollQueries(deviceId)
.then(results => {
const cartridges = results.cartridges
const reboot = reboots[fingerprint] === pid
const reboot = reboots[deviceId] === pid
const response = {
err: null,
@ -103,7 +104,7 @@ function poll (req, res) {
})
.catch(logger.error)
plugins.recordPing(session(req), req.query)
plugins.recordPing(deviceId, deviceTime, req.query)
.catch(logger.error)
}
@ -111,7 +112,7 @@ function trade (req, res) {
const tx = req.body
tx.cryptoAtoms = new BigNumber(tx.cryptoAtoms)
plugins.trade(session(req), tx)
plugins.trade(getDeviceId(req), tx)
.then(() => res.status(201).json({}))
.catch(err => {
logger.error(err)
@ -120,7 +121,7 @@ function trade (req, res) {
}
function stateChange (req, res) {
plugins.stateChange(session(req), req.body)
plugins.stateChange(getDeviceId(req), getDeviceTime(req), req.body)
.then(() => res.json({success: true}))
.catch(err => {
console.error(err)
@ -135,7 +136,7 @@ function send (req, res) {
// TODO: use status.statusCode here after confirming machine compatibility
// FIX: (joshm) set txHash to status.txId instead of previous status.txHash which wasn't being set
// Need to clean up txHash vs txId
return plugins.sendCoins(session(req), tx)
return plugins.sendCoins(getDeviceId(req), tx)
.then(status => res.json({
txHash: status && status.txHash,
txId: status && status.txId
@ -154,8 +155,8 @@ function cashOut (req, res) {
const tx = req.body
tx.cryptoAtoms = new BigNumber(tx.cryptoAtoms)
return plugins.cashOut(session(req), req.body)
.then(cryptoAddress => res.json({bitcoinAddress: cryptoAddress}))
return plugins.cashOut(tx)
.then(cryptoAddress => res.json({toAddress: cryptoAddress}))
.catch(err => {
res.json({
err: err.message,
@ -166,12 +167,12 @@ function cashOut (req, res) {
}
function dispenseAck (req, res) {
plugins.dispenseAck(session(req), req.body)
plugins.dispenseAck(req.body)
res.json({success: true})
}
function deviceEvent (req, res) {
plugins.logEvent(session(req), req.body)
plugins.logEvent(getDeviceId(req), req.body)
res.json({err: null})
}
@ -207,7 +208,7 @@ function pair (req, res) {
lamassuConfig.pair(
token,
getFingerprint(req),
getDeviceId(req),
name,
err => {
if (err) {
@ -235,7 +236,9 @@ function phoneCode (req, res) {
function updatePhone (req, res) {
const notified = req.query.notified === 'true'
return plugins.updatePhone(session(req), req.body, notified)
const tx = req.body
return plugins.updatePhone(tx, notified)
.then(r => res.json(r))
.catch(err => {
logger.error(err)
@ -253,7 +256,8 @@ function fetchPhoneTx (req, res) {
}
function registerRedeem (req, res) {
return plugins.registerRedeem(session(req))
const txId = req.params.txId
return plugins.registerRedeem(txId)
.then(() => res.json({success: true}))
.catch(err => {
logger.error(err)
@ -263,7 +267,7 @@ function registerRedeem (req, res) {
function waitForDispense (req, res) {
logger.debug('waitForDispense')
return plugins.fetchTx(session(req))
return plugins.fetchTx(req.params.txId)
.then(tx => {
logger.debug('tx fetched')
logger.debug(tx)
@ -279,7 +283,15 @@ function waitForDispense (req, res) {
function dispense (req, res) {
const tx = req.body.tx
const deviceId = getDeviceId(req)
return cachedResponse(deviceId, tx.id, req)
.then(r => {
// Cache hit
if (r.body && r.body.pendingRequest) return res.sendStatus(409)
if (r.body) res.json(r.body)
// No cache hit
return plugins.requestDispense(tx)
.then(r => {
return cacheResponse(req, r)
@ -289,6 +301,7 @@ function dispense (req, res) {
logger.error(err)
res.sendStatus(500)
})
})
}
function init (localConfig) {
@ -316,9 +329,9 @@ function init (localConfig) {
app.post('/phone_code', authMiddleware, phoneCode)
app.post('/update_phone', authMiddleware, updatePhone)
app.get('/phone_tx', authMiddleware, fetchPhoneTx)
app.post('/register_redeem', authMiddleware, registerRedeem)
app.get('/await_dispense', authMiddleware, waitForDispense)
app.post('/dispense', authMiddleware, cachedResponse, dispense)
app.post('/register_redeem/:txId', authMiddleware, registerRedeem)
app.get('/await_dispense/:txId', authMiddleware, waitForDispense)
app.post('/dispense', authMiddleware, dispense)
localApp.get('/pid', (req, res) => {
const machineFingerprint = req.query.fingerprint
@ -342,28 +355,20 @@ function init (localConfig) {
return app
}
function session (req) {
return {
fingerprint: getFingerprint(req),
id: req.get('session-id'),
deviceTime: Date.parse(req.get('date'))
}
function getDeviceTime (req) {
return Date.parse(req.get('date'))
}
function getFingerprint (req) {
function getDeviceId (req) {
return (typeof req.connection.getPeerCertificate === 'function' &&
req.connection.getPeerCertificate().fingerprint) || 'unknown'
}
function cachedResponse (req, res, next) {
return plugins.cachedResponse(session(req), req.path, req.method)
.then(r => {
if (!r.body) return next()
if (r.body.pendingRequest) return res.sendStatus(409)
res.json(r.body)
})
function cachedResponse (deviceId, txId, req) {
return plugins.cachedResponse(deviceId, txId, req.path, req.method)
.then(r => r.body)
}
function cacheResponse (req, body) {
return plugins.cacheResponse(session(req), req.path, req.method, body)
function cacheResponse (deviceId, txId, req, body) {
return plugins.cacheResponse(deviceId, txId, req.path, req.method, body)
}