2014-05-11 02:02:52 +02:00
|
|
|
var fs = require('fs');
|
2014-05-12 05:29:37 +02:00
|
|
|
var cluster = require('cluster');
|
2014-06-19 22:15:02 +02:00
|
|
|
var os = require('os');
|
2014-05-11 02:02:52 +02:00
|
|
|
|
2014-05-13 21:11:46 +02:00
|
|
|
var redis = require('redis');
|
|
|
|
|
2014-05-11 03:24:25 +02:00
|
|
|
|
2014-07-04 02:48:01 +02:00
|
|
|
require('./lib/configReader.js');
|
2014-06-25 02:20:58 +02:00
|
|
|
|
|
|
|
require('./lib/logger.js');
|
|
|
|
|
|
|
|
|
|
|
|
global.redisClient = redis.createClient(config.redis.port, config.redis.host);
|
|
|
|
|
2014-06-23 08:46:49 +02:00
|
|
|
|
2014-05-12 05:29:37 +02:00
|
|
|
if (cluster.isWorker){
|
|
|
|
switch(process.env.workerType){
|
|
|
|
case 'pool':
|
2014-05-14 02:41:28 +02:00
|
|
|
require('./lib/pool.js');
|
2014-05-12 05:29:37 +02:00
|
|
|
break;
|
2014-06-19 20:38:19 +02:00
|
|
|
case 'blockUnlocker':
|
|
|
|
require('./lib/blockUnlocker.js');
|
|
|
|
break;
|
2014-05-12 05:29:37 +02:00
|
|
|
case 'paymentProcessor':
|
2014-05-14 02:41:28 +02:00
|
|
|
require('./lib/paymentProcessor.js');
|
2014-05-12 05:29:37 +02:00
|
|
|
break;
|
|
|
|
case 'api':
|
2014-05-14 02:41:28 +02:00
|
|
|
require('./lib/api.js');
|
2014-05-12 05:29:37 +02:00
|
|
|
break;
|
|
|
|
case 'cli':
|
2014-05-14 02:41:28 +02:00
|
|
|
require('./lib/cli.js');
|
2014-05-12 05:29:37 +02:00
|
|
|
break
|
2014-08-07 22:45:33 +02:00
|
|
|
case 'chartsDataCollector':
|
|
|
|
require('./lib/chartsDataCollector.js');
|
|
|
|
break
|
|
|
|
|
2014-05-12 05:29:37 +02:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2014-05-11 02:02:52 +02:00
|
|
|
|
2014-06-25 02:20:58 +02:00
|
|
|
var logSystem = 'master';
|
|
|
|
require('./lib/exceptionWriter.js')(logSystem);
|
2014-06-19 22:15:02 +02:00
|
|
|
|
2014-05-11 02:02:52 +02:00
|
|
|
|
2014-06-28 04:02:02 +02:00
|
|
|
var singleModule = (function(){
|
|
|
|
|
2014-08-07 22:45:33 +02:00
|
|
|
var validModules = ['pool', 'api', 'unlocker', 'payments', 'chartsDataCollector'];
|
2014-06-28 04:02:02 +02:00
|
|
|
|
|
|
|
for (var i = 0; i < process.argv.length; i++){
|
|
|
|
if (process.argv[i].indexOf('-module=') === 0){
|
|
|
|
var moduleName = process.argv[i].split('=')[1];
|
|
|
|
if (validModules.indexOf(moduleName) > -1)
|
|
|
|
return moduleName;
|
|
|
|
|
|
|
|
log('error', logSystem, 'Invalid module "%s", valid modules: %s', [moduleName, validModules.join(', ')]);
|
|
|
|
process.exit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})();
|
|
|
|
|
|
|
|
|
2014-05-12 05:29:37 +02:00
|
|
|
(function init(){
|
2014-06-28 04:02:02 +02:00
|
|
|
|
2014-05-13 21:11:46 +02:00
|
|
|
checkRedisVersion(function(){
|
2014-06-28 04:02:02 +02:00
|
|
|
|
|
|
|
if (singleModule){
|
|
|
|
log('info', logSystem, 'Running in single module mode: %s', [singleModule]);
|
|
|
|
|
|
|
|
switch(singleModule){
|
|
|
|
case 'pool':
|
|
|
|
spawnPoolWorkers();
|
|
|
|
break;
|
|
|
|
case 'unlocker':
|
|
|
|
spawnBlockUnlocker();
|
|
|
|
break;
|
|
|
|
case 'payments':
|
|
|
|
spawnPaymentProcessor();
|
|
|
|
break;
|
|
|
|
case 'api':
|
|
|
|
spawnApi();
|
|
|
|
break;
|
2014-08-07 22:45:33 +02:00
|
|
|
case 'chartsDataCollector':
|
|
|
|
spawnChartsDataCollector();
|
|
|
|
break;
|
2014-06-28 04:02:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
spawnPoolWorkers();
|
|
|
|
spawnBlockUnlocker();
|
|
|
|
spawnPaymentProcessor();
|
|
|
|
spawnApi();
|
2014-08-07 22:45:33 +02:00
|
|
|
spawnChartsDataCollector();
|
2014-06-28 04:02:02 +02:00
|
|
|
}
|
|
|
|
|
2014-05-13 21:11:46 +02:00
|
|
|
spawnCli();
|
2014-06-28 04:02:02 +02:00
|
|
|
|
2014-05-13 21:11:46 +02:00
|
|
|
});
|
2014-05-12 05:29:37 +02:00
|
|
|
})();
|
2014-05-11 02:02:52 +02:00
|
|
|
|
|
|
|
|
2014-05-13 21:11:46 +02:00
|
|
|
function checkRedisVersion(callback){
|
2014-06-25 02:20:58 +02:00
|
|
|
|
2014-05-13 21:11:46 +02:00
|
|
|
redisClient.info(function(error, response){
|
|
|
|
if (error){
|
2014-06-25 02:20:58 +02:00
|
|
|
log('error', logSystem, 'Redis version check failed');
|
2014-05-13 21:11:46 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
var parts = response.split('\r\n');
|
|
|
|
var version;
|
|
|
|
var versionString;
|
|
|
|
for (var i = 0; i < parts.length; i++){
|
|
|
|
if (parts[i].indexOf(':') !== -1){
|
|
|
|
var valParts = parts[i].split(':');
|
|
|
|
if (valParts[0] === 'redis_version'){
|
|
|
|
versionString = valParts[1];
|
|
|
|
version = parseFloat(versionString);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!version){
|
2014-06-28 04:02:02 +02:00
|
|
|
log('error', logSystem, 'Could not detect redis version - must be super old or broken');
|
2014-05-13 21:11:46 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (version < 2.6){
|
2014-06-25 02:20:58 +02:00
|
|
|
log('error', logSystem, "You're using redis version %s the minimum required version is 2.6. Follow the damn usage instructions...", [versionString]);
|
2014-05-13 21:11:46 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
callback();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2014-05-12 05:29:37 +02:00
|
|
|
function spawnPoolWorkers(){
|
2014-05-11 02:02:52 +02:00
|
|
|
|
2014-05-17 19:23:39 +02:00
|
|
|
if (!config.poolServer || !config.poolServer.enabled || !config.poolServer.ports || config.poolServer.ports.length === 0) return;
|
|
|
|
|
2014-06-25 02:20:58 +02:00
|
|
|
if (config.poolServer.ports.length === 0){
|
|
|
|
log('error', logSystem, 'Pool server enabled but no ports specified');
|
2014-05-23 21:27:14 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-12 05:29:37 +02:00
|
|
|
var numForks = (function(){
|
2014-05-23 21:27:14 +02:00
|
|
|
if (!config.poolServer.clusterForks)
|
2014-05-12 05:29:37 +02:00
|
|
|
return 1;
|
2014-05-23 21:27:14 +02:00
|
|
|
if (config.poolServer.clusterForks === 'auto')
|
2014-05-12 05:29:37 +02:00
|
|
|
return os.cpus().length;
|
2014-05-23 21:27:14 +02:00
|
|
|
if (isNaN(config.poolServer.clusterForks))
|
2014-05-12 05:29:37 +02:00
|
|
|
return 1;
|
2014-05-23 21:27:14 +02:00
|
|
|
return config.poolServer.clusterForks;
|
2014-05-12 05:29:37 +02:00
|
|
|
})();
|
2014-05-11 02:02:52 +02:00
|
|
|
|
2014-05-12 05:29:37 +02:00
|
|
|
var poolWorkers = {};
|
2014-05-11 02:02:52 +02:00
|
|
|
|
2014-05-12 05:29:37 +02:00
|
|
|
var createPoolWorker = function(forkId){
|
|
|
|
var worker = cluster.fork({
|
|
|
|
workerType: 'pool',
|
|
|
|
forkId: forkId
|
2014-05-11 02:02:52 +02:00
|
|
|
});
|
2014-05-12 05:29:37 +02:00
|
|
|
worker.forkId = forkId;
|
|
|
|
worker.type = 'pool';
|
|
|
|
poolWorkers[forkId] = worker;
|
|
|
|
worker.on('exit', function(code, signal){
|
2014-06-25 02:20:58 +02:00
|
|
|
log('error', logSystem, 'Pool fork %s died, spawning replacement worker...', [forkId]);
|
2014-05-12 05:29:37 +02:00
|
|
|
setTimeout(function(){
|
|
|
|
createPoolWorker(forkId);
|
|
|
|
}, 2000);
|
|
|
|
}).on('message', function(msg){
|
|
|
|
switch(msg.type){
|
2014-05-14 02:41:28 +02:00
|
|
|
case 'banIP':
|
|
|
|
Object.keys(cluster.workers).forEach(function(id) {
|
|
|
|
if (cluster.workers[id].type === 'pool'){
|
|
|
|
cluster.workers[id].send({type: 'banIP', ip: msg.ip});
|
|
|
|
}
|
|
|
|
});
|
2014-05-12 05:29:37 +02:00
|
|
|
break;
|
2014-05-11 02:02:52 +02:00
|
|
|
}
|
|
|
|
});
|
2014-05-12 05:29:37 +02:00
|
|
|
};
|
2014-05-11 02:02:52 +02:00
|
|
|
|
2014-06-25 02:20:58 +02:00
|
|
|
var i = 1;
|
2014-05-12 05:29:37 +02:00
|
|
|
var spawnInterval = setInterval(function(){
|
2014-06-25 02:20:58 +02:00
|
|
|
createPoolWorker(i.toString());
|
2014-05-12 05:29:37 +02:00
|
|
|
i++;
|
2014-06-25 02:20:58 +02:00
|
|
|
if (i - 1 === numForks){
|
2014-05-12 05:29:37 +02:00
|
|
|
clearInterval(spawnInterval);
|
2014-06-25 02:20:58 +02:00
|
|
|
log('info', logSystem, 'Pool spawned on %d thread(s)', [numForks]);
|
2014-05-11 02:02:52 +02:00
|
|
|
}
|
2014-05-12 05:29:37 +02:00
|
|
|
}, 10);
|
2014-05-11 03:24:25 +02:00
|
|
|
}
|
2014-05-11 02:02:52 +02:00
|
|
|
|
2014-06-19 20:38:19 +02:00
|
|
|
function spawnBlockUnlocker(){
|
|
|
|
|
|
|
|
if (!config.blockUnlocker || !config.blockUnlocker.enabled) return;
|
|
|
|
|
|
|
|
var worker = cluster.fork({
|
|
|
|
workerType: 'blockUnlocker'
|
|
|
|
});
|
|
|
|
worker.on('exit', function(code, signal){
|
2014-06-25 02:20:58 +02:00
|
|
|
log('error', logSystem, 'Block unlocker died, spawning replacement...');
|
2014-06-19 20:38:19 +02:00
|
|
|
setTimeout(function(){
|
|
|
|
spawnBlockUnlocker();
|
|
|
|
}, 2000);
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2014-05-12 05:29:37 +02:00
|
|
|
function spawnPaymentProcessor(){
|
2014-05-13 21:11:46 +02:00
|
|
|
|
|
|
|
if (!config.payments || !config.payments.enabled) return;
|
|
|
|
|
2014-05-12 05:29:37 +02:00
|
|
|
var worker = cluster.fork({
|
|
|
|
workerType: 'paymentProcessor'
|
2014-05-11 05:03:04 +02:00
|
|
|
});
|
2014-05-12 05:29:37 +02:00
|
|
|
worker.on('exit', function(code, signal){
|
2014-06-25 02:20:58 +02:00
|
|
|
log('error', logSystem, 'Payment processor died, spawning replacement...');
|
2014-05-12 05:29:37 +02:00
|
|
|
setTimeout(function(){
|
|
|
|
spawnPaymentProcessor();
|
|
|
|
}, 2000);
|
|
|
|
});
|
|
|
|
}
|
2014-05-11 05:03:04 +02:00
|
|
|
|
2014-05-12 05:29:37 +02:00
|
|
|
function spawnApi(){
|
2014-05-14 02:41:28 +02:00
|
|
|
if (!config.api || !config.api.enabled) return;
|
2014-05-11 02:02:52 +02:00
|
|
|
|
2014-05-14 02:41:28 +02:00
|
|
|
var worker = cluster.fork({
|
|
|
|
workerType: 'api'
|
|
|
|
});
|
|
|
|
worker.on('exit', function(code, signal){
|
2014-06-25 02:20:58 +02:00
|
|
|
log('error', logSystem, 'API died, spawning replacement...');
|
2014-05-14 02:41:28 +02:00
|
|
|
setTimeout(function(){
|
|
|
|
spawnApi();
|
|
|
|
}, 2000);
|
|
|
|
});
|
2014-05-11 03:24:25 +02:00
|
|
|
}
|
2014-05-11 02:02:52 +02:00
|
|
|
|
2014-05-12 05:29:37 +02:00
|
|
|
function spawnCli(){
|
2014-05-11 02:02:52 +02:00
|
|
|
|
2014-08-07 22:45:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function spawnChartsDataCollector(){
|
|
|
|
if (!config.charts) return;
|
|
|
|
|
|
|
|
var worker = cluster.fork({
|
|
|
|
workerType: 'chartsDataCollector'
|
|
|
|
});
|
|
|
|
worker.on('exit', function(code, signal){
|
|
|
|
log('error', logSystem, 'chartsDataCollector died, spawning replacement...');
|
|
|
|
setTimeout(function(){
|
|
|
|
spawnChartsDataCollector();
|
|
|
|
}, 2000);
|
|
|
|
});
|
|
|
|
}
|