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             .canUpgrade(appConfig.http.canUpgrade)
64             .resourceCacheTime(staticFilesConfig.cacheTime.seconds);
65 
66         version(WITH_HUNT_TRACE) {
67             hsb.localServiceName(appConfig.application.name)
68                 .isB3HeaderRequired(appConfig.trace.b3Required);
69         }
70 
71 
72         RouteConfigManager routeConfig = container.resolve!RouteConfigManager();
73         RouteItem[][RouteGroup] allRoutes = routeConfig.allRoutes;
74 
75         foreach(RouteGroup group, RouteItem[] routes; allRoutes) {
76             foreach (RouteItem item; routes) {
77                 addRoute(hsb, item, group);
78             }
79 
80             RouteGroupType groupType = RouteGroupType.Host;
81             if (group.type == "path") {
82                 groupType = RouteGroupType.Path;
83             }
84             // if(!isRootStaticPathAdded) {
85             // default static files
86             hsb.resource("/", staticFilesConfig.location, staticFilesConfig.canList, group.value, groupType);
87             // }
88         }
89 
90         // default static files
91         hsb.resource("/", staticFilesConfig.location, staticFilesConfig.canList);
92         // hsb.setDefaultRequest((RoutingContext ctx) {
93         //     string content = "The resource " ~ ctx.getURI().getPath() ~ " is not found";
94         //     string title = "404 - Not Found";
95 
96         //     ctx.responseHeader(HttpHeader.CONTENT_TYPE, "text/html");
97 
98         //     ctx.write("<!DOCTYPE html>")
99         //         .write("<html>")
100         //         .write("<head>")
101         //         .write("<title>")
102         //         .write(title)
103         //         .write("</title>")
104         //         .write("</head>")
105         //         .write("<body>")
106         //         .write("<h1> " ~ title ~ " </h1>")
107         //         .write("<p>" ~ content ~ "</p>")
108         //         .write("</body>")
109         //         .end("</html>");
110         // });
111 
112         return hsb.build();
113     }
114 
115 
116     private void addRoute(HttpServer.Builder hsb, RouteItem item, RouteGroup group) {
117         ResourceRouteItem resourceItem = cast(ResourceRouteItem) item;
118 
119         // add route for static files 
120         if (resourceItem !is null) {
121             // if(resourceItem.path == "/") isRootStaticPathAdded = true;
122             if (group is null || group.type == RouteGroup.DEFAULT) {
123                 hsb.resource(resourceItem.path, resourceItem.resourcePath,
124                         resourceItem.canListing);
125             } else if (group.type == RouteGroup.HOST || group.type == RouteGroup.DOMAIN) {
126                 hsb.resource(resourceItem.path, resourceItem.resourcePath,
127                         resourceItem.canListing, group.value, RouteGroupType.Host);
128             } else if (group.type == RouteGroup.PATH) {
129                 hsb.resource(resourceItem.path, resourceItem.resourcePath,
130                         resourceItem.canListing, group.value, RouteGroupType.Path);
131             } else {
132                 errorf("Unknown route group type: %s", group.type);
133             }
134         } else { // add route for controller action
135             string handlerKey = makeRouteHandlerKey(cast(ActionRouteItem) item, group);
136             RoutingHandler handler = getRouteHandler(handlerKey);
137             // warning(item.toString());
138             if (handler is null) {
139                 version(HUNT_DEBUG) {
140                     warningf("No handler found for group route {%s}, key: %s", item.toString(), handlerKey);
141                 }
142             } else {
143                 version(HUNT_FM_DEBUG)
144                     tracef("handler found for group route {%s}, key: %s", item.toString(), handlerKey);
145                 string[] methods = item.methods;
146                 version(HUNT_DEBUG) {
147                     string methodsString = "[*]";
148                     if(!methods.empty)
149                         methodsString = methods.to!string();
150                 }
151 
152                 RouterContex contex = new RouterContex();
153                 contex.routeGroup = group;
154                 contex.routeItem = item;
155 
156                 if (group is null || group.type == RouteGroup.DEFAULT) {
157                     version(HUNT_DEBUG) infof("adding %s %s into DEFAULT", methodsString, item.path);
158                     hsb.addRoute([item.path], methods, handler, null, 
159                         RouteGroupType.Default, RouterContex.stringof, contex);
160                 } else if (group.type == RouteGroup.HOST || group.type == RouteGroup.DOMAIN) {
161                     version(HUNT_DEBUG) infof("adding %s %s into DOMAIN", methodsString, item.path);
162                     hsb.addRoute([item.path], methods, handler, group.value, 
163                         RouteGroupType.Host, RouterContex.stringof, contex);
164                 } else if (group.type == RouteGroup.PATH) {
165                     version(HUNT_DEBUG) infof("adding %s %s into PATH", methodsString, item.path);
166                     hsb.addRoute([item.path], methods, handler, group.value, 
167                         RouteGroupType.Path, RouterContex.stringof, contex);
168                 } else {
169                     errorf("Unknown route group type: %s", group.type);
170                 }
171             }
172         }
173     }
174 }