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 }