1 module hunt.framework.provider.HttpServiceProvider;
2 
3 import hunt.framework.controller.Controller;
4 import hunt.framework.config.ApplicationConfig;
5 import hunt.framework.config.ConfigManager;
6 import hunt.framework.http.HttpErrorResponseHandler;
7 import hunt.framework.Init;
8 import hunt.framework.provider.ServiceProvider;
9 import hunt.framework.routing;
10 
11 import hunt.http.routing.RoutingContext;
12 import hunt.http.routing.RouterManager;
13 import hunt.http.server.HttpServer;
14 import hunt.http.server.HttpServerOptions;
15 import hunt.http.server.WebSocketHandler;
16 import hunt.http.WebSocketPolicy;
17 import hunt.http.WebSocketCommon;
18 
19 import hunt.logging;
20 
21 import poodinis;
22 
23 import core.time;
24 import std.array;
25 import std.exception;
26 import std.conv;
27 import std.container.array;
28 import std.file;
29 import std.path;
30 import std.socket;
31 import std.stdio;
32 import std.string;
33 import std.uni;
34 
35 /**
36  * 
37  */
38 class HttpServiceProvider : ServiceProvider {
39 
40     override void register() {
41         container.register!HttpServer.initializedBy(&buildServer).singleInstance();
42     }
43 
44     private HttpServer buildServer() {
45         DefaultErrorResponseHandler.Default = new HttpErrorResponseHandler();
46         ConfigManager manager = container.resolve!ConfigManager;
47         ApplicationConfig appConfig = container.resolve!ApplicationConfig();
48         auto staticFilesConfig = appConfig.staticfiles;
49         // SimpleWebSocketHandler webSocketHandler = new SimpleWebSocketHandler();
50         // webSocketHandler.setWebSocketPolicy(_webSocketPolicy);
51 
52         //if(conf.webSocketFactory)
53         //    _wfactory = conf.webSocketFactory;
54 
55         // Building http server
56         // HttpServerOptions options = new HttpServerOptions();
57         HttpServer.Builder hsb = HttpServer.builder()
58             .setListener(appConfig.http.port, appConfig.http.address)
59             .workerThreadSize(appConfig.http.workerThreads)
60             .maxRequestSize(cast(int)appConfig.http.maxHeaderSize)
61             .maxFileSize(cast(int)appConfig.upload.maxSize)
62             .ioThreadSize(appConfig.http.ioThreads)
63             .resourceCacheTime(staticFilesConfig.cacheTime.seconds);
64 
65         version(WITH_HUNT_TRACE) {
66             hsb.localServiceName(appConfig.application.name)
67                 .isB3HeaderRequired(appConfig.trace.b3Required);
68         }
69 
70 
71         RouteConfigManager routeConfig = container.resolve!RouteConfigManager();
72         RouteItem[][RouteGroup] allRoutes = routeConfig.allRoutes;
73 
74         foreach(RouteGroup group, RouteItem[] routes; allRoutes) {
75             foreach (RouteItem item; routes) {
76                 addRoute(hsb, item, group);
77             }
78 
79             RouteGroupType groupType = RouteGroupType.Host;
80             if (group.type == "path") {
81                 groupType = RouteGroupType.Path;
82             }
83             // if(!isRootStaticPathAdded) {
84             // default static files
85             hsb.resource("/", staticFilesConfig.location, staticFilesConfig.canList, group.value, groupType);
86             // }
87         }
88 
89         // default static files
90         hsb.resource("/", staticFilesConfig.location, staticFilesConfig.canList);
91         // hsb.setDefaultRequest((RoutingContext ctx) {
92         //     string content = "The resource " ~ ctx.getURI().getPath() ~ " is not found";
93         //     string title = "404 - Not Found";
94 
95         //     ctx.responseHeader(HttpHeader.CONTENT_TYPE, "text/html");
96 
97         //     ctx.write("<!DOCTYPE html>")
98         //         .write("<html>")
99         //         .write("<head>")
100         //         .write("<title>")
101         //         .write(title)
102         //         .write("</title>")
103         //         .write("</head>")
104         //         .write("<body>")
105         //         .write("<h1> " ~ title ~ " </h1>")
106         //         .write("<p>" ~ content ~ "</p>")
107         //         .write("</body>")
108         //         .end("</html>");
109         // });
110 
111         return hsb.build();
112     }
113 
114 
115     private void addRoute(HttpServer.Builder hsb, RouteItem item, RouteGroup group) {
116         ResourceRouteItem resourceItem = cast(ResourceRouteItem) item;
117 
118         // add route for static files 
119         if (resourceItem !is null) {
120             // if(resourceItem.path == "/") isRootStaticPathAdded = true;
121             if (group is null || group.type == RouteGroup.DEFAULT) {
122                 hsb.resource(resourceItem.path, resourceItem.resourcePath,
123                         resourceItem.canListing);
124             } else if (group.type == RouteGroup.HOST || group.type == RouteGroup.DOMAIN) {
125                 hsb.resource(resourceItem.path, resourceItem.resourcePath,
126                         resourceItem.canListing, group.value, RouteGroupType.Host);
127             } else if (group.type == RouteGroup.PATH) {
128                 hsb.resource(resourceItem.path, resourceItem.resourcePath,
129                         resourceItem.canListing, group.value, RouteGroupType.Path);
130             } else {
131                 errorf("Unknown route group type: %s", group.type);
132             }
133         } else { // add route for controller action
134             string handlerKey = makeRouteHandlerKey(cast(ActionRouteItem) item, group);
135             RoutingHandler handler = getRouteHandler(handlerKey);
136             // warning(item.toString());
137             if (handler is null) {
138                 version(HUNT_DEBUG) {
139                     warningf("No handler found for group route {%s}, key: %s", item.toString(), handlerKey);
140                 }
141             } else {
142                 version(HUNT_FM_DEBUG)
143                     tracef("handler found for group route {%s}, key: %s", item.toString(), handlerKey);
144                 string[] methods = item.methods;
145                 version(HUNT_DEBUG) {
146                     string methodsString = "[*]";
147                     if(!methods.empty)
148                         methodsString = methods.to!string();
149                 }
150 
151                 RouterContex contex = new RouterContex();
152                 contex.routeGroup = group;
153                 contex.routeItem = item;
154 
155                 if (group is null || group.type == RouteGroup.DEFAULT) {
156                     version(HUNT_DEBUG) infof("adding %s %s into DEFAULT", methodsString, item.path);
157                     hsb.addRoute([item.path], methods, handler, null, 
158                         RouteGroupType.Default, RouterContex.stringof, contex);
159                 } else if (group.type == RouteGroup.HOST || group.type == RouteGroup.DOMAIN) {
160                     version(HUNT_DEBUG) infof("adding %s %s into DOMAIN", methodsString, item.path);
161                     hsb.addRoute([item.path], methods, handler, group.value, 
162                         RouteGroupType.Host, RouterContex.stringof, contex);
163                 } else if (group.type == RouteGroup.PATH) {
164                     version(HUNT_DEBUG) infof("adding %s %s into PATH", methodsString, item.path);
165                     hsb.addRoute([item.path], methods, handler, group.value, 
166                         RouteGroupType.Path, RouterContex.stringof, contex);
167                 } else {
168                     errorf("Unknown route group type: %s", group.type);
169                 }
170             }
171         }
172     }
173 }