add simple HTML & text representations

This commit is contained in:
Sami Samhuri 2013-07-14 17:43:36 -07:00
parent 36930d666d
commit b9b49c0471
11 changed files with 173 additions and 71 deletions

116
app.js Normal file
View file

@ -0,0 +1,116 @@
// Copyright 2013 Sami Samhuri
var express = require('express')
, Negotiator = require('negotiator')
, kwikemon = require('./kwikemon.js')
, app = module.exports = express()
, version = require('./version.js')
;
// Middleware
app.use(express.favicon('/dev/null'));
app.use(express.logger());
app.use(express.static(__dirname + '/public'));
// Views
app.set('view engine', 'jade');
app.set('views', __dirname + '/views');
// Routes
app.get('/', route('monitors', getMonitors));
app.get('/:name', route('monitor', getMonitor));
function route(template, buildContext) {
return function(req, res) {
buildContext(req, res, function(err, ctx) {
if (err) {
var message = err.message || String(err)
, status = message == 'not found' ? 404 : 500
;
res.format({
html: function() {
res.render('error', {
version: version,
pageTitle: 'Error',
err: err
});
},
text: function() {
res.send(renderText('error', { err: err }));
},
json: function() {
res.json({ message: message });
}
});
}
else {
ctx = ctx || {};
res.format({
html: function() {
ctx.version = version;
res.render(template, ctx);
},
text: function() {
res.send(renderText(template, ctx));
},
json: function() {
res.json(ctx);
}
});
}
});
};
}
// Rendering
function renderText(template, ctx) {
var text;
switch (template) {
case 'monitor':
text = String(ctx.monitor.text);
break;
case 'monitors':
text = Object.keys(ctx.monitors).sort().map(function(name) {
return name + ': ' + ctx.monitors[name].text;
}).join('\n');
break;
case 'error':
text = ctx.err.message || String(ctx.err);
break;
default:
throw new Error('unknown text template: ' + template);
}
return text;
}
//////////////////////
// Request handlers //
//////////////////////
function getMonitors(req, res, cb) {
kwikemon.getAll(function(err, monitors) {
cb(err, err ? null : {
pageTitle: 'Monitors',
monitors: monitors
});
});
}
function getMonitor(req, res, cb) {
var name = req.params.name;
kwikemon.get(name, function(err, mon) {
if (!mon) {
err = new Error('not found');
}
cb(err, err ? null : {
pageTitle: mon.name,
monitor: mon
});
});
}

View file

@ -1,8 +1,9 @@
#!/usr/bin/env node #!/usr/bin/env node
var server = require('../server.js') var port = process.argv[2] || 1111
, port = process.argv[2] , host = process.argv[3] || '127.0.0.1'
, host = process.argv[3] , app = require('../app.js')
; ;
server.start(port, host); app.listen(port, host);
console.log('kwikemond listening on ' + host + ':' + port);

View file

@ -105,7 +105,8 @@ function set(name, text, options, cb) {
; ;
exists(name, function(err, exists) { exists(name, function(err, exists) {
var fields = { var fields = {
text: text name: name
, text: text
, modified: Date.now() , modified: Date.now()
} }
, multi = redis().multi() , multi = redis().multi()

View file

@ -11,8 +11,11 @@
, "kwikemond": "./bin/kwikemond" , "kwikemond": "./bin/kwikemond"
} }
, "dependencies": { , "dependencies": {
"redis": "0.8.x" "async": "0.2.x"
, "async": "0.2.x" , "express": "3.0.x"
, "jade": "0.31.x"
, "negotiator": "0.2.x"
, "redis": "0.8.x"
, "toml": "0.4.x" , "toml": "0.4.x"
} }
, "devDependencies": { , "devDependencies": {

15
public/css/style.css Normal file
View file

@ -0,0 +1,15 @@
ul#monitors {
list-style: none;
}
li.monitor {
}
#footer {
width: 80%;
margin: 0.5em auto;
padding: 0.3em 1em;
text-align: center;
border-top: solid 1px #aaa;
}

View file

@ -1,64 +0,0 @@
// Copyright 2013 Sami Samhuri
module.exports = {
create: create
, start: start
, stop: stop
};
var http = require('http')
, kwikemon = require('./kwikemon.js')
, _server
;
function create() {
return http.createServer(handleRequest);
}
function start(port, host) {
port = port || 1111;
host = host || '127.0.0.1';
_server = create();
_server.listen(port, host);
console.log('kwikemond listening on ' + host + ':' + port);
return _server;
}
function stop() {
_server.close();
_server = null;
}
function handleRequest(req, res) {
var name = req.url.replace(/^\//, '')
, type = 'html'
, m
;
if (name == 'favicon.ico') return res.end();
if (m = name.match(/\.(json|txt)$/)) {
type = m[1];
name = name.replace(RegExp('\.' + type + '$'), '');
}
if (name) {
kwikemon.get(name, function(err, text) {
if (err) {
res.end('error: ' + (err.message || 'unknown'));
return;
}
res.end(text);
});
}
// all
else {
kwikemon.getAll(function(err, monitors) {
if (err) {
res.end('error: ' + (err.message || 'unknown'));
return;
}
Object.keys(monitors).sort().forEach(function(name) {
res.write(name + ': ' + monitors[name] + '\n');
});
res.end();
});
}
}

3
version.js Normal file
View file

@ -0,0 +1,3 @@
// Copyright 2013 Sami Samhuri
module.exports = JSON.parse(require('fs').readFileSync('./package.json')).version;

4
views/error.jade Normal file
View file

@ -0,0 +1,4 @@
extends layout
block content
p.
error: #{err.message || err}

13
views/layout.jade Normal file
View file

@ -0,0 +1,13 @@
doctype 5
html(lang="en")
head
title kwikemon
link(rel="stylesheet", href="/css/style.css")
body
block nav
block title
h1= pageTitle || 'kwikemon'
#content
block content
#footer
a(href="https://github.com/samsonjs/kwikemon") kwikemon #{version}

5
views/monitor.jade Normal file
View file

@ -0,0 +1,5 @@
extends layout
block nav
p: a(href="/") ← monitors
block content
p= monitor.text

5
views/monitors.jade Normal file
View file

@ -0,0 +1,5 @@
extends layout
block content
ul#monitors
- each monitor in monitors
li.monitor: a(href="/#{monitor.name}") #{monitor.name}: #{monitor.text}