Skip to content

Instantly share code, notes, and snippets.

@rikkimax
Created January 2, 2014 09:20
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rikkimax/8216759 to your computer and use it in GitHub Desktop.
Save rikkimax/8216759 to your computer and use it in GitHub Desktop.
My little router. Written in D utilising Vibe.
module rh.common.routing;
public import vibe.http.router;
import std.file : append, write;
import std.traits : moduleName;
__gshared URLRouter urlRouter = new URLRouter();
private string logFile = null;
void setRoutingLogFile(string file) {
logFile = file;
}
enum RouteType {
Get = "get",
Post = "post",
Put = "put",
Delete = "delete",
Any = "any"
}
alias bool function(HTTPServerRequest req, HTTPServerResponse res) RouteFilter;
struct RouteFunction {
RouteType type;
string route = "";
RouteFilter filterFunction = null;
}
struct RouteGroup {
RouteFilter filterFunction = null;
string routeBase = "";
}
struct RouteGroupId {
string routeName = "";
}
struct RouteGroupIds {
// bug in dmd 2.064
/*this(string[] args ...) {
//routeNames = args;
}*/
string[] routeNames;
}
interface OORoute {
}
void registerRoute(T : OORoute)() {
string routeOutput = "";
T t = new T;
foreach(string f; __traits(allMembers, T)) {
static if (__traits(compiles, {
mixin("t." ~ f ~ "(cast(HTTPServerRequest)null, cast(HTTPServerResponse)null);"); } )) {
static if (hasFilters!(T, f)()) {
mixin(filterFunctionWrapper!(T, f, getRouteTypeFromMethod!(T, f)(), getPathFromMethod!(T, f)())());
} else {
mixin(functionWrapper!(T, f, getRouteTypeFromMethod!(T, f)(), getPathFromMethod!(T, f)())());
}
routeOutput ~= getRouteTypeFromMethod!(T, f)() ~ ":" ~ T.stringof ~ "." ~ f ~ ":" ~ getPathFromMethod!(T, f)() ~ "\n";
}
}
if (logFile !is null)
append(logFile, routeOutput);
}
string functionWrapper(T, string f, RouteType type, string path)() {
string ret;
ret ~= "void " ~ T.stringof ~ "_" ~ f ~ "(HTTPServerRequest req, HTTPServerResponse res) {";
ret ~= "import " ~ moduleName!T ~ ";";
ret ~= T.stringof ~ " t = new " ~ T.stringof ~ ";";
ret ~= "t." ~ f ~ "(req, res);""";
ret ~= "}";
switch(type) {
case RouteType.Get:
ret ~= "(cast(URLRouter)urlRouter).get(\"" ~ path ~ "\", &" ~ T.stringof ~ "_" ~ f ~ ");";
break;
case RouteType.Post:
ret ~= "(cast(URLRouter)urlRouter).post(\"" ~ path ~ "\", &" ~ T.stringof ~ "_" ~ f ~ ");";
break;
case RouteType.Put:
ret ~= "(cast(URLRouter)urlRouter).put(\"" ~ path ~ "\", &" ~ T.stringof ~ "_" ~ f ~ ");";
break;
case RouteType.Delete:
ret ~= "(cast(URLRouter)urlRouter).delete_(\"" ~ path ~ "\", &" ~ T.stringof ~ "_" ~ f ~ ");";
break;
case RouteType.Any:
ret ~= "(cast(URLRouter)urlRouter).any(\"" ~ path ~ "\", &" ~ T.stringof ~ "_" ~ f ~ ");";
break;
default:
break;
}
return ret;
}
string filterFunctionWrapper(T, string f, RouteType type, string path)() {
string ret;
ret ~= "void " ~ T.stringof ~ "_" ~ f ~ "(HTTPServerRequest req, HTTPServerResponse res) {";
ret ~= "import " ~ moduleName!T ~ ";";
ret ~= T.stringof ~ " t = new " ~ T.stringof ~ ";";
ret ~= """bool result = true;
foreach(filter; getFiltersFromMethod!(" ~ T.stringof ~ ", \"" ~ f ~ "\")()) {
if (result)
result = filter(req, res);
}
if (result)
t." ~ f ~ "(req, res);""";
ret ~= "}";
switch(type) {
case RouteType.Get:
ret ~= "(cast(URLRouter)urlRouter).get(\"" ~ path ~ "\", &" ~ T.stringof ~ "_" ~ f ~ ");";
break;
case RouteType.Post:
ret ~= "(cast(URLRouter)urlRouter).post(\"" ~ path ~ "\", &" ~ T.stringof ~ "_" ~ f ~ ");";
break;
case RouteType.Put:
ret ~= "(cast(URLRouter)urlRouter).put(\"" ~ path ~ "\", &" ~ T.stringof ~ "_" ~ f ~ ");";
break;
case RouteType.Delete:
ret ~= "(cast(URLRouter)urlRouter).delete_(\"" ~ path ~ "\", &" ~ T.stringof ~ "_" ~ f ~ ");";
break;
case RouteType.Any:
ret ~= "(cast(URLRouter)urlRouter).any(\"" ~ path ~ "\", &" ~ T.stringof ~ "_" ~ f ~ ");";
break;
default:
break;
}
return ret;
}
pure RouteType getRouteTypeFromMethod(C, string f)() {
C c = new C;
foreach(UDA; __traits(getAttributes, mixin("c." ~ f))) {
static if (__traits(compiles, {RouteFunction rf = UDA; } )) {
return UDA.type;
}
}
return RouteType.Any;
}
pure string getPathFromMethod(C, string f)() {
C c = new C;
string ret;
foreach(UDA; __traits(getAttributes, mixin("c." ~ f))) {
static if (__traits(compiles, {RouteFunction rf = UDA; } )) {
static if (UDA.route != "")
ret ~= UDA.route;
} else static if (__traits(compiles, {RouteGroup rf = UDA; } )) {
static if (UDA.routeBase != "")
ret ~= UDA.routeBase;
} else static if (__traits(compiles, {RouteGroupId rf = UDA; } )) {
ret ~= "/:" ~ UDA.routeName;
} else static if (__traits(compiles, {RouteGroupIds rf = UDA; } )) {
foreach(rn; UDA.routeNames) {
ret ~= "/:" ~ rn;
}
}
}
return ret;
}
pure RouteFilter[] getFiltersFromMethod(C, string f)() {
C c = new C;
RouteFilter[] ret;
foreach(UDA; __traits(getAttributes, mixin("c." ~ f))) {
static if (__traits(compiles, {RouteFunction rf = UDA; } )) {
static if (UDA.filterFunction !is null)
ret ~= UDA.filterFunction;
} else static if (__traits(compiles, {RouteGroup rf = UDA; } )) {
static if (UDA.filterFunction !is null)
ret ~= UDA.filterFunction;
}
}
return ret;
}
pure bool hasFilters(C, string f)() {
C c = new C;
foreach(UDA; __traits(getAttributes, mixin("c." ~ f))) {
static if (__traits(compiles, {RouteFunction rf = UDA; } )) {
static if (UDA.filterFunction !is null)
return true;
} else static if (__traits(compiles, {RouteGroup rf = UDA; } )) {
static if (UDA.filterFunction !is null)
return true;
}
}
return false;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment