Clean the Config module, use static things instead of a stupid singleton
This commit is contained in:
@@ -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();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user