1 module app;
2 
3 // cannot use vibe.d due symbol clash for logging
4 import vibe.core.core;
5 import vibe.core.log;
6 import vibe.http.server;
7 import vibe.http.router;
8 
9 import jsonizer;
10 import std.json;
11 import std.file;
12 import std.path;
13 import std.getopt;
14 
15 import fileCache;
16 
17 immutable string settingsFileName = "web.json";
18 
19 void loadRouteSpecs(RouteSettings[] routes, string basePath, URLRouter router)
20 {
21     auto settings = new HTTPFileServerSettings;
22     settings.cache = new FileServerCache;
23     foreach(route; routes)
24     {
25         auto targetPath = route.arg.absolutePath(basePath);
26         if(route.type == "path")
27         {
28             router.get(route.path, serveStaticFiles(targetPath, settings)); 
29         }
30         else if(route.type == "file")
31         {
32             router.get(route.path, serveStaticFile(targetPath, settings));
33         }
34         else throw new Error("Invalid type: " ~ route.type);
35         logInfo("Mapping path: " ~ route.path ~ " with " ~ targetPath);
36     }
37 }
38 
39 int runServer(string settingsFileName)
40 {
41     settingsFileName = settingsFileName.absolutePath(thisExePath.dirName);
42     auto basePath = settingsFileName.dirName;
43 
44     // Load settings from file
45     auto settingsFileContents = readText(settingsFileName);
46     auto json = parseJSON(settingsFileContents);
47     auto settings = json.fromJSON!Settings;
48 
49     settings.logFileName = settings.logFileName.absolutePath(basePath);
50 
51     // Setup loggers
52     setLogFile(settings.logFileName, settings.logLevel);
53     
54     // Default vibe initialization
55     auto svrSettings = new HTTPServerSettings;
56     svrSettings.port = cast(ushort)settings.port;
57     svrSettings.useCompressionIfPossible = settings.useCompressionIfPossible;
58     svrSettings.bindAddresses = settings.bindAddresses;
59     //svrSettings.options |= HTTPServerOption.distribute;
60 
61     auto router = new URLRouter;
62     logInfo("Loading routes from settings");
63     loadRouteSpecs(settings.routes, basePath, router);
64 
65     listenHTTP(svrSettings, router);
66 
67     return runEventLoop();
68 }
69 
70 struct RouteSettings 
71 {
72     mixin JsonizeMe;
73 
74     @jsonize string type;
75     @jsonize string path;
76     @jsonize string arg;
77 }
78 
79 struct Settings 
80 {
81     mixin JsonizeMe;
82 
83     @jsonize(JsonizeOptional.yes) int port = 3000;
84     @jsonize(JsonizeOptional.yes) string[] bindAddresses = ["::", "0.0.0.0"];
85     @jsonize(JsonizeOptional.yes) bool useCompressionIfPossible = true;
86     @jsonize(JsonizeOptional.yes) string logFileName = "vibe.log";
87     @jsonize(JsonizeOptional.yes) LogLevel logLevel = LogLevel.none;
88     @jsonize RouteSettings[] routes;
89 }
90 
91 int main(string[] args)
92 {
93     string settingsFileNameOpt = settingsFileName;
94     auto helpInformation = getopt(args, 
95         "settings", "JSON settings file name.", &settingsFileNameOpt);
96 
97     if (helpInformation.helpWanted)
98     {
99         defaultGetoptPrinter(
100             "Help about this program. "
101             "Settings file path is relative to this executable",
102             helpInformation.options);
103         return 0;
104     }
105 
106     logInfo("Loading info from " ~ settingsFileNameOpt);
107 
108     return runServer(settingsFileNameOpt);
109 }