This commit is contained in:
Josh Harvey 2016-11-27 18:12:49 +02:00
parent 3a99b7a6bc
commit 00d986376e
8 changed files with 149 additions and 155 deletions

View file

@ -35,10 +35,10 @@ function runOnce () {
const seedPath = options.seedPath || './seeds/seed.txt' const seedPath = options.seedPath || './seeds/seed.txt'
plugins.init(seedPath) plugins.init(seedPath)
return settingsLoader.settings() return settingsLoader.load()
.then(settings => { .then(settings => {
plugins.startPolling() plugins.startPolling()
plugins.startCheckingNotification(settings.config) plugins.startCheckingNotification()
const httpsServerOptions = { const httpsServerOptions = {
key: fs.readFileSync(options.keyPath), key: fs.readFileSync(options.keyPath),

View file

@ -1,8 +1,10 @@
const configManager = require('./config-manager') const configManager = require('./config-manager')
const settingsLoader = require('./settings-loader')
function fetchExchange (settings, cryptoCode) { function fetchExchange (cryptoCode) {
return Promise.resolve() return Promise.resolve()
.then(() => { .then(() => {
const settings = settingsLoader.settings
const plugin = configManager.cryptoScoped(cryptoCode, settings.config).cryptoServices.wallet const plugin = configManager.cryptoScoped(cryptoCode, settings.config).cryptoServices.wallet
if (!plugin) throw new Error('No exchange plugin defined for: ' + cryptoCode) if (!plugin) throw new Error('No exchange plugin defined for: ' + cryptoCode)
const account = settings.accounts.plugin const account = settings.accounts.plugin
@ -12,18 +14,18 @@ function fetchExchange (settings, cryptoCode) {
}) })
} }
function buy (settings, cryptoAtoms, fiatCode, cryptoCode) { function buy (cryptoAtoms, fiatCode, cryptoCode) {
return fetchExchange(settings, cryptoCode) return fetchExchange(cryptoCode)
.then(r => r.exchange.buy(r.account, cryptoAtoms, fiatCode, cryptoCode)) .then(r => r.exchange.buy(r.account, cryptoAtoms, fiatCode, cryptoCode))
} }
function sell (settings, cryptoAtoms, fiatCode, cryptoCode) { function sell (cryptoAtoms, fiatCode, cryptoCode) {
return fetchExchange(settings, cryptoCode) return fetchExchange(cryptoCode)
.then(r => r.exchange.sell(r.account, cryptoAtoms, fiatCode, cryptoCode)) .then(r => r.exchange.sell(r.account, cryptoAtoms, fiatCode, cryptoCode))
} }
function active (settings, cryptoCode) { function active (cryptoCode) {
return fetchExchange(settings, cryptoCode) return fetchExchange(cryptoCode)
.then(() => true) .then(() => true)
.catch(() => false) .catch(() => false)
} }

View file

@ -1,23 +1,20 @@
var crypto = require('crypto') const crypto = require('crypto')
var R = require('ramda') const R = require('ramda')
var prettyMs = require('pretty-ms') const prettyMs = require('pretty-ms')
var numeral = require('numeral') const numeral = require('numeral')
var db = null
var getBalances = null
var LOW_BALANCE_THRESHOLD = null const configManager = require('./config-manager')
var STALE_STATE = 2 * 60 * 1000 const settingsLoader = require('./settingsLoader')
var NETWORK_DOWN_TIME = 60 * 1000 const db = require('./postgresql_interface')
function init (_db, _getBalances, config) { const STALE_STATE = 2 * 60 * 1000
db = _db const NETWORK_DOWN_TIME = 60 * 1000
let getBalances
function init (_getBalances) {
getBalances = _getBalances getBalances = _getBalances
if (config && config.lowBalanceThreshold) {
LOW_BALANCE_THRESHOLD = config.lowBalanceThreshold
}
} }
exports.init = init
function toInt10 (str) { return parseInt(str, 10) } function toInt10 (str) { return parseInt(str, 10) }
@ -30,7 +27,10 @@ function sameState (a, b) {
} }
function checkBalance (rec) { function checkBalance (rec) {
return LOW_BALANCE_THRESHOLD && rec.fiatBalance < LOW_BALANCE_THRESHOLD const settings = settingsLoader.settings
const config = configManager.unscoped(settings.config)
const lowBalanceThreshold = config.notifications.lowBalanceThreshold
return lowBalanceThreshold && rec.fiatBalance < lowBalanceThreshold
? {code: 'lowBalance', cryptoCode: rec.cryptoCode, fiatBalance: rec.fiatBalance, fiatCode: rec.fiatCode} ? {code: 'lowBalance', cryptoCode: rec.cryptoCode, fiatBalance: rec.fiatBalance, fiatCode: rec.fiatCode}
: null : null
} }
@ -41,14 +41,14 @@ function checkBalances () {
} }
function checkPing (deviceEvents) { function checkPing (deviceEvents) {
var sortedEvents = R.sortBy(R.compose(toInt10, R.prop('device_time')), R.map(jsonParse, deviceEvents)) const sortedEvents = R.sortBy(R.compose(toInt10, R.prop('device_time')), R.map(jsonParse, deviceEvents))
var lastEvent = R.last(sortedEvents) const lastEvent = R.last(sortedEvents)
if (!lastEvent) { if (!lastEvent) {
return [{code: 'ping'}] return [{code: 'ping'}]
} }
var age = Math.floor(lastEvent.age) const age = Math.floor(lastEvent.age)
if (age > NETWORK_DOWN_TIME) { if (age > NETWORK_DOWN_TIME) {
return [{code: 'ping', age: age}] return [{code: 'ping', age: age}]
} }
@ -57,22 +57,22 @@ function checkPing (deviceEvents) {
} }
function checkStuckScreen (deviceEvents) { function checkStuckScreen (deviceEvents) {
var sortedEvents = R.sortBy(R.compose(toInt10, R.prop('device_time')), R.map(jsonParse, deviceEvents)) const sortedEvents = R.sortBy(R.compose(toInt10, R.prop('device_time')), R.map(jsonParse, deviceEvents))
var noRepeatEvents = R.dropRepeatsWith(sameState, sortedEvents) const noRepeatEvents = R.dropRepeatsWith(sameState, sortedEvents)
var lastEvent = R.last(noRepeatEvents) const lastEvent = R.last(noRepeatEvents)
if (!lastEvent) { if (!lastEvent) {
return [] return []
} }
var state = lastEvent.note.state const state = lastEvent.note.state
var isIdle = lastEvent.note.isIdle const isIdle = lastEvent.note.isIdle
if (isIdle) { if (isIdle) {
return [] return []
} }
var age = Math.floor(lastEvent.age) const age = Math.floor(lastEvent.age)
if (age > STALE_STATE) { if (age > STALE_STATE) {
return [{code: 'stale', state: state, age: age}] return [{code: 'stale', state: state, age: age}]
} }
@ -86,24 +86,22 @@ function devicesAndEvents () {
} }
function checkStatus () { function checkStatus () {
var alerts = {devices: {}, deviceNames: {}} const alerts = {devices: {}, deviceNames: {}}
return Promise.all([checkBalances(), devicesAndEvents()]) return Promise.all([checkBalances(), devicesAndEvents()])
.then(([balances, rec]) => { .then(([balances, rec]) => {
var devices = rec.devices const devices = rec.devices
var events = rec.events const events = rec.events
alerts.general = balances alerts.general = balances
devices.forEach(function (deviceRow) { devices.forEach(function (deviceRow) {
var deviceId = deviceRow.device_id const deviceId = deviceRow.device_id
var deviceName = deviceRow.name || deviceId const deviceName = deviceRow.name || deviceId
var deviceEvents = events.filter(function (eventRow) { const deviceEvents = events.filter(function (eventRow) {
return eventRow.device_id === deviceId return eventRow.device_id === deviceId
}) })
var deviceAlerts = [] const deviceAlerts = checkStuckScreen(deviceEvents).concat(checkPing(deviceEvents))
deviceAlerts = R.concat(deviceAlerts, checkStuckScreen(deviceEvents))
deviceAlerts = R.concat(deviceAlerts, checkPing(deviceEvents))
alerts.devices[deviceId] = deviceAlerts alerts.devices[deviceId] = deviceAlerts
alerts.deviceNames[deviceId] = deviceName alerts.deviceNames[deviceId] = deviceName
@ -112,7 +110,6 @@ function checkStatus () {
return alerts return alerts
}) })
} }
exports.checkStatus = checkStatus
function formatCurrency (num, code) { function formatCurrency (num, code) {
return numeral(num).format('0,0.00') + ' ' + code return numeral(num).format('0,0.00') + ' ' + code
@ -122,15 +119,15 @@ function emailAlert (alert) {
switch (alert.code) { switch (alert.code) {
case 'ping': case 'ping':
if (alert.age) { if (alert.age) {
var pingAge = prettyMs(alert.age, {compact: true, verbose: true}) const pingAge = prettyMs(alert.age, {compact: true, verbose: true})
return 'Connection to machine down for ' + pingAge return 'Connection to machine down for ' + pingAge
} }
return 'Machine down for a while or never connected' return 'Machine down for a while or never connected'
case 'stale': case 'stale':
var stuckAge = prettyMs(alert.age, {compact: true, verbose: true}) const stuckAge = prettyMs(alert.age, {compact: true, verbose: true})
return 'Machine is stuck on ' + alert.state + 'screen for ' + stuckAge return 'Machine is stuck on ' + alert.state + 'screen for ' + stuckAge
case 'lowBalance': case 'lowBalance':
var balance = formatCurrency(alert.fiatBalance, alert.fiatCode) const balance = formatCurrency(alert.fiatBalance, alert.fiatCode)
return 'Low balance of ' + balance + ' in ' + alert.cryptoCode + ' wallet' return 'Low balance of ' + balance + ' in ' + alert.cryptoCode + ' wallet'
} }
} }
@ -140,7 +137,7 @@ function emailAlerts (alerts) {
} }
function printEmailAlerts (alertRec) { function printEmailAlerts (alertRec) {
var body = 'Errors were reported by your Lamassu Machines.\n' let body = 'Errors were reported by your Lamassu Machines.\n'
if (alertRec.general.length !== 0) { if (alertRec.general.length !== 0) {
body = body + '\nGeneral errors:\n' body = body + '\nGeneral errors:\n'
@ -148,29 +145,34 @@ function printEmailAlerts (alertRec) {
} }
R.keys(alertRec.devices).forEach(function (device) { R.keys(alertRec.devices).forEach(function (device) {
var deviceName = alertRec.deviceNames[device] const deviceName = alertRec.deviceNames[device]
body = body + '\nErrors for ' + deviceName + ':\n' body = body + '\nErrors for ' + deviceName + ':\n'
body = body + emailAlerts(alertRec.devices[device]) body = body + emailAlerts(alertRec.devices[device])
}) })
return body return body
} }
exports.printEmailAlerts = printEmailAlerts
function alertSubject (alertRec) { function alertSubject (alertRec) {
var alerts = alertRec.general let alerts = alertRec.general
R.keys(alertRec.devices).forEach(function (device) { R.keys(alertRec.devices).forEach(function (device) {
alerts = R.concat(alerts, alertRec.devices[device]) alerts = R.concat(alerts, alertRec.devices[device])
}) })
if (alerts.length === 0) return null if (alerts.length === 0) return null
var alertTypes = R.uniq(R.pluck('code', alerts)).sort() const alertTypes = R.uniq(R.pluck('code', alerts)).sort()
return '[Lamassu] Errors reported: ' + alertTypes.join(', ') return '[Lamassu] Errors reported: ' + alertTypes.join(', ')
} }
exports.alertSubject = alertSubject
function alertFingerprint (alertRec) { function alertFingerprint (alertRec) {
var subject = alertSubject(alertRec) const subject = alertSubject(alertRec)
if (!subject) return null if (!subject) return null
return crypto.createHash('sha256').update(subject).digest('hex') return crypto.createHash('sha256').update(subject).digest('hex')
} }
exports.alertFingerprint = alertFingerprint
module.exports = {
init,
checkStatus,
printEmailAlerts,
alertFingerprint,
alertSubject
}

View file

@ -11,7 +11,7 @@ const logger = require('./logger')
const notifier = require('./notifier') const notifier = require('./notifier')
const T = require('./time') const T = require('./time')
const configManager = require('./config-manager') const configManager = require('./config-manager')
const settingsLoader = require('./settings-loader') const settingsLoader = require('./settingsLoader')
const ticker = require('./ticker') const ticker = require('./ticker')
const wallet = require('./wallet') const wallet = require('./wallet')
const exchange = require('./exchange') const exchange = require('./exchange')
@ -47,7 +47,8 @@ let lastAlertTime = null
exports.logEvent = db.recordDeviceEvent exports.logEvent = db.recordDeviceEvent
function buildRates (settings, deviceId, tickers) { function buildRates (deviceId, tickers) {
const settings = settingsLoader.settings
const config = configManager.machineScoped(deviceId, settings.config) const config = configManager.machineScoped(deviceId, settings.config)
const cryptoCodes = config.currencies.cryptoCurrencies const cryptoCodes = config.currencies.cryptoCurrencies
@ -69,7 +70,8 @@ function buildRates (settings, deviceId, tickers) {
return rates return rates
} }
function buildBalances (settings, deviceId, balanceRecs) { function buildBalances (deviceId, balanceRecs) {
const settings = settingsLoader.settings
const config = configManager.machineScoped(deviceId, settings.config) const config = configManager.machineScoped(deviceId, settings.config)
const cryptoCodes = config.currencies.cryptoCurrencies const cryptoCodes = config.currencies.cryptoCurrencies
@ -102,7 +104,8 @@ function buildCartridges (cartridges, virtualCartridges, rec) {
} }
} }
exports.pollQueries = function pollQueries (settings, deviceTime, deviceId, deviceRec) { exports.pollQueries = function pollQueries (deviceTime, deviceId, deviceRec) {
const settings = settingsLoader.settings
const config = configManager.machineScoped(deviceId, settings.config) const config = configManager.machineScoped(deviceId, settings.config)
const fiatCode = config.currencies.fiatCurrency const fiatCode = config.currencies.fiatCurrency
const cryptoCodes = config.currencies.cryptoCurrencies const cryptoCodes = config.currencies.cryptoCurrencies
@ -110,8 +113,8 @@ exports.pollQueries = function pollQueries (settings, deviceTime, deviceId, devi
config.currencies.bottomCashOutDenomination ] config.currencies.bottomCashOutDenomination ]
const virtualCartridges = [config.currencies.virtualCashOutDenomination] const virtualCartridges = [config.currencies.virtualCashOutDenomination]
const tickerPromises = cryptoCodes.map(c => ticker.getRates(settings, fiatCode, c)) const tickerPromises = cryptoCodes.map(c => ticker.getRates(fiatCode, c))
const balancePromises = cryptoCodes.map(c => wallet.balance(settings, c)) const balancePromises = cryptoCodes.map(wallet.balance)
const pingPromise = recordPing(deviceId, deviceTime, deviceRec) const pingPromise = recordPing(deviceId, deviceTime, deviceRec)
const promises = [db.cartridgeCounts(deviceId), pingPromise].concat(tickerPromises, balancePromises) const promises = [db.cartridgeCounts(deviceId), pingPromise].concat(tickerPromises, balancePromises)
@ -124,8 +127,8 @@ exports.pollQueries = function pollQueries (settings, deviceTime, deviceId, devi
return { return {
cartridges: buildCartridges(cartridges, virtualCartridges, cartridgeCounts), cartridges: buildCartridges(cartridges, virtualCartridges, cartridgeCounts),
rates: buildRates(settings, deviceId, tickers), rates: buildRates(deviceId, tickers),
balances: buildBalances(settings, deviceId, balances) balances: buildBalances(deviceId, balances)
} }
}) })
} }
@ -224,7 +227,8 @@ exports.cashOut = function cashOut (deviceId, tx) {
}) })
} }
exports.dispenseAck = function (settings, deviceId, tx) { exports.dispenseAck = function (deviceId, tx) {
const settings = settingsLoader.settings
const config = configManager.machineScoped(deviceId, settings.config) const config = configManager.machineScoped(deviceId, settings.config)
const cartridges = [ config.currencies.topCashOutDenomination, const cartridges = [ config.currencies.topCashOutDenomination,
config.currencies.bottomCashOutDenomination ] config.currencies.bottomCashOutDenomination ]
@ -232,7 +236,8 @@ exports.dispenseAck = function (settings, deviceId, tx) {
return db.addDispense(deviceId, tx, cartridges) return db.addDispense(deviceId, tx, cartridges)
} }
function fiatBalance (settings, fiatCode, cryptoCode, deviceId) { function fiatBalance (fiatCode, cryptoCode, deviceId) {
const settings = settingsLoader.settings
const config = configManager.scoped(cryptoCode, deviceId, settings.config) const config = configManager.scoped(cryptoCode, deviceId, settings.config)
return Promise.all([ticker.ticker(cryptoCode), wallet.balance(cryptoCode)]) return Promise.all([ticker.ticker(cryptoCode), wallet.balance(cryptoCode)])
@ -257,8 +262,8 @@ function fiatBalance (settings, fiatCode, cryptoCode, deviceId) {
}) })
} }
function processTxStatus (settings, tx) { function processTxStatus (tx) {
return wallet.getStatus(settings, tx.toAddress, tx.cryptoAtoms, tx.cryptoCode) return wallet.getStatus(tx.toAddress, tx.cryptoAtoms, tx.cryptoCode)
.then(res => db.updateTxStatus(tx, res.status)) .then(res => db.updateTxStatus(tx, res.status))
} }
@ -280,29 +285,23 @@ function notifyConfirmation (tx) {
function monitorLiveIncoming () { function monitorLiveIncoming () {
const statuses = ['notSeen', 'published', 'insufficientFunds'] const statuses = ['notSeen', 'published', 'insufficientFunds']
return settingsLoader.settings()
.then(settings => {
return db.fetchOpenTxs(statuses, STALE_LIVE_INCOMING_TX_AGE) return db.fetchOpenTxs(statuses, STALE_LIVE_INCOMING_TX_AGE)
.then(txs => Promise.all(txs.map(r => processTxStatus(settings, r)))) .then(txs => Promise.all(txs.map(processTxStatus)))
})
.catch(logger.error) .catch(logger.error)
} }
function monitorIncoming () { function monitorIncoming () {
const statuses = ['notSeen', 'published', 'authorized', 'instant', 'rejected', 'insufficientFunds'] const statuses = ['notSeen', 'published', 'authorized', 'instant', 'rejected', 'insufficientFunds']
return settingsLoader.settings() return db.fetchOpenTxs(statuses, STALE_INCOMING_TX_AGE)
.then(settings => { .then(txs => Promise.all(txs.map(processTxStatus)))
db.fetchOpenTxs(statuses, STALE_INCOMING_TX_AGE)
.then(txs => Promise.all(txs.map(r => processTxStatus(settings, r))))
})
.catch(logger.error) .catch(logger.error)
} }
function monitorUnnotified () { function monitorUnnotified () {
db.fetchUnnotifiedTxs(MAX_NOTIFY_AGE, MIN_NOTIFY_AGE) db.fetchUnnotifiedTxs(MAX_NOTIFY_AGE, MIN_NOTIFY_AGE)
.then(txs => Promise.all(txs.map(notifyConfirmation))) .then(txs => Promise.all(txs.map(notifyConfirmation)))
.catch(err => logger.error(err)) .catch(logger.error)
} }
/* /*
@ -368,8 +367,7 @@ function consolidateTrades (cryptoCode, fiatCode) {
} }
function executeTrades () { function executeTrades () {
return settingsLoader() const settings = settingsLoader.settings
.then(settings => {
const config = settings.config const config = settings.config
return db.devices() return db.devices()
.then(devices => { .then(devices => {
@ -386,7 +384,6 @@ function executeTrades () {
return Promise.all(tradesPromises) return Promise.all(tradesPromises)
}) })
})
.catch(logger.error) .catch(logger.error)
} }
@ -470,11 +467,12 @@ function checkNotification () {
}) })
} }
function checkDeviceBalances (settings, deviceId) { function checkDeviceBalances (deviceId) {
const settings = settingsLoader.settings
const config = configManager.machineScoped(deviceId, settings.config) const config = configManager.machineScoped(deviceId, settings.config)
const cryptoCodes = config.currencies.cryptoCurrencies const cryptoCodes = config.currencies.cryptoCurrencies
const fiatCode = config.currencies.fiatCurrency const fiatCode = config.currencies.fiatCurrency
const fiatBalancePromises = cryptoCodes.map(c => fiatBalance(settings, fiatCode, c, deviceId)) const fiatBalancePromises = cryptoCodes.map(c => fiatBalance(fiatCode, c, deviceId))
return Promise.all(fiatBalancePromises) return Promise.all(fiatBalancePromises)
.then(arr => { .then(arr => {
@ -487,11 +485,11 @@ function checkDeviceBalances (settings, deviceId) {
}) })
} }
function checkBalances (settings) { function checkBalances () {
return db.devices() return db.devices()
.then(devices => { .then(devices => {
const deviceIds = devices.map(r => r.device_id) const deviceIds = devices.map(r => r.device_id)
const deviceBalancePromises = deviceIds.map(deviceId => checkDeviceBalances(settings, deviceId)) const deviceBalancePromises = deviceIds.map(deviceId => checkDeviceBalances(deviceId))
return Promise.all(deviceBalancePromises) return Promise.all(deviceBalancePromises)
.then(arr => { .then(arr => {
@ -503,7 +501,7 @@ function checkBalances (settings) {
} }
exports.startCheckingNotification = function startCheckingNotification (config) { exports.startCheckingNotification = function startCheckingNotification (config) {
notifier.init(db, checkBalances, config.notifications) notifier.init(checkBalances)
checkNotification() checkNotification()
setInterval(checkNotification, CHECK_NOTIFICATION_INTERVAL) setInterval(checkNotification, CHECK_NOTIFICATION_INTERVAL)
} }

View file

@ -22,20 +22,11 @@ const REQUEST_TTL = 3 * 60 * 1000
const pids = {} const pids = {}
const reboots = {} const reboots = {}
function loadSettings (req, res, next) {
settingsLoader.settings()
.then(settings => {
req.settings = settings
next()
})
.catch(next)
}
function poll (req, res, next) { function poll (req, res, next) {
const deviceId = req.deviceId const deviceId = req.deviceId
const deviceTime = req.deviceTime const deviceTime = req.deviceTime
const pid = req.query.pid const pid = req.query.pid
const settings = req.settings const settings = settingsLoader.settings
const config = configManager.machineScoped(deviceId, settings.config) const config = configManager.machineScoped(deviceId, settings.config)
pids[deviceId] = {pid, ts: Date.now()} pids[deviceId] = {pid, ts: Date.now()}
@ -84,13 +75,13 @@ 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(req.settings, req.deviceId, tx) plugins.trade(req.deviceId, tx)
.then(() => cacheAndRespond(req, res)) .then(() => cacheAndRespond(req, res))
.catch(next) .catch(next)
} }
function stateChange (req, res, next) { function stateChange (req, res, next) {
plugins.stateChange(req.settings, req.deviceId, req.deviceTime, req.body) plugins.stateChange(req.deviceId, req.deviceTime, req.body)
.then(() => cacheAndRespond(req, res)) .then(() => cacheAndRespond(req, res))
.catch(next) .catch(next)
} }
@ -99,7 +90,7 @@ function send (req, res, next) {
const tx = req.body const tx = req.body
tx.cryptoAtoms = new BigNumber(tx.cryptoAtoms) tx.cryptoAtoms = new BigNumber(tx.cryptoAtoms)
return plugins.sendCoins(req.settings, req.deviceId, tx) return plugins.sendCoins(req.deviceId, tx)
.then(status => { .then(status => {
const body = {txId: status && status.txId} const body = {txId: status && status.txId}
return cacheAndRespond(req, res, body) return cacheAndRespond(req, res, body)
@ -112,13 +103,13 @@ function cashOut (req, res, next) {
const tx = req.body const tx = req.body
tx.cryptoAtoms = new BigNumber(tx.cryptoAtoms) tx.cryptoAtoms = new BigNumber(tx.cryptoAtoms)
return plugins.cashOut(req.settings, req.deviceId, tx) return plugins.cashOut(req.deviceId, tx)
.then(cryptoAddress => cacheAndRespond(req, res, {toAddress: cryptoAddress})) .then(cryptoAddress => cacheAndRespond(req, res, {toAddress: cryptoAddress}))
.catch(next) .catch(next)
} }
function dispenseAck (req, res, next) { function dispenseAck (req, res, next) {
plugins.dispenseAck(req.settings, req.deviceId, req.body.tx) plugins.dispenseAck(req.deviceId, req.body.tx)
.then(() => cacheAndRespond(req, res)) .then(() => cacheAndRespond(req, res))
.catch(next) .catch(next)
} }
@ -130,13 +121,13 @@ function deviceEvent (req, res, next) {
} }
function verifyUser (req, res, next) { function verifyUser (req, res, next) {
plugins.verifyUser(req.settings, req.body) plugins.verifyUser(req.body)
.then(idResult => cacheAndRespond(req, res, idResult)) .then(idResult => cacheAndRespond(req, res, idResult))
.catch(next) .catch(next)
} }
function verifyTx (req, res, next) { function verifyTx (req, res, next) {
plugins.verifyTransaction(req.settings, req.body) plugins.verifyTransaction(req.body)
.then(idResult => cacheAndRespond(req, res, idResult)) .then(idResult => cacheAndRespond(req, res, idResult))
.catch(next) .catch(next)
} }
@ -164,7 +155,7 @@ function pair (req, res, next) {
function phoneCode (req, res, next) { function phoneCode (req, res, next) {
const phone = req.body.phone const phone = req.body.phone
return plugins.getPhoneCode(req.settings, phone) return plugins.getPhoneCode(phone)
.then(code => cacheAndRespond(req, res, {code})) .then(code => cacheAndRespond(req, res, {code}))
.catch(err => { .catch(err => {
if (err.name === 'BadNumberError') throw httpError('Bad number', 410) if (err.name === 'BadNumberError') throw httpError('Bad number', 410)
@ -259,7 +250,7 @@ function errorHandler (err, req, res, next) {
const statusCode = err.code || 500 const statusCode = err.code || 500
const json = {error: err.message} const json = {error: err.message}
logger.debug(err) logger.error(err)
return updateCachedAction(req, json, statusCode) return updateCachedAction(req, json, statusCode)
.then(() => res.status(statusCode).json(json)) .then(() => res.status(statusCode).json(json))
@ -334,19 +325,19 @@ function init (opts) {
app.post('/pair', pair) app.post('/pair', pair)
app.get('/ca', ca) app.get('/ca', ca)
app.get('/poll', authMiddleware, loadSettings, poll) app.get('/poll', authMiddleware, poll)
app.post('/trade', authMiddleware, loadSettings, trade) app.post('/trade', authMiddleware, trade)
app.post('/send', authMiddleware, loadSettings, send) app.post('/send', authMiddleware, send)
app.post('/state', authMiddleware, loadSettings, stateChange) app.post('/state', authMiddleware, stateChange)
app.post('/cash_out', authMiddleware, loadSettings, cashOut) app.post('/cash_out', authMiddleware, cashOut)
app.post('/dispense_ack', authMiddleware, loadSettings, dispenseAck) app.post('/dispense_ack', authMiddleware, dispenseAck)
app.post('/event', authMiddleware, deviceEvent) app.post('/event', authMiddleware, deviceEvent)
app.post('/verify_user', authMiddleware, loadSettings, verifyUser) app.post('/verify_user', authMiddleware, verifyUser)
app.post('/verify_transaction', authMiddleware, loadSettings, verifyTx) app.post('/verify_transaction', authMiddleware, verifyTx)
app.post('/phone_code', authMiddleware, loadSettings, phoneCode) app.post('/phone_code', authMiddleware, phoneCode)
app.post('/update_phone', authMiddleware, updatePhone) app.post('/update_phone', authMiddleware, updatePhone)
app.get('/phone_tx', authMiddleware, fetchPhoneTx) app.get('/phone_tx', authMiddleware, fetchPhoneTx)
app.post('/register_redeem/:txId', authMiddleware, registerRedeem) app.post('/register_redeem/:txId', authMiddleware, registerRedeem)
@ -373,13 +364,13 @@ function init (opts) {
res.sendStatus(200) res.sendStatus(200)
}) })
localApp.post('/dbChange', (req, res) => { localApp.post('/dbChange', (req, res, next) => {
return configManager.load() return settingsLoader.load()
.then(config => {
return plugins.configure(config)
.then(() => logger.info('Config reloaded')) .then(() => logger.info('Config reloaded'))
.catch(err => {
logger.error(err)
res.sendStatus(500)
}) })
.catch(logger.error)
}) })
setInterval(pruneIdempotents, 60000) setInterval(pruneIdempotents, 60000)

View file

@ -2,8 +2,7 @@ const R = require('ramda')
const db = require('./db') const db = require('./db')
// Note: We won't prematurely optimize by caching yet let settings
// This shouldn't really affect performance at these scales
function load () { function load () {
return Promise.all([ return Promise.all([
@ -11,10 +10,16 @@ function load () {
loadAccounts() loadAccounts()
]) ])
.then(function ([data, accounts]) { .then(function ([data, accounts]) {
return { settings = {
config: data.data, config: data.data,
accounts: accounts accounts: accounts
} }
return settings
})
.catch(err => {
settings = undefined
throw err
}) })
} }
@ -29,15 +34,7 @@ function loadAccounts () {
}) })
} }
function settings () {
return load()
}
function clear () {
// Do nothing, since no caching
}
module.exports = { module.exports = {
settings, settings,
clear load
} }

View file

@ -1,10 +1,12 @@
const mem = require('mem') const mem = require('mem')
const configManager = require('./config-manager') const configManager = require('./config-manager')
const settingsLoader = require('./settings-loader')
const FETCH_INTERVAL = 10000 const FETCH_INTERVAL = 10000
function getRates (settings, fiatCode, cryptoCode) { function getRates (fiatCode, cryptoCode) {
return Promise.resolve() return Promise.resolve()
.then(() => { .then(() => {
const settings = settingsLoader.settings
const config = settings.config const config = settings.config
const plugin = configManager.cryptoScoped(cryptoCode, config).cryptoServices.ticker const plugin = configManager.cryptoScoped(cryptoCode, config).cryptoServices.ticker
const account = settings.accounts.plugin const account = settings.accounts.plugin

View file

@ -1,11 +1,13 @@
const mem = require('mem') const mem = require('mem')
const configManager = require('./config-manager') const configManager = require('./config-manager')
const settingsLoader = require('./settings-loader')
const FETCH_INTERVAL = 5000 const FETCH_INTERVAL = 5000
function fetchWallet (settings, cryptoCode) { function fetchWallet (cryptoCode) {
return Promise.resolve() return Promise.resolve()
.then(() => { .then(() => {
const settings = settingsLoader.settings
const plugin = configManager.cryptoScoped(cryptoCode, settings.config).cryptoServices.wallet const plugin = configManager.cryptoScoped(cryptoCode, settings.config).cryptoServices.wallet
const account = settings.accounts.plugin const account = settings.accounts.plugin
const wallet = require('lamassu-' + plugin) const wallet = require('lamassu-' + plugin)
@ -14,8 +16,8 @@ function fetchWallet (settings, cryptoCode) {
}) })
} }
function balance (settings, cryptoCode) { function balance (cryptoCode) {
return fetchWallet(settings, cryptoCode) return fetchWallet(cryptoCode)
.then(r => r.wallet.balance(r.account)) .then(r => r.wallet.balance(r.account))
.then(balance => ({balance, timestamp: Date.now()})) .then(balance => ({balance, timestamp: Date.now()}))
} }
@ -31,13 +33,13 @@ function sendCoins (toAddress, cryptoAtoms, cryptoCode) {
}) })
} }
function newAddress (settings, cryptoCode, info) { function newAddress (cryptoCode, info) {
return fetchWallet(settings, cryptoCode) return fetchWallet(cryptoCode)
.then(r => r.wallet.newAddress(r.account, cryptoCode, info)) .then(r => r.wallet.newAddress(r.account, cryptoCode, info))
} }
function getStatus (settings, toAdress, cryptoAtoms, cryptoCode) { function getStatus (toAdress, cryptoAtoms, cryptoCode) {
return fetchWallet(settings, cryptoCode) return fetchWallet(cryptoCode)
.then(r => r.wallet.getStatus(r.account, toAdress, cryptoAtoms, cryptoCode)) .then(r => r.wallet.getStatus(r.account, toAdress, cryptoAtoms, cryptoCode))
} }