]> git.stg.codes - stg.git/blob - projects/stargazer/settings_impl.cpp
Allow to have multi-leveled module settings.
[stg.git] / projects / stargazer / settings_impl.cpp
1 /*
2  *    This program is free software; you can redistribute it and/or modify
3  *    it under the terms of the GNU General Public License as published by
4  *    the Free Software Foundation; either version 2 of the License, or
5  *    (at your option) any later version.
6  *
7  *    This program is distributed in the hope that it will be useful,
8  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *    GNU General Public License for more details.
11  *
12  *    You should have received a copy of the GNU General Public License
13  *    along with this program; if not, write to the Free Software
14  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15  */
16
17 /*
18  *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
19  */
20
21 #include "settings_impl.h"
22
23 #include "stg/logger.h"
24 #include "stg/dotconfpp.h"
25 #include "stg/common.h"
26
27 #include <stdexcept>
28 #include <cstring>
29 #include <cerrno>
30
31 namespace
32 {
33
34 struct Error : public std::runtime_error
35 {
36     Error(const std::string& message) : runtime_error(message) {}
37 };
38
39 std::vector<std::string> toValues(const DOTCONFDocumentNode& node)
40 {
41     std::vector<std::string> values;
42
43     size_t i = 0;
44     const char* value = NULL;
45     while ((value = node.getValue(i++)) != NULL)
46         values.push_back(value);
47
48     return values;
49 }
50
51 std::vector<PARAM_VALUE> toPVS(const DOTCONFDocumentNode& node)
52 {
53     std::vector<PARAM_VALUE> pvs;
54
55     const DOTCONFDocumentNode* child = node.getChildNode();
56     while (child != NULL)
57         {
58         if (child->getName() == NULL)
59             continue;
60
61         if (child->getChildNode() == NULL)
62             pvs.push_back(PARAM_VALUE(child->getName(), toValues(*child)));
63         else
64             pvs.push_back(PARAM_VALUE(child->getName(), toValues(*child), toPVS(*child)));
65
66         child = child->getNextNode();
67         }
68
69     return pvs;
70 }
71
72 unsigned toPeriod(const char* value)
73 {
74     if (value == NULL)
75         throw Error("No detail stat period value.");
76
77     std::string period(value);
78     if (period == "1")
79         return dsPeriod_1;
80     else if (period == "1/2")
81         return dsPeriod_1_2;
82     else if (period == "1/4")
83         return dsPeriod_1_4;
84     else if (period == "1/6")
85         return dsPeriod_1_6;
86
87     throw Error("Invalid detail stat period value: '" + period + "'. Should be one of '1', '1/2', '1/4' or '1/6'.");
88 }
89
90 }
91
92 //-----------------------------------------------------------------------------
93 SETTINGS_IMPL::SETTINGS_IMPL(const std::string & cd)
94     : modulesPath("/usr/lib/stg"),
95       dirName(DIR_NUM),
96       confDir(cd.empty() ? "/etc/stargazer" : cd),
97       scriptsDir(confDir),
98       rules(confDir + "/rules"),
99       logFile("/var/log/stargazer.log"),
100       pidFile("/var/run/stargazer.pid"),
101       monitorDir("/var/stargazer/monitoring"),
102       monitoring(false),
103       detailStatWritePeriod(dsPeriod_1_6),
104       statWritePeriod(10),
105       stgExecMsgKey(5555),
106       executersNum(1),
107       fullFee(false),
108       dayFee(0),
109       dayResetTraff(0),
110       spreadFee(false),
111       freeMbAllowInet(false),
112       dayFeeIsLastDay(false),
113       writeFreeMbTraffCost(false),
114       showFeeInCash(true),
115       messageTimeout(0),
116       feeChargeType(0),
117       reconnectOnTariffChange(false),
118       logger(GetStgLogger())
119 {
120 }
121 //-----------------------------------------------------------------------------
122 void SETTINGS_IMPL::ErrorCallback(void * data, const char * buf)
123 {
124     printfd(__FILE__, "SETTINGS_IMPL::ErrorCallback() - %s\n", buf);
125     SETTINGS_IMPL * settings = static_cast<SETTINGS_IMPL *>(data);
126     settings->logger("%s", buf);
127 }
128 //-----------------------------------------------------------------------------
129 int SETTINGS_IMPL::ReadSettings()
130 {
131 const char * requiredOptions[] = {
132     "ModulesPath",
133     "Modules",
134     "StoreModule",
135     "Rules",
136     "LogFile",
137     "DetailStatWritePeriod",
138     "DayFee",
139     "DayResetTraff",
140     "SpreadFee",
141     "FreeMbAllowInet",
142     "DayFeeIsLastDay",
143     "WriteFreeMbTraffCost",
144     NULL
145     };
146 int storeModulesCount = 0;
147 modulesSettings.clear();
148
149 DOTCONFDocument conf(DOTCONFDocument::CASEINSENSITIVE);
150 conf.setErrorCallback(SETTINGS_IMPL::ErrorCallback, this);
151 conf.setRequiredOptionNames(requiredOptions);
152 std::string confFile = confDir + "/stargazer.conf";
153
154 if(conf.setContent(confFile.c_str()) != 0)
155     {
156     strError = "Cannot read file " + confFile;
157     return -1;
158     }
159
160 const DOTCONFDocumentNode * node = conf.getFirstNode();
161
162 while (node)
163     {
164     if (strcasecmp(node->getName(), "ScriptDir") == 0)
165         {
166         scriptsDir = node->getValue(0);
167         }
168
169     if (strcasecmp(node->getName(), "LogFile") == 0)
170         {
171         logFile = node->getValue(0);
172         }
173
174     if (strcasecmp(node->getName(), "PIDFile") == 0)
175         {
176         pidFile = node->getValue(0);
177         }
178
179     if (strcasecmp(node->getName(), "ModulesPath") == 0)
180         {
181         modulesPath = node->getValue(0);
182         }
183
184     if (strcasecmp(node->getName(), "Rules") == 0)
185         {
186         rules = node->getValue(0);
187         }
188
189     if (strcasecmp(node->getName(), "DetailStatWritePeriod") == 0)
190         {
191         try
192         {
193             detailStatWritePeriod = toPeriod(node->getValue(0));
194         }
195         catch (const Error& error)
196         {
197             strError = error.what();
198             return -1;
199         }
200         }
201
202     if (strcasecmp(node->getName(), "StatWritePeriod") == 0)
203         {
204         if (ParseUnsignedInRange(node->getValue(0), 1, 1440, &statWritePeriod) != 0)
205             {
206             strError = "Incorrect StatWritePeriod value: \'" + std::string(node->getValue(0)) + "\'";
207             return -1;
208             }
209         }
210
211     if (strcasecmp(node->getName(), "ExecMsgKey") == 0)
212         {
213         if (ParseInt(node->getValue(0), &stgExecMsgKey) != 0)
214             {
215             strError = "Incorrect ExecMsgKey value: \'" + std::string(node->getValue(0)) + "\'";
216             return -1;
217             }
218         }
219
220     if (strcasecmp(node->getName(), "ExecutersNum") == 0)
221         {
222         if (ParseUnsignedInRange(node->getValue(0), 1, 1024, &executersNum) != 0)
223             {
224             strError = "Incorrect ExecutersNum value: \'" + std::string(node->getValue(0)) + "\'";
225             return -1;
226             }
227         }
228
229     if (strcasecmp(node->getName(), "DayFee") == 0)
230         {
231         if (ParseUnsignedInRange(node->getValue(0), 0, 31, &dayFee) != 0)
232             {
233             strError = "Incorrect DayFee value: \'" + std::string(node->getValue(0)) + "\'";
234             return -1;
235             }
236         }
237
238     if (strcasecmp(node->getName(), "FullFee") == 0)
239         {
240         if (ParseYesNo(node->getValue(0), &fullFee) != 0)
241             {
242             strError = "Incorrect FullFee value: \'" + std::string(node->getValue(0)) + "\'";
243             return -1;
244             }
245         }
246
247     if (strcasecmp(node->getName(), "DayResetTraff") == 0)
248         {
249         if (ParseUnsignedInRange(node->getValue(0), 0, 31, &dayResetTraff) != 0)
250             {
251             strError = "Incorrect DayResetTraff value: \'" + std::string(node->getValue(0)) + "\'";
252             return -1;
253             }
254         }
255
256     if (strcasecmp(node->getName(), "SpreadFee") == 0)
257         {
258         if (ParseYesNo(node->getValue(0), &spreadFee) != 0)
259             {
260             strError = "Incorrect SpreadFee value: \'" + std::string(node->getValue(0)) + "\'";
261             return -1;
262             }
263         }
264
265     if (strcasecmp(node->getName(), "FreeMbAllowInet") == 0)
266         {
267         if (ParseYesNo(node->getValue(0), &freeMbAllowInet) != 0)
268             {
269             strError = "Incorrect FreeMbAllowInet value: \'" + std::string(node->getValue(0)) + "\'";
270             return -1;
271             }
272         }
273
274     if (strcasecmp(node->getName(), "DayFeeIsLastDay") == 0)
275         {
276         if (ParseYesNo(node->getValue(0), &dayFeeIsLastDay) != 0)
277             {
278             strError = "Incorrect DayFeeIsLastDay value: \'" + std::string(node->getValue(0)) + "\'";
279             return -1;
280             }
281         }
282
283     if (strcasecmp(node->getName(), "WriteFreeMbTraffCost") == 0)
284         {
285         if (ParseYesNo(node->getValue(0), &writeFreeMbTraffCost) != 0)
286             {
287             strError = "Incorrect WriteFreeMbTraffCost value: \'" + std::string(node->getValue(0)) + "\'";
288             return -1;
289             }
290         }
291
292     if (strcasecmp(node->getName(), "ShowFeeInCash") == 0)
293         {
294         if (ParseYesNo(node->getValue(0), &showFeeInCash) != 0)
295             {
296             strError = "Incorrect ShowFeeInCash value: \'" + std::string(node->getValue(0)) + "\'";
297             return -1;
298             }
299         }
300
301     if (strcasecmp(node->getName(), "MonitorDir") == 0)
302         {
303         monitorDir = node->getValue(0);
304         struct stat stat;
305         monitoring = false;
306
307         if (!lstat(monitorDir.c_str(), &stat) && S_ISDIR(stat.st_mode))
308             {
309             monitoring = true;
310             }
311         }
312
313     if (strcasecmp(node->getName(), "MessageTimeout") == 0)
314         {
315         if (ParseUnsigned(node->getValue(0), &messageTimeout) != 0)
316             {
317             strError = "Incorrect MessageTimeout value: \'" + std::string(node->getValue(0)) + "\'";
318             return -1;
319             }
320         }
321
322     if (strcasecmp(node->getName(), "FeeChargeType") == 0)
323         {
324         if (ParseUnsignedInRange(node->getValue(0), 0, 3, &feeChargeType) != 0)
325             {
326             strError = "Incorrect FeeChargeType value: \'" + std::string(node->getValue(0)) + "\'";
327             return -1;
328             }
329         }
330
331     if (strcasecmp(node->getName(), "ReconnectOnTariffChange") == 0)
332         {
333         if (ParseYesNo(node->getValue(0), &reconnectOnTariffChange) != 0)
334             {
335             strError = "Incorrect ReconnectOnTariffChange value: \'" + std::string(node->getValue(0)) + "\'";
336             return -1;
337             }
338         }
339
340     if (strcasecmp(node->getName(), "DirNames") == 0)
341         {
342         const DOTCONFDocumentNode * child = node->getChildNode();
343         if (child)
344             {
345             const DOTCONFDocumentNode * dirNameNode;
346             dirName.reserve(DIR_NUM);
347             for (int i = 0; i < DIR_NUM; i++)
348                 {
349                 char strDirName[12];
350                 sprintf(strDirName, "DirName%d", i);
351                 dirNameNode = conf.findNode(strDirName, node);
352                 if (dirNameNode && dirNameNode->getValue(0))
353                     {
354                     dirName[i] = dirNameNode->getValue(0);
355                     }
356                 }
357             }
358         }
359
360     if (strcasecmp(node->getName(), "StoreModule") == 0)
361         {
362         if (node->getValue(1))
363             {
364             strError = "Unexpected \'" + std::string(node->getValue(1)) + "\'.";
365             return -1;
366             }
367
368         if (storeModulesCount)
369             {
370             strError = "Should be only one StoreModule.";
371             return -1;
372             }
373         storeModulesCount++;
374
375         if (node->getValue(0) == NULL)
376             {
377             strError = "No module name in the StoreModule section.";
378             return -1;
379             }
380         storeModuleSettings.moduleName = node->getValue(0);
381         storeModuleSettings.moduleParams = toPVS(*node);
382         }
383
384     if (strcasecmp(node->getName(), "Modules") == 0)
385         {
386         if (node->getValue(0))
387             {
388             strError = "Unexpected \'" + std::string(node->getValue(0)) + "\'.";
389             return -1;
390             }
391         const DOTCONFDocumentNode * child = node->getChildNode();
392         while (child)
393             {
394             if (strcasecmp(child->getName(), "Module") != 0)
395                 {
396                 child = child->getNextNode();
397                 continue;
398                 }
399
400             if (child->getValue(0) == NULL)
401                 {
402                 strError = "No module name in the Module section.";
403                 return -1;
404                 }
405
406             modulesSettings.push_back(MODULE_SETTINGS(child->getValue(0), toPVS(*child)));
407
408             child = child->getNextNode();
409             }
410         }
411
412     if (strcasecmp(node->getName(), "ScriptParams") == 0)
413         {
414         for (int i = 0; node->getValue(i) != NULL; ++i)
415             {
416             scriptParams.push_back(node->getValue(i));
417             }
418         }
419     node = node->getNextNode();
420     }
421
422 return 0;
423 }
424 //-----------------------------------------------------------------------------