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.Simplify;
13 
14 public import hunt.framework.config.ApplicationConfig;
15 public import hunt.framework.config.ConfigManager;
16 public import hunt.framework.Init;
17 public import hunt.framework.routing;
18 public import hunt.util.DateTime : time, date;
19 
20 import hunt.framework.provider;
21 import hunt.logging;
22 import hunt.util.TaskPool;
23 import hunt.util.ResoureManager;
24 
25 import poodinis;
26 
27 import std.array;
28 import std.string;
29 import std.json;
30 
31 ConfigManager configManager() {
32     return serviceContainer().resolve!(ConfigManager);
33 }
34 
35 ApplicationConfig config() {
36     return serviceContainer().resolve!(ApplicationConfig);
37 }
38 
39 RouteConfigManager routeConfig() {
40     return serviceContainer().resolve!(RouteConfigManager);
41 }
42 
43 string url(string actionId) {
44     return url(actionId, null);
45 }
46 
47 
48 string url(string actionId, string[string] params, string group) {
49     // return routeConfig().createUrl(actionId, params, group);
50 
51     // admin:user.user.view
52     string[] items = actionId.split(":");
53     string m_group = "";
54     string pathItem = "";
55     if (items.length == 1) {
56         m_group = "";
57         pathItem = actionId;
58     } else if (items.length == 2) {
59         m_group = items[0];
60         pathItem = items[1];
61     } else {
62         throw new Exception("Wrong format for actionId");
63     }
64 
65     if(m_group.empty) {
66         m_group = group;
67     }
68 
69     return routeConfig().createUrl(pathItem, params, m_group);    
70 }
71 
72 string url(string actionId, string[string] params) {
73     // admin:user.user.view
74     // string[] items = actionId.split(":");
75     // string group = "";
76     // string pathItem = "";
77     // if (items.length == 1) {
78     //     group = "";
79     //     pathItem = actionId;
80     // } else if (items.length == 2) {
81     //     group = items[0];
82     //     pathItem = items[1];
83     // } else {
84     //     throw new Exception("Wrong format for actionId");
85     // }
86 
87     // return routeConfig().createUrl(pathItem, params, group);
88     return url(actionId, params, null);
89 }
90 
91 public import hunt.entity.EntityManager;
92 
93 import hunt.entity.DefaultEntityManagerFactory;
94 import hunt.entity.EntityManagerFactory;
95 import hunt.framework.application.closer.EntityCloser;
96 import hunt.util.Common;
97 
98 version(HUNT_TEST) {
99     import std.datetime;
100     import std.format;
101     import core.atomic;
102     import core.sync.mutex;
103     import core.thread ;
104 
105     import hunt.framework.http.Request;
106     import hunt.util.ThreadHelper;
107     import hunt.collection.ArrayList;
108     import hunt.collection.ArrayList;
109 
110 
111     class EntityManagerInfo {
112         ThreadID threadId;
113         int number;
114         string path;
115         SysTime holdUpTime;
116         SysTime releaseTime;
117         // string connection;
118 
119         this() {
120             threadId = getTid();
121             holdUpTime = Clock.currTime;
122             releaseTime = holdUpTime;
123             number = atomicOp!"+="(counter, 1);
124             Request req = request();
125             if(req is null) {
126                 warning("Called from a non-Controller thread.");
127             } else {
128                 path = req.path();
129             }
130         }
131 
132         override string toString() {
133             string str = format("%6d | %05d | %s | %s | %s | %s", 
134                 threadId, number, holdUpTime, releaseTime, releaseTime-holdUpTime, path);
135 
136             return str;
137         }
138 
139         shared static int counter;
140         __gshared EntityManagerInfo[] _entityManagers;
141         __gshared Mutex _mtx;
142 
143         shared static this() {
144             // entityManagers = new ArrayList!EntityManagerInfo(500);
145             _mtx = new Mutex();
146         }
147 
148         static void append() {
149             EntityManagerInfo managerInfo = new EntityManagerInfo();
150             _mtx.lock();
151             scope(exit) _mtx.unlock();
152             _entityManagers ~= managerInfo;
153 
154             error(managerInfo.toString());
155         }
156 
157         static void remove() {
158             ThreadID tid = getTid();
159             
160             string reqPath;
161             Request req = request();
162             if(req !is null)
163                 reqPath = req.path();
164 
165             _mtx.lock();
166             scope(exit) _mtx.unlock();
167 
168             bool isRemoved = false;
169             foreach(size_t index, EntityManagerInfo managerInfo; _entityManagers) {
170                 if(managerInfo.threadId == tid && managerInfo.path == reqPath) {
171                     managerInfo.releaseTime = Clock.currTime;
172 
173                     error(managerInfo);
174                     if(index == 0) {
175                         _entityManagers = _entityManagers[index+1 .. $];
176                     } else if(index + 1 == _entityManagers.length) {
177                         _entityManagers =  _entityManagers[0 .. index];
178                     } else {
179                         _entityManagers =  _entityManagers[0 .. index] ~  _entityManagers[index+1 .. $];
180                     }
181                     isRemoved = true;
182                     break;
183                 }
184 
185                 if(!isRemoved) {
186                     warningf("Nothing removed: ", tid, reqPath);
187                 }
188             }
189         }
190 
191         static string[] listAll() {
192             string[] result;
193             _mtx.lock();
194             scope(exit) _mtx.unlock();
195 
196             foreach(EntityManagerInfo managerInfo; _entityManagers) {
197                 result ~= managerInfo.toString();
198             }
199 
200             return result;
201         }
202     }
203 
204 
205     //global entity manager
206     private EntityManager _em;
207     EntityManager defaultEntityManager() {
208         if (_em is null) {
209             _em = serviceContainer.resolve!(EntityManagerFactory).currentEntityManager();
210             registerResoure(new class Closeable {
211                 void close() {
212                     closeDefaultEntityManager();
213                     EntityManagerInfo.remove();
214                 }
215             });
216 
217             EntityManagerInfo.append();
218         }
219         return _em;
220     }
221 
222 } else {
223     //global entity manager
224     private EntityManager _em;
225     EntityManager defaultEntityManager() {
226         if (_em is null) {
227             _em = serviceContainer.resolve!(EntityManagerFactory).currentEntityManager();
228             registerResoure(new class Closeable {
229                 void close() {
230                     closeDefaultEntityManager();
231                 }
232             });
233         }
234         return _em;
235     }
236 }
237 
238 //close global entity manager
239 void closeDefaultEntityManager() {
240     if (_em !is null) {
241         _em.close();
242         _em = null;
243     }
244 }
245 
246 // i18n
247 import hunt.framework.i18n.I18n;
248 
249 private __gshared string _local /* = I18N_DEFAULT_LOCALE */ ;
250 
251 @property string getLocale() {
252     if (_local)
253         return _local;
254     return serviceContainer.resolve!(I18n).defaultLocale;
255 }
256 
257 @property setLocale(string _l) {
258     _local = toLower(_l);
259 }
260 
261 string trans(A...)(string key, lazy A args) {
262     import std.format;
263 
264     Appender!string buffer;
265     string text = _trans(key);
266     version (HUNT_DEBUG)
267         tracef("format string: %s, key: %s, args.length: ", text, key, args.length);
268     formattedWrite(buffer, text, args);
269 
270     return buffer.data;
271 }
272 
273 string transWithLocale(A...)(string locale, string key, lazy A args) {
274     import std.format;
275 
276     Appender!string buffer;
277     string text = _transWithLocale(locale, key);
278     formattedWrite(buffer, text, args);
279 
280     return buffer.data;
281 }
282 
283 string transWithLocale(string locale, string key, JSONValue args) {
284     import hunt.framework.util.Formatter;
285 
286     string text = _transWithLocale(locale, key);
287     return StrFormat(text, args);
288 }
289 
290 ///key is [filename.key]
291 private string _trans(string key) {
292     string defaultValue = key;
293     I18n i18n = serviceContainer.resolve!(I18n);
294     if (!i18n.isResLoaded) {
295         logWarning("The lang resources haven't loaded yet!");
296         return key;
297     }
298 
299     auto p = getLocale in i18n.resources;
300     if (p !is null) {
301         return p.get(key, defaultValue);
302     }
303     logWarning("unsupported local: ", getLocale, ", use default now: ", i18n.defaultLocale);
304 
305     p = i18n.defaultLocale in i18n.resources;
306 
307     if (p !is null) {
308         return p.get(key, defaultValue);
309     }
310 
311     logWarning("unsupported locale: ", i18n.defaultLocale);
312 
313     return defaultValue;
314 }
315 
316 ///key is [filename.key]
317 private string _transWithLocale(string locale, string key) {
318     string defaultValue = key;
319     I18n i18n = serviceContainer.resolve!(I18n);
320     if (!i18n.isResLoaded) {
321         logWarning("The lang resources has't loaded yet!");
322         return key;
323     }
324 
325     auto p = locale in i18n.resources;
326     if (p !is null) {
327         return p.get(key, defaultValue);
328     }
329     version(HUNT_DEBUG) { 
330         logWarning("No language resource found for ", locale, 
331             ". Use the default now: ", i18n.defaultLocale);
332     }
333 
334     locale = i18n.defaultLocale;
335     p = locale in i18n.resources;
336 
337     if (p !is null) {
338         return p.get(key, defaultValue);
339     }
340 
341     warning("No language resource found for: ", locale);
342 
343     return defaultValue;
344 }
345 
346 
347 import hunt.util.worker;
348 
349 TaskQueue taskQueue() {
350     return serviceContainer.resolve!(TaskQueue);
351 }