~singpolyma/biboumi

46ff73662cc94220c5ee962b591c8ee327de6f85 — louiz’ 8 years ago 550ab46
Clean the Config module, use static things instead of a stupid singleton
M louloulibs/config/config.cpp => louloulibs/config/config.cpp +23 -43
@@ 6,22 6,21 @@
#include <stdlib.h>

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)
{
  Config* self = Config::instance().get();
  auto it = self->values.find(option);
  auto it = Config::values.find(option);

  if (it == self->values.end())
  if (it == Config::values.end())
    return def;
  return it->second;
}

int Config::get_int(const std::string& option, const int& def)
{
  Config* self = Config::instance().get();
  std::string res = self->get(option, "");
  std::string res = Config::get(option, "");
  if (!res.empty())
    return atoi(res.c_str());
  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)
{
  Config* self = Config::instance().get();
  self->values[option] = value;
  Config::values[option] = value;
  if (save)
    {
      self->save_to_file();
      self->trigger_configuration_change();
      Config::save_to_file();
      Config::trigger_configuration_change();
    }
}

void Config::connect(t_config_changed_callback callback)
{
  Config* self = Config::instance().get();
  self->callbacks.push_back(callback);
    Config::callbacks.push_back(callback);
}

void Config::close()
void Config::clear()
{
  Config* self = Config::instance().get();
  self->values.clear();
  Config::instance().reset();
  Config::values.clear();
}

/**
 * Private methods
 */

void Config::trigger_configuration_change()
{
  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)();
}

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)
    {
      instance = std::make_unique<Config>();
      instance->read_conf();
    }
  return instance;
}

bool Config::read_conf()
{
  std::ifstream file;
  file.open(filename.data());
  std::ifstream file(Config::filename.data());
  if (!file.is_open())
    {
      if (Config::file_must_exist)
        {
          perror(("Error while opening file " + filename + " for reading.").c_str());
          file.exceptions(std::ifstream::failbit);
        }
      perror(("Error while opening file " + filename + " for reading.").c_str());
      return false;
    }

  Config::clear();

  std::string line;
  size_t pos;
  std::string option;


@@ 103,20 85,18 @@ bool Config::read_conf()
        continue ;
      option = line.substr(0, pos);
      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())
    {
      std::cerr << "Could not save config file." << std::endl;
      return ;
    }
  for (auto& it: this->values)
  for (const auto& it: Config::values)
    file << it.first << "=" << it.second << '\n';
  file.close();
}

M louloulibs/config/config.hpp => louloulibs/config/config.hpp +12 -16
@@ 60,38 60,34 @@ public:
   * Destroy the instance, forcing it to be recreated (with potentially
   * different parameters) the next time it’s needed.
   */
  static void close();
  static void clear();
  /**
   * Set the value of the filename to use, before calling any method.
   * Read the configuration file at the given path.
   */
  static std::string filename;
  static bool read_conf(const std::string& name="");
  /**
   * Set to true if you want an exception to be raised if the file does not
   * exist when reading it.
   * Get the filename
   */
  static bool file_must_exist;
  static const std::string& get_filename()
  { return Config::filename; }

private:
  /**
   * Get the singleton instance
   */
  static std::unique_ptr<Config>& instance();
  /**
   * Read the configuration file at the given path.
   * Set the value of the filename to use, before calling any method.
   */
  bool read_conf();
  static std::string filename;
  /**
   * 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().
   * 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;
  std::vector<t_config_changed_callback> callbacks;
  static std::map<std::string, std::string> values;
  static std::vector<t_config_changed_callback> callbacks;

};


M louloulibs/utils/reload.cpp => louloulibs/utils/reload.cpp +1 -3
@@ 3,9 3,7 @@

void reload_process()
{
  // Closing the config will just force it to be reopened the next time
  // a configuration option is needed
  Config::close();
  Config::read_conf();
  // Destroy the logger instance, to be recreated the next time a log
  // line needs to be written
  Logger::instance().reset();

M src/main.cpp => src/main.cpp +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
  // 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.
  int sig_to_reset = (sig == SIGINT? SIGTERM: SIGINT);
  sigset_t mask;


@@ 70,24 70,16 @@ static void sigusr_handler(int, siginfo_t*, void*)

int main(int ac, char** av)
{
  if (ac > 1)
    Config::filename = av[1];
  else
    Config::filename = xdg_config_path("biboumi.cfg");
  const std::string conf_filename = ac > 1 ? av[1] : xdg_config_path("biboumi.cfg");
  std::cerr << "Using configuration file: " << conf_filename << std::endl;

  Config::file_must_exist = true;
  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) {
  if (!Config::read_conf(conf_filename))
    return config_help("");
  }
  const std::string hostname = Config::get("hostname", "");

  const std::string password = Config::get("password", "");
  if (password.empty())
    return config_help("password");
  const std::string hostname = Config::get("hostname", "");
  if (hostname.empty())
    return config_help("hostname");


M tests/config.cpp => tests/config.cpp +5 -5
@@ 4,18 4,18 @@

TEST_CASE("Config basic")
{
  Config::filename = "test.cfg";
  Config::file_must_exist = false;
  // Write a value in the config file
  Config::read_conf("test.cfg");
  Config::set("coucou", "bonjour", true);
  Config::close();
  Config::clear();

  bool error = false;
  try
    {
      Config::file_must_exist = true;
      CHECK(Config::read_conf());
      CHECK(Config::get("coucou", "") == "bonjour");
      CHECK(Config::get("does not exist", "default") == "default");
      Config::close();
      Config::clear();
    }
  catch (const std::ios::failure& e)
    {