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 11 import std.json; 12 import std.file; 13 import std.path; 14 import std.getopt; 15 import std.datetime; 16 17 import fileCache; 18 19 immutable string settingsFileName = "web.json"; 20 21 void loadRouteSpecs(HTTPFileServerSettings settings, RouteSettings[] routes, string basePath, URLRouter router) 22 { 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 fileServerSettings = new HTTPFileServerSettings; 62 fileServerSettings.cache = settings.useServerCache ? new FileServerCache : null; 63 logInfo("Using cache: " ~ (settings.useServerCache ? "true" : "false")); 64 fileServerSettings.maxAge = settings.clientCacheMaxAge.seconds; 65 66 auto router = new URLRouter; 67 logInfo("Loading routes from settings"); 68 loadRouteSpecs(fileServerSettings, settings.routes, basePath, router); 69 70 listenHTTP(svrSettings, router); 71 72 return runEventLoop(); 73 } 74 75 struct RouteSettings 76 { 77 mixin JsonizeMe; 78 79 @jsonize string type; 80 @jsonize string path; 81 @jsonize string arg; 82 } 83 84 struct Settings 85 { 86 mixin JsonizeMe; 87 88 @jsonize(JsonizeOptional.yes) int port = 3000; 89 @jsonize(JsonizeOptional.yes) string[] bindAddresses = ["::", "0.0.0.0"]; 90 @jsonize(JsonizeOptional.yes) bool useCompressionIfPossible = true; 91 @jsonize(JsonizeOptional.yes) string logFileName = "vibe.log"; 92 @jsonize(JsonizeOptional.yes) LogLevel logLevel = LogLevel.none; 93 @jsonize(JsonizeOptional.yes) bool useServerCache = false; 94 @jsonize(JsonizeOptional.yes) uint clientCacheMaxAge = 0; 95 @jsonize RouteSettings[] routes; 96 } 97 98 int main(string[] args) 99 { 100 string settingsFileNameOpt = settingsFileName; 101 auto helpInformation = getopt(args, 102 "settings", "JSON settings file name.", &settingsFileNameOpt); 103 104 if (helpInformation.helpWanted) 105 { 106 defaultGetoptPrinter( 107 "Help about this program. " 108 "Settings file path is relative to this executable", 109 helpInformation.options); 110 return 0; 111 } 112 113 logInfo("Loading info from " ~ settingsFileNameOpt); 114 115 return runServer(settingsFileNameOpt); 116 }