From 73d4576b0db5095f8de36801c1ae8bcab59010c9 Mon Sep 17 00:00:00 2001 From: Zane Shannon Date: Tue, 16 Sep 2014 12:33:05 -0500 Subject: [PATCH 1/7] added tests for /apps.json endpoint --- test/test_http_server.coffee | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/test_http_server.coffee b/test/test_http_server.coffee index 2ee994c..c0386a7 100644 --- a/test/test_http_server.coffee +++ b/test/test_http_server.coffee @@ -262,3 +262,11 @@ module.exports = testCase test.same 200, response.statusCode test.same server.toJSON(), JSON.parse body done -> test.done() + + "http://pow/apps.json": (test) -> + test.expect 2 + serveRoot "apps", (request, done, server) -> + request "GET", "/apps.json", host: "pow", (body, response) -> + test.same 200, response.statusCode + test.same server.runningApps(), JSON.parse body + done -> test.done() \ No newline at end of file From dede0c91455b92ed539f559dba4bed8cee5772be Mon Sep 17 00:00:00 2001 From: Zane Shannon Date: Tue, 16 Sep 2014 12:35:14 -0500 Subject: [PATCH 2/7] added started time. added toJSON() --- lib/rack_application.js | 10 ++++++++++ src/rack_application.coffee | 9 +++++++++ 2 files changed, 19 insertions(+) diff --git a/lib/rack_application.js b/lib/rack_application.js index 643b1d8..6861d47 100644 --- a/lib/rack_application.js +++ b/lib/rack_application.js @@ -23,6 +23,15 @@ this.statCallbacks = []; } + RackApplication.prototype.toJSON = function() { + return { + root: this.root, + host: this.firstHost, + started: this.started, + mtime: this.mtime + }; + }; + RackApplication.prototype.ready = function(callback) { if (this.state === "ready") { return callback(); @@ -164,6 +173,7 @@ _this.logger.error("stderr: " + err.stderr); } else { _this.state = "ready"; + _this.started = +(new Date); _this.pool = nack.createPool(join(_this.root, "config.ru"), { env: env, size: (_ref2 = env != null ? env.POW_WORKERS : void 0) != null ? _ref2 : _this.configuration.workers, diff --git a/src/rack_application.coffee b/src/rack_application.coffee index d8bd0bf..256d077 100644 --- a/src/rack_application.coffee +++ b/src/rack_application.coffee @@ -41,6 +41,14 @@ module.exports = class RackApplication @quitCallbacks = [] @statCallbacks = [] + # Gets an object describing the server's current status that can be + # passed to `JSON.stringify`. + toJSON: -> + root: @root + host: @firstHost + started: @started + mtime: @mtime + # Queue `callback` to be invoked when the application becomes ready, # then start the initialization process. If the application's state # is ready, the callback is invoked immediately. @@ -160,6 +168,7 @@ module.exports = class RackApplication # the application's environment or the global configuration. else @state = "ready" + @started = +new Date @pool = nack.createPool join(@root, "config.ru"), env: env From d1fb4eaaa0191b8e068fc3f9272b75aa60cb30aa Mon Sep 17 00:00:00 2001 From: Zane Shannon Date: Tue, 16 Sep 2014 12:35:50 -0500 Subject: [PATCH 3/7] added runningApps(). added /apps.json endpoint. --- lib/http_server.js | 13 +++++++++++++ src/http_server.coffee | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/lib/http_server.js b/lib/http_server.js index b727d8c..680d05a 100644 --- a/lib/http_server.js +++ b/lib/http_server.js @@ -104,6 +104,16 @@ }; }; + HttpServer.prototype.runningApps = function() { + var apps, rootPath; + + apps = []; + for (rootPath in this.rackApplications) { + apps.push(this.rackApplications[rootPath]); + } + return apps; + }; + HttpServer.prototype.logRequest = function(req, res, next) { this.accessLog.info("[" + req.socket.remoteAddress + "] " + req.method + " " + req.headers.host + " " + req.url); this.requestCount++; @@ -134,6 +144,9 @@ case "/status.json": res.writeHead(200); return res.end(JSON.stringify(this)); + case "/apps.json": + res.writeHead(200); + return res.end(JSON.stringify(this.runningApps())); default: return this.handleLocationNotFound(req, res, next); } diff --git a/src/http_server.coffee b/src/http_server.coffee index dfc853f..52aac77 100644 --- a/src/http_server.coffee +++ b/src/http_server.coffee @@ -83,6 +83,14 @@ module.exports = class HttpServer extends connect.HTTPServer version: version requestCount: @requestCount + # Gets an array of objects describing the server's currently + # running applications passed to `JSON.stringify`. + runningApps: -> + apps = [] + for rootPath of @rackApplications + apps.push @rackApplications[rootPath] + apps + # The first middleware in the stack logs each incoming request's # source address, method, hostname, and path to the access log # (`~/Library/Logs/Pow/access.log` by default). @@ -109,6 +117,8 @@ module.exports = class HttpServer extends connect.HTTPServer # applications inherit. # * `/status.json`: Returns information about the current server # version, number of requests handled, and process ID. + # * `/apps.json`: Returns information about the currently running + # applications from the `rackApplications` instance. # # Third-party utilities may use these endpoints to inspect a running # Pow server. @@ -125,6 +135,9 @@ module.exports = class HttpServer extends connect.HTTPServer when "/status.json" res.writeHead 200 res.end JSON.stringify this + when "/apps.json" + res.writeHead 200 + res.end JSON.stringify @runningApps() else @handleLocationNotFound req, res, next From 8b2bbd9797a6e842a7cd56d8f0c506083a064652 Mon Sep 17 00:00:00 2001 From: Zane Shannon Date: Tue, 16 Sep 2014 12:42:09 -0500 Subject: [PATCH 4/7] added /apps.json endpoint to MANUAL. bumped version in MANUAL and README --- MANUAL.md | 5 +++++ README.md | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/MANUAL.md b/MANUAL.md index bd41ad8..a1abdba 100644 --- a/MANUAL.md +++ b/MANUAL.md @@ -381,6 +381,8 @@ request with the header `Host: pow`. The available endpoints are: environment, which is inherited by each application worker. * `/config.json`: A JSON-encoded object representing the running server's [configuration](http://pow.cx/docs/configuration.html). +* `/apps.json`: A JSON-encoded object representing the running + server's running applications. Example of requesting an endpoint with `curl`: @@ -457,6 +459,9 @@ looks like. ## Version History ## +* **0.4.4** (September 16, 2014): + * Added support for `http://pow/apps.json` endpoint. + * **0.4.3** (April 3, 2014): * Upgrade Nack to 0.16 to fix issues when requiring the json library. diff --git a/README.md b/README.md index 3c7acb4..1427bce 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ ----- -Current Version: **0.4.3** +Current Version: **0.4.4** To install or upgrade Pow, open a terminal and run this command: From 1a390366e34a96c7dda6e86ddacaae5af24e78bb Mon Sep 17 00:00:00 2001 From: Zane Shannon Date: Tue, 16 Sep 2014 12:42:16 -0500 Subject: [PATCH 5/7] bumped version --- install.sh | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/install.sh b/install.sh index 1a5f1c1..6c19a8f 100755 --- a/install.sh +++ b/install.sh @@ -44,7 +44,7 @@ POW_ROOT="$HOME/Library/Application Support/Pow" NODE_BIN="$POW_ROOT/Current/bin/node" POW_BIN="$POW_ROOT/Current/bin/pow" - [[ -z "$VERSION" ]] && VERSION=0.4.3 + [[ -z "$VERSION" ]] && VERSION=0.4.4 # Fail fast if we're not on OS X >= 10.6.0. diff --git a/package.json b/package.json index 9182423..70f9395 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pow" , "description": "Zero-configuration Rack server for Mac OS X" -, "version": "0.4.3" +, "version": "0.4.4" , "author": "Sam Stephenson" , "repository": { "type": "git" From f73572841e743fa85a17fece335bbc7aa8a0cd76 Mon Sep 17 00:00:00 2001 From: Zane Shannon Date: Wed, 17 Sep 2014 00:35:43 -0500 Subject: [PATCH 6/7] added lastRequest timestamp and requestCount to `RackApplication` --- lib/rack_application.js | 4 +++- lib/templates/http_server/layout.html.js | 18 +++++++++--------- .../installer/cx.pow.firewall.plist.js | 2 +- src/rack_application.coffee | 5 +++++ 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/lib/rack_application.js b/lib/rack_application.js index 6861d47..ee09a67 100644 --- a/lib/rack_application.js +++ b/lib/rack_application.js @@ -28,7 +28,8 @@ root: this.root, host: this.firstHost, started: this.started, - mtime: this.mtime + mtime: this.mtime, + lastRequest: this.lastRequestTime }; }; @@ -239,6 +240,7 @@ SERVER_PORT: _this.configuration.dstPort.toString() }; try { + _this.lastRequestTime = +(new Date); return _this.pool.proxy(req, res, function(err) { if (err) { _this.quit(); diff --git a/lib/templates/http_server/layout.html.js b/lib/templates/http_server/layout.html.js index 59a3143..b2f2671 100644 --- a/lib/templates/http_server/layout.html.js +++ b/lib/templates/http_server/layout.html.js @@ -38,22 +38,22 @@ module.exports = function(__obj) { (function() { (function() { __out.push('\n\n\n \n '); - + __out.push(__sanitize(this.title)); - + __out.push('\n \n\n\n
\n '); - + __out.push(__sanitize(this.yieldContents())); - + __out.push('\n \n
\n\n\n'); - + }).call(this); - + }).call(__obj); __obj.safe = __objSafe, __obj.escape = __escape; return __out.join(''); -} +} \ No newline at end of file diff --git a/lib/templates/installer/cx.pow.firewall.plist.js b/lib/templates/installer/cx.pow.firewall.plist.js index b86201b..a7d5873 100644 --- a/lib/templates/installer/cx.pow.firewall.plist.js +++ b/lib/templates/installer/cx.pow.firewall.plist.js @@ -52,4 +52,4 @@ module.exports = function(__obj) { }).call(__obj); __obj.safe = __objSafe, __obj.escape = __escape; return __out.join(''); -} +} \ No newline at end of file diff --git a/src/rack_application.coffee b/src/rack_application.coffee index 256d077..01a6b64 100644 --- a/src/rack_application.coffee +++ b/src/rack_application.coffee @@ -48,6 +48,8 @@ module.exports = class RackApplication host: @firstHost started: @started mtime: @mtime + lastRequest: @lastRequestTime + requestCount: @requestCount # Queue `callback` to be invoked when the application becomes ready, # then start the initialization process. If the application's state @@ -146,6 +148,7 @@ module.exports = class RackApplication # uninitialized state. (If the application is terminating, queue a # call to `initialize` after all workers have exited.) initialize: -> + @requestCount = 0 if @state if @state is "terminating" @quit => @initialize() @@ -223,6 +226,8 @@ module.exports = class RackApplication req.proxyMetaVariables = SERVER_PORT: @configuration.dstPort.toString() try + @lastRequestTime = +new Date + @requestCount++ @pool.proxy req, res, (err) => @quit() if err next err From baa1114db081e6c474b8eb584cd8cc08a0446271 Mon Sep 17 00:00:00 2001 From: Zane Shannon Date: Wed, 17 Sep 2014 00:56:45 -0500 Subject: [PATCH 7/7] added more attributes to `RackApplication` - renamed attributes to be more understandable - converted timestamps to seconds --- lib/rack_application.js | 17 ++++++++++++----- src/rack_application.coffee | 15 +++++++++------ 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/lib/rack_application.js b/lib/rack_application.js index ee09a67..62b2094 100644 --- a/lib/rack_application.js +++ b/lib/rack_application.js @@ -27,9 +27,13 @@ return { root: this.root, host: this.firstHost, - started: this.started, - mtime: this.mtime, - lastRequest: this.lastRequestTime + startedAt: Math.round(this.started / 1000), + lastRestartedAt: Math.round(this.mtime / 1000), + lastRequestAt: Math.round(this.lastRequestTime / 1000), + requestCount: this.requestCount, + timeout: Math.round(this.timeout / 1000), + mightIdleAt: Math.round((this.lastRequestTime + this.timeout) / 1000), + status: ((+(new Date)) - this.lastRequestTime) > this.timeout ? 'idle' : 'active' }; }; @@ -155,6 +159,7 @@ RackApplication.prototype.initialize = function() { var _this = this; + this.requestCount = 0; if (this.state) { if (this.state === "terminating") { this.quit(function() { @@ -175,10 +180,11 @@ } else { _this.state = "ready"; _this.started = +(new Date); + _this.timeout = ((_ref2 = env != null ? env.POW_TIMEOUT : void 0) != null ? _ref2 : _this.configuration.timeout) * 1000; _this.pool = nack.createPool(join(_this.root, "config.ru"), { env: env, - size: (_ref2 = env != null ? env.POW_WORKERS : void 0) != null ? _ref2 : _this.configuration.workers, - idle: ((_ref3 = env != null ? env.POW_TIMEOUT : void 0) != null ? _ref3 : _this.configuration.timeout) * 1000 + size: (_ref3 = env != null ? env.POW_WORKERS : void 0) != null ? _ref3 : _this.configuration.workers, + idle: _this.timeout }); bufferLines(_this.pool.stdout, function(line) { return _this.logger.info(line); @@ -241,6 +247,7 @@ }; try { _this.lastRequestTime = +(new Date); + _this.requestCount++; return _this.pool.proxy(req, res, function(err) { if (err) { _this.quit(); diff --git a/src/rack_application.coffee b/src/rack_application.coffee index 01a6b64..c43f0ce 100644 --- a/src/rack_application.coffee +++ b/src/rack_application.coffee @@ -46,10 +46,13 @@ module.exports = class RackApplication toJSON: -> root: @root host: @firstHost - started: @started - mtime: @mtime - lastRequest: @lastRequestTime + startedAt: Math.round(@started / 1000) + lastRestartedAt: Math.round(@mtime / 1000) + lastRequestAt: Math.round(@lastRequestTime / 1000) requestCount: @requestCount + timeout: Math.round(@timeout / 1000) + mightIdleAt: Math.round((@lastRequestTime + @timeout) / 1000) + status: if ((+new Date) - @lastRequestTime) > @timeout then 'idle' else 'active' # Queue `callback` to be invoked when the application becomes ready, # then start the initialization process. If the application's state @@ -172,11 +175,11 @@ module.exports = class RackApplication else @state = "ready" @started = +new Date - + @timeout = (env?.POW_TIMEOUT ? @configuration.timeout) * 1000 @pool = nack.createPool join(@root, "config.ru"), env: env size: env?.POW_WORKERS ? @configuration.workers - idle: (env?.POW_TIMEOUT ? @configuration.timeout) * 1000 + idle: @timeout # Log the workers' stderr and stdout, and log each worker's # PID as it spawns and exits. @@ -227,7 +230,7 @@ module.exports = class RackApplication SERVER_PORT: @configuration.dstPort.toString() try @lastRequestTime = +new Date - @requestCount++ + @requestCount++ @pool.proxy req, res, (err) => @quit() if err next err