1 module appbase.options;
2 
3 import std.array;
4 import std.conv;
5 import std.exception;
6 import std.string;
7 import std.format;
8 import std.datetime;
9 
10 import database.mysql;
11 
12 import appbase.configuration;
13 import appbase.mysql;
14 
15 alias options = Options.getInstance;
16 
17 class OptionsNotLoadException : Exception
18 {
19     mixin basicExceptionCtors;
20 }
21 
22 final class Options
23 {
24     @property value(string name)
25     {
26         enforce!OptionsNotLoadException(_loaded, "Options is not be load().");
27 
28         refresh();
29         return _value.value(name);
30     }
31 
32     auto opDispatch(string s)()
33     {
34         enforce!OptionsNotLoadException(_loaded, "Options is not be load().");
35 
36         refresh();
37         return _value.opDispatch!(s)();
38     }
39 
40     @property __gshared static Options getInstance()
41     {
42         if (_instance is null)
43         {
44             synchronized(Options.classinfo)
45             {
46                 if (_instance is null)
47                 {
48                     _instance = new Options();
49                 }
50             }
51         }
52 
53         return _instance;
54     }
55 
56     void load(string tableName, int expire = 0)
57     {
58         Connection conn = getConnection();
59         DataRows rows = query(conn, "select * from " ~ tableName ~ " order by id;");
60         releaseConnection(conn);
61 
62         _value = new ConfigurationItem!("database")();
63 
64         foreach (row; rows)
65         {
66             string key = strip(row["key"]);
67 
68             if (key.length == 0) continue;
69             if (key[0] == '#' || key[0] == ';') continue;
70 
71             fill(split(key, '.'), row["value"].strip);
72         }
73 
74         _loaded = true;
75 
76         _tableName = tableName;
77         _expire = expire;
78         _loadTime = cast(DateTime)Clock.currTime();
79     }
80 
81 private:
82 
83     void fill(string[] key, string value)
84     {
85         auto cvalue = _value;
86         foreach (ref k; key)
87         {
88             if (k.length == 0) continue;
89 
90             auto tvalue = cvalue._map.get(k, null);
91 
92             if (tvalue is null)
93             {
94                 tvalue = new ConfigurationItem!("database")();
95                 cvalue._map[k] = tvalue;
96             }
97 
98             cvalue = tvalue;
99         }
100 
101         if (cvalue is _value)
102         {
103             return;
104         }
105 
106         cvalue._value = value;
107     }
108 
109     void refresh()
110     {
111         if (_expire <= 0)
112             return;
113 
114         DateTime now = cast(DateTime)Clock.currTime();
115         if ((now - _loadTime).total!"minutes" > _expire)
116         {
117             synchronized (Options.classinfo)
118             {
119                 if ((now - _loadTime).total!"minutes" > _expire)
120                 {
121                     load(_tableName, _expire);
122                 }
123             }
124         }
125     }
126 
127     bool _loaded;
128     ConfigurationItem!("database") _value;
129     __gshared Options _instance = null;
130 
131     string _tableName;
132     int _expire;
133     DateTime _loadTime;
134 }