forked from coolaj86/walnut.js
		
	load services
This commit is contained in:
		
							parent
							
								
									96b7c9bb65
								
							
						
					
					
						commit
						78178eb43d
					
				| @ -78,6 +78,10 @@ cluster.on('online', function (worker) { | |||||||
|       info.conf.ipcKey = conf.ipcKey; |       info.conf.ipcKey = conf.ipcKey; | ||||||
|       info.conf.memstoreSock = conf.memstoreSock; |       info.conf.memstoreSock = conf.memstoreSock; | ||||||
|       info.conf.sqlite3Sock = conf.sqlite3Sock; |       info.conf.sqlite3Sock = conf.sqlite3Sock; | ||||||
|  |       // TODO get this from db config instead
 | ||||||
|  |       var config = require('../config'); | ||||||
|  |       info.conf.primaryNameserver = config.primaryNameserver; | ||||||
|  |       info.conf.nameservers = config.nameservers; | ||||||
|       worker.send(info); |       worker.send(info); | ||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -20,6 +20,10 @@ module.exports.create = function (conf, deps, app) { | |||||||
| 
 | 
 | ||||||
|     return new PromiseA(function (resolve, reject) { |     return new PromiseA(function (resolve, reject) { | ||||||
|       try { |       try { | ||||||
|  |         // TODO dynamic requires are a no-no
 | ||||||
|  |         // can we statically generate a require-er? on each install?
 | ||||||
|  |         // module.exports = { {{pkgpath}}: function () { return require({{pkgpath}}) } }
 | ||||||
|  |         // requirer[pkgpath]()
 | ||||||
|         route.route = require(pkgpath).create(conf, deps, app); |         route.route = require(pkgpath).create(conf, deps, app); | ||||||
|       } catch(e) { |       } catch(e) { | ||||||
|         reject(e); |         reject(e); | ||||||
|  | |||||||
							
								
								
									
										113
									
								
								lib/services-loader.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								lib/services-loader.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,113 @@ | |||||||
|  | 'use strict'; | ||||||
|  | 
 | ||||||
|  | module.exports.create = function (conf, deps) { | ||||||
|  |   var PromiseA = deps.Promise; | ||||||
|  | 
 | ||||||
|  |   function loadService(node) { | ||||||
|  |     var path = require('path'); | ||||||
|  | 
 | ||||||
|  |     return new PromiseA(function (resolve) { | ||||||
|  |       // process.nextTick runs at the end of the current event loop
 | ||||||
|  |       // we actually want time to pass so that potential api traffic can be handled
 | ||||||
|  |       setTimeout(function () { | ||||||
|  |         var servicepath = path.join(conf.servicespath, node); | ||||||
|  |         var pkg; | ||||||
|  | 
 | ||||||
|  |         try { | ||||||
|  |           // TODO no package should be named package.json
 | ||||||
|  |           pkg = require(servicepath + '/package.json'); | ||||||
|  |           resolve({ | ||||||
|  |             pkg: pkg | ||||||
|  |           , name: node | ||||||
|  |           , service: require(servicepath) | ||||||
|  |           }); | ||||||
|  |           return; | ||||||
|  |         } catch(e) { | ||||||
|  |           // TODO report errors to admin console
 | ||||||
|  |           // TODO take sha256sum of e.stack and store in db with tick for updatedAt
 | ||||||
|  |           console.error("[Service] could not require service '" + servicepath + "'"); | ||||||
|  |           console.error(e.stack); | ||||||
|  |           //services.push({ error: e });
 | ||||||
|  |           resolve(null); | ||||||
|  |           return; | ||||||
|  |         } | ||||||
|  |       }, 1); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function loadServices() { | ||||||
|  |     var fs = PromiseA.promisifyAll(require('fs')); | ||||||
|  | 
 | ||||||
|  |     // deps : { memstore, sqlstores, clientSqlFactory, systemSqlFactory }
 | ||||||
|  |      | ||||||
|  |     // XXX this is a no-no (file system access in a worker, cannot be statically analyzed)
 | ||||||
|  |     // TODO regenerate a static file of all requires on each install
 | ||||||
|  |     // TODO read system config db to find which services auto-start
 | ||||||
|  |     // TODO allow certain apis access to certain services
 | ||||||
|  |     return fs.readdirAsync(conf.servicespath).then(function (nodes) { | ||||||
|  |       var promise = PromiseA.resolve(); | ||||||
|  |       var services = []; | ||||||
|  |        | ||||||
|  |       nodes.forEach(function (node) { | ||||||
|  |         promise = promise.then(function () { | ||||||
|  |           return loadService(node).then(function (srv) { | ||||||
|  |             if (!srv) { | ||||||
|  |               return; | ||||||
|  |             } | ||||||
|  |             services.push(srv); | ||||||
|  |           }); | ||||||
|  |         }); | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |       return promise.then(function () { | ||||||
|  |         return services; | ||||||
|  |       }); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function startService(srv) { | ||||||
|  |     return new PromiseA(function (resolve) { | ||||||
|  |       // process.nextTick runs at the end of the current event loop
 | ||||||
|  |       // we actually want time to pass so that potential api traffic can be handled
 | ||||||
|  |       setTimeout(function () { | ||||||
|  |         try { | ||||||
|  |           PromiseA.resolve(srv.service.create(conf, deps)).then(resolve, function (e) { | ||||||
|  |             console.error("[Service] couldn't promise service"); | ||||||
|  |             console.error(e.stack); | ||||||
|  |             resolve(null); | ||||||
|  |           }); | ||||||
|  |           return; | ||||||
|  |         } catch(e) { | ||||||
|  |           console.error("[Service] couldn't start service"); | ||||||
|  |           console.error(e.stack); | ||||||
|  |           resolve(null); | ||||||
|  |           return; | ||||||
|  |         } | ||||||
|  |       }, 1); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function startServices(services) { | ||||||
|  |     var promise = PromiseA.resolve(); | ||||||
|  |     var servicesMap = {}; | ||||||
|  |      | ||||||
|  |     services.forEach(function (srv) { | ||||||
|  |       promise = promise.then(function () { | ||||||
|  |         return startService(srv).then(function (service) { | ||||||
|  |           if (!service) { | ||||||
|  |             // TODO log
 | ||||||
|  |             return null; | ||||||
|  |           } | ||||||
|  |           srv.service = service; | ||||||
|  |           servicesMap[srv.name] = srv; | ||||||
|  |         });  | ||||||
|  |       }); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     return promise.then(function () { | ||||||
|  |       return servicesMap; | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   return loadServices().then(startServices); | ||||||
|  | }; | ||||||
| @ -11,6 +11,7 @@ module.exports.create = function (webserver, info, state) { | |||||||
|   var express = require('express-lazy'); |   var express = require('express-lazy'); | ||||||
|   var app = express(); |   var app = express(); | ||||||
|   var apiHandler; |   var apiHandler; | ||||||
|  |   var Services; | ||||||
|   var memstore; |   var memstore; | ||||||
|   var sqlstores = {}; |   var sqlstores = {}; | ||||||
|   var models = {}; |   var models = {}; | ||||||
| @ -110,6 +111,8 @@ module.exports.create = function (webserver, info, state) { | |||||||
|   app.use('/', caddyBugfix); |   app.use('/', caddyBugfix); | ||||||
| 
 | 
 | ||||||
|   return PromiseA.all([ |   return PromiseA.all([ | ||||||
|  |     // TODO security on memstore
 | ||||||
|  |     // TODO memstoreFactory.create
 | ||||||
|     cstore.create({ |     cstore.create({ | ||||||
|       sock: info.conf.memstoreSock |       sock: info.conf.memstoreSock | ||||||
|     , connect: info.conf.memstoreSock |     , connect: info.conf.memstoreSock | ||||||
| @ -146,14 +149,28 @@ module.exports.create = function (webserver, info, state) { | |||||||
|     return require('../lib/schemes-config').create(sqlstores.config).then(function (tables) { |     return require('../lib/schemes-config').create(sqlstores.config).then(function (tables) { | ||||||
|       models.Config = tables; |       models.Config = tables; | ||||||
|       return models.Config.Config.get().then(function (vhostsMap) { |       return models.Config.Config.get().then(function (vhostsMap) { | ||||||
|  |         // TODO the core needs to be replacable in one shot
 | ||||||
|  |         // rm -rf /tmp/walnut/; tar xvf -C /tmp/walnut/; mv /srv/walnut /srv/walnut.{{version}}; mv /tmp/walnut /srv/
 | ||||||
|  |         // this means that any packages must be outside, perhaps /srv/walnut/{boot,core,packages}
 | ||||||
|  |         var apiConf = { | ||||||
|  |           apppath: '../packages/apps/' | ||||||
|  |         , apipath: '../packages/apis/' | ||||||
|  |         , servicespath: path.join(__dirname, '..', 'packages', 'services') | ||||||
|  |         , vhostsMap: vhostsMap | ||||||
|  |         , server: webserver | ||||||
|  |         , externalPort: info.conf.externalPort | ||||||
|  |         , primaryNameserver: info.conf.primaryNameserver | ||||||
|  |         , nameservers: info.conf.nameservers | ||||||
|  |         , apiPrefix: '/api' | ||||||
|  |         }; | ||||||
| 
 | 
 | ||||||
|         /* |         Services = require('./services-loader').create(apiConf, { | ||||||
|           // todo getDomainInfo
 |           memstore: memstore | ||||||
|           var utils = require('./utils'); |         , sqlstores: sqlstores | ||||||
|           results.domains.forEach(function (domain) { |         , clientSqlFactory: clientFactory | ||||||
|             utils.getDomainInfo(domain.id); |         , systemSqlFactory: systemFactory | ||||||
|  |         , Promise: PromiseA | ||||||
|         }); |         }); | ||||||
|         */ |  | ||||||
| 
 | 
 | ||||||
|         function handleApi(req, res, next) { |         function handleApi(req, res, next) { | ||||||
|           var myApp; |           var myApp; | ||||||
| @ -183,29 +200,22 @@ module.exports.create = function (webserver, info, state) { | |||||||
|             return; |             return; | ||||||
|           } |           } | ||||||
| 
 | 
 | ||||||
|           // apiHandler = require('./vhost-server').create(info.localPort, vhostsdir).create(webserver, app)
 |           // apiHandler = require('./vhost-server').create(info.conf.localPort, vhostsdir).create(webserver, app)
 | ||||||
|           myApp = express(); |           myApp = express(); | ||||||
|           if (app.get('trust proxy')) { |           if (app.get('trust proxy')) { | ||||||
|             myApp.set('trust proxy', app.get('trust proxy')); |             myApp.set('trust proxy', app.get('trust proxy')); | ||||||
|           } |           } | ||||||
|           apiHandler = require('./api-server').create( |           apiHandler = require('./api-server').create(apiConf, { | ||||||
|             { apppath: '../packages/apps/' |             app: myApp | ||||||
|             , apipath: '../packages/apis/' |  | ||||||
|             , vhostsMap: vhostsMap |  | ||||||
|             , server: webserver |  | ||||||
|             , externalPort: info.externalPort |  | ||||||
|             , apiPrefix: '/api' |  | ||||||
|             } |  | ||||||
|           , { app: myApp |  | ||||||
|           , memstore: memstore |           , memstore: memstore | ||||||
|           , sqlstores: sqlstores |           , sqlstores: sqlstores | ||||||
|           , clientSqlFactory: clientFactory |           , clientSqlFactory: clientFactory | ||||||
|           , systemSqlFactory: systemFactory |           , systemSqlFactory: systemFactory | ||||||
|           //, handlePromise: require('./lib/common').promisableRequest;
 |           //, handlePromise: require('./lib/common').promisableRequest;
 | ||||||
|           //, handleRejection: require('./lib/common').rejectableRequest;
 |           //, handleRejection: require('./lib/common').rejectableRequest;
 | ||||||
|             //, localPort: info.localPort
 |           //, localPort: info.conf.localPort
 | ||||||
|             } |           , Promise: PromiseA | ||||||
|           ).api; |           }, Services).api; | ||||||
| 
 | 
 | ||||||
|           apiHandler(req, res, next); |           apiHandler(req, res, next); | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -86,6 +86,7 @@ | |||||||
|     "mime-db": "^1.8.0", |     "mime-db": "^1.8.0", | ||||||
|     "mime-types": "^2.0.10", |     "mime-types": "^2.0.10", | ||||||
|     "ms": "^0.7.0", |     "ms": "^0.7.0", | ||||||
|  |     "native-dns": "^0.7.0", | ||||||
|     "negotiator": "^0.5.1", |     "negotiator": "^0.5.1", | ||||||
|     "node-pre-gyp": "^0.6.4", |     "node-pre-gyp": "^0.6.4", | ||||||
|     "node-uuid": "^1.4.4", |     "node-uuid": "^1.4.4", | ||||||
|  | |||||||
| @ -22,5 +22,9 @@ Math.random = function () { | |||||||
| if (cluster.isMaster) { | if (cluster.isMaster) { | ||||||
|   require('./boot/master'); |   require('./boot/master'); | ||||||
| } else { | } else { | ||||||
|  |   /* | ||||||
|  |   alternately we could use this and then check require.main | ||||||
|  |   cluster.setupMaster({ exec : "app.js", }); | ||||||
|  |   */ | ||||||
|   require('./boot/worker').create(null); |   require('./boot/worker').create(null); | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user