diff --git a/package.json b/package.json index f965440f..d59e21a8 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "mongojs": "^2.4.0", "node-cryptojs-aes": "^0.4.0", "nodemailer": "^4.0.1", + "redis": "^2.8.0", "request": "^2.72.0", "socket.io": "^2.0.3", "socket.io-redis": "^5.2.0", diff --git a/server/app.js b/server/app.js index 88358055..1d63b630 100644 --- a/server/app.js +++ b/server/app.js @@ -2,126 +2,124 @@ var cluster = require('cluster'), net = require('net'), path = require('path'), publicPath = path.join(__dirname, 'public'), - http = require('http'); - -var port = 8080, + http = require('http'), + port = 8080, num_processes = require('os').cpus().length; -if (cluster.isMaster) { - // This stores our workers. We need to keep them to be able to reference - // them based on source IP address. It's also useful for auto-restart, - // for example. - var workers = []; +try { + var redis = require("redis"); + var client = redis.createClient({host: "localhost", port: 6379}); + client.quit(); + startClustered(); +} catch(e) { + console.log("Couldn't connect to redis-server, assuming non-clustered run"); + startSingle(false); +} - // Helper function for spawning worker at index 'i'. - var spawn = function(i) { - workers[i] = cluster.fork(); +function startClustered() { + //Found https://stackoverflow.com/questions/40885592/use-node-js-cluster-with-socket-io-chat-application + if (cluster.isMaster) { + var workers = []; + var spawn = function(i) { + workers[i] = cluster.fork(); + workers[i].on('exit', function(code, signal) { + console.log('respawning worker', i); + spawn(i); + }); + }; - // Optional: Restart worker on exit - workers[i].on('exit', function(code, signal) { - console.log('respawning worker', i); + for (var i = 0; i < num_processes; i++) { spawn(i); - }); - }; - - // Spawn workers. - for (var i = 0; i < num_processes; i++) { - spawn(i); - } - - // Helper function for getting a worker index based on IP address. - // This is a hot path so it should be really fast. The way it works - // is by converting the IP address to a number by removing non numeric - // characters, then compressing it to the number of slots we have. - // - // Compared against "real" hashing (from the sticky-session code) and - // "real" IP number conversion, this function is on par in terms of - // worker index distribution only much faster. - var worker_index = function(ip, len) { - var s = ''; - for (var i = 0, _len = ip.length; i < _len; i++) { - if (!isNaN(ip[i])) { - s += ip[i]; - } } - return Number(s) % len; - }; + var worker_index = function(ip, len) { + var s = ''; + for (var i = 0, _len = ip.length; i < _len; i++) { + if (!isNaN(ip[i])) { + s += ip[i]; + } + } + return Number(s) % len; + }; - // Create the outside facing server listening on our port. - var server = net.createServer({ pauseOnConnect: true }, function(connection) { - // We received a connection and need to pass it to the appropriate - // worker. Get the worker for this connection's source IP and pass - // it the connection. - var worker = workers[worker_index(connection.remoteAddress, num_processes)]; - worker.send('sticky-session:connection', connection); - }).listen(port); -} else { - // Note we don't use a port here because the master listens on it for us. + var server = net.createServer({ pauseOnConnect: true }, function(connection) { + var worker = workers[worker_index(connection.remoteAddress, num_processes)]; + worker.send('sticky-session:connection', connection); + }).listen(port); + } else { + startSingle(true); + } +} + +function startSingle(clustered) { var app = require('./index.js'); - - // Here you might use middleware, attach routes, etc - - // Don't expose our internal server to the outside. + var cors_options = {}; try { var cert_config = require(path.join(path.join(__dirname, 'config'), 'cert_config.js')); - var fs = require('fs'); - var privateKey = fs.readFileSync(cert_config.privateKey).toString(); - var certificate = fs.readFileSync(cert_config.certificate).toString(); - var ca = fs.readFileSync(cert_config.ca).toString(); - var credentials = { - key: privateKey, - cert: certificate, - ca: ca - }; + var fs = require('fs'); + var privateKey = fs.readFileSync(cert_config.privateKey).toString(); + var certificate = fs.readFileSync(cert_config.certificate).toString(); + var ca = fs.readFileSync(cert_config.ca).toString(); + var credentials = { + key: privateKey, + cert: certificate, + ca: ca + }; - var https = require('https'); - server = https.Server(credentials, app); + var https = require('https'); + server = https.Server(credentials, app); - var cors_proxy = require('cors-anywhere'); + cors_options = { + requireHeader: ['origin', 'x-requested-with'], + removeHeaders: ['cookie', 'cookie2'], + httpsOptions: credentials + }; - cors_proxy.createServer({ - requireHeader: ['origin', 'x-requested-with'], - removeHeaders: ['cookie', 'cookie2'], - httpsOptions: credentials - }).listen(8081, function() { - console.log('Running CORS Anywhere on :' + 8081); - }); } catch(err){ - console.log("Starting without https (probably on localhost)"); - var cors_proxy = require('cors-anywhere'); - cors_proxy.createServer({ - requireHeader: ['origin', 'x-requested-with'], - removeHeaders: ['cookie', 'cookie2'], - }).listen(8081, function() { - console.log('Running CORS Anywhere on :' + 8081); - }); - var http = require('http'); - server = http.Server(app); - //add = ",http://localhost:80*,http://localhost:8080*,localhost:8080*, localhost:8082*,http://zoff.dev:80*,http://zoff.dev:8080*,zoff.dev:8080*, zoff.dev:8082*"; + console.log("Starting without https (probably on localhost)"); + cors_options = { + requireHeader: ['origin', 'x-requested-with'], + removeHeaders: ['cookie', 'cookie2'], + }; + var cors_proxy = require('cors-anywhere'); + var http = require('http'); + server = http.Server(app); + //add = ",http://localhost:80*,http://localhost:8080*,localhost:8080*, localhost:8082*,http://zoff.dev:80*,http://zoff.dev:8080*,zoff.dev:8080*, zoff.dev:8082*"; } - server.listen(); + cors_proxy.createServer(cors_options).listen(8081, function() { + console.log('Running CORS Anywhere on :' + 8081 + " [" + process.pid + "]"); + }); + + if(clustered) { + server.listen(onListen); + } else { + server.listen(port, onListen); + } var socketIO = app.socketIO; - var redis = require('socket.io-redis'); - try { - socketIO.adapter(redis({ host: 'localhost', port: 6379 })); - } catch(e) { - console.log("No redis-server to connect to.."); - } + socketIO.listen(server); - // Listen to messages sent from the master. Ignore everything else. - process.on('message', function(message, connection) { - if (message !== 'sticky-session:connection') { - return; + if(clustered) { + var redis = require('socket.io-redis'); + try { + socketIO.adapter(redis({ host: 'localhost', port: 6379 })); + } catch(e) { + console.log("No redis-server to connect to.."); } + socketIO.listen(server); + process.on('message', function(message, connection) { + if (message !== 'sticky-session:connection') { + return; + } + server.emit('connection', connection); - // Emulate a connection event on the server by emitting the - // event with the connection the master sent us. - server.emit('connection', connection); - - connection.resume(); - }); + connection.resume(); + }); + } +} + +function onListen() { + console.log("Started with pid [" + process.pid + "]"); }