Skip to content

Commit

Permalink
added status endpoint
Browse files Browse the repository at this point in the history
fixed bugs related to query parameters not being loaded
  • Loading branch information
mrak committed Nov 24, 2012
1 parent f8f829a commit 86c17f0
Show file tree
Hide file tree
Showing 11 changed files with 2,197 additions and 31 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -2,3 +2,4 @@ node_modules
npm-debug.log
data/*
lib/*
webroot/status/js/**
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -3,6 +3,8 @@
## 0.1.40

* bugfixes related to command line parsing
* fixed bug where query params were not being saved
* added `status` endpoint on admin portal.

## 0.1.39

Expand Down
35 changes: 27 additions & 8 deletions spec/endpoints.spec.coffee
Expand Up @@ -12,6 +12,29 @@ describe 'Endpoints', ->
data =
request : {}

it 'should at least copy over valid data', ->
endpoint =
request:
url: '/'
method: 'post'
query:
variable: 'value'
headers:
header: 'string'
post: 'data'
file: 'file.txt'
response:
latency: 3000
body: 'contents'
file: 'another.file'
status: 420
headers:
'access-control-allow-origin': '*'

actual = sut.purify endpoint

expect(actual).toEqual endpoint

it 'should default method to GET', ->
expected = 'GET'

Expand All @@ -26,19 +49,15 @@ describe 'Endpoints', ->

expect(actual.response.status).toBe expected

it 'should default response headers to empty object', ->
expected = {}

it 'should not default response headers', ->
actual = sut.purify data

expect(actual.response.headers).toEqual expected

it 'should default request headers to empty object', ->
expected = {}
expect(actual.response.headers).not.toBeDefined()

it 'should not default request headers', ->
actual = sut.purify data

expect(actual.request.headers).toEqual expected
expect(actual.request.headers).not.toBeDefined()

it 'should lower case headers properties', ->
data.request =
Expand Down
12 changes: 10 additions & 2 deletions src/console/watch.coffee
Expand Up @@ -6,6 +6,7 @@ yaml = require 'js-yaml'

timeout = 3000
timeoutId = null
watching = false

module.exports = class Watcher
constructor: (endpoints, filename) ->
Expand All @@ -22,8 +23,15 @@ module.exports = class Watcher

@activate()

deactivate: -> clearTimeout timeoutId
activate: -> timeoutId = setTimeout @refresh, timeout
deactivate: ->
watching = false
clearTimeout timeoutId

activate: ->
return if watching

watching = true
timeoutId = setTimeout @refresh, timeout

refresh: =>
shasum = crypto.createHash 'sha1'
Expand Down
6 changes: 3 additions & 3 deletions src/models/endpoints.coffee
Expand Up @@ -16,12 +16,12 @@ module.exports.Endpoints = class Endpoints
request:
url: data.request.url
method: data.request.method ? 'GET'
headers: data.request.headers ? {}
headers: data.request.headers
query: data.request.query
response:
headers: data.response.headers ? {}
headers: data.response.headers
status: parseInt(data.response.status) or 200

#optionals
@purifyBody item, data
item.request.file = data.request.file if data.request.file?
item.request.post = data.request.post if data.request.post?
Expand Down
11 changes: 5 additions & 6 deletions src/portals/admin.coffee
@@ -1,8 +1,8 @@
contract = require '../models/contract'
Portal = require('./portal').Portal
http = require 'http'
#ns = require 'node-static'
#status = new ns.Server 'webroot'
ns = require 'node-static'
status = new ns.Server 'webroot'

module.exports.Admin = class Admin extends Portal
constructor : (endpoints) ->
Expand Down Expand Up @@ -145,10 +145,9 @@ module.exports.Admin = class Admin extends Portal

if request.url is '/ping' then @goPong response

#else if request.url.match /^\/status/
#request.on 'end', ->
#debugger
#status.serve request, response
else if request.url.match /^\/status/
request.on 'end', ->
status.serve request, response

else if @urlValid request.url
switch request.method.toUpperCase()
Expand Down
47 changes: 46 additions & 1 deletion webroot/status/coffee/scripts.coffee
@@ -1,4 +1,49 @@
stubby = window.stubby ?= {}

Handlebars.registerHelper 'queryParams', (request) ->
result = "?"

for key, value of request.query
result += encodeURIComponent key
result += "="
result += encodeURIComponent value
result += "&"

return result.replace /\&$/, ''

Handlebars.registerHelper 'enumerate', (context, options) ->
result = ""

for key, value of context
result += options.fn { key: key, value: value }

return result

ajax = null
list = null
template = null

success = ->
endpoints = JSON.parse ajax.responseText
for endpoint in endpoints
do (endpoint) ->
endpoint.adminUrl = window.location.href.replace /status/, endpoint.id
html = template endpoint
list.innerHTML += html

complete = (e) ->
return unless ajax.readyState is 4

if ajax.status is 200
success()
else
console.error ajax.statusText

stubby.status = ->
console.log 'started!'
template = Handlebars.compile document.getElementById('endpoint-template').innerText
list = document.getElementById 'endpoints'

ajax = new window.XMLHttpRequest()
ajax.open 'GET', '/', true
ajax.onreadystatechange = complete
ajax.send null
84 changes: 84 additions & 0 deletions webroot/status/css/styles.css
@@ -0,0 +1,84 @@
* {
margin: 0;
padding: 0;
}

body {
background: #333333;
color: #DDDDDD;
font-family: "Helvetica", "Arial", "sans serif"
}

a {
text-decoration: none;
font-weight: bold;
color: #6EBEFF;
}

a:hover {
text-decoration: underline;
color: green;
}

li { list-style: none; }

#endpoints {
width: 960px;
margin: auto;
}

#endpoints > li {
margin: 25px 0;
border-radius: 6px;
overflow: hidden;
}

table {
border: 1px solid lightgray;
width: 100%;
border-collapse: collapse;
}

dd, dt {
display: inline;
}

dt::after {
content: ":";
}

caption {
text-align: left;
padding: 10px;
background: black;
}

th, td {
border: 1px solid black;
padding: 10px;
}

td {
font-family: monospace;
}

th{
border-top: 1px solid #333333;
vertical-align: top;
background: black;
color: #FCC971;
width: 100px;
text-align: right;
}

th.section {
text-align: center;
}

.query-params li {
margin: 0;
}

.query-params td, .query-params th {
padding: 0;
}
99 changes: 99 additions & 0 deletions webroot/status/index.html
Expand Up @@ -5,9 +5,108 @@
<title>Stubby Status</title>

<link rel="stylesheet" href="status/css/styles.css">
<script type="text/javascript" src="status/js/handlebars.js"></script>
<script type="text/javascript" src="status/js/scripts.js"></script>
</head>
<body>
<ul id="endpoints"></ul>
<script type="text/x-handlebars-template" id="endpoint-template">
<li>
<table>
<caption><a href="{{adminUrl}}">Endpoint {{id}}</a></caption>
<tr>
<th class="section" colspan="2">request</th>
</tr>
{{#with request}}
<tr>
<th>url</th>
<td>{{url}}</td>
</tr>
{{#if method}}
<tr>
<th>method</th>
<td>{{method}}</td>
</tr>
{{/if}}
{{#if query}}
<tr>
<th>query</th>
<td>{{queryParams this}}</td>
</tr>
<tr>
<th></th>
<td>
<ul>
{{#enumerate query}}
<li>
<dt>{{key}}</dt>
<dd>{{value}}</dd>
</li>
{{/enumerate}}
</ul>
</td>
</tr>
{{/if}}
{{#if headers}}
<tr>
<th>headers</th>
<td>
<ul>
{{#enumerate headers}}
<li>
<dt>{{key}}</dt>
<dd>{{value}}</dd>
</li>
{{/enumerate}}
</ul>
</td>
</tr>
{{/if}}
{{#if post}}
<tr>
<th>post</th>
<td>{{post}}</td>
</tr>
{{/if}}
{{#if file}}
<tr>
<th>file</th>
<td>{{file}}</td>
</tr>
{{/if}}
{{/with}}
<tr>
<th class="section" colspan="2">response</th>
</tr>
{{#with response}}
{{#if status}}
<tr>
<th>status</th>
<td>{{status}}</td>
</tr>
{{/if}}
{{#if body}}
<tr>
<th>body</th>
<td>{{body}}</td>
</tr>
{{/if}}
{{#if file}}
<tr>
<th>file</th>
<td>{{file}}</td>
</tr>
{{/if}}
{{#if latency}}
<tr>
<th>latency</th>
<td>{{latency}}</td>
</tr>
{{/if}}
{{/with}}
</table>
</li>
</script>
<script type="text/javascript">
stubby.status()
</script>
Expand Down

0 comments on commit 86c17f0

Please sign in to comment.