| 
									
										
										
										
											2015-11-06 11:05:32 +00:00
										 |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  | module.exports.create = function (webserver, xconfx, state) { | 
					
						
							| 
									
										
										
										
											2017-05-10 23:26:25 +00:00
										 |  |  |   console.log('[worker] create'); | 
					
						
							|  |  |  |   xconfx.debug = true; | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |   console.log('DEBUG create worker'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-12 11:14:59 +00:00
										 |  |  |   if (!state) { | 
					
						
							|  |  |  |     state = {}; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   var PromiseA = state.Promise || require('bluebird'); | 
					
						
							|  |  |  |   var memstore; | 
					
						
							|  |  |  |   var sqlstores = {}; | 
					
						
							|  |  |  |   var systemFactory = require('sqlite3-cluster/client').createClientFactory({ | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |       dirname: xconfx.varpath | 
					
						
							|  |  |  |     , prefix: 'com.daplie.walnut.' | 
					
						
							| 
									
										
										
										
											2015-11-12 11:14:59 +00:00
										 |  |  |     //, dbname: 'config'
 | 
					
						
							|  |  |  |     , suffix: '' | 
					
						
							|  |  |  |     , ext: '.sqlite3' | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |     , sock: xconfx.sqlite3Sock | 
					
						
							|  |  |  |     , ipcKey: xconfx.ipcKey | 
					
						
							| 
									
										
										
										
											2015-11-12 11:14:59 +00:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |   /* | 
					
						
							| 
									
										
										
										
											2015-11-12 11:14:59 +00:00
										 |  |  |   var clientFactory = require('sqlite3-cluster/client').createClientFactory({ | 
					
						
							|  |  |  |       algorithm: 'aes' | 
					
						
							|  |  |  |     , bits: 128 | 
					
						
							|  |  |  |     , mode: 'cbc' | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |     , dirname: xconfx.varpath // TODO conf
 | 
					
						
							|  |  |  |     , prefix: 'com.daplie.walnut.' | 
					
						
							| 
									
										
										
										
											2015-11-12 11:14:59 +00:00
										 |  |  |     //, dbname: 'cluster'
 | 
					
						
							|  |  |  |     , suffix: '' | 
					
						
							|  |  |  |     , ext: '.sqlcipher' | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |     , sock: xconfx.sqlite3Sock | 
					
						
							|  |  |  |     , ipcKey: xconfx.ipcKey | 
					
						
							| 
									
										
										
										
											2015-11-12 11:14:59 +00:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2015-11-06 11:05:32 +00:00
										 |  |  |   */ | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |   var cstore = require('cluster-store'); | 
					
						
							| 
									
										
										
										
											2015-11-06 11:05:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-10 23:26:25 +00:00
										 |  |  |   console.log('[worker] creating data stores...'); | 
					
						
							| 
									
										
										
										
											2015-11-12 11:14:59 +00:00
										 |  |  |   return PromiseA.all([ | 
					
						
							| 
									
										
										
										
											2015-11-18 11:44:22 +00:00
										 |  |  |     // TODO security on memstore
 | 
					
						
							|  |  |  |     // TODO memstoreFactory.create
 | 
					
						
							| 
									
										
										
										
											2015-11-12 11:14:59 +00:00
										 |  |  |     cstore.create({ | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |       sock: xconfx.memstoreSock | 
					
						
							|  |  |  |     , connect: xconfx.memstoreSock | 
					
						
							| 
									
										
										
										
											2015-11-12 11:14:59 +00:00
										 |  |  |       // TODO implement
 | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |     , key: xconfx.ipcKey | 
					
						
							| 
									
										
										
										
											2015-11-12 11:14:59 +00:00
										 |  |  |     }).then(function (_memstore) { | 
					
						
							| 
									
										
										
										
											2017-05-10 23:26:25 +00:00
										 |  |  |       console.log('[worker] cstore created'); | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |       memstore = PromiseA.promisifyAll(_memstore); | 
					
						
							| 
									
										
										
										
											2015-11-12 11:14:59 +00:00
										 |  |  |       return memstore; | 
					
						
							|  |  |  |     }) | 
					
						
							|  |  |  |     // TODO mark a device as lost, stolen, missing in DNS records
 | 
					
						
							|  |  |  |     // (and in turn allow other devices to lock it, turn on location reporting, etc)
 | 
					
						
							|  |  |  |   , systemFactory.create({ | 
					
						
							|  |  |  |         init: true | 
					
						
							|  |  |  |       , dbname: 'config' | 
					
						
							| 
									
										
										
										
											2017-05-10 23:26:25 +00:00
										 |  |  |     }).then(function (sysdb) { | 
					
						
							|  |  |  |       console.log('[worker] sysdb created'); | 
					
						
							|  |  |  |       return sysdb; | 
					
						
							| 
									
										
										
										
											2015-11-12 11:14:59 +00:00
										 |  |  |     }) | 
					
						
							|  |  |  |   ]).then(function (args) { | 
					
						
							| 
									
										
										
										
											2017-05-10 23:26:25 +00:00
										 |  |  |     console.log('[worker] database factories created'); | 
					
						
							| 
									
										
										
										
											2015-11-12 11:14:59 +00:00
										 |  |  |     memstore = args[0]; | 
					
						
							|  |  |  |     sqlstores.config = args[1]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |     var wrap = require('masterquest-sqlite3'); | 
					
						
							|  |  |  |     var dir = [ | 
					
						
							|  |  |  |       { tablename: 'com_daplie_walnut_config' | 
					
						
							|  |  |  |       , idname: 'id' | 
					
						
							|  |  |  |       , unique: [ 'id' ] | 
					
						
							|  |  |  |       , indices: [ 'createdAt', 'updatedAt' ] | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     , { tablename: 'com_daplie_walnut_redirects' | 
					
						
							|  |  |  |       , idname: 'id'      // blog.example.com:sample.net/blog
 | 
					
						
							|  |  |  |       , unique: [ 'id' ] | 
					
						
							|  |  |  |       , indices: [ 'createdAt', 'updatedAt' ] | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     ]; | 
					
						
							| 
									
										
										
										
											2015-11-14 04:25:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |     function scopeMemstore(expId) { | 
					
						
							|  |  |  |       var scope = expId + '|'; | 
					
						
							|  |  |  |       return { | 
					
						
							|  |  |  |         getAsync: function (id) { | 
					
						
							|  |  |  |           return memstore.getAsync(scope + id); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       , setAsync: function (id, data) { | 
					
						
							|  |  |  |           return memstore.setAsync(scope + id, data); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       , touchAsync: function (id, data) { | 
					
						
							|  |  |  |           return memstore.touchAsync(scope + id, data); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       , destroyAsync: function (id) { | 
					
						
							|  |  |  |           return memstore.destroyAsync(scope + id); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2015-11-14 04:25:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |       // helpers
 | 
					
						
							|  |  |  |       , allAsync: function () { | 
					
						
							| 
									
										
										
										
											2016-06-07 10:49:26 -04:00
										 |  |  |           return memstore.allAsync().then(function (db) { | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |             return Object.keys(db).filter(function (key) { | 
					
						
							|  |  |  |               return 0 === key.indexOf(scope); | 
					
						
							|  |  |  |             }).map(function (key) { | 
					
						
							|  |  |  |               return db[key]; | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       , lengthAsync: function () { | 
					
						
							| 
									
										
										
										
											2016-06-07 10:49:26 -04:00
										 |  |  |           return memstore.allAsync().then(function (db) { | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |             return Object.keys(db).filter(function (key) { | 
					
						
							|  |  |  |               return 0 === key.indexOf(scope); | 
					
						
							|  |  |  |             }).length; | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       , clearAsync: function () { | 
					
						
							| 
									
										
										
										
											2016-06-07 10:49:26 -04:00
										 |  |  |           return memstore.allAsync().then(function (db) { | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |             return Object.keys(db).filter(function (key) { | 
					
						
							|  |  |  |               return 0 === key.indexOf(scope); | 
					
						
							|  |  |  |             }).map(function (key) { | 
					
						
							|  |  |  |               return memstore.destroyAsync(key); | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |           }).then(function () { | 
					
						
							|  |  |  |             return null; | 
					
						
							|  |  |  |           }); | 
					
						
							| 
									
										
										
										
											2015-11-14 04:25:12 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |       }; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return wrap.wrap(sqlstores.config, dir).then(function (models) { | 
					
						
							| 
									
										
										
										
											2017-05-10 23:26:25 +00:00
										 |  |  |       console.log('[worker] database wrapped'); | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |       return models.ComDaplieWalnutConfig.find(null, { limit: 100 }).then(function (results) { | 
					
						
							| 
									
										
										
										
											2017-05-10 23:26:25 +00:00
										 |  |  |         console.log('[worker] config query complete'); | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |         return models.ComDaplieWalnutConfig.find(null, { limit: 10000 }).then(function (redirects) { | 
					
						
							| 
									
										
										
										
											2017-05-10 23:26:25 +00:00
										 |  |  |           console.log('[worker] configuring express'); | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |           var express = require('express-lazy'); | 
					
						
							|  |  |  |           var app = express(); | 
					
						
							|  |  |  |           var recase = require('connect-recase')({ | 
					
						
							|  |  |  |             // TODO allow explicit and or default flag
 | 
					
						
							|  |  |  |             explicit: false | 
					
						
							|  |  |  |           , default: 'snake' | 
					
						
							|  |  |  |           , prefixes: ['/api'] | 
					
						
							|  |  |  |             // TODO allow exclude
 | 
					
						
							|  |  |  |           //, exclusions: [config.oauthPrefix]
 | 
					
						
							|  |  |  |           , exceptions: {} | 
					
						
							|  |  |  |           //, cancelParam: 'camel'
 | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  |           var bootstrapApp; | 
					
						
							|  |  |  |           var mainApp; | 
					
						
							|  |  |  |           var apiDeps = { | 
					
						
							|  |  |  |             models: models | 
					
						
							|  |  |  |             // TODO don't let packages use this directly
 | 
					
						
							|  |  |  |           , Promise: PromiseA | 
					
						
							|  |  |  |           }; | 
					
						
							|  |  |  |           var apiFactories = { | 
					
						
							|  |  |  |             memstoreFactory: { create: scopeMemstore } | 
					
						
							|  |  |  |           , systemSqlFactory: systemFactory | 
					
						
							|  |  |  |           }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-07 10:49:26 -04:00
										 |  |  |           var hostsmap = {}; | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |           function log(req, res, next) { | 
					
						
							| 
									
										
										
										
											2016-06-07 10:49:26 -04:00
										 |  |  |             var hostname = (req.hostname || req.headers.host || '').split(':').shift(); | 
					
						
							|  |  |  |             console.log('[worker/log]', req.method, hostname, req.url); | 
					
						
							|  |  |  |             if (hostname && !hostsmap[hostname]) { | 
					
						
							|  |  |  |               hostsmap[hostname] = true; | 
					
						
							|  |  |  |               require('fs').writeFile( | 
					
						
							|  |  |  |                 require('path').join(__dirname, '..', '..', 'var', 'hostnames', hostname) | 
					
						
							|  |  |  |               , hostname, function () {}); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |             next(); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           function setupMain() { | 
					
						
							| 
									
										
										
										
											2017-05-10 23:26:25 +00:00
										 |  |  |             if (xconfx.debug) { console.log('[main] setup'); } | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |             mainApp = express(); | 
					
						
							|  |  |  |             require('./main').create(mainApp, xconfx, apiFactories, apiDeps).then(function () { | 
					
						
							| 
									
										
										
										
											2017-05-10 23:26:25 +00:00
										 |  |  |               if (xconfx.debug) { console.log('[main] ready'); } | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |               // TODO process.send({});
 | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           if (!bootstrapApp) { | 
					
						
							| 
									
										
										
										
											2017-05-10 23:26:25 +00:00
										 |  |  |             if (xconfx.debug) { console.log('[bootstrap] setup'); } | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |             bootstrapApp = express(); | 
					
						
							|  |  |  |             require('./bootstrap').create(bootstrapApp, xconfx, models).then(function () { | 
					
						
							| 
									
										
										
										
											2017-05-10 23:26:25 +00:00
										 |  |  |               if (xconfx.debug) { console.log('[bootstrap] ready'); } | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |               // TODO process.send({});
 | 
					
						
							|  |  |  |               setupMain(); | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2015-11-14 04:25:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |           process.on('message', function (data) { | 
					
						
							|  |  |  |             if ('com.daplie.walnut.bootstrap' === data.type) { | 
					
						
							|  |  |  |               setupMain(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           }); | 
					
						
							| 
									
										
										
										
											2015-11-14 04:25:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |           app.disable('x-powered-by'); | 
					
						
							|  |  |  |           app.use('/', log); | 
					
						
							|  |  |  |           app.use('/api', require('body-parser').json({ | 
					
						
							| 
									
										
										
										
											2015-11-14 04:25:12 +00:00
										 |  |  |             strict: true // only objects and arrays
 | 
					
						
							|  |  |  |           , inflate: true | 
					
						
							|  |  |  |             // limited to due performance issues with JSON.parse and JSON.stringify
 | 
					
						
							|  |  |  |             // http://josh.zeigler.us/technology/web-development/how-big-is-too-big-for-json/
 | 
					
						
							|  |  |  |           //, limit: 128 * 1024
 | 
					
						
							|  |  |  |           , limit: 1.5 * 1024 * 1024 | 
					
						
							|  |  |  |           , reviver: undefined | 
					
						
							|  |  |  |           , type: 'json' | 
					
						
							|  |  |  |           , verify: undefined | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |           })); | 
					
						
							|  |  |  |           app.use('/api', recase); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-04 23:09:56 -06:00
										 |  |  |           app.set('trust proxy', ['loopback', 'linklocal', 'uniquelocal']); | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |           app.use('/', function (req, res) { | 
					
						
							| 
									
										
										
										
											2017-05-04 23:09:56 -06:00
										 |  |  |             if (!(req.encrypted || req.secure)) { | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |               // did not come from https
 | 
					
						
							|  |  |  |               if (/\.(appcache|manifest)\b/.test(req.url)) { | 
					
						
							|  |  |  |                 require('./unbrick-appcache').unbrick(req, res); | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |               } | 
					
						
							| 
									
										
										
										
											2017-05-04 23:09:56 -06:00
										 |  |  |               res.end("Connection is not encrypted. That's no bueno or, as we say in Hungarian, nem szabad!"); | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |               return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // TODO check https://letsencrypt.status.io to see if https certification is not available
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (mainApp) { | 
					
						
							|  |  |  |               mainApp(req, res); | 
					
						
							|  |  |  |               return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else { | 
					
						
							|  |  |  |               bootstrapApp(req, res); | 
					
						
							|  |  |  |               return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           return app; | 
					
						
							| 
									
										
										
										
											2015-11-19 07:42:20 +00:00
										 |  |  |         }); | 
					
						
							| 
									
										
										
										
											2015-11-12 11:14:59 +00:00
										 |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2015-11-06 11:05:32 +00:00
										 |  |  | }; |