1 /*
2  * Hunt - A high-level D Programming Language Web framework that encourages rapid development and clean, pragmatic design.
3  *
4  * Copyright (C) 2015-2019, HuntLabs
5  *
6  * Website: https://www.huntlabs.net/
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module hunt.framework.config.ApplicationConfig;
13 
14 import hunt.framework.Init;
15 import hunt.framework.auth.AuthOptions;
16 
17 import std.exception;
18 import std.format;
19 import std.parallelism : totalCPUs;
20 import std.process;
21 import std.socket : Address, parseAddress;
22 import std.string;
23 
24 import hunt.http.MultipartOptions;
25 import hunt.logging;
26 import hunt.util.Configuration;
27 
28 
29 // @Configuration("hunt")
30 @ConfigurationFile("application")
31 class ApplicationConfig {
32     struct ApplicationConf {
33         string name = "Hunt Application";
34         string baseUrl = "http://localhost:8080";
35         string defaultCookieDomain = "localhost";
36         string defaultLanguage = "en-US";
37         string languages = "zh-CN,en-US";
38         string secret = "CD6CABB1123C86EDAD9";
39         string encoding = "utf-8";
40         int staticFileCacheMinutes = 30;
41         string langLocation = "./translations";
42     }
43 
44     struct AuthConf {
45         string loginUrl = "/";
46         string successUrl = "/";
47         string unauthorizedUrl = "";
48 
49         string basicRealm = "Secure Area";
50 
51         // AuthenticationScheme: basic, bear/jwt
52         string guardScheme = "jwt";
53 
54         // the max inactive interval. The time unit is second.
55         int tokenExpiration = DEFAULT_TOKEN_EXPIRATION*24*60*60; 
56         
57         int shiroTokenExpiration = 30*1000;
58     }
59 
60     /** Config for static files */
61     struct StaticFilesConf {
62         bool enabled = true;
63         // default root path
64         string location = DEFAULT_STATIC_FILES_LACATION;
65         bool canList = true;
66         int cacheTime = -1; // seconds
67     }
68     
69     struct CacheConf {
70         string adapter = "memory";
71         string prefix = "";
72 
73         bool useSecondLevelCache = false;
74         uint maxEntriesLocalHeap = 10000;
75         bool eternal = false;
76         uint timeToIdleSeconds = 3600;
77         uint timeToLiveSeconds = 10;
78         bool overflowToDisk = true;
79         bool diskPersistent = true;
80         uint diskExpiryThreadIntervalSeconds = 120;
81         uint maxEntriesLocalDisk = 10000;
82     }
83 
84     struct CookieConf {
85         string domain = "";
86         string path = "/";
87         int expires = 3600;
88         bool secure = false;
89         bool httpOnly = true;
90     }
91 
92     struct SessionConf {
93         // string storage = "memory";
94         // string args = "/tmp";
95         string prefix = "huntsession_";
96         uint expire = 3600; // in seconds
97     }
98 
99     struct HttpConf {
100         string address = "0.0.0.0";
101         string path = DEFAULT_STATIC_FILES_LACATION;
102         ushort port = 8080;
103         uint workerThreads = 4;
104         uint ioThreads = 2;
105         size_t keepAliveTimeOut = 30;
106         size_t maxHeaderSize = 64 * 1024;
107         int cacheControl;
108         bool enableCors = false; // CORS support
109         string allowOrigin = "*";
110         string allowMethods = "*";
111         string allowHeaders = "*";
112         // DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type
113     }
114 
115     struct HttpsConf {
116         bool enabled = false;
117         string protocol;
118         string keyStore;
119         string keyStoreType;
120         string keyStorePassword;
121     }
122 
123     struct RouteConf {
124         RouteGroupConfig[] groups;
125     }
126 
127     struct LoggingConfig {
128         string level = "all";
129         string path;
130         string file = "";
131         bool disableConsole = false;
132         string maxSize = "8M";
133         uint maxNum = 8;
134     }
135 
136     // struct MemcacheConf {
137     //     bool enabled = false;
138     //     string servers;
139     // }
140 
141     struct RedisConf {
142         bool enabled = false;
143         string host = "127.0.0.1";
144         string password = "";
145         ushort database = 0;
146         ushort port = 6379;
147         uint timeout = 5000;
148         RedisPoolConf pool;
149         RedisClusterConf cluster;
150     }
151 
152     struct RedisPoolConf {
153         bool enabled = false;
154 
155         int maxWaitQueueSize = -1;
156         uint idleTimeout = 30000; // millisecond
157         uint maxPoolSize = 20;
158         uint minPoolSize = 5;
159         uint maxLifetime = 2000000;
160         uint connectionTimeout = 15000;
161         int waitTimeout = 15000; // -1: forever
162         uint maxConnection = 20;
163         uint minConnection = 5;        
164     }
165 
166     struct RedisClusterConf {
167         bool enabled = false;
168         string[] nodes;
169         uint redirections = 5;
170     }
171 
172     struct QueueConf {
173         bool enabled = false;
174         // Drivers: "memeory", "redis", "null"
175         string driver = null;
176     }
177 
178     struct TaskConf {
179         bool enabled = false;
180         uint workerThreads = 4;
181     }
182 
183     struct GrpcConf {
184         GrpcServerConf server;
185         GrpcClientConf[] clientChannels;
186     }
187 
188     struct UploadConf {
189         string path = "/tmp";
190         long maxSize = 4 * 1024 * 1024;
191     }
192 
193     struct MailSmtpConf {
194         string host;
195         string channel;
196         ushort port;
197         string protocol;
198         string user;
199         string password;
200     }
201 
202     struct MailConf {
203         MailSmtpConf smtp;
204     }
205 
206     struct DbPoolConf {
207         string name = "";
208         int minIdle = 5;
209         int idleTimeout = 30000;
210         int maxPoolSize = 20;
211         int minPoolSize = 5;
212         int maxLifetime = 2000000;
213         int connectionTimeout = 30000;
214         int maxConnection = 20;
215         int minConnection = 5;
216         int maxWaitQueueSize = -1;
217     }
218 
219     struct DatabaseConf {
220         
221         string url() {
222             string s = format("%s://%s:%s@%s:%d/%s?prefix=%s&charset=%s",
223                     driver, username, password, host, port, database, prefix, charset);
224             return s;
225         }
226 
227         string driver = "postgresql";
228         string host = "localhost";
229         ushort port = 5432;
230         string database = "test";
231         string username = "root";
232         string password = "";
233         string charset = "utf8";
234         string prefix = "";
235         bool enabled = false;
236 
237         DbPoolConf pool;
238     }
239 
240     struct DateConf {
241         string format;
242         string timeZone;
243     }
244 
245     struct CornConf {
246         string noon;
247     }
248 
249     struct ServiceConf {
250         string address = "127.0.0.1";
251         ushort port = 8080;
252         int workerThreads = 2;
253         string password;
254     }
255 
256     struct RpcConf {
257         bool enabled = true;
258         ServiceConf service;
259     }
260 
261     struct View {
262         string path = "./resources/views/";
263         string ext = ".html";
264         uint arrayDepth = 3;
265     }
266 
267     struct TraceConf {
268         bool enable = false;
269         bool b3Required = true;
270         TraceService service;
271         string zipkin = "http://127.0.0.1:9411/api/v2/spans";
272     }
273 
274     struct TraceService {
275         string host;
276         ushort port;
277     }
278 
279     DatabaseConf database;
280     ApplicationConf application;
281     AuthConf auth;
282     StaticFilesConf staticfiles;
283     CookieConf cookie;
284     SessionConf session;
285     CacheConf cache;
286     HttpConf http;
287     HttpsConf https;
288     RouteConf route;
289     QueueConf queue;
290     TaskConf task;
291     RedisConf redis;
292     GrpcConf grpc;
293     LoggingConfig logging;
294     UploadConf upload;
295     CornConf cron;
296     DateConf date;
297     MailConf mail;
298     RpcConf rpc;
299     View view;
300     TraceConf trace;
301 
302     // MultipartOptions multipartConfig() {
303     //     if (_multipartConfig is null) {
304     //         string path = buildPath(DEFAULT_TEMP_PATH, upload.path);
305     //         if (!path.exists()) {
306     //             // for Exception now?
307     //             path.mkdirRecurse();
308     //         }
309     //         _multipartConfig = new MultipartOptions(path, upload.maxSize, upload.maxSize, 50);
310     //     }
311     //     return _multipartConfig;
312     // }
313 
314     // private MultipartOptions _multipartConfig;
315 
316     this() {
317         http.workerThreads = totalCPUs * 4;
318         http.ioThreads = totalCPUs;
319         task.workerThreads = totalCPUs;
320         upload.path = DEFAULT_TEMP_PATH;
321         view.path = DEFAULT_TEMPLATE_PATH;
322         application.langLocation = DEFAULT_LANGUAGE_PATH;
323     }
324 }
325 
326 /**
327  * 
328  */
329 struct GrpcServerConf {
330     bool enabled = false;
331     uint workerThreads = 4;
332     string host = "127.0.0.1";
333     ushort port = 50051;
334 }
335 
336 /**
337  * 
338  */
339 struct GrpcClientConf {
340     string name="unnamed";
341     string host = "127.0.0.1";
342     ushort port = 50051;
343     uint timeout = 15000;
344 }
345 
346 /**
347  * 
348  */
349 struct RouteGroupConfig {
350     string name;
351     string type;
352     string value;
353     string guard = DEFAULT_GURAD_NAME;
354 }
355 
356 
357 import core.sync.rwmutex;
358 
359 import std.array;
360 import std.file;
361 import std.path;
362 import std.exception : basicExceptionCtors;
363 
364 /** 
365  * 
366  */
367 class ConfigNotFoundException : Exception {
368     mixin basicExceptionCtors;
369 }
370 
371 // ConfigManager configManager() {
372 //     return _manger;
373 // }
374 
375 // shared static this() {
376 //     _manger = new ConfigManager();
377 // }
378 
379 // private:
380 // __gshared ConfigManager _manger;