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