Add a Config module, and use it to get the password from a file
This commit is contained in:
+16
-2
@@ -32,6 +32,14 @@ file(GLOB source_utils
|
|||||||
add_library(utils STATIC ${source_utils})
|
add_library(utils STATIC ${source_utils})
|
||||||
target_link_libraries(utils ${ICONV_LIBRARIES})
|
target_link_libraries(utils ${ICONV_LIBRARIES})
|
||||||
|
|
||||||
|
#
|
||||||
|
## config
|
||||||
|
#
|
||||||
|
file(GLOB source_config
|
||||||
|
src/config/*.[hc]pp)
|
||||||
|
add_library(config STATIC ${source_config})
|
||||||
|
target_link_libraries(config utils)
|
||||||
|
|
||||||
#
|
#
|
||||||
## network
|
## network
|
||||||
#
|
#
|
||||||
@@ -64,11 +72,16 @@ file(GLOB source_bridge
|
|||||||
add_library(bridge STATIC ${source_bridge})
|
add_library(bridge STATIC ${source_bridge})
|
||||||
target_link_libraries(bridge xmpp irc)
|
target_link_libraries(bridge xmpp irc)
|
||||||
|
|
||||||
|
#
|
||||||
|
## Main executable
|
||||||
|
#
|
||||||
add_executable(${PROJECT_NAME} src/main.cpp)
|
add_executable(${PROJECT_NAME} src/main.cpp)
|
||||||
target_link_libraries(${PROJECT_NAME}
|
target_link_libraries(${PROJECT_NAME}
|
||||||
xmpp
|
xmpp
|
||||||
irc
|
irc
|
||||||
bridge)
|
bridge
|
||||||
|
utils
|
||||||
|
config)
|
||||||
|
|
||||||
#
|
#
|
||||||
## Tests
|
## Tests
|
||||||
@@ -79,6 +92,7 @@ target_link_libraries(test
|
|||||||
xmpp
|
xmpp
|
||||||
irc
|
irc
|
||||||
bridge
|
bridge
|
||||||
utils)
|
utils
|
||||||
|
config)
|
||||||
|
|
||||||
CONFIGURE_FILE(config.h.cmake src/config.h @ONLY)
|
CONFIGURE_FILE(config.h.cmake src/config.h @ONLY)
|
||||||
|
|||||||
@@ -0,0 +1,129 @@
|
|||||||
|
#include <utils/make_unique.hpp>
|
||||||
|
#include <config/config.hpp>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
std::string Config::filename = "./biboumi.cfg";
|
||||||
|
bool Config::file_must_exist = false;
|
||||||
|
|
||||||
|
std::string Config::get(const std::string& option, const std::string& def)
|
||||||
|
{
|
||||||
|
Config* self = Config::instance().get();
|
||||||
|
auto it = self->values.find(option);
|
||||||
|
|
||||||
|
if (it == self->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, "");
|
||||||
|
if (!res.empty())
|
||||||
|
return atoi(res.c_str());
|
||||||
|
else
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::set_int(const std::string& option, const int& value, bool save)
|
||||||
|
{
|
||||||
|
std::ostringstream os;
|
||||||
|
os << value;
|
||||||
|
Config::set(option, os.str(), save);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::set(const std::string& option, const std::string& value, bool save)
|
||||||
|
{
|
||||||
|
Config* self = Config::instance().get();
|
||||||
|
self->values[option] = value;
|
||||||
|
if (save)
|
||||||
|
{
|
||||||
|
self->save_to_file();
|
||||||
|
self->trigger_configuration_change();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::connect(t_config_changed_callback callback)
|
||||||
|
{
|
||||||
|
Config* self = Config::instance().get();
|
||||||
|
self->callbacks.push_back(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::close()
|
||||||
|
{
|
||||||
|
Config* self = Config::instance().get();
|
||||||
|
self->save_to_file();
|
||||||
|
self->values.clear();
|
||||||
|
Config::instance().reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)
|
||||||
|
(*it)();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Config>& Config::instance()
|
||||||
|
{
|
||||||
|
static std::unique_ptr<Config> instance;
|
||||||
|
|
||||||
|
if (!instance)
|
||||||
|
{
|
||||||
|
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 (Config::file_must_exist)
|
||||||
|
{
|
||||||
|
perror(("Error while opening file " + filename + " for reading.").c_str());
|
||||||
|
file.exceptions(std::ifstream::failbit);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
size_t pos;
|
||||||
|
std::string option;
|
||||||
|
std::string value;
|
||||||
|
while (file.good())
|
||||||
|
{
|
||||||
|
std::getline(file, line);
|
||||||
|
if (line == "" || line[0] == '#')
|
||||||
|
continue ;
|
||||||
|
pos = line.find('=');
|
||||||
|
if (pos == std::string::npos)
|
||||||
|
continue ;
|
||||||
|
option = line.substr(0, pos);
|
||||||
|
value = line.substr(pos+1);
|
||||||
|
this->values[option] = value;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::save_to_file() const
|
||||||
|
{
|
||||||
|
std::ofstream file(this->filename.data());
|
||||||
|
if (file.fail())
|
||||||
|
{
|
||||||
|
std::cerr << "Could not save config file." << std::endl;
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
for (auto& it: this->values)
|
||||||
|
file << it.first << "=" << it.second << std::endl;
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
/**
|
||||||
|
* Read the config file and save all the values in a map.
|
||||||
|
* Also, a singleton.
|
||||||
|
*
|
||||||
|
* Use Config::filename = "bla" to set the filename you want to use.
|
||||||
|
*
|
||||||
|
* If you want to exit if the file does not exist when it is open for
|
||||||
|
* reading, set Config::file_must_exist = true.
|
||||||
|
*
|
||||||
|
* Config::get() can the be used to access the values in the conf.
|
||||||
|
*
|
||||||
|
* Use Config::close() when you're done getting/setting value. This will
|
||||||
|
* save the config into the file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CONFIG_INCLUDED
|
||||||
|
# define CONFIG_INCLUDED
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <fstream>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
typedef std::function<void()> t_config_changed_callback;
|
||||||
|
|
||||||
|
class Config
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Config(){};
|
||||||
|
~Config(){};
|
||||||
|
/**
|
||||||
|
* returns a value from the config. If it doesn’t exist, use
|
||||||
|
* the second argument as the default.
|
||||||
|
* @param option The option we want
|
||||||
|
* @param def The default value in case the option does not exist
|
||||||
|
*/
|
||||||
|
static std::string get(const std::string&, const std::string&);
|
||||||
|
/**
|
||||||
|
* returns a value from the config. If it doesn’t exist, use
|
||||||
|
* the second argument as the default.
|
||||||
|
* @param option The option we want
|
||||||
|
* @param def The default value in case the option does not exist
|
||||||
|
*/
|
||||||
|
static int get_int(const std::string&, const int&);
|
||||||
|
/**
|
||||||
|
* Set a value for the given option. And write all the config
|
||||||
|
* in the file from which it was read if boolean is set.
|
||||||
|
* @param option The option to set
|
||||||
|
* @param value The value to use
|
||||||
|
* @param save if true, save the config file
|
||||||
|
*/
|
||||||
|
static void set(const std::string&, const std::string&, bool save = false);
|
||||||
|
/**
|
||||||
|
* Set a value for the given option. And write all the config
|
||||||
|
* in the file from which it was read if boolean is set.
|
||||||
|
* @param option The option to set
|
||||||
|
* @param value The value to use
|
||||||
|
* @param save if true, save the config file
|
||||||
|
*/
|
||||||
|
static void set_int(const std::string&, const int&, bool save = false);
|
||||||
|
/**
|
||||||
|
* Adds a function to a list. This function will be called whenever a
|
||||||
|
* configuration change occurs.
|
||||||
|
*/
|
||||||
|
static void connect(t_config_changed_callback);
|
||||||
|
/**
|
||||||
|
* Close the config file, saving it to the file is save == true.
|
||||||
|
*/
|
||||||
|
static void close();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the value of the filename to use, before calling any method.
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
void save_to_file() const;
|
||||||
|
/**
|
||||||
|
* Call all the callbacks previously registered using connect().
|
||||||
|
* This is used to notify any class that a configuration change occured.
|
||||||
|
*/
|
||||||
|
void trigger_configuration_change();
|
||||||
|
|
||||||
|
std::map<std::string, std::string> values;
|
||||||
|
std::vector<t_config_changed_callback> callbacks;
|
||||||
|
|
||||||
|
Config(const Config&) = delete;
|
||||||
|
Config& operator=(const Config&) = delete;
|
||||||
|
Config(Config&&) = delete;
|
||||||
|
Config& operator=(Config&&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CONFIG_INCLUDED
|
||||||
+23
-4
@@ -1,13 +1,32 @@
|
|||||||
#include <network/poller.hpp>
|
|
||||||
#include <xmpp/xmpp_component.hpp>
|
#include <xmpp/xmpp_component.hpp>
|
||||||
|
#include <network/poller.hpp>
|
||||||
|
#include <config/config.hpp>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
int main()
|
int main(int ac, char** av)
|
||||||
{
|
{
|
||||||
Poller p;
|
if (ac > 1)
|
||||||
|
Config::filename = av[1];
|
||||||
|
Config::file_must_exist = true;
|
||||||
|
|
||||||
|
std::string password;
|
||||||
|
try { // The file must exist
|
||||||
|
password = Config::get("password", "");
|
||||||
|
}
|
||||||
|
catch (const std::ios::failure& e) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (password.empty())
|
||||||
|
{
|
||||||
|
std::cerr << "No password provided." << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
std::shared_ptr<XmppComponent> xmpp_component =
|
std::shared_ptr<XmppComponent> xmpp_component =
|
||||||
std::make_shared<XmppComponent>("irc.localhost", "secret");
|
std::make_shared<XmppComponent>("irc.abricot", password);
|
||||||
|
|
||||||
|
Poller p;
|
||||||
p.add_socket_handler(xmpp_component);
|
p.add_socket_handler(xmpp_component);
|
||||||
xmpp_component->start();
|
xmpp_component->start();
|
||||||
while (p.poll())
|
while (p.poll())
|
||||||
|
|||||||
+25
-1
@@ -10,6 +10,8 @@
|
|||||||
#include <utils/encoding.hpp>
|
#include <utils/encoding.hpp>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <config/config.hpp>
|
||||||
|
|
||||||
#include <xmpp/xmpp_parser.hpp>
|
#include <xmpp/xmpp_parser.hpp>
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
@@ -49,7 +51,7 @@ int main()
|
|||||||
* XML parsing
|
* XML parsing
|
||||||
*/
|
*/
|
||||||
XmppParser xml;
|
XmppParser xml;
|
||||||
const std::string doc = "<stream xmlns='stream_ns'><stanza b='c'>inner<child1/><child2 xmlns='child2_ns'/>tail</stanza></stream>";
|
const std::string doc = "<stream xmlns='stream_ns'><stanza b='c'>inner<child1><grandchild/></child1><child2 xmlns='child2_ns'/>tail</stanza></stream>";
|
||||||
xml.add_stanza_callback([](const Stanza& stanza)
|
xml.add_stanza_callback([](const Stanza& stanza)
|
||||||
{
|
{
|
||||||
assert(stanza.get_name() == "stream_ns:stanza");
|
assert(stanza.get_name() == "stream_ns:stanza");
|
||||||
@@ -62,5 +64,27 @@ int main()
|
|||||||
assert(stanza.get_child("child2_ns:child2")->get_tail() == "tail");
|
assert(stanza.get_child("child2_ns:child2")->get_tail() == "tail");
|
||||||
});
|
});
|
||||||
xml.feed(doc.data(), doc.size(), true);
|
xml.feed(doc.data(), doc.size(), true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Config
|
||||||
|
*/
|
||||||
|
Config::filename = "test.cfg";
|
||||||
|
Config::file_must_exist = false;
|
||||||
|
Config::set("coucou", "bonjour");
|
||||||
|
Config::close();
|
||||||
|
|
||||||
|
bool error = false;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Config::file_must_exist = true;
|
||||||
|
assert(Config::get("coucou", "") == "bonjour");
|
||||||
|
assert(Config::get("does not exist", "default") == "default");
|
||||||
|
Config::close();
|
||||||
|
}
|
||||||
|
catch (const std::ios::failure& e)
|
||||||
|
{
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
assert(error == false);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user