UNPKG

node-sitefile

Version:

Bootstrap Express webserver for misc. resources using Sitefile

279 lines (241 loc) 7.41 kB
fs = require 'fs' path = require 'path' cc = require 'coffee-script' _ = require 'lodash' pm2_app_defaults = ( obj ) -> _.defaultsDeep obj, { name: null pid: null pm_id: null pm2_env: status: null cwd: null pm_uptime: null pm_exec_path: null ENV: null versioning: {} } class PM2Config constructor: ( @cwd ) -> @pm2_config = [] @pm2_config_dir = null @pm2_config_file = null load: ( filename ) -> @pm2_config_file = filename if path.dirname(filename) != filename @pm2_config_dir = path.join @cwd, path.dirname filename if not fs.existsSync @pm2_config_dir throw new Error "Directory should exist: #{filename}" @pm2_config_file = path.join @cwd, filename if fs.existsSync @pm2_config_file @pm2_config = require(@pm2_config_file).apps for pm2_proc in @pm2_config pm2_app_defaults pm2_proc class PM2Dump constructor: ( @cwd ) -> @pm2_dump = [] @pm2_dump_dir = null @pm2_dump_file = null load: ( filename ) -> @pm2_dump_file = filename @pm2_dump_file = path.join @cwd, filename if not fs.existsSync @pm2_dump_file throw new Error "No such file #{filename}" @pm2_dump = require(@pm2_dump_file) class PM2Manager constructor: ( @cwd ) -> @procs = [] add: ( pm2_proc ) -> pm2_app_defaults pm2_proc @procs.push pm2_proc save: -> load: ( filename ) -> cfg = new PM2Config @cwd cfg.load filename @procs = cfg.pm2_config get_by_id: ( app_id) -> for app in @procs if app.pm_id == app_id return app get_by_name: ( app_name ) -> for app in @procs if app.name == app_name return app update_by_name: ( app ) -> for pm2_proc in @procs if app.name == pm2_proc.name _.merge pm2_proc, app name_exists: ( app_name ) -> for app in @procs if app.name == app_name return true return false module.exports = ( ctx ) -> try pug = require 'pug' pm2 = require 'pm2' catch return httprouter = require('./http') ctx pugrouter = require('./pug') ctx detailPugFn = path.join( __dirname, 'pm2/view/detail.pug' ) listPugFn = path.join( __dirname, 'pm2/view/list.pug' ) listCoffeeFn = path.join( __dirname, 'pm2/view/list.coffee' ) ### TODO: PM2Manager dump/config loader m = new PM2Manager ctx.cwd # If given, use spec for JSON config file if rctx.route.spec and rctx.route.spec != '#' m.load rctx.route.spec pm2.list (err, ps_list) -> for app in ps_list if m.name_exists app.name m.update_by_name app else m.add app ### generators = default: ( rctx ) -> # FIXME: allow string descriptions; # auto-export routes based on route.default mapping # XXX: console.log 'PM2', ctx.site.base, rctx.name, rctx.res, rctx.route route = '.json': get: generators.list '-data.json': get: generators.data '.js': get: generators.script '.html': get: generators.view '/:pm_id.html': get: generators['view/app'] '/:pm_id.json': get: generators['data/app'] '/:pm_id/start': post: generators.start '/:pm_id/reload': post: generators.reload '/:pm_id/restart': post: generators.reload '/:pm_id/stop': post: generators.stop '': get: (rctx) -> (req, res) -> res.redirect ctx.site.base+rctx.name+'.html' '/': get: (rctx) -> (req, res) -> res.redirect ctx.site.base+rctx.name+'.html' # TODO: see r0.0.6 for module generate export scheme for name of route for method of route[name] ref = ctx.site.base+rctx.name+name unless "function" is typeof route[name][method] throw Error \ "Expected callback #{name}:#{method}:#{route[name][method]}" r = route[name][method] rctx if "object" is typeof r throw Error "Expected callback #{name}:#{method}:#{r}" ctx.app[method] ref, r null # List all PM2 procs in JSON data: ( rctx ) -> (req, res) -> res.type 'json' res.write JSON.stringify m.procs res.end() list: ( rctx ) -> (req, res) -> pm2.list (err, ps_list) -> res.type 'json' if err res.status 500 res.write JSON.stringify ps_list res.end() # Describe single PM2 proc in JSON 'data/app': ( rctx ) -> (req, res) -> pm2.describe req.params.pm_id, (err, ps_list) -> res.type 'json' if err res.status 500 res.write JSON.stringify ps_list[0] res.end() start: ( rctx ) -> (req, res) -> pm2.gracefulReload req.params.pm_id, ( err ) -> res.type 'txt' if err res.status 500 res.write err res.end() stop: ( rctx ) -> (req, res) -> pm2.stop req.params.pm_id, ( err ) -> res.type 'txt' if err res.status 500 res.write err res.end() reload: ( rctx ) -> (req, res) -> pm2.gracefulReload req.params.pm_id, ( err ) -> res.type 'txt' if err res.status 500 res.write err res.end() # Serve JS for view(s?) script: ( rctx ) -> (req, res) -> res.type 'js' res.write cc._compileFile listCoffeeFn res.end() # XXX: pm2_proc = m.get_by_id parseInt req.params.pm_id, 10 # Serve HTML list view view: ( rctx ) -> (req, res) -> httprouter.promise.resource( hostname: 'localhost' port: ctx.app.get('port') path: ctx.site.base + rctx.name + '.json' ).then ( apps ) -> res.type 'html' res.write pugrouter.compile listPugFn, { compile: rctx.route.options.compile merge: pid: process.pid pm2_base: ctx.site.base+rctx.name script: ctx.site.base+rctx.name+'.js' options: rctx.options query: req.query context: rctx apps: apps } res.end() # Serve PM2 proc HTML details 'view/app': ( rctx ) -> (req, res) -> console.log req.path.substring(0, req.path.length - 5) + '.json' httprouter.promise.json( hostname: 'localhost' port: ctx.app.get('port') path: req.path.substring(0, req.path.length - 5) + '.json' ).then ( app ) -> res.type 'html' res.write pugrouter.compile detailPugFn, { compile: rctx.route.options.compile merge: pid: process.pid pm2_base: ctx.site.base+rctx.name script: ctx.site.base+rctx.name+'.js' options: rctx.route.options query: req.query context: rctx app: app } res.end() ### # TODO: see r0.0.6 route: default: '/': 'redir:pm2.html' '.json': '.data' '.html': '.view' '.js': '.script' '/:pm_id.json': '.data/app' '/:pm_id.html': '.view/app' '/:pm_id/start': '.start' '/:pm_id/reload': '.reload' '/:pm_id/stop': '.stop' ### name: 'pm2' generate: generators