]> git.stg.codes - stg.git/blob - projects/stargazer/settings_impl.cpp
Add subscriptions (to replace notifiers).
[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 #include "stg/const.h"
27
28 #include <stdexcept>
29 #include <cstring>
30 #include <cerrno>
31
32 using STG::SettingsImpl;
33 using STG::ParamValue;
34
35 namespace
36 {
37
38 struct Error : public std::runtime_error
39 {
40     explicit Error(const std::string& message) : runtime_error(message) {}
41 };
42
43 std::vector<std::string> toValues(const DOTCONFDocumentNode& node)
44 {
45     std::vector<std::string> values;
46
47     size_t i = 0;
48     const char* value = NULL;
49     while ((value = node.getValue(i++)) != NULL)
50         values.push_back(value);
51
52     return values;
53 }
54
55 std::vector<ParamValue> toPVS(const DOTCONFDocumentNode& node)
56 {
57     std::vector<ParamValue> pvs;
58
59     const DOTCONFDocumentNode* child = node.getChildNode();
60     while (child != NULL)
61         {
62         if (child->getName() == NULL)
63             continue;
64
65         if (child->getChildNode() == NULL)
66             pvs.push_back(ParamValue(child->getName(), toValues(*child)));
67         else
68             pvs.push_back(ParamValue(child->getName(), toValues(*child), toPVS(*child)));
69
70         child = child->getNextNode();
71         }
72
73     return pvs;
74 }
75
76 unsigned toPeriod(const char* value)
77 {
78     if (value == NULL)
79         throw Error("No detail stat period value.");
80
81     std::string period(value);
82     if (period == "1")
83         return STG::dsPeriod_1;
84     else if (period == "1/2")
85         return STG::dsPeriod_1_2;
86     else if (period == "1/4")
87         return STG::dsPeriod_1_4;
88     else if (period == "1/6")
89         return STG::dsPeriod_1_6;
90
91     throw Error("Invalid detail stat period value: '" + period + "'. Should be one of '1', '1/2', '1/4' or '1/6'.");
92 }
93
94 void errorCallback(void* /*data*/, const char* buf)
95 {
96     printfd(__FILE__, "SettingsImpl::errorCallback() - %s\n", buf);
97     STG::Logger::get()("%s", buf);
98 }
99
100 }
101
102 //-----------------------------------------------------------------------------
103 SettingsImpl::SettingsImpl(const std::string & cd)
104     : modulesPath("/usr/lib/stg"),
105       dirName(DIR_NUM),
106       confDir(cd.empty() ? "/etc/stargazer" : cd),
107       scriptsDir(confDir),
108       rules(confDir + "/rules"),
109       logFile("/var/log/stargazer.log"),
110       pidFile("/var/run/stargazer.pid"),
111       monitorDir("/var/stargazer/monitoring"),
112       monitoring(false),
113       detailStatWritePeriod(dsPeriod_1_6),
114       statWritePeriod(10),
115       stgExecMsgKey(5555),
116       executersNum(1),
117       fullFee(false),
118       dayFee(0),
119       dayResetTraff(0),
120       spreadFee(false),
121       freeMbAllowInet(false),
122       dayFeeIsLastDay(false),
123       stopOnError(true),
124       writeFreeMbTraffCost(false),
125       showFeeInCash(true),
126       messageTimeout(0),
127       feeChargeType(0),
128       reconnectOnTariffChange(false),
129       disableSessionLog(false)
130 {
131     filterParamsLog.push_back("*");
132 }
133 //-----------------------------------------------------------------------------
134 int SettingsImpl::ReadSettings()
135 {
136 const char * requiredOptions[] = {
137     "ModulesPath",
138     "Modules",
139     "StoreModule",
140     "Rules",
141     "LogFile",
142     "DetailStatWritePeriod",
143     "DayFee",
144     "DayResetTraff",
145     "SpreadFee",
146     "FreeMbAllowInet",
147     "DayFeeIsLastDay",
148     "WriteFreeMbTraffCost",
149     NULL
150     };
151 int storeModulesCount = 0;
152 modulesSettings.clear();
153
154 DOTCONFDocument conf(DOTCONFDocument::CASEINSENSITIVE);
155 conf.setErrorCallback(errorCallback, nullptr);
156 conf.setRequiredOptionNames(requiredOptions);
157 std::string confFile = confDir + "/stargazer.conf";
158
159 if(conf.setContent(confFile.c_str()) != 0)
160     {
161     strError = "Cannot read file " + confFile;
162     return -1;
163     }
164
165 auto node = conf.getFirstNode();
166
167 while (node)
168     {
169     if (strcasecmp(node->getName(), "ScriptDir") == 0)
170         {
171         scriptsDir = node->getValue(0);
172         }
173
174     if (strcasecmp(node->getName(), "LogFile") == 0)
175         {
176         logFile = node->getValue(0);
177         }
178
179     if (strcasecmp(node->getName(), "PIDFile") == 0)
180         {
181         pidFile = node->getValue(0);
182         }
183
184     if (strcasecmp(node->getName(), "ModulesPath") == 0)
185         {
186         modulesPath = node->getValue(0);
187         }
188
189     if (strcasecmp(node->getName(), "Rules") == 0)
190         {
191         rules = node->getValue(0);
192         }
193
194     if (strcasecmp(node->getName(), "DetailStatWritePeriod") == 0)
195         {
196         try
197         {
198             detailStatWritePeriod = toPeriod(node->getValue(0));
199         }
200         catch (const Error& error)
201         {
202             strError = error.what();
203             return -1;
204         }
205         }
206
207     if (strcasecmp(node->getName(), "StatWritePeriod") == 0)
208         {
209         if (ParseUnsignedInRange(node->getValue(0), 1, 1440, &statWritePeriod) != 0)
210             {
211             strError = "Incorrect StatWritePeriod value: \'" + std::string(node->getValue(0)) + "\'";
212             return -1;
213             }
214         }
215
216     if (strcasecmp(node->getName(), "ExecMsgKey") == 0)
217         {
218         if (ParseInt(node->getValue(0), &stgExecMsgKey) != 0)
219             {
220             strError = "Incorrect ExecMsgKey value: \'" + std::string(node->getValue(0)) + "\'";
221             return -1;
222             }
223         }
224
225     if (strcasecmp(node->getName(), "ExecutersNum") == 0)
226         {
227         if (ParseUnsignedInRange(node->getValue(0), 1, 1024, &executersNum) != 0)
228             {
229             strError = "Incorrect ExecutersNum value: \'" + std::string(node->getValue(0)) + "\'";
230             return -1;
231             }
232         }
233
234     if (strcasecmp(node->getName(), "DayFee") == 0)
235         {
236         if (ParseUnsignedInRange(node->getValue(0), 0, 31, &dayFee) != 0)
237             {
238             strError = "Incorrect DayFee value: \'" + std::string(node->getValue(0)) + "\'";
239             return -1;
240             }
241         }
242
243     if (strcasecmp(node->getName(), "FullFee") == 0)
244         {
245         if (ParseYesNo(node->getValue(0), &fullFee) != 0)
246             {
247             strError = "Incorrect FullFee value: \'" + std::string(node->getValue(0)) + "\'";
248             return -1;
249             }
250         }
251
252     if (strcasecmp(node->getName(), "DayResetTraff") == 0)
253         {
254         if (ParseUnsignedInRange(node->getValue(0), 0, 31, &dayResetTraff) != 0)
255             {
256             strError = "Incorrect DayResetTraff value: \'" + std::string(node->getValue(0)) + "\'";
257             return -1;
258             }
259         }
260
261     if (strcasecmp(node->getName(), "SpreadFee") == 0)
262         {
263         if (ParseYesNo(node->getValue(0), &spreadFee) != 0)
264             {
265             strError = "Incorrect SpreadFee value: \'" + std::string(node->getValue(0)) + "\'";
266             return -1;
267             }
268         }
269
270     if (strcasecmp(node->getName(), "FreeMbAllowInet") == 0)
271         {
272         if (ParseYesNo(node->getValue(0), &freeMbAllowInet) != 0)
273             {
274             strError = "Incorrect FreeMbAllowInet value: \'" + std::string(node->getValue(0)) + "\'";
275             return -1;
276             }
277         }
278
279     if (strcasecmp(node->getName(), "DayFeeIsLastDay") == 0)
280         {
281         if (ParseYesNo(node->getValue(0), &dayFeeIsLastDay) != 0)
282             {
283             strError = "Incorrect DayFeeIsLastDay value: \'" + std::string(node->getValue(0)) + "\'";
284             return -1;
285             }
286         }
287
288     if (strcasecmp(node->getName(), "StopOnError") == 0)
289         {
290         if (ParseYesNo(node->getValue(0), &stopOnError) != 0)
291             {
292             strError = "Incorrect StopOnError value: \'" + std::string(node->getValue(0)) + "\'";
293             return -1;
294             }
295         }
296
297     if (strcasecmp(node->getName(), "WriteFreeMbTraffCost") == 0)
298         {
299         if (ParseYesNo(node->getValue(0), &writeFreeMbTraffCost) != 0)
300             {
301             strError = "Incorrect WriteFreeMbTraffCost value: \'" + std::string(node->getValue(0)) + "\'";
302             return -1;
303             }
304         }
305
306     if (strcasecmp(node->getName(), "ShowFeeInCash") == 0)
307         {
308         if (ParseYesNo(node->getValue(0), &showFeeInCash) != 0)
309             {
310             strError = "Incorrect ShowFeeInCash value: \'" + std::string(node->getValue(0)) + "\'";
311             return -1;
312             }
313         }
314
315     if (strcasecmp(node->getName(), "MonitorDir") == 0)
316         {
317         monitorDir = node->getValue(0);
318         struct stat stat;
319         monitoring = false;
320
321         if (!lstat(monitorDir.c_str(), &stat) && S_ISDIR(stat.st_mode))
322             {
323             monitoring = true;
324             }
325         }
326
327     if (strcasecmp(node->getName(), "MessageTimeout") == 0)
328         {
329         if (ParseUnsigned(node->getValue(0), &messageTimeout) != 0)
330             {
331             strError = "Incorrect MessageTimeout value: \'" + std::string(node->getValue(0)) + "\'";
332             return -1;
333             }
334         }
335
336     if (strcasecmp(node->getName(), "FeeChargeType") == 0)
337         {
338         if (ParseUnsignedInRange(node->getValue(0), 0, 3, &feeChargeType) != 0)
339             {
340             strError = "Incorrect FeeChargeType value: \'" + std::string(node->getValue(0)) + "\'";
341             return -1;
342             }
343         }
344
345     if (strcasecmp(node->getName(), "ReconnectOnTariffChange") == 0)
346         {
347         if (ParseYesNo(node->getValue(0), &reconnectOnTariffChange) != 0)
348             {
349             strError = "Incorrect ReconnectOnTariffChange value: \'" + std::string(node->getValue(0)) + "\'";
350             return -1;
351             }
352         }
353
354     if (strcasecmp(node->getName(), "DisableSessionLog") == 0)
355         {
356         if (ParseYesNo(node->getValue(0), &disableSessionLog) != 0)
357             {
358             strError = "Incorrect DisableSessionLog value: \'" + std::string(node->getValue(0)) + "\'";
359             return -1;
360             }
361         }
362
363     if (strcasecmp(node->getName(), "FilterParamsLog") == 0)
364         {
365         filterParamsLog.clear();
366         for (int i = 0; node->getValue(i) != NULL; ++i)
367             filterParamsLog.push_back(node->getValue(i));
368         }
369
370     if (strcasecmp(node->getName(), "DirNames") == 0)
371         {
372         const DOTCONFDocumentNode * child = node->getChildNode();
373         if (child)
374             {
375             const DOTCONFDocumentNode * dirNameNode;
376             dirName.reserve(DIR_NUM);
377             for (int i = 0; i < DIR_NUM; i++)
378                 {
379                 char strDirName[12];
380                 sprintf(strDirName, "DirName%d", i);
381                 dirNameNode = conf.findNode(strDirName, node);
382                 if (dirNameNode && dirNameNode->getValue(0))
383                     {
384                     dirName[i] = dirNameNode->getValue(0);
385                     }
386                 }
387             }
388         }
389
390     if (strcasecmp(node->getName(), "StoreModule") == 0)
391         {
392         if (node->getValue(1))
393             {
394             strError = "Unexpected \'" + std::string(node->getValue(1)) + "\'.";
395             return -1;
396             }
397
398         if (storeModulesCount)
399             {
400             strError = "Should be only one StoreModule.";
401             return -1;
402             }
403         storeModulesCount++;
404
405         if (node->getValue(0) == NULL)
406             {
407             strError = "No module name in the StoreModule section.";
408             return -1;
409             }
410         storeModuleSettings.moduleName = node->getValue(0);
411         storeModuleSettings.moduleParams = toPVS(*node);
412         }
413
414     if (strcasecmp(node->getName(), "Modules") == 0)
415         {
416         if (node->getValue(0))
417             {
418             strError = "Unexpected \'" + std::string(node->getValue(0)) + "\'.";
419             return -1;
420             }
421         const DOTCONFDocumentNode * child = node->getChildNode();
422         while (child)
423             {
424             if (strcasecmp(child->getName(), "Module") != 0)
425                 {
426                 child = child->getNextNode();
427                 continue;
428                 }
429
430             if (child->getValue(0) == NULL)
431                 {
432                 strError = "No module name in the Module section.";
433                 return -1;
434                 }
435
436             modulesSettings.push_back(ModuleSettings(child->getValue(0), toPVS(*child)));
437
438             child = child->getNextNode();
439             }
440         }
441
442     if (strcasecmp(node->getName(), "ScriptParams") == 0)
443         {
444         for (int i = 0; node->getValue(i) != NULL; ++i)
445             scriptParams.push_back(node->getValue(i));
446         }
447     node = node->getNextNode();
448     }
449
450 return 0;
451 }
452 //-----------------------------------------------------------------------------