Merge pull request #41 from chester1000/plugin-reload
Instant plugins reload
This commit is contained in:
commit
214e39b444
5 changed files with 119 additions and 53 deletions
|
|
@ -1,8 +1,10 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var createServer = require('../lib/app.js');
|
var createServer = require('../lib/app.js');
|
||||||
var argv = require('minimist')(process.argv.slice(2));
|
var argv = require('minimist')(process.argv.slice(2));
|
||||||
var logger = require('../lib/logger');
|
|
||||||
|
|
||||||
var options = {
|
var options = {
|
||||||
postgres: process.env.DATABASE_URL
|
postgres: process.env.DATABASE_URL
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,39 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
var bunyan = require('bunyan');
|
var bunyan = require('bunyan');
|
||||||
|
var async = require('async');
|
||||||
|
|
||||||
var logLevel = process.env.LAMASSU_ENV === 'debug' ?
|
var logLevel = process.env.LAMASSU_ENV === 'debug' ?
|
||||||
'debug' :
|
'debug' :
|
||||||
'info';
|
'info';
|
||||||
|
|
||||||
module.exports = bunyan.createLogger({name: 'lamassu-server', level: logLevel});
|
var bunyan = bunyan.createLogger({name: 'lamassu-server', level: logLevel});
|
||||||
|
|
||||||
|
|
||||||
|
// log version
|
||||||
|
var version = require('../package.json').version;
|
||||||
|
bunyan.info('Version: %s', version);
|
||||||
|
|
||||||
|
|
||||||
|
// log git stuff (optional)
|
||||||
|
// `git-rev` omits `err` param in callback, without this wrapper
|
||||||
|
// `async` interprets returned values as errors.
|
||||||
|
function wrapper(fn, cb) {
|
||||||
|
fn(function(value) {
|
||||||
|
cb(null, value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
var git = require('git-rev');
|
||||||
|
|
||||||
|
async.parallel([
|
||||||
|
async.apply(wrapper, git.branch),
|
||||||
|
async.apply(wrapper, git.short)
|
||||||
|
],
|
||||||
|
function(err, values) {
|
||||||
|
bunyan.info('Git: #%s @%s', values[0], values[1]);
|
||||||
|
});
|
||||||
|
} catch(_) {}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = bunyan;
|
||||||
|
|
|
||||||
126
lib/plugins.js
126
lib/plugins.js
|
|
@ -11,13 +11,17 @@ var POLLING_RATE = 60 * 1000; // poll each minute
|
||||||
|
|
||||||
var db = null;
|
var db = null;
|
||||||
|
|
||||||
|
|
||||||
var tickerPlugin = null;
|
var tickerPlugin = null;
|
||||||
var traderPlugin = null;
|
var traderPlugin = null;
|
||||||
var walletPlugin = null;
|
var walletPlugin = null;
|
||||||
var idVerifierPlugin = null;
|
var idVerifierPlugin = null;
|
||||||
|
|
||||||
|
var currentlyUsedPlugins = {};
|
||||||
|
|
||||||
|
|
||||||
var cachedConfig = null;
|
var cachedConfig = null;
|
||||||
var deviceCurrency = 'USD'; // Can 'USD' be set as default?
|
var deviceCurrency = 'USD';
|
||||||
|
|
||||||
var lastBalances = null;
|
var lastBalances = null;
|
||||||
var lastRates = {};
|
var lastRates = {};
|
||||||
|
|
@ -33,7 +37,7 @@ var sessions = {};
|
||||||
// that's basically a constructor
|
// that's basically a constructor
|
||||||
exports.init = function init(databaseHandle) {
|
exports.init = function init(databaseHandle) {
|
||||||
if (!databaseHandle) {
|
if (!databaseHandle) {
|
||||||
throw new Error('`db` is required');
|
throw new Error('\'db\' is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
db = databaseHandle;
|
db = databaseHandle;
|
||||||
|
|
@ -93,56 +97,73 @@ function loadPlugin(name, config) {
|
||||||
return plugin;
|
return plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function loadOrConfigPlugin(pluginHandle, pluginType, currency, onChangeCallback) {
|
||||||
|
var currentName = cachedConfig.exchanges.plugins.current[pluginType];
|
||||||
|
var pluginChanged = currentlyUsedPlugins[pluginType] !== currentName;
|
||||||
|
|
||||||
|
if (!currentName) pluginHandle = null;
|
||||||
|
else { // some plugins may be disabled
|
||||||
|
var pluginConfig = cachedConfig.exchanges.plugins.settings[currentName] || {};
|
||||||
|
|
||||||
|
if (currency) pluginConfig.currency = currency;
|
||||||
|
|
||||||
|
if (pluginHandle && !pluginChanged) pluginHandle.config(pluginConfig);
|
||||||
|
else pluginHandle = loadPlugin(currentName, pluginConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof onChangeCallback === 'function') onChangeCallback(pluginHandle, currency);
|
||||||
|
|
||||||
|
return pluginHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
exports.configure = function configure(config) {
|
exports.configure = function configure(config) {
|
||||||
if (config.exchanges.settings.lowBalanceMargin < 1) {
|
if (config.exchanges.settings.lowBalanceMargin < 1) {
|
||||||
throw new Error('`settings.lowBalanceMargin` has to be >= 1');
|
throw new Error('\'settings.lowBalanceMargin\' has to be >= 1');
|
||||||
}
|
}
|
||||||
|
|
||||||
deviceCurrency = config.exchanges.settings.currency;
|
|
||||||
var plugins = config.exchanges.plugins;
|
|
||||||
|
|
||||||
// [required] configure (or load) ticker
|
|
||||||
var tickerName = plugins.current.ticker;
|
|
||||||
var tickerConfig = plugins.settings[tickerName] || {};
|
|
||||||
tickerConfig.currency = deviceCurrency;
|
|
||||||
|
|
||||||
if (tickerPlugin) tickerPlugin.config(tickerConfig);
|
|
||||||
else tickerPlugin = loadPlugin(tickerName, tickerConfig);
|
|
||||||
|
|
||||||
|
|
||||||
// [required] configure (or load) wallet
|
|
||||||
var walletName = plugins.current.transfer;
|
|
||||||
var walletConfig = plugins.settings[walletName] || {};
|
|
||||||
|
|
||||||
if (walletPlugin) walletPlugin.config(walletConfig);
|
|
||||||
else walletPlugin = loadPlugin(walletName, walletConfig);
|
|
||||||
|
|
||||||
|
|
||||||
// [optional] configure (or load) trader
|
|
||||||
var traderName = plugins.current.trade;
|
|
||||||
if (traderName) { // traderPlugin may be disabled
|
|
||||||
var traderConfig = plugins.settings[traderName] || {};
|
|
||||||
|
|
||||||
if (traderPlugin) traderPlugin.config(traderConfig);
|
|
||||||
else traderPlugin = loadPlugin(traderName, traderConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// [optional] ID Verifier
|
|
||||||
var verifierName = plugins.current.idVerifier;
|
|
||||||
if (verifierName) { // idVerifierPlugin may be disabled
|
|
||||||
var verifierConfig = plugins.settings[verifierName] || {};
|
|
||||||
|
|
||||||
if (idVerifierPlugin) idVerifierPlugin.config(verifierConfig);
|
|
||||||
else idVerifierPlugin = loadPlugin(verifierName, verifierConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
cachedConfig = config;
|
cachedConfig = config;
|
||||||
|
deviceCurrency = config.exchanges.settings.currency;
|
||||||
|
|
||||||
pollBalance();
|
// TICKER [required] configure (or load)
|
||||||
|
loadOrConfigPlugin(
|
||||||
|
tickerPlugin,
|
||||||
|
'ticker',
|
||||||
|
deviceCurrency, // device currency
|
||||||
|
function onTickerChange(newTicker) {
|
||||||
|
tickerPlugin = newTicker;
|
||||||
pollRate();
|
pollRate();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// WALLET [required] configure (or load)
|
||||||
|
loadOrConfigPlugin(
|
||||||
|
walletPlugin,
|
||||||
|
'transfer',
|
||||||
|
null,
|
||||||
|
function onWalletChange(newWallet) {
|
||||||
|
walletPlugin = newWallet;
|
||||||
|
pollBalance();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// TRADER [optional] configure (or load)
|
||||||
|
traderPlugin = loadOrConfigPlugin(
|
||||||
|
traderPlugin,
|
||||||
|
'trade',
|
||||||
|
null,
|
||||||
|
function onTraderChange(newTrader) {
|
||||||
|
traderPlugin = newTrader;
|
||||||
|
if (newTrader === null) stopTrader();
|
||||||
|
else startTrader();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// ID VERIFIER [optional] configure (or load)
|
||||||
|
idVerifierPlugin = loadOrConfigPlugin(
|
||||||
|
idVerifierPlugin,
|
||||||
|
'idVerifier'
|
||||||
|
);
|
||||||
};
|
};
|
||||||
exports.getCachedConfig = function getCachedConfig() {
|
exports.getCachedConfig = function getCachedConfig() {
|
||||||
return cachedConfig;
|
return cachedConfig;
|
||||||
|
|
@ -257,17 +278,28 @@ exports.startPolling = function startPolling() {
|
||||||
rateInterval = setInterval(pollRate, POLLING_RATE);
|
rateInterval = setInterval(pollRate, POLLING_RATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
startTrader();
|
||||||
|
};
|
||||||
|
|
||||||
|
function startTrader() {
|
||||||
// Always start trading, even if we don't have a trade exchange configured,
|
// Always start trading, even if we don't have a trade exchange configured,
|
||||||
// since configuration can always change in `Trader#configure`.
|
// since configuration can always change in `Trader#configure`.
|
||||||
// `Trader#executeTrades` returns early if we don't have a trade exchange
|
// `Trader#executeTrades` returns early if we don't have a trade exchange
|
||||||
// configured at the moment.
|
// configured at the moment.
|
||||||
if (!tradeInterval) {
|
if (traderPlugin && !tradeInterval) {
|
||||||
tradeInterval = setInterval(
|
tradeInterval = setInterval(
|
||||||
executeTrades,
|
executeTrades,
|
||||||
cachedConfig.exchanges.settings.tradeInterval
|
cachedConfig.exchanges.settings.tradeInterval
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
function stopTrader() {
|
||||||
|
if (tradeInterval) {
|
||||||
|
clearInterval(tradeInterval);
|
||||||
|
tradeInterval = null;
|
||||||
|
tradesQueue = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function pollBalance(callback) {
|
function pollBalance(callback) {
|
||||||
|
|
@ -298,7 +330,7 @@ function pollBalance(callback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function pollRate(callback) {
|
function pollRate(callback) {
|
||||||
logger.debug('polling for rates');
|
logger.debug('polling for rates (%s)', tickerPlugin.NAME);
|
||||||
|
|
||||||
tickerPlugin.ticker(deviceCurrency, function(err, resRates) {
|
tickerPlugin.ticker(deviceCurrency, function(err, resRates) {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ var mock = false;
|
||||||
|
|
||||||
var plugins;
|
var plugins;
|
||||||
var lamassuConfig;
|
var lamassuConfig;
|
||||||
var config;
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
init: init,
|
init: init,
|
||||||
|
|
@ -58,7 +57,7 @@ function poll(req, res) {
|
||||||
};
|
};
|
||||||
|
|
||||||
if (response.idVerificationEnabled)
|
if (response.idVerificationEnabled)
|
||||||
response.idVerificationLimit = complianceSettings.idVerificationLimit
|
response.idVerificationLimit = complianceSettings.idVerificationLimit;
|
||||||
|
|
||||||
res.json(response);
|
res.json(response);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"chai": "^1.9.1",
|
"chai": "^1.9.1",
|
||||||
|
"git-rev": "^0.2.1",
|
||||||
"lodash": "^2.4.1",
|
"lodash": "^2.4.1",
|
||||||
"mocha": "^1.21.4",
|
"mocha": "^1.21.4",
|
||||||
"mockery": "^1.4.0"
|
"mockery": "^1.4.0"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue