Clean the Config module, use static things instead of a stupid singleton

This commit is contained in:
louiz’
2016-06-14 03:02:36 +02:00
parent 550ab46f02
commit 46ff73662c
5 changed files with 52 additions and 86 deletions
+22 -42
View File
@@ -6,22 +6,21 @@
#include <stdlib.h> #include <stdlib.h>
std::string Config::filename{}; std::string Config::filename{};
bool Config::file_must_exist = false; std::map<std::string, std::string> Config::values{};
std::vector<t_config_changed_callback> Config::callbacks{};
std::string Config::get(const std::string& option, const std::string& def) std::string Config::get(const std::string& option, const std::string& def)
{ {
Config* self = Config::instance().get(); auto it = Config::values.find(option);
auto it = self->values.find(option);
if (it == self->values.end()) if (it == Config::values.end())
return def; return def;
return it->second; return it->second;
} }
int Config::get_int(const std::string& option, const int& def) int Config::get_int(const std::string& option, const int& def)
{ {
Config* self = Config::instance().get(); std::string res = Config::get(option, "");
std::string res = self->get(option, "");
if (!res.empty()) if (!res.empty())
return atoi(res.c_str()); return atoi(res.c_str());
else else
@@ -30,65 +29,48 @@ int Config::get_int(const std::string& option, const int& def)
void Config::set(const std::string& option, const std::string& value, bool save) void Config::set(const std::string& option, const std::string& value, bool save)
{ {
Config* self = Config::instance().get(); Config::values[option] = value;
self->values[option] = value;
if (save) if (save)
{ {
self->save_to_file(); Config::save_to_file();
self->trigger_configuration_change(); Config::trigger_configuration_change();
} }
} }
void Config::connect(t_config_changed_callback callback) void Config::connect(t_config_changed_callback callback)
{ {
Config* self = Config::instance().get(); Config::callbacks.push_back(callback);
self->callbacks.push_back(callback);
} }
void Config::close() void Config::clear()
{ {
Config* self = Config::instance().get(); Config::values.clear();
self->values.clear();
Config::instance().reset();
} }
/** /**
* Private methods * Private methods
*/ */
void Config::trigger_configuration_change() void Config::trigger_configuration_change()
{ {
std::vector<t_config_changed_callback>::iterator it; std::vector<t_config_changed_callback>::iterator it;
for (it = this->callbacks.begin(); it < this->callbacks.end(); ++it) for (it = Config::callbacks.begin(); it < Config::callbacks.end(); ++it)
(*it)(); (*it)();
} }
std::unique_ptr<Config>& Config::instance() bool Config::read_conf(const std::string& name)
{ {
static std::unique_ptr<Config> instance; if (!name.empty())
Config::filename = name;
if (!instance) std::ifstream file(Config::filename.data());
{
instance = std::make_unique<Config>();
instance->read_conf();
}
return instance;
}
bool Config::read_conf()
{
std::ifstream file;
file.open(filename.data());
if (!file.is_open()) if (!file.is_open())
{
if (Config::file_must_exist)
{ {
perror(("Error while opening file " + filename + " for reading.").c_str()); perror(("Error while opening file " + filename + " for reading.").c_str());
file.exceptions(std::ifstream::failbit);
}
return false; return false;
} }
Config::clear();
std::string line; std::string line;
size_t pos; size_t pos;
std::string option; std::string option;
@@ -103,20 +85,18 @@ bool Config::read_conf()
continue ; continue ;
option = line.substr(0, pos); option = line.substr(0, pos);
value = line.substr(pos+1); value = line.substr(pos+1);
this->values[option] = value; Config::values[option] = value;
} }
return true;
} }
void Config::save_to_file() const void Config::save_to_file()
{ {
std::ofstream file(this->filename.data()); std::ofstream file(Config::filename.data());
if (file.fail()) if (file.fail())
{ {
std::cerr << "Could not save config file." << std::endl; std::cerr << "Could not save config file." << std::endl;
return ; return ;
} }
for (auto& it: this->values) for (const auto& it: Config::values)
file << it.first << "=" << it.second << '\n'; file << it.first << "=" << it.second << '\n';
file.close();
} }
+16 -20
View File
@@ -60,38 +60,34 @@ public:
* Destroy the instance, forcing it to be recreated (with potentially * Destroy the instance, forcing it to be recreated (with potentially
* different parameters) the next time it’s needed. * different parameters) the next time it’s needed.
*/ */
static void close(); static void clear();
/**
* Read the configuration file at the given path.
*/
static bool read_conf(const std::string& name="");
/**
* Get the filename
*/
static const std::string& get_filename()
{ return Config::filename; }
private:
/** /**
* Set the value of the filename to use, before calling any method. * Set the value of the filename to use, before calling any method.
*/ */
static std::string filename; static std::string filename;
/**
* Set to true if you want an exception to be raised if the file does not
* exist when reading it.
*/
static bool file_must_exist;
private:
/**
* Get the singleton instance
*/
static std::unique_ptr<Config>& instance();
/**
* Read the configuration file at the given path.
*/
bool read_conf();
/** /**
* Write all the config values into the configuration file * Write all the config values into the configuration file
*/ */
void save_to_file() const; static void save_to_file();
/** /**
* Call all the callbacks previously registered using connect(). * Call all the callbacks previously registered using connect().
* This is used to notify any class that a configuration change occured. * This is used to notify any class that a configuration change occured.
*/ */
void trigger_configuration_change(); static void trigger_configuration_change();
std::map<std::string, std::string> values; static std::map<std::string, std::string> values;
std::vector<t_config_changed_callback> callbacks; static std::vector<t_config_changed_callback> callbacks;
}; };
+1 -3
View File
@@ -3,9 +3,7 @@
void reload_process() void reload_process()
{ {
// Closing the config will just force it to be reopened the next time Config::read_conf();
// a configuration option is needed
Config::close();
// Destroy the logger instance, to be recreated the next time a log // Destroy the logger instance, to be recreated the next time a log
// line needs to be written // line needs to be written
Logger::instance().reset(); Logger::instance().reset();
+7 -15
View File
@@ -47,7 +47,7 @@ static void sigint_handler(int sig, siginfo_t*, void*)
{ {
// We reset the SIGTERM or SIGINT (the one that didn't trigger this // We reset the SIGTERM or SIGINT (the one that didn't trigger this
// handler) signal handler to its default value. This avoid calling this // handler) signal handler to its default value. This avoid calling this
// handler twice, if the process receive both signals in a quick // handler twice, if the process receives both signals in a quick
// succession. // succession.
int sig_to_reset = (sig == SIGINT? SIGTERM: SIGINT); int sig_to_reset = (sig == SIGINT? SIGTERM: SIGINT);
sigset_t mask; sigset_t mask;
@@ -70,24 +70,16 @@ static void sigusr_handler(int, siginfo_t*, void*)
int main(int ac, char** av) int main(int ac, char** av)
{ {
if (ac > 1) const std::string conf_filename = ac > 1 ? av[1] : xdg_config_path("biboumi.cfg");
Config::filename = av[1]; std::cerr << "Using configuration file: " << conf_filename << std::endl;
else
Config::filename = xdg_config_path("biboumi.cfg");
Config::file_must_exist = true; if (!Config::read_conf(conf_filename))
std::cerr << "Using configuration file: " << Config::filename << std::endl;
std::string password;
try { // The file must exist
password = Config::get("password", "");
}
catch (const std::ios::failure& e) {
return config_help(""); return config_help("");
}
const std::string hostname = Config::get("hostname", ""); const std::string password = Config::get("password", "");
if (password.empty()) if (password.empty())
return config_help("password"); return config_help("password");
const std::string hostname = Config::get("hostname", "");
if (hostname.empty()) if (hostname.empty())
return config_help("hostname"); return config_help("hostname");
+5 -5
View File
@@ -4,18 +4,18 @@
TEST_CASE("Config basic") TEST_CASE("Config basic")
{ {
Config::filename = "test.cfg"; // Write a value in the config file
Config::file_must_exist = false; Config::read_conf("test.cfg");
Config::set("coucou", "bonjour", true); Config::set("coucou", "bonjour", true);
Config::close(); Config::clear();
bool error = false; bool error = false;
try try
{ {
Config::file_must_exist = true; CHECK(Config::read_conf());
CHECK(Config::get("coucou", "") == "bonjour"); CHECK(Config::get("coucou", "") == "bonjour");
CHECK(Config::get("does not exist", "default") == "default"); CHECK(Config::get("does not exist", "default") == "default");
Config::close(); Config::clear();
} }
catch (const std::ios::failure& e) catch (const std::ios::failure& e)
{ {