Permalink
Browse files

0.0.9 sigint sigusr2 better watchdelay warning coloring apprunner

  • Loading branch information...
1 parent 46a3361 commit a907cd10efa76a86940e07dbf0d27ba627eacce4 @haraldrudell committed Sep 11, 2012
Showing with 419 additions and 329 deletions.
  1. +1 −0 .gitignore
  2. +15 −5 app.js
  3. +35 −1 lib/appentity.js
  4. +1 −1 lib/childmanager.js
  5. +9 −0 lib/godmodel.js
  6. +107 −0 lib/requesturl.js
  7. +1 −1 lib/watchcopy.js
  8. +1 −0 lib/watchit.js
  9. +21 −13 package.json
  10. +39 −1 public/javascripts/frontgod.js
  11. +97 −4 public/stylesheets/style.css
  12. +1 −0 routes/godview.js
  13. +17 −263 test/test-package.js
  14. +31 −12 views/index.ejs
  15. +43 −28 views/partials/app.ejs
View
@@ -1,3 +1,4 @@
/node_modules
/test/data/tofolder
/test/data/tofolder2
+/*-cov
View
20 app.js
@@ -1,18 +1,24 @@
// Node God
// keeps node apps running
-var haraldops = require('haraldops')
-var defaults = haraldops.init({
- appName: 'Node God',
- sessionSecret: 'veryGreat', PORT: 1111 })
+var defaults = require('haraldops').init({appName: 'Node God',
+ appFolder: __dirname,
+ sessionSecret: 'veryGreat',
+ PORT: 1111 })
// https://github.com/visionmedia/express
var express = require('express')
+var apprunner = require('apprunner')
+apprunner.enableAnomalyMail(false)
+var cbc = apprunner.getCbCounter(/*{callback: initAppResult}*/)
+
+// get app and start error listener
+var app = module.exports = express.createServer()
+apprunner.initApp(defaults, app, cbc.add(initAppResult))
var godcontrol = require('./lib/godcontrol')
var godview = require('./routes/godview')
// Configuration
-var app = module.exports = express.createServer()
godview.setTitle(defaults.init.appName)
godcontrol.init(app, defaults)
app.configure(function(){
@@ -54,6 +60,10 @@ app.listen(defaults.PORT, function(){
app.settings.env)
})
*/
+
+function initAppResult(err) {
+ if (err) throw err
+}
app.listen(defaults.PORT, defaults.appInterface)
//app.listen(defaults.worldPort)
console.log('Application %s on node %s available on port %s in %s mode',
View
@@ -1,5 +1,7 @@
// appentity.js
+// © Harald Rudell 2012
+var requesturl = require('apprunner').getApi({api: 'requesturl'})
var watchit = require('./watchit')
var watchcopy = require('./watchcopy')
var appstate = require('./appstate')
@@ -34,6 +36,10 @@ function AppEntity(conf) {
var lastLaunch
var lastCrash
var pid
+ var webInfo = {
+ PORT: 0,
+ URL: '',
+ }
// init file watchers
var myWatch = new watchit.WatchIt(doWatcherRestart, watchNotify)
@@ -57,6 +63,7 @@ function AppEntity(conf) {
var doWatch
var restart
var count = 0
+ conf.signal = o.signal
conf.name = o.name
if (stringOrArrayDifferent(conf.start, o.start)) {
@@ -99,7 +106,31 @@ function AppEntity(conf) {
appState.doCommand('restart')
}
- function childCallback(event, value) {
+ function webInfoCb(err, data) {
+ if (!err) {
+ if (!isSame(webInfo, data)) {
+ webInfo = data
+ sendUpdate()
+ }
+ } else console.error(err) // TODO
+ }
+
+ function isSame(o1, o2) {
+ var t1 = typeof o1
+ var same = t1 == typeof o2
+ if (same && t1 == 'object') {
+ var keys = Object.keys(o1)
+ var same = keys.length == Object.keys(o2).length
+ if (same) {
+ same = keys.every(function (prop) {
+ return o1[prop] == o2[prop]
+ })
+ }
+ }
+ return same
+ }
+
+ function childCallback(event, value, val2) {
switch (event) {
case 'exit':
exitCode = value
@@ -113,6 +144,7 @@ function AppEntity(conf) {
else write = false
if (write) myStore.save()
}
+ if (pid && !val2 && conf.signal) requesturl.requestUrl(pid, webInfoCb)
break
case 'state':
switch (value) {
@@ -167,6 +199,8 @@ function AppEntity(conf) {
exitCode: exitCode,
pid: pid,
watchers: myWatch.getCount(),
+ port: webInfo && webInfo.PORT || 0,
+ url: webInfo && webInfo.URL || '',
}
}
View
@@ -33,7 +33,7 @@ function childManager(cb, stateChange) {
if (debug) args.unshift('--debug-brk')
didKill = false
child = child_process.spawn('node', args)
- cb('pid', child.pid)
+ cb('pid', child.pid, debug)
child.stdout.on('data', log)
child.stderr.on('data', log)
child.on('exit', function (code) {
View
@@ -1,6 +1,7 @@
// nodegod.js
var getfilenames = require('./getfilenames')
+var apprunner = require('apprunner')
// https://github.com/haraldrudell/haraldops
var haraldops = require('haraldops')
// https://github.com/haraldrudell/haraldutil
@@ -24,6 +25,7 @@ var appFiles = {}
var apps = {}
var parentFolder
var launchedBrowser
+var signal = false
// defaults come from haraldops
function loadAppFiles(defaults) {
@@ -35,8 +37,13 @@ function loadAppFiles(defaults) {
defaults.init.identifier + 'store.json'))
appentity.setStore(myStore)
+ if (typeof defaults.signal == 'boolean') signal = defaults.signal
+
// default parentFolder is the parent folder of our application folder
parentFolder = path.join(defaults.init.appFolder, '..')
+ try {
+ apprunner.getApi({api: 'requesturl'}).setTmpFolder(defaults.init.tmpFolder)
+ } catch (e) {}
// find files containing app configurations
var fileArray = defaults.appFiles
@@ -78,6 +85,8 @@ console.log(arguments.callee.name, filename)
o.state = fileApp.state || 'run'
o.watchFiles = fileApp.watchFiles
o.watchCopy = fileApp.watchCopy
+ o.signal = typeof fileApp.signal == 'boolean' ?
+ fileApp.signal : signal
if (fileApp.launchBrowser && !launchedBrowser) {
launchedBrowser = true
View
@@ -0,0 +1,107 @@
+// requesturl.js
+// fetch the port and url of another process
+// © Harald Rudell 2012
+
+// https://github.com/haraldrudell/haraldutil
+var haraldutil = require('haraldutil')
+// https://github.com/haraldrudell/greatjson
+var greatjson = require('greatjson')
+// http://nodejs.org/api/fs.html
+var fs = require('fs')
+// http://nodejs.org/api/path.html
+var path = require('path')
+// http://nodejs.org/api/events.html
+var events = require('events')
+if (!fs.exists) fs.exists = path.exists
+
+exports.initApi = initApi
+
+var emitter = new events.EventEmitter()
+emitter.id = 'Request URL'
+
+function initApi(opts, cb) {
+ return {
+ emitter: emitter,
+ requestUrl: requestUrl,
+ setTmpFolder: setTmpFolder,
+ }
+}
+
+var tmpFolder
+
+function requestUrl(pid, cb) {
+ var result
+ var err
+
+ // must have pid and folder
+ if (!tmpFolder || !pid) end()
+
+ var file = path.join(tmpFolder, pid + '.json')
+ readDelete(file, false, rmResult)
+
+ function rmResult(err) {
+ if (!err) {
+ // allow 2 seconds for the app to start
+ if (!err) setTimeout(sendSignal, 2000)
+ } else end(err)
+ }
+
+ function sendSignal() {
+ var isDone
+
+ // instruct process to write to filesystem
+ try {
+ // returns true
+//console.log(arguments.callee.name, pid)
+ var x = process.kill(pid, 'SIGUSR2')
+ } catch (e) {
+ // if process can't be found, it probably died already
+ if (e instanceof Error && e.code == 'ESRCH') end()
+ else end(e)
+ isDone = true
+ }
+
+ // allow 0.5 seconds for process to complete
+ if (!isDone) setTimeout(fetchData, 500)
+ }
+
+ function fetchData() {
+ readDelete(file, true, end)
+ }
+
+ function end(err, data) {
+ if (err) emitter.emit.apply(this, ['error'].concat( Array.prototype.slice.call(arguments)))
+ cb(err, data)
+ }
+}
+
+function readDelete(file, doRead, cb) {
+ var result
+ fs.exists(file, existsResult)
+
+ function existsResult(exists) {
+ if (exists) {
+ if (doRead) fs.readFile(file, readResult)
+ else fs.unlink(file, cb)
+ } else cb()
+ }
+
+ function readResult(err, data) {
+ if (!err) {
+ var obj = greatjson.parse(data)
+ if (!(obj instanceof Error)) {
+ result = obj
+ fs.unlink(file, rmResult)
+ }
+ else cb(obj)
+ } else cb(err)
+ }
+
+ function rmResult(err) {
+ cb(err, result)
+ }
+}
+
+function setTmpFolder(folder) {
+ tmpFolder = folder
+}
View
@@ -48,7 +48,7 @@ function watchCopy(id) {
copy.forEach(function (instance) {
copyWatchCount += instance.watchers.length
})
- console.log(arguments.callee.name, id, 'watchers:', copyWatchCount)
+//console.log(arguments.callee.name, id, 'watchers:', copyWatchCount)
}
function addInstance(instance, count) {
View
@@ -1,5 +1,6 @@
// watchit.js
// watch file modifications
+// © Harald Rudell 2012
// http://nodejs.org/docs/latest/api/fs.html
var fs = require('fs')
View
@@ -2,8 +2,13 @@
"name": "nodegod",
"description": "Web interface supervising node apps with dashboard and restart on file changes and exits by Harald Rudell",
"author": "Harald Rudell <harald@allgoodapps.com> (http://www.haraldrudell.com)",
- "keywords": ["app", "management", "node", "operations"],
- "version": "0.0.8",
+ "keywords": [
+ "app",
+ "management",
+ "node",
+ "operations"
+ ],
+ "version": "0.0.9",
"contributors": [
{
"name": "Harald Rudell",
@@ -12,25 +17,28 @@
}
],
"devDependencies": {
- "greatjson": ">= 0.0.8",
- "uglify-js": "",
- "nodeunit": ""
+ "mochawrapper": "*"
},
"dependencies": {
- "ejsinbrowser": "*",
+ "greatjson": ">= 0.0.8",
"request": "*",
- "express": "< 3",
- "ejs": "*",
"socket.io": "*",
"haraldutil": ">= 0.1.5",
+ "ejsinbrowser": "*",
+ "ejs": "*",
+ "express": "< 3",
+ "apprunner": "*",
"haraldops": ">= 0.1.3"
},
- "repository" : {
- "type" : "git",
- "url" : "https://haraldrudell@github.com/haraldrudell/nodegod.git"
+ "repository": {
+ "type": "git",
+ "url": "https://haraldrudell@github.com/haraldrudell/nodegod.git"
},
"scripts": {
"start": "node app",
- "test": "nodeunit test"
+ "test": "mocha --ui exports --reporter spec",
+ "monitor": "mocha --ui exports --reporter min --watch",
+ "debugtest": "mocha --debug-brk --ui exports --reporter spec",
+ "coverage": "mochacoverage"
}
-}
+}
Oops, something went wrong.

0 comments on commit a907cd1

Please sign in to comment.