Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

208 lines (185 sloc) 7.711 kb
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Net;
using System.Text.RegularExpressions;
namespace TaoEngine
{
public class TaoEngine
{
RoutingSystem router = new RoutingSystem();
Dictionary<String, Metadata> methodMap = new Dictionary<string, Metadata>();
private HttpListener server;
private Response failureResponse;
private string site;
public static string domain;
public TaoEngine(String site, Response failureResponse)
{
this.site = site;
TaoEngine.domain = site;
this.failureResponse = failureResponse;
}
public void set404(Response failureResponse)
{
this.failureResponse = failureResponse;
}
public void set505(Response errorResponse)
{
this.errorResponse = errorResponse;
}
private Metadata retrieveRoute(String route)
{
String rule;
Metadata data;
// if the router returns null then the route is either invalid or incomplete
rule = router.matchRoute(route);
if (rule == null)
{
return null;
}
try { data = methodMap[rule]; }
catch (KeyNotFoundException) { return null; }
data.methArgs = reduceToArgs(route, rule);
return data;
}
private Args reduceToArgs(String route, String rule)
{
String[] chunksOfRoute = route.Split(new char[] { '/' }, StringSplitOptions.None);
String[] chunksOfRule = rule.Split(new char[] { '/' }, StringSplitOptions.None);
Dictionary<String, dynamic> args = new Dictionary<string, dynamic>();
for (int i = 0; i < chunksOfRoute.Length; i++)
{
if (router.isDynamic(chunksOfRule[i]))
{
// find dynamic arg like <name>
// store it like this 'name' : 'james'
args.Add(chunksOfRule[i].Trim(new char[] { '<', '>' }), chunksOfRoute[i]);
}
}
return new Args(args);
}
private Response invokeRoute(Request request)
{
Metadata methodMetadata = retrieveRoute(request.path);
if (methodMetadata != null)
{
var method = methodMetadata.method;
var klass = methodMetadata.klass;
// Prepare the arguements when invoking the method
object[] args = { methodMetadata.methArgs, request };
Response response = (Response)method.Invoke(klass, args);
response.session = request.session;
return response;
}
return null;
}
private void handleSession(Response response, HttpListenerResponse serverResponse)
{
// We use session a lot, lets make the name a bit more 'local'
Session session = response.session;
// update our internal cache of the session.
SessionOverlord.commitSession(session);
if (session.isNew)
{
Cookie cookie = new Cookie("sessionID", session.id);
// Set the expiry date
String expires = DateTime.UtcNow.AddMinutes(30).ToString("ddd, dd-MMM-yyyy H:mm:ss");
serverResponse.Headers.Add("Set-Cookie", "sessionID=" + session.id + ";Path=/;Expires=" + expires + " GMT");
session.isNew = false;
}
}
private void writeResponse(Response response, HttpListenerResponse serverResponse)
{
// Now write the actual response.
serverResponse.ContentType = response.mimeType;
serverResponse.StatusCode = response.status;
byte[] buffer = Encoding.UTF8.GetBytes(response.render());
serverResponse.ContentLength64 = buffer.Length;
serverResponse.OutputStream.Write(buffer, 0, buffer.Length);
serverResponse.OutputStream.Close();
}
private void handleContextAsync(IAsyncResult asyncContext)
{
HttpListenerContext context = server.EndGetContext(asyncContext);
Request request = new Request(context.Request);
Console.WriteLine("TaoEngine: Got request for following path: {0}", request.path);
Response response = null;
try
{
response = invokeRoute(request);
if (response == null)
{
// Right. So when we get back a null response from the router, we can't write the session.
response = failureResponse.clone().setStatus(404);
}
}
catch (Exception e)
{
// ugh. this is an internal error and is the developers fault.
Dictionary<String,String> errorMessage = new Dictionary<string,string>();
errorMessage.Add("err", e.InnerException.ToString());
if (errorResponse == null)
{
response = failureResponse.clone().setStatus(500).inlineTemplate("$err$").addNamespace(errorMessage);
}
else
{
response = errorResponse.clone().setStatus(500).addNamespace(errorMessage);
}
}
finally
{
Console.WriteLine("Response code: {0}\n", response.status);
if (response.session != null)
{
handleSession(response, context.Response);
}
writeResponse(response, context.Response);
context.Response.Close();
}
// Start listening for another request.
server.BeginGetContext(new AsyncCallback(handleContextAsync), null);
}
public void registerClass(Object klass)
{
Type klass_type = klass.GetType();
Console.WriteLine("TaoEngine: Registering Routes.\n");
foreach (var method in klass_type.GetMethods())
{
object[] routes = method.GetCustomAttributes(typeof(Route), false);
try
{
object route_object = routes[0];
Route _route = (Route)route_object;
foreach (String rule in _route.routes)
{
router.addRoute(rule);
Console.WriteLine("TaoEngine: Rule = {0}\n Matching Method = {1}.{2}\n", rule, klass_type.Name, method.Name);
methodMap.Add(rule, new Metadata(klass, method));
}
}
catch (IndexOutOfRangeException)
{
// We don't care if we failed to register a method. Their loss.
}
}
}
public void spin()
{
using (server = new HttpListener())
{
server.Prefixes.Add(this.site);
Console.WriteLine("\nTaoEngine: Starting " + server);
server.Start();
server.BeginGetContext(new AsyncCallback(handleContextAsync), null);
while (server.IsListening)
{
// hold main thread.
}
}
}
public Response errorResponse { get; set; }
}
}
Jump to Line
Something went wrong with that request. Please try again.