1 /**
2 * Copyright © Yurai Web Framework 2021
3 * License: MIT (https://github.com/YuraiWeb/yurai/blob/main/LICENSE)
4 * Author: Jacob Jensen (bausshf)
5 */
6 module yurai.services.apicontrollers;
7 
8 import yurai.external.iserver;
9 import yurai.core.ihttprequest;
10 import yurai.core.ihttpresponse;
11 import yurai.services.contentservice;
12 import yurai.services.middlewarestate;
13 
14 private string removeControllerFromName(string s)
15 {
16   import std.string : strip;
17   import std.algorithm : endsWith;
18 
19   s = s.strip;
20 
21   if (s.endsWith("Controller"))
22   {
23     return s[0 .. "Controller".length];
24   }
25 
26   return s;
27 }
28 
29 public final class ApiControllerContentMiddleware : IContentMiddleware
30 {
31   final:
32   private this() {}
33 
34   public:
35   ContentMiddlewareState handle(IHttpRequest request, IHttpResponse response)
36   {
37     import std.string : toLower, format;
38 
39     import yurai.prebuild.controllersmap;
40     import yurai.controllers : Controller, ApiController, Status, HttpRoute;
41 
42     auto route = request.path && request.path.length && request.path[0].length ? request.path[0] : "/";
43 
44     switch (route.toLower)
45     {
46       static foreach (controllerModule; Yurai_ControllerModules)
47       {{
48         mixin("import moduleImport = " ~ controllerModule ~ ";");
49 
50         static foreach (symbolName; __traits(allMembers, moduleImport))
51         {
52           static if (__traits(compiles, { mixin("alias symbol = moduleImport." ~ symbolName ~ ";"); }))
53           {
54             mixin("alias symbol = moduleImport." ~ symbolName ~ ";");
55             enum isClass = (is(symbol == class));
56 
57             static if (isClass)
58             {
59               static if (__traits(compiles, { static const _ = new symbol(null, null); }))
60               {
61                 import std.traits : BaseClassesTuple;
62                 import std.meta : AliasSeq;
63                 import std.traits : hasUDA, getUDAs;
64 
65                 static const isApiController = is(BaseClassesTuple!symbol == AliasSeq!(ApiController, Controller, Object));
66 
67                 static if (isApiController)
68                 {
69                   static if (hasUDA!(symbol, HttpRoute))
70                   {
71                     static const routeAttribute = getUDAs!(symbol, HttpRoute)[0];
72 
73                     static const routeName = routeAttribute.name.toLower;
74                   }
75                   else
76                   {
77                     static const routeName = symbolName.removeControllerFromName().toLower;
78                   }
79 
80                   mixin(`
81                     case "%s":
82                       auto status = new symbol(request, response).handle();
83 
84                       if (status == Status.notFound) return ContentMiddlewareState.shouldContinue;
85                       else return ContentMiddlewareState.exit;
86                     `.format(routeName));
87                 }
88               }
89             }
90           }
91         }
92       }}
93 
94       default: return ContentMiddlewareState.shouldContinue;
95     }
96   }
97 }
98 
99 IServer registerApiControllers(IServer server)
100 {
101   return server.registerContentService(new ApiControllerContentMiddleware);
102 }