forked from coolaj86/walnut.js
		
	
		
			
				
	
	
		
			162 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			162 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 'use strict';
 | |
| 
 | |
| module.exports.create = function () {
 | |
|   var id = '0';
 | |
|   var promiseApp;
 | |
| 
 | |
|   //
 | |
|   // Worker Mode
 | |
|   //
 | |
|   function createAndBind(conf) {
 | |
|     // NOTE: this callback must return a promise for an express app
 | |
|     function getOrCreateHttpApp(err, insecserver, webserver/*, newMessage*/) {
 | |
|       var PromiseA = require('bluebird');
 | |
| 
 | |
|       if (promiseApp) {
 | |
|         return promiseApp;
 | |
|       }
 | |
| 
 | |
|       promiseApp = new PromiseA(function (resolve) {
 | |
|         function initHttpApp(srvmsg) {
 | |
|           if ('walnut.webserver.onrequest' !== srvmsg.type) {
 | |
|             console.warn('[Worker] [onrequest] unexpected message:');
 | |
|             console.warn(srvmsg);
 | |
|             return;
 | |
|           }
 | |
| 
 | |
|           process.removeListener('message', initHttpApp);
 | |
| 
 | |
|           if (srvmsg.conf) {
 | |
|             Object.keys(srvmsg.conf).forEach(function (key) {
 | |
|               conf[key] = srvmsg.conf[key];
 | |
|             });
 | |
|           }
 | |
| 
 | |
|           resolve(require('../lib/worker').create(webserver, conf));
 | |
|         }
 | |
| 
 | |
|         process.send({ type: 'walnut.webserver.listening' });
 | |
|         process.on('message', initHttpApp);
 | |
|       }).then(function (app) {
 | |
|         console.info('[Worker Ready]');
 | |
|         return app;
 | |
|       });
 | |
| 
 | |
|       return promiseApp;
 | |
|     }
 | |
| 
 | |
|     function serverCallback(err, webserver) {
 | |
|       if (err) {
 | |
|         console.error('[ERROR] worker.js');
 | |
|         console.error(err.stack);
 | |
|         throw err;
 | |
|       }
 | |
| 
 | |
|       console.info("#" + id + " Listening on " + conf.protocol + "://" + webserver.address().address + ":" + webserver.address().port, '\n');
 | |
| 
 | |
|       // we are returning the promise result to the caller
 | |
|       return getOrCreateHttpApp(null, null, webserver, conf);
 | |
|     }
 | |
| 
 | |
|     // Note the odd use of callbacks (instead of promises) here
 | |
|     // It's to avoid loading bluebird yet (see sni-server.js for explanation)
 | |
|     function localServerCreate(port) {
 | |
|       function initServer(err, server) {
 | |
|         var app;
 | |
|         var promiseApp;
 | |
| 
 | |
|         if (err) {
 | |
|           serverCallback(err);
 | |
|           return;
 | |
|         }
 | |
| 
 | |
|         server.on('error', serverCallback);
 | |
|         server.listen(port, function () {
 | |
|           // is it even theoritically possible for
 | |
|           // a request to come in before this callback has fired?
 | |
|           // I'm assuming this event must fire before any request event
 | |
|           promiseApp = serverCallback(null, server);
 | |
|         });
 | |
|         /*
 | |
|         server.listen(port, '::::', function () {
 | |
|           // is it even theoritically possible for
 | |
|           // a request to come in before this callback has fired?
 | |
|           // I'm assuming this event must fire before any request event
 | |
|           promiseApp = serverCallback(null, server);
 | |
|         });
 | |
|         */
 | |
| 
 | |
|         // Get up and listening as absolutely quickly as possible
 | |
|         function onRequest(req, res) {
 | |
|           // this is a hot piece of code, so we cache the result
 | |
|           if (app) {
 | |
|             app(req, res);
 | |
|             return;
 | |
|           }
 | |
| 
 | |
|           promiseApp.then(function (_app) {
 | |
|             console.log('[Server]', req.method, req.host || req.headers['x-forwarded-host'] || req.headers.host, req.url);
 | |
|             app = _app;
 | |
|             app(req, res);
 | |
|           });
 | |
|         }
 | |
| 
 | |
|         server.on('request', onRequest);
 | |
|       }
 | |
| 
 | |
|       initServer(null, require('http').createServer());
 | |
|     }
 | |
| 
 | |
|     // NOTE that message.conf[x] will be overwritten when the next message comes in
 | |
|     localServerCreate(conf.localPort);
 | |
|   }
 | |
| 
 | |
|   function waitForConfig(realMessage) {
 | |
|     console.log('realMessage', realMessage);
 | |
|     if ('walnut.init' !== realMessage.type) {
 | |
|       console.warn('[Worker] 0 got unexpected message:');
 | |
|       console.warn(realMessage);
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     var conf = realMessage.conf;
 | |
|     process.removeListener('message', waitForConfig);
 | |
| 
 | |
|     createAndBind(conf);
 | |
|   }
 | |
| 
 | |
|   // we are in cluster mode, as opposed to standalone mode
 | |
|   id = require('cluster').worker.id.toString();
 | |
|   // We have to wait to get the configuration from the master process
 | |
|   // before we can start our webserver
 | |
|   console.info('[Worker #' + id + '] online!');
 | |
|   process.on('message', waitForConfig);
 | |
| 
 | |
|   //
 | |
|   // Debugging
 | |
|   //
 | |
|   process.on('exit', function (code) {
 | |
|     // only sync code can run here
 | |
|     console.info('uptime:', process.uptime());
 | |
|     console.info(process.memoryUsage());
 | |
|     console.info('[exit] process.exit() has been called (or master has killed us).');
 | |
|     console.info(code);
 | |
|   });
 | |
|   process.on('beforeExit', function () {
 | |
|     // async can be scheduled here
 | |
|     console.info('[beforeExit] Event Loop is empty. Process will end.');
 | |
|   });
 | |
|   process.on('unhandledRejection', function (err) {
 | |
|     // this should always throw
 | |
|     // (it means somewhere we're not using bluebird by accident)
 | |
|     console.error('[caught] [unhandledRejection]');
 | |
|     console.error(Object.keys(err));
 | |
|     console.error(err);
 | |
|     console.error(err.stack);
 | |
|   });
 | |
|   process.on('rejectionHandled', function (msg) {
 | |
|     console.error('[rejectionHandled]');
 | |
|     console.error(msg);
 | |
|   });
 | |
| };
 |