summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/main.js236
-rw-r--r--lib/paste.js68
-rw-r--r--lib/templates.js46
3 files changed, 275 insertions, 75 deletions
diff --git a/lib/main.js b/lib/main.js
index 6e2f36a..191dbaa 100644
--- a/lib/main.js
+++ b/lib/main.js
@@ -1,103 +1,189 @@
var http = require('http'),
-router = require('choreographer').router(),
+fs = require('fs'),
+path = require('path'),
+bee = require('beeline'),
qs = require('querystring'),
-uuid = require(__dirname + '/uuid'),
hl = require(__dirname + '/highlight'),
-kyoto = require('kyoto');
+tmpl = require(__dirname + '/templates'),
+pasteInit = require(__dirname + '/paste');
-var db = new kyoto.open(__dirname + '/../db/pastes.kch', 'a+', kyotoOpen);
+var config = {
+ port: 8080,
+ database: __dirname + '/../db/pastes.kch'
+};
-function generateId(callback) {
- var id = uuid.generate(14);
- db.get(id, function(err, value) {
- if (value) {
- generateId();
- }
- else {
- callback(id);
- }
+var paste;
+
+function _200(res, contentType, data) {
+ res.writeHead(200, {'Content-Type': contentType});
+ res.write(data);
+ res.end('\n');
+}
+
+function _404(res) {
+ res.writeHead(404, {'Content-Type': 'text/plain'});
+ res.end('404: Not found.\n');
+}
+
+function _500(res, err) {
+ res.writeHead(404, {'Content-Type': 'text/plain'});
+ res.write('500: Internal Server Error');
+
+ if (err) {
+ res.write(':\n');
+ res.write(JSON.stringify(err));
+ }
+
+ res.end('\n');
+}
+
+function parsePost(req, callback) {
+ var content = '';
+
+ req.on('data', function(chunk) {
+ content += chunk;
+ });
+
+ req.on('end', function() {
+ var post = qs.parse(content);
+ callback(post);
});
}
-function getPaste(plain, req, res, paste) {
- db.get(paste, function(err, value) {
- if (err) {
- res.writeHead(404, {'Content-Type': 'text/plain'});
- res.end('404: ' + req.url + ' not found:\n' + err + '\n');
- }
- else {
- var data = JSON.parse(value);
- if (plain) {
- res.writeHead(200, {'Content-Type': 'text/plain'});
- res.write(data.content);
+function getContentType(ext) {
+ contentType = {
+ '.css': 'text/css',
+ '.js': 'text/javascript',
+ '.png': 'image/png'
+ };
+
+ if (contentType[ext]) {
+ return contentType[ext];
+ }
+ else {
+ return 'unknown';
+ }
+}
+
+function checkPath(file, base) {
+ var normFile = path.normalize(file);
+ var normBase = path.normalize(base);
+
+ if (normFile.indexOf(normBase) === 0) {
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+function serveStaticFiles(res, filepath) {
+ var base = path.join(__dirname, '..', 'static');
+ var file = path.join(base, filepath);
+
+ if (checkPath(file, base)) {
+ path.exists(file, function(exists) {
+ if (exists) {
+ var ext = path.extname(file);
+ var contentType = getContentType(ext);
+
+ fs.readFile(file, function (err, data) {
+ if (err) {
+ _500(res, err);
+ }
+ else {
+ _200(res, contentType, data);
+ }
+ });
}
else {
- res.writeHead(200, {'Content-Type': 'text/html'});
- res.write(hl.highlight(data.content, data.language));
+ _404(res);
}
- res.end('\n');
- }
- });
+ });
+ }
+ else {
+ _404(res);
+ }
}
-router
- .get('/plain/*', function(req, res, paste) {
- getPaste(true, req, res, paste);
- })
- .get('/get/*', function(req, res, paste) {
- getPaste(false, req, res, paste);
- })
- .get('/', function(req, res) {
- })
- .post('/add', function(req, res) {
- var content = '';
-
- req.on('data', function(chunk) {
- content += chunk;
+var router = bee.route({
+ "/": function(req, res) {
+ tmpl.renderHtml('submit-form.tmpl', {}, res);
+ },
+
+ "r`^/plain/([^/]+)$`": function(req, res, id) {
+ paste.get(id[0], function(data) {
+ if (data) {
+ _200(res, 'text/plain', data.content);
+ }
+ else {
+ _404(res);
+ }
+ });
+ },
+
+ "r`^/get/([^/]+)$`": function(req, res, id) {
+ paste.get(id[0], function(data) {
+ if (data) {
+ data.styles = [{name: '/static/highlight/github.css'}];
+ data.content = hl.highlight(data.content, data.language);
+
+ tmpl.renderHtml('paste.tmpl', data, res);
+ }
+ else {
+ _404(res);
+ }
});
+ },
- req.on('end', function() {
- var post = qs.parse(content);
+ "r`^/static/(.+)$`": function(req, res, filepath) {
+ serveStaticFiles(res, filepath[0]);
+ },
- generateId(function(id) {
- var data = {
- content: post.content,
- language: post.language,
- time: Date()
- };
- db.set(id, JSON.stringify(data), function(err) {
+ "/add": {
+ POST: function(req, res) {
+ parsePost(req, function(post) {
+ paste.add(post, function(err, id) {
if (err) {
- res.writeHead(500, {'Content-Type': 'text/plain'});
- res.write(err);
- res.end('\n');
+ _500(res, err);
}
else {
console.log('new paste: %s', id);
- res.writeHead(200, {'Content-Type': 'text/plain'});
- res.write(id);
- res.end('\n');
+ tmpl.renderHtml('newPaste.tmpl', {id: id}, res);
}
});
});
- });
- })
- .notFound(function(req, res) {
- res.writeHead(404, {'Content-Type': 'text/plain'});
- res.end('404: ' + req.url + ' not found.\n');
- });
-
+ },
-function kyotoOpen(err) {
- if (err) throw err;
+ GET: function(req, res) {
+ _404(res);
+ }
+ },
- http.createServer(router).listen(8080);
- console.log('Listening on port 8080...');
-}
+ "`404`": function(req, res) {
+ _404(res);
+ },
-process.on('uncaughtException', function(exeption) {
- process.exit(1);
+ "`503`": function(req, res, err) {
+ _500(res, err);
+ }
});
-process.on('exit', function() {
- db.close(function(err) { console.log(err); });
-});
+var server = function(port) {
+ port = port || config.port;
+
+ pasteInit.init(config, function(func) {
+ paste = func;
+
+ http.createServer(router).listen(port);
+ console.log('Listening on port %d...', port);
+ });
+};
+
+if (typeof module == "object" && typeof require == "function") {
+ exports.server = server;
+ exports.config = config;
+}
+if (module === require.main) {
+ server();
+}
diff --git a/lib/paste.js b/lib/paste.js
new file mode 100644
index 0000000..a60bee2
--- /dev/null
+++ b/lib/paste.js
@@ -0,0 +1,68 @@
+var kyoto = require('kyoto'),
+uuid = require(__dirname + '/uuid');
+
+var db;
+
+var generateId = function(callback) {
+ var id = uuid.generate(14);
+
+ db.get(id, function(err, value) {
+ if (value) {
+ generateId();
+ }
+ else {
+ callback(id);
+ }
+ });
+};
+
+var get = function(id, callback) {
+ db.get(id, function(err, value) {
+ if (value) {
+ value = JSON.parse(value);
+ }
+
+ callback(value);
+ });
+};
+
+var add = function(post, callback) {
+ generateId(function(id) {
+ var data = {
+ content: post.content,
+ language: post.language,
+ time: new Date()
+ };
+
+ db.set(id, JSON.stringify(data), function(err) {
+ callback(err, id);
+ });
+ });
+};
+
+var init = function(config, callback) {
+ db = new kyoto.open(config.database, 'a+', function(err) {
+ if (err) throw err;
+
+ process.on('uncaughtException', function(exeption) {
+ console.error('%j', exeption);
+ process.exit(1);
+ });
+
+ process.on('exit', function() {
+ db.close(function(err) { console.log(err); });
+ });
+
+ var thismodule = {
+ get: get,
+ add: add
+ };
+
+ callback(thismodule);
+
+ });
+};
+
+module.exports = {
+ init: init
+};
diff --git a/lib/templates.js b/lib/templates.js
new file mode 100644
index 0000000..c470454
--- /dev/null
+++ b/lib/templates.js
@@ -0,0 +1,46 @@
+var nun = require('nun');
+
+var templates = {};
+
+var render = function(template, args, callback) {
+ if (template in templates) {
+ callback(undefined, templates[template](args));
+ }
+ else {
+ nun.compile(__dirname + '/../templates/' + template, "", function(err, tmpl) {
+ if (err) {
+ callback(err);
+ }
+ else {
+ templates[template] = tmpl;
+ callback(err, tmpl(args));
+ }
+ });
+ }
+};
+
+var renderHtml = function(template, args, res) {
+ render(template, args, function(err, events) {
+ if (err) {
+ res.writeHead(500, {'Content-Type': 'text/plain'});
+ res.write(JSON.stringify(err));
+ res.end('\n');
+ }
+ else {
+ res.writeHead(200, {'Content-Type': 'text/html'});
+
+ events.on('data', function(data) {
+ res.write(data);
+ });
+
+ events.on('end', function() {
+ res.end('\n');
+ });
+ }
+ });
+};
+
+module.exports = {
+ render: render,
+ renderHtml: renderHtml
+};