| 
									
										
										
										
											2015-11-17 08:18:56 +00:00
										 |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-04 23:09:56 -06:00
										 |  |  | module.exports.create = function () { | 
					
						
							| 
									
										
										
										
											2015-11-17 08:18:56 +00:00
										 |  |  |   var id = '0'; | 
					
						
							| 
									
										
										
										
											2015-11-21 12:36:22 +00:00
										 |  |  |   var promiseApp; | 
					
						
							| 
									
										
										
										
											2015-11-17 08:18:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   //
 | 
					
						
							|  |  |  |   // Worker Mode
 | 
					
						
							|  |  |  |   //
 | 
					
						
							| 
									
										
										
										
											2017-05-04 23:09:56 -06:00
										 |  |  |   function createAndBind(conf) { | 
					
						
							| 
									
										
										
										
											2015-11-17 08:18:56 +00:00
										 |  |  |     // NOTE: this callback must return a promise for an express app
 | 
					
						
							| 
									
										
										
										
											2017-05-04 23:09:56 -06:00
										 |  |  |     function getOrCreateHttpApp(err, insecserver, webserver/*, newMessage*/) { | 
					
						
							| 
									
										
										
										
											2015-11-17 08:18:56 +00:00
										 |  |  |       var PromiseA = require('bluebird'); | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-21 12:36:22 +00:00
										 |  |  |       if (promiseApp) { | 
					
						
							|  |  |  |         return promiseApp; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-21 12:36:22 +00:00
										 |  |  |       promiseApp = new PromiseA(function (resolve) { | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |         function initHttpApp(srvmsg) { | 
					
						
							| 
									
										
										
										
											2015-11-28 05:57:07 +00:00
										 |  |  |           if ('walnut.webserver.onrequest' !== srvmsg.type) { | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |             console.warn('[Worker] [onrequest] unexpected message:'); | 
					
						
							| 
									
										
										
										
											2015-11-17 08:18:56 +00:00
										 |  |  |             console.warn(srvmsg); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |           process.removeListener('message', initHttpApp); | 
					
						
							| 
									
										
										
										
											2015-11-17 08:18:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |           if (srvmsg.conf) { | 
					
						
							|  |  |  |             Object.keys(srvmsg.conf).forEach(function (key) { | 
					
						
							|  |  |  |               conf[key] = srvmsg.conf[key]; | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           resolve(require('../lib/worker').create(webserver, conf)); | 
					
						
							| 
									
										
										
										
											2015-11-17 08:18:56 +00:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-28 05:57:07 +00:00
										 |  |  |         process.send({ type: 'walnut.webserver.listening' }); | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |         process.on('message', initHttpApp); | 
					
						
							| 
									
										
										
										
											2015-11-17 08:18:56 +00:00
										 |  |  |       }).then(function (app) { | 
					
						
							|  |  |  |         console.info('[Worker Ready]'); | 
					
						
							|  |  |  |         return app; | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-21 12:36:22 +00:00
										 |  |  |       return promiseApp; | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-04 23:09:56 -06:00
										 |  |  |     function serverCallback(err, webserver) { | 
					
						
							|  |  |  |       if (err) { | 
					
						
							|  |  |  |         console.error('[ERROR] worker.js'); | 
					
						
							|  |  |  |         console.error(err.stack); | 
					
						
							|  |  |  |         throw err; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2015-11-17 08:18:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-04 23:09:56 -06:00
										 |  |  |       console.info("#" + id + " Listening on " + conf.protocol + "://" + webserver.address().address + ":" + webserver.address().port, '\n'); | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-04 23:09:56 -06:00
										 |  |  |       // we are returning the promise result to the caller
 | 
					
						
							|  |  |  |       return getOrCreateHttpApp(null, null, webserver, conf); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-04 23:09:56 -06:00
										 |  |  |     // 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); | 
					
						
							| 
									
										
										
										
											2015-11-17 08:18:56 +00:00
										 |  |  |         }); | 
					
						
							| 
									
										
										
										
											2017-05-04 23:09:56 -06:00
										 |  |  |         /* | 
					
						
							|  |  |  |         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); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |         */ | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-04 23:09:56 -06:00
										 |  |  |         // 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); | 
					
						
							| 
									
										
										
										
											2015-11-17 08:18:56 +00:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-04 23:09:56 -06:00
										 |  |  |   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); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-17 08:18:56 +00:00
										 |  |  |   //
 | 
					
						
							|  |  |  |   // 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); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | }; |