Created
December 23, 2013 14:01
-
-
Save rikkimax/8097560 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module common.routing; | |
public import vibe.http.router; | |
import std.file : append, write; | |
__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; | |
} | |
private void FilterFunctionWrapper(alias me, string f, alias filters)(HTTPServerRequest req, HTTPServerResponse res) { | |
bool result = true; | |
foreach(filter; filters) { | |
result = filter(req, res); | |
if (!result) | |
break; | |
} | |
if (result) | |
mixin("me." ~ f ~ "(req, res);"); | |
} | |
/** | |
* Route manager is the base router (on top of stock URLRouter). | |
* It provides an singleton class based route controller. | |
* Supports: | |
* @RouteFunction(RouteType, route, RouteFilter) | |
* @RouteGroup(RouteFilter, routeBase) | |
* @RouteGroupId(name) | |
* @RouteGroupIds([name, ...]) | |
*/ | |
abstract class Routes { | |
this(this T)() { | |
this(cast(T)this); | |
} | |
this(T)(T me) { | |
string routeOutput = ""; | |
foreach(string f; __traits(allMembers, T)) { | |
mixin("alias symbol = me." ~ f ~ ";"); | |
static if (__traits(compiles, { | |
mixin("me." ~ f ~ "(cast(HTTPServerRequest)null, cast(HTTPServerResponse)null);"); } )) { | |
RouteType routeType = cast(RouteType)""; | |
string route = ""; | |
RouteFilter[] filters; | |
bool isLastGroupId = false; | |
handleRouteGroups!(symbol)(isLastGroupId, route, filters); | |
foreach (UDA; __traits(getAttributes, symbol)) { | |
static if (is(typeof(UDA) == RouteFunction)) { | |
routeType = UDA.type; | |
if (!isLastGroupId) | |
route ~= UDA.route; | |
if (UDA.filterFunction !is null) | |
filters ~= UDA.filterFunction; | |
} | |
} | |
handleRouteFunction!(T, f)(me, routeType, route, filters, routeOutput); | |
} | |
} | |
if (logFile !is null) | |
append(logFile, routeOutput); | |
} | |
protected { | |
void handleRouteFunction(T, string f)(T me, ref RouteType routeType, ref string route, ref RouteFilter[] filters, ref string routeOutput) { | |
if (routeType != "") { | |
routeOutput ~= T.stringof ~ "." ~ f ~ " = " ~ | |
(cast(string)routeType) ~ ":" ~ route ~ "\n"; | |
if (filters.length == 0) { | |
// we have no filters hurray! | |
// little to no over head | |
if (routeType == RouteType.Get) | |
(cast(URLRouter)urlRouter).get(route, mixin("&me." ~ f)); | |
else if (routeType == RouteType.Post) | |
(cast(URLRouter)urlRouter).post(route, mixin("&me." ~ f)); | |
else if (routeType == RouteType.Put) | |
(cast(URLRouter)urlRouter).put(route, mixin("&me." ~ f)); | |
else if (routeType == RouteType.Delete) | |
(cast(URLRouter)urlRouter).delete_(route, mixin("&me." ~ f)); | |
else if (routeType == RouteType.Any) | |
(cast(URLRouter)urlRouter).any(route, mixin("&me." ~ f)); | |
} else { | |
// ok so we have filters.. | |
// now how do we chain them exactly? | |
if (routeType == RouteType.Get) | |
(cast(URLRouter)urlRouter).get(route, mixin("&FilterFunctionWrapper! | |
(me, \"" ~ f ~ "\", filters)")); | |
else if (routeType == RouteType.Post) | |
(cast(URLRouter)urlRouter).post(route, mixin("&FilterFunctionWrapper! | |
(me, \"" ~ f ~ "\", filters)")); | |
else if (routeType == RouteType.Put) | |
(cast(URLRouter)urlRouter).put(route, mixin("&FilterFunctionWrapper! | |
(me, \"" ~ f ~ "\", filters)")); | |
else if (routeType == RouteType.Delete) | |
(cast(URLRouter)urlRouter).delete_(route, mixin("&FilterFunctionWrapper! | |
(me, \"" ~ f ~ "\", filters)")); | |
else if (routeType == RouteType.Any) | |
(cast(URLRouter)urlRouter).any(route, mixin("&FilterFunctionWrapper! | |
(me, \"" ~ f ~ "\", filters)")); | |
} | |
} | |
} | |
void handleRouteGroups(alias symbol)(ref bool isLastGroupId, ref string route, ref RouteFilter[] filters) { | |
foreach (UDA; __traits(getAttributes, symbol)) { | |
static if (is(typeof(UDA) == RouteGroup)) { | |
// lets just hope this operates in | |
isLastGroupId = false; | |
if (UDA.routeBase != "") | |
route ~= UDA.routeBase; | |
if (UDA.filterFunction !is null) | |
filters ~= UDA.filterFunction; | |
} else static if (is(typeof(UDA) == RouteGroupId)) { | |
// lets just hope this operates in | |
isLastGroupId = true; | |
if (UDA.routeName != "") | |
route ~= "/" ~ UDA.routeName ~ "s/:" ~ UDA.routeName ~ "Id"; | |
} else static if (is(typeof(UDA) == RouteGroupIds)) { | |
// lets just hope this operates in | |
isLastGroupId = true; | |
foreach(routeName; UDA.routeNames) { | |
if (routeName != "") | |
route ~= "/" ~ routeName ~ "s/:" ~ routeName ~ "Id"; | |
} | |
} | |
} | |
} | |
} | |
} | |
/** | |
* Action router is like the normal router except it has a bunch of name associations | |
* for functions as well. | |
* Provides name association for: | |
* index -> GET / | |
* show -> GET /:id | |
* init -> GET /new | |
* create -> POST / | |
* update -> PUT /:id | |
* delete -> DELETE /:id | |
* | |
* Built based off of the issue below: | |
* https://github.com/rejectedsoftware/vibe.d/issues/444#issuecomment-31112692 | |
*/ | |
abstract class ActionRouter : Routes { | |
this(this T)() { | |
this(cast(T)this); | |
} | |
this(T)(T me) { | |
super(me); | |
string routeOutput = ""; | |
foreach(f; __traits(allMembers, T)) { | |
mixin("alias symbol = me." ~ f ~ ";"); | |
static if (__traits(compiles, { | |
mixin("me." ~ f ~ "(cast(HTTPServerRequest)null, cast(HTTPServerResponse)null);"); } )) { | |
RouteType routeType = cast(RouteType)""; | |
string route = ""; | |
RouteFilter[] filters; | |
bool isLastGroupId = false; | |
handleRouteGroups!(symbol)(isLastGroupId, route, filters); | |
foreach (UDA; __traits(getAttributes, symbol)) { | |
static if (is(typeof(UDA) == RouteFunction)) { | |
routeType = UDA.type; | |
if (!isLastGroupId) { | |
route ~= UDA.route; | |
} | |
if (UDA.filterFunction !is null) | |
filters ~= UDA.filterFunction; | |
} else { | |
switch(f) { | |
case "index": | |
routeType = RouteType.Get; | |
if (route == "") | |
route = "/"; | |
break; | |
case "show": | |
routeType = RouteType.Get; | |
route ~= "/:id"; | |
break; | |
case "init": | |
routeType = RouteType.Get; | |
route ~= "/new"; | |
break; | |
case "create": | |
routeType = RouteType.Post; | |
if (route == "") | |
route = "/"; | |
break; | |
case "update": | |
routeType = RouteType.Put; | |
route ~= "/:id"; | |
break; | |
case "delete": | |
routeType = RouteType.Delete; | |
route ~= "/:id"; | |
break; | |
default: | |
break; | |
} | |
} | |
} | |
handleRouteFunction!(T, f)(me, routeType, route, filters, routeOutput); | |
} | |
} | |
if (logFile !is null) | |
append(logFile, routeOutput); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment