1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2025-05-03 16:04:10 +00:00

Marginally improve the elegance of the simple HTTP server

This commit is contained in:
Jeremy Ruston 2013-03-17 17:57:46 +00:00
parent dbde2bf23b
commit 210f596d0c

View File

@ -12,47 +12,107 @@ Serve tiddlers over http
/*global $tw: false */ /*global $tw: false */
"use strict"; "use strict";
if(!$tw.browser) {
var util = require("util"),
fs = require("fs"),
url = require("url"),
path = require("path"),
http = require("http");
}
exports.info = { exports.info = {
name: "server", name: "server",
synchronous: true synchronous: true
}; };
var Command = function(params,commander,callback) { /*
this.params = params; A simple HTTP server with regexp-based routes
this.commander = commander; */
this.callback = callback; function SimpleServer(options) {
this.routes = options.routes || [];
this.wiki = options.wiki;
this.variables = options.variables || {};
}
SimpleServer.prototype.set = function(obj) {
var self = this;
$tw.utils.each(obj,function(value,name) {
self.variables[name] = value;
});
}; };
Command.prototype.execute = function() { SimpleServer.prototype.get = function(name) {
var self = this, return this.variables[name];
util = require("util"), };
fs = require("fs"),
url = require("url"), SimpleServer.prototype.addRoute = function(route) {
path = require("path"), this.routes.push(route);
http = require("http"), };
port = this.params[0] || "8080",
rootTiddler = this.params[1] || "$:/core/templates/tiddlywiki5.template.html", SimpleServer.prototype.listen = function(port) {
renderType = this.params[2] || "text/plain", var self = this;
serveType = this.params[3] || "text/html",
prefix;
http.createServer(function(request, response) { http.createServer(function(request, response) {
var requestPath = url.parse(request.url).pathname, // Compose the state object
text; var state = {};
state.wiki = self.wiki;
state.server = self;
state.urlInfo = url.parse(request.url);
// Find the route that matches this path
var route;
for(var t=0; t<self.routes.length; t++) {
var potentialRoute = self.routes[t],
pathRegExp = potentialRoute.path,
match = potentialRoute.path.exec(state.urlInfo.pathname);
if(request.method === potentialRoute.method && match) {
state.params = [];
for(var p=1; p<match.length; p++) {
state.params.push(match[p]);
}
route = potentialRoute;
break;
}
}
// Return a 404 if we didn't find a route
if(!route) {
response.writeHead(404);
response.end();
return;
}
// Dispatch the appropriate method
switch(request.method) { switch(request.method) {
case "GET": // Intentional fall-through
case "DELETE":
route.handler(request,response,state);
break;
case "PUT": case "PUT":
var data = ""; var data = "";
request.on("data",function(chunk) { request.on("data",function(chunk) {
data += chunk.toString(); data += chunk.toString();
}); });
request.on("end",function() { request.on("end",function() {
prefix = "/recipes/default/tiddlers/"; state.data = data;
if(requestPath.indexOf(prefix) === 0) { route.handler(request,response,state);
var title = decodeURIComponent(requestPath.substr(prefix.length)), });
fields = JSON.parse(data); break;
// Use the title from the PUT URL if we don't have one
if(!fields.title) {
fields.title = title;
} }
}).listen(port);
};
var Command = function(params,commander,callback) {
this.params = params;
this.commander = commander;
this.callback = callback;
// Set up server
this.server = new SimpleServer({
wiki: this.commander.wiki
});
// Add route handlers
this.server.addRoute({
method: "PUT",
path: /^\/recipes\/default\/tiddlers\/(.+)$/,
handler: function(request,response,state) {
var title = decodeURIComponent(state.params[0]),
fields = JSON.parse(state.data);
// Pull up any subfields in the `fields` object // Pull up any subfields in the `fields` object
if(fields.fields) { if(fields.fields) {
$tw.utils.each(fields.fields,function(field,name) { $tw.utils.each(fields.fields,function(field,name) {
@ -65,39 +125,40 @@ Command.prototype.execute = function() {
delete fields["revision"]; delete fields["revision"];
} }
console.log("PUT tiddler",title,fields) console.log("PUT tiddler",title,fields)
self.commander.wiki.addTiddler(new $tw.Tiddler(JSON.parse(data),{title: title})); state.wiki.addTiddler(new $tw.Tiddler(fields,{title: title}));
var changeCount = self.commander.wiki.getChangeCount(title).toString(); var changeCount = state.wiki.getChangeCount(title).toString();
response.writeHead(204, "OK",{ response.writeHead(204, "OK",{
Etag: "\"default/" + title + "/" + changeCount + ":\"" Etag: "\"default/" + title + "/" + changeCount + ":\""
}); });
response.end(); response.end();
} else { }
response.writeHead(404); });
this.server.addRoute({
method: "DELETE",
path: /^\/bags\/default\/tiddlers\/(.+)$/,
handler: function(request,response,state) {
var title = decodeURIComponent(state.params[0]);
console.log("DELETE tiddler",title)
state.wiki.deleteTiddler(title);
response.writeHead(204, "OK");
response.end(); response.end();
} }
}); });
break; this.server.addRoute({
case "DELETE": method: "GET",
prefix = "/bags/default/tiddlers/"; path: /^\/$/,
if(requestPath.indexOf(prefix) === 0) { handler: function(request,response,state) {
var title = decodeURIComponent(requestPath.substr(prefix.length)); response.writeHead(200, {"Content-Type": state.server.get("serveType")});
console.log("DELETE tiddler",title) var text = state.wiki.renderTiddler(state.server.get("renderType"),state.server.get("rootTiddler"));
self.commander.wiki.deleteTiddler(decodeURIComponent(title));
response.writeHead(204, "OK");
response.end();
} else {
response.writeHead(404);
response.end();
}
break;
case "GET":
if(requestPath === "/") {
response.writeHead(200, {"Content-Type": serveType});
text = self.commander.wiki.renderTiddler(renderType,rootTiddler);
response.end(text,"utf8"); response.end(text,"utf8");
} else if(requestPath === "/status") { }
});
this.server.addRoute({
method: "GET",
path: /^\/status$/,
handler: function(request,response,state) {
response.writeHead(200, {"Content-Type": "application/json"}); response.writeHead(200, {"Content-Type": "application/json"});
text = JSON.stringify({ var text = JSON.stringify({
username: "ANONYMOUS", username: "ANONYMOUS",
space: { space: {
recipe: "default" recipe: "default"
@ -105,10 +166,15 @@ console.log("DELETE tiddler",title)
tiddlywiki_version: $tw.version tiddlywiki_version: $tw.version
}); });
response.end(text,"utf8"); response.end(text,"utf8");
} else if(requestPath === "/recipes/default/tiddlers.json") { }
});
this.server.addRoute({
method: "GET",
path: /^\/recipes\/default\/tiddlers.json$/,
handler: function(request,response,state) {
response.writeHead(200, {"Content-Type": "application/json"}); response.writeHead(200, {"Content-Type": "application/json"});
var tiddlers = []; var tiddlers = [];
$tw.wiki.forEachTiddler("title",function(title,tiddler) { state.wiki.forEachTiddler("title",function(title,tiddler) {
var tiddlerFields = {}; var tiddlerFields = {};
$tw.utils.each(tiddler.fields,function(field,name) { $tw.utils.each(tiddler.fields,function(field,name) {
if(name !== "text") { if(name !== "text") {
@ -118,13 +184,16 @@ console.log("DELETE tiddler",title)
tiddlerFields["revision"] = $tw.wiki.getChangeCount(title); tiddlerFields["revision"] = $tw.wiki.getChangeCount(title);
tiddlers.push(tiddlerFields); tiddlers.push(tiddlerFields);
}); });
text = JSON.stringify(tiddlers); var text = JSON.stringify(tiddlers);
response.end(text,"utf8"); response.end(text,"utf8");
} else { }
prefix = "/recipes/default/tiddlers/"; });
if(requestPath.indexOf(prefix) === 0) { this.server.addRoute({
var title = decodeURIComponent(requestPath.substr(prefix.length)), method: "GET",
tiddler = $tw.wiki.getTiddler(title), path: /^\/recipes\/default\/tiddlers\/(.+)$/,
handler: function(request,response,state) {
var title = decodeURIComponent(state.params[0]),
tiddler = state.wiki.getTiddler(title),
tiddlerFields = {}, tiddlerFields = {},
knownFields = [ knownFields = [
"bag", "created", "creator", "modified", "modifier", "permissions", "recipe", "revision", "tags", "text", "title", "type", "uri" "bag", "created", "creator", "modified", "modifier", "permissions", "recipe", "revision", "tags", "text", "title", "type", "uri"
@ -145,18 +214,21 @@ console.log("DELETE tiddler",title)
response.writeHead(404); response.writeHead(404);
response.end(); response.end();
} }
} else {
response.writeHead(404);
response.end();
} }
} });
break; };
case "POST":
response.writeHead(404); Command.prototype.execute = function() {
response.end(); var port = this.params[0] || "8080",
break; rootTiddler = this.params[1] || "$:/core/templates/tiddlywiki5.template.html",
} renderType = this.params[2] || "text/plain",
}).listen(port); serveType = this.params[3] || "text/html";
this.server.set({
rootTiddler: rootTiddler,
renderType: renderType,
serveType: serveType
});
this.server.listen(port);
if(this.commander.verbose) { if(this.commander.verbose) {
console.log("Serving on port " + port); console.log("Serving on port " + port);
} }