# HG changeset patch # User David Demelier # Date 1533476830 -7200 # Node ID c216d148558d8f4afca674eb405080c93fb5b57d # Parent 6d09b5fc82e87b33bd969e407b22983a3743f1d9 Irccd: remove service directory diff -r 6d09b5fc82e8 -r c216d148558d irccd-test/main.cpp --- a/irccd-test/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/irccd-test/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -37,9 +37,8 @@ #include #include - -#include -#include +#include +#include #include diff -r 6d09b5fc82e8 -r c216d148558d irccd/main.cpp --- a/irccd/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/irccd/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -30,11 +30,10 @@ #include #include #include - -#include -#include -#include -#include +#include +#include +#include +#include #if defined(IRCCD_HAVE_JS) # include diff -r 6d09b5fc82e8 -r c216d148558d irccdctl/cli.cpp --- a/irccdctl/cli.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/irccdctl/cli.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -24,7 +24,7 @@ #include -#include +#include #include "cli.hpp" diff -r 6d09b5fc82e8 -r c216d148558d libirccd-js/irccd/js/logger_jsapi.cpp --- a/libirccd-js/irccd/js/logger_jsapi.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/libirccd-js/irccd/js/logger_jsapi.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -18,7 +18,7 @@ #include #include -#include +#include #include "irccd_jsapi.hpp" #include "js_plugin.hpp" diff -r 6d09b5fc82e8 -r c216d148558d libirccd-js/irccd/js/plugin_jsapi.cpp --- a/libirccd-js/irccd/js/plugin_jsapi.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/libirccd-js/irccd/js/plugin_jsapi.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -17,8 +17,7 @@ */ #include - -#include +#include #include "irccd_jsapi.hpp" #include "js_plugin.hpp" diff -r 6d09b5fc82e8 -r c216d148558d libirccd-js/irccd/js/server_jsapi.cpp --- a/libirccd-js/irccd/js/server_jsapi.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/libirccd-js/irccd/js/server_jsapi.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -21,10 +21,9 @@ #include #include +#include #include -#include - #include "duktape_vector.hpp" #include "irccd_jsapi.hpp" #include "js_plugin.hpp" diff -r 6d09b5fc82e8 -r c216d148558d libirccd-js/irccd/js/timer_jsapi.cpp --- a/libirccd-js/irccd/js/timer_jsapi.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/libirccd-js/irccd/js/timer_jsapi.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -20,7 +20,7 @@ #include #include -#include +#include #include "irccd_jsapi.hpp" #include "js_plugin.hpp" diff -r 6d09b5fc82e8 -r c216d148558d libirccd-test/irccd/test/cli_test.cpp --- a/libirccd-test/irccd/test/cli_test.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/libirccd-test/irccd/test/cli_test.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -22,7 +22,8 @@ #include #include -#include +#include +#include #include "cli_test.hpp" diff -r 6d09b5fc82e8 -r c216d148558d libirccd-test/irccd/test/command_test.hpp --- a/libirccd-test/irccd/test/command_test.hpp Sun Aug 05 12:14:16 2018 +0200 +++ b/libirccd-test/irccd/test/command_test.hpp Sun Aug 05 15:47:10 2018 +0200 @@ -27,7 +27,8 @@ #include #include #include -#include +#include +#include #include diff -r 6d09b5fc82e8 -r c216d148558d libirccd-test/irccd/test/plugin_cli_test.cpp --- a/libirccd-test/irccd/test/plugin_cli_test.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/libirccd-test/irccd/test/plugin_cli_test.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include #include +#include #include "plugin_cli_test.hpp" diff -r 6d09b5fc82e8 -r c216d148558d libirccd-test/irccd/test/plugin_cli_test.hpp --- a/libirccd-test/irccd/test/plugin_cli_test.hpp Sun Aug 05 12:14:16 2018 +0200 +++ b/libirccd-test/irccd/test/plugin_cli_test.hpp Sun Aug 05 15:47:10 2018 +0200 @@ -24,9 +24,8 @@ * \brief Test fixture for irccdctl frontend (plugins support). */ -#include - #include +#include #include "cli_test.hpp" diff -r 6d09b5fc82e8 -r c216d148558d libirccd-test/irccd/test/plugin_test.cpp --- a/libirccd-test/irccd/test/plugin_test.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/libirccd-test/irccd/test/plugin_test.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -19,9 +19,8 @@ #include #include - -#include -#include +#include +#include #include #include diff -r 6d09b5fc82e8 -r c216d148558d libirccd-test/irccd/test/rule_cli_test.cpp --- a/libirccd-test/irccd/test/rule_cli_test.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/libirccd-test/irccd/test/rule_cli_test.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include #include +#include #include "rule_cli_test.hpp" diff -r 6d09b5fc82e8 -r c216d148558d libirccd-test/irccd/test/rule_cli_test.hpp --- a/libirccd-test/irccd/test/rule_cli_test.hpp Sun Aug 05 12:14:16 2018 +0200 +++ b/libirccd-test/irccd/test/rule_cli_test.hpp Sun Aug 05 15:47:10 2018 +0200 @@ -24,9 +24,8 @@ * \brief Test fixture for irccdctl frontend (rule support). */ -#include - #include +#include #include "cli_test.hpp" diff -r 6d09b5fc82e8 -r c216d148558d libirccd-test/irccd/test/server_cli_test.cpp --- a/libirccd-test/irccd/test/server_cli_test.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/libirccd-test/irccd/test/server_cli_test.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include #include +#include #include "server_cli_test.hpp" diff -r 6d09b5fc82e8 -r c216d148558d libirccd-test/irccd/test/server_cli_test.hpp --- a/libirccd-test/irccd/test/server_cli_test.hpp Sun Aug 05 12:14:16 2018 +0200 +++ b/libirccd-test/irccd/test/server_cli_test.hpp Sun Aug 05 15:47:10 2018 +0200 @@ -24,7 +24,7 @@ * \brief Test fixture for irccdctl frontend (server support). */ -#include +#include #include diff -r 6d09b5fc82e8 -r c216d148558d libirccd/CMakeLists.txt --- a/libirccd/CMakeLists.txt Sun Aug 05 12:14:16 2018 +0200 +++ b/libirccd/CMakeLists.txt Sun Aug 05 15:47:10 2018 +0200 @@ -22,20 +22,20 @@ HEADERS ${libirccd_SOURCE_DIR}/irccd/daemon/command.hpp ${libirccd_SOURCE_DIR}/irccd/daemon/dynlib_plugin.hpp + ${libirccd_SOURCE_DIR}/irccd/daemon/irc.hpp ${libirccd_SOURCE_DIR}/irccd/daemon/irccd.hpp - ${libirccd_SOURCE_DIR}/irccd/daemon/irc.hpp ${libirccd_SOURCE_DIR}/irccd/daemon/logger.hpp ${libirccd_SOURCE_DIR}/irccd/daemon/plugin.hpp + ${libirccd_SOURCE_DIR}/irccd/daemon/plugin_service.hpp ${libirccd_SOURCE_DIR}/irccd/daemon/rule.hpp + ${libirccd_SOURCE_DIR}/irccd/daemon/rule_service.hpp ${libirccd_SOURCE_DIR}/irccd/daemon/rule_util.hpp ${libirccd_SOURCE_DIR}/irccd/daemon/server.hpp + ${libirccd_SOURCE_DIR}/irccd/daemon/server_service.hpp ${libirccd_SOURCE_DIR}/irccd/daemon/server_util.hpp - ${libirccd_SOURCE_DIR}/irccd/daemon/service/plugin_service.hpp - ${libirccd_SOURCE_DIR}/irccd/daemon/service/rule_service.hpp - ${libirccd_SOURCE_DIR}/irccd/daemon/service/server_service.hpp - ${libirccd_SOURCE_DIR}/irccd/daemon/service/transport_service.hpp ${libirccd_SOURCE_DIR}/irccd/daemon/transport_client.hpp ${libirccd_SOURCE_DIR}/irccd/daemon/transport_server.hpp + ${libirccd_SOURCE_DIR}/irccd/daemon/transport_service.hpp ${libirccd_SOURCE_DIR}/irccd/daemon/transport_util.hpp ) @@ -43,20 +43,20 @@ SOURCES ${libirccd_SOURCE_DIR}/irccd/daemon/command.cpp ${libirccd_SOURCE_DIR}/irccd/daemon/dynlib_plugin.cpp + ${libirccd_SOURCE_DIR}/irccd/daemon/irc.cpp ${libirccd_SOURCE_DIR}/irccd/daemon/irccd.cpp - ${libirccd_SOURCE_DIR}/irccd/daemon/irc.cpp ${libirccd_SOURCE_DIR}/irccd/daemon/logger.cpp ${libirccd_SOURCE_DIR}/irccd/daemon/plugin.cpp + ${libirccd_SOURCE_DIR}/irccd/daemon/plugin_service.cpp ${libirccd_SOURCE_DIR}/irccd/daemon/rule.cpp + ${libirccd_SOURCE_DIR}/irccd/daemon/rule_service.cpp ${libirccd_SOURCE_DIR}/irccd/daemon/rule_util.cpp ${libirccd_SOURCE_DIR}/irccd/daemon/server.cpp + ${libirccd_SOURCE_DIR}/irccd/daemon/server_service.cpp ${libirccd_SOURCE_DIR}/irccd/daemon/server_util.cpp - ${libirccd_SOURCE_DIR}/irccd/daemon/service/plugin_service.cpp - ${libirccd_SOURCE_DIR}/irccd/daemon/service/rule_service.cpp - ${libirccd_SOURCE_DIR}/irccd/daemon/service/server_service.cpp - ${libirccd_SOURCE_DIR}/irccd/daemon/service/transport_service.cpp ${libirccd_SOURCE_DIR}/irccd/daemon/transport_client.cpp ${libirccd_SOURCE_DIR}/irccd/daemon/transport_server.cpp + ${libirccd_SOURCE_DIR}/irccd/daemon/transport_service.cpp ${libirccd_SOURCE_DIR}/irccd/daemon/transport_util.cpp ) diff -r 6d09b5fc82e8 -r c216d148558d libirccd/irccd/daemon/command.cpp --- a/libirccd/irccd/daemon/command.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/libirccd/irccd/daemon/command.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -16,21 +16,19 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - #include #include "command.hpp" +#include "irccd.hpp" +#include "plugin.hpp" +#include "plugin_service.hpp" +#include "rule.hpp" +#include "rule_service.hpp" +#include "rule_util.hpp" +#include "server.hpp" +#include "server_service.hpp" +#include "server_util.hpp" +#include "transport_client.hpp" using namespace std::string_literals; diff -r 6d09b5fc82e8 -r c216d148558d libirccd/irccd/daemon/irccd.cpp --- a/libirccd/irccd/daemon/irccd.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/libirccd/irccd/daemon/irccd.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -25,11 +25,10 @@ #include "irccd.hpp" #include "logger.hpp" - -#include "service/plugin_service.hpp" -#include "service/rule_service.hpp" -#include "service/server_service.hpp" -#include "service/transport_service.hpp" +#include "plugin_service.hpp" +#include "rule_service.hpp" +#include "server_service.hpp" +#include "transport_service.hpp" namespace irccd { diff -r 6d09b5fc82e8 -r c216d148558d libirccd/irccd/daemon/plugin_service.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd/irccd/daemon/plugin_service.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -0,0 +1,265 @@ +/* + * plugin_service.cpp -- plugin service + * + * Copyright (c) 2013-2018 David Demelier + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include +#include + +#include "irccd.hpp" +#include "logger.hpp" +#include "plugin_service.hpp" + +using boost::format; +using boost::str; + +namespace irccd { + +namespace { + +auto to_map(const config& conf, const std::string& section) -> plugin::map +{ + plugin::map ret; + + for (const auto& opt : conf.get(section)) + ret.emplace(opt.key(), opt.value()); + + return ret; +} + +} // !namespace + +plugin_service::plugin_service(irccd& irccd) noexcept + : irccd_(irccd) +{ +} + +plugin_service::~plugin_service() +{ + for (const auto& plg : plugins_) { + try { + plg->handle_unload(irccd_); + } catch (const std::exception& ex) { + irccd_.get_log().warning(*plg) << ex.what() << std::endl; + } + } +} + +auto plugin_service::all() const noexcept -> plugins +{ + return plugins_; +} + +auto plugin_service::has(std::string_view id) const noexcept -> bool +{ + return get(id) != nullptr; +} + +auto plugin_service::get(std::string_view id) const noexcept -> std::shared_ptr +{ + const auto find = [id] (const auto& plg) { + return plg->get_id() == id; + }; + + if (const auto it = std::find_if(plugins_.begin(), plugins_.end(), find); it != plugins_.end()) + return *it; + + return nullptr; +} + +auto plugin_service::require(std::string_view id) const -> std::shared_ptr +{ + auto plugin = get(id); + + if (!plugin) + throw plugin_error(plugin_error::not_found, id); + + return plugin; +} + +void plugin_service::add(std::shared_ptr plugin) +{ + assert(plugin); + + plugins_.push_back(std::move(plugin)); +} + +void plugin_service::add_loader(std::unique_ptr loader) +{ + assert(loader); + + loaders_.push_back(std::move(loader)); +} + +auto plugin_service::get_options(std::string_view id) -> plugin::map +{ + return to_map(irccd_.get_config(), str(format("plugin.%1%") % id)); +} + +auto plugin_service::get_formats(std::string_view id) -> plugin::map +{ + return to_map(irccd_.get_config(), str(format("format.%1%") % id)); +} + +auto plugin_service::get_paths(std::string_view id) -> plugin::map +{ + auto defaults = to_map(irccd_.get_config(), "paths"); + auto paths = to_map(irccd_.get_config(), str(format("paths.%1%") % id)); + + // Fill defaults paths. + if (!defaults.count("cache")) + defaults.emplace("cache", sys::cachedir().string()); + if (!defaults.count("data")) + defaults.emplace("data", sys::datadir().string()); + if (!defaults.count("config")) + defaults.emplace("config", sys::sysconfdir().string()); + + const auto join = [id] (auto path) { + return (boost::filesystem::path(path) / "plugin" / std::string(id)).string(); + }; + + // Now fill missing fields. + if (!paths.count("cache")) + paths.emplace("cache", join(defaults["cache"])); + if (!paths.count("data")) + paths.emplace("data", join(defaults["data"])); + if (!paths.count("config")) + paths.emplace("config", join(defaults["config"])); + + return paths; +} + +auto plugin_service::open(std::string_view id, std::string_view path) -> std::shared_ptr +{ + for (const auto& loader : loaders_) { + auto plugin = loader->open(id, path); + + if (plugin) + return plugin; + } + + return nullptr; +} + +auto plugin_service::find(std::string_view id) -> std::shared_ptr +{ + for (const auto& loader : loaders_) { + try { + auto plugin = loader->find(id); + + if (plugin) + return plugin; + } catch (const std::exception& ex) { + irccd_.get_log().warning("plugin", id) << ex.what() << std::endl; + } + } + + return nullptr; +} + +void plugin_service::load(std::string_view id, std::string_view path) +{ + if (has(id)) + throw plugin_error(plugin_error::already_exists, id); + + std::shared_ptr plugin; + + if (path.empty()) + plugin = find(id); + else + plugin = open(id, std::move(path)); + + if (!plugin) + throw plugin_error(plugin_error::not_found, id); + + plugin->set_options(get_options(id)); + plugin->set_formats(get_formats(id)); + plugin->set_paths(get_paths(id)); + + exec(plugin, &plugin::handle_load, irccd_); + add(std::move(plugin)); +} + +void plugin_service::reload(std::string_view id) +{ + auto plugin = get(id); + + if (!plugin) + throw plugin_error(plugin_error::not_found, id); + + exec(plugin, &plugin::handle_reload, irccd_); +} + +void plugin_service::unload(std::string_view id) +{ + const auto find = [id] (const auto& plg) { + return plg->get_id() == id; + }; + + const auto it = std::find_if(plugins_.begin(), plugins_.end(), find); + + if (it == plugins_.end()) + throw plugin_error(plugin_error::not_found, id); + + // Erase first, in case of throwing. + const auto save = *it; + + plugins_.erase(it); + exec(save, &plugin::handle_unload, irccd_); +} + +void plugin_service::load(const config& cfg) noexcept +{ + for (const auto& option : cfg.get("plugins")) { + if (!string_util::is_identifier(option.key())) + continue; + + auto id = option.key(); + auto p = get(id); + + // Reload the plugin if already loaded. + if (p) { + p->set_options(get_options(id)); + p->set_formats(get_formats(id)); + p->set_paths(get_paths(id)); + } else { + try { + load(id, option.value()); + } catch (const std::exception& ex) { + irccd_.get_log().warning("plugin", id) << ex.what() << std::endl; + } + } + } +} + +namespace logger { + +auto loggable_traits::get_category(const plugin&) -> std::string_view +{ + return "plugin"; +} + +auto loggable_traits::get_component(const plugin& plugin) -> std::string_view +{ + return plugin.get_id(); +} + +} // !logger + +} // !irccd diff -r 6d09b5fc82e8 -r c216d148558d libirccd/irccd/daemon/plugin_service.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd/irccd/daemon/plugin_service.hpp Sun Aug 05 15:47:10 2018 +0200 @@ -0,0 +1,279 @@ +/* + * plugin_service.hpp -- plugin service + * + * Copyright (c) 2013-2018 David Demelier + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_DAEMON_PLUGIN_SERVICE_HPP +#define IRCCD_DAEMON_PLUGIN_SERVICE_HPP + +/** + * \file plugin_service.hpp + * \brief Plugin service. + */ + +#include +#include +#include +#include +#include + +#include "plugin.hpp" + +namespace irccd { + +class irccd; +class config; + +/** + * \brief Manage plugins. + * \ingroup services + */ +class plugin_service { +public: + /** + * \brief Map of plugins. + */ + using plugins = std::vector>; + + /** + * \brief List of loaders. + */ + using plugin_loaders = std::vector>; + +private: + irccd& irccd_; + plugins plugins_; + plugin_loaders loaders_; + +public: + /** + * Create the plugin service. + * + * \param irccd the irccd instance + */ + plugin_service(irccd& irccd) noexcept; + + /** + * Destroy plugins. + */ + virtual ~plugin_service(); + + /** + * Get the list of plugins. + * + * \return the list of plugins + */ + auto all() const noexcept -> plugins; + + /** + * Check if a plugin is loaded. + * + * \param id the plugin id + * \return true if has plugin + */ + auto has(std::string_view id) const noexcept -> bool; + + /** + * Get a loaded plugin or null if not found. + * + * \param id the plugin id + * \return the plugin or empty one if not found + */ + auto get(std::string_view id) const noexcept -> std::shared_ptr; + + /** + * Find a loaded plugin. + * + * \param id the plugin id + * \return the plugin + * \throw plugin_error on errors + */ + auto require(std::string_view id) const -> std::shared_ptr; + + /** + * Add the specified plugin to the registry. + * + * \pre plg != nullptr + * \param plg the plugin + * \note the plugin is only added to the list, no action is performed on it + */ + void add(std::shared_ptr plg); + + /** + * Add a loader. + * + * \pre loader != nullptr + * \param loader the loader + */ + void add_loader(std::unique_ptr loader); + + /** + * Get the configuration for the specified plugin. + * + * \param id the plugin id + * \return the configuration + */ + auto get_options(std::string_view id) -> plugin::map; + + /** + * Get the formats for the specified plugin. + * + * \param id the plugin id + * \return the formats + */ + auto get_formats(std::string_view id) -> plugin::map; + + /** + * Get the paths for the specified plugin. + * + * If none is defined, return the default ones. + * + * \param id the plugin id + * \return the paths + */ + auto get_paths(std::string_view id) -> plugin::map; + + /** + * Generic function for opening the plugin at the given path. + * + * This function will search for every pluginLoader and call open() on it, + * the first one that success will be returned. + * + * \param id the plugin id + * \param path the path to the file + * \return the plugin or nullptr on failures + */ + auto open(std::string_view id, std::string_view path) -> std::shared_ptr; + + /** + * Generic function for finding a plugin. + * + * \param id the plugin id + * \return the plugin or nullptr on failures + */ + auto find(std::string_view id) -> std::shared_ptr; + + /** + * Convenient wrapper that loads a plugin, call handle_load and add it to + * the registry. + * + * Any errors are printed using logger. + * + * \param id the plugin id + * \param path the optional path (searched if empty) + */ + void load(std::string_view name, std::string_view path = ""); + + /** + * Unload a plugin and remove it. + * + * \param id the plugin id + * \param name the plugin id + */ + void unload(std::string_view id); + + /** + * Reload a plugin by calling onReload. + * + * \param id the plugin id + * \throw std::exception on failures + */ + void reload(std::string_view id); + + /** + * Call a plugin function and throw an exception with the following errors: + * + * - plugin_error::not_found if not loaded + * - plugin_error::exec_error if function failed + * + * \pre plugin != nullptr + * \param plugin the plugin + * \param fn the plugin member function (pointer to member) + * \param args the arguments to pass + */ + template + void exec(std::shared_ptr plugin, Func fn, Args&&... args) + { + assert(plugin); + + // TODO: replace with C++17 std::invoke. + try { + ((*plugin).*(fn))(std::forward(args)...); + } catch (const std::exception& ex) { + throw plugin_error(plugin_error::exec_error, plugin->get_name(), ex.what()); + } catch (...) { + throw plugin_error(plugin_error::exec_error, plugin->get_name()); + } + } + + /** + * Overloaded function. + * + * \param name the plugin name + * \param fn the plugin member function (pointer to member) + * \param args the arguments to pass + */ + template + void exec(const std::string& name, Func fn, Args&&... args) + { + auto plugin = find(name); + + if (!plugin) + throw plugin_error(plugin_error::not_found, plugin->get_name()); + + exec(plugin, fn, std::forward(args)...); + } + + /** + * Load all plugins. + * + * \param cfg the config + */ + void load(const config& cfg) noexcept; +}; + +namespace logger { + +template +struct loggable_traits; + +/** + * \brief Implement Loggable traits for plugin. + */ +template <> +struct loggable_traits { + /** + * Return "plugin" + * + * \param plugin the plugin + * \return the category + */ + static auto get_category(const plugin& plugin) -> std::string_view; + + /** + * Return the plugin id. + * + * \param plugin the plugin + * \return the plugin id + */ + static auto get_component(const plugin& plugin) -> std::string_view; +}; + +} // !logger + +} // !irccd + +#endif // !IRCCD_DAEMON_PLUGIN_SERVICE_HPP diff -r 6d09b5fc82e8 -r c216d148558d libirccd/irccd/daemon/rule_service.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd/irccd/daemon/rule_service.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -0,0 +1,135 @@ +/* + * rule_service.cpp -- rule service + * + * Copyright (c) 2013-2018 David Demelier + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include + +#include "irccd.hpp" +#include "logger.hpp" +#include "rule_service.hpp" +#include "rule_util.hpp" + +namespace irccd { + +rule_service::rule_service(irccd &irccd) + : irccd_(irccd) +{ +} + +void rule_service::add(rule rule) +{ + rules_.push_back(std::move(rule)); +} + +void rule_service::insert(rule rule, unsigned position) +{ + assert(position <= rules_.size()); + + rules_.insert(rules_.begin() + position, std::move(rule)); +} + +void rule_service::remove(unsigned position) +{ + assert(position < rules_.size()); + + rules_.erase(rules_.begin() + position); +} + +const rule &rule_service::require(unsigned position) const +{ + if (position >= rules_.size()) + throw rule_error(rule_error::invalid_index); + + return rules_[position]; +} + +rule &rule_service::require(unsigned position) +{ + if (position >= rules_.size()) + throw rule_error(rule_error::invalid_index); + + return rules_[position]; +} + +bool rule_service::solve(std::string_view server, + std::string_view channel, + std::string_view origin, + std::string_view plugin, + std::string_view event) noexcept +{ + bool result = true; + + irccd_.get_log().debug("rule", "") + << "solving for server=" << server + << ", channel=" << channel + << ", origin=" << origin + << ", plugin=" << plugin + << ", event=" << event << std::endl; + + int i = 0; + for (const auto& rule : rules_) { + auto action = rule.get_action() == rule::action::accept ? "accept" : "drop"; + + irccd_.get_log().debug(rule) << "candidate " << i++ << ":" << std::endl; + irccd_.get_log().debug(rule) << " servers: " << string_util::join(rule.get_servers()) << std::endl; + irccd_.get_log().debug(rule) << " channels: " << string_util::join(rule.get_channels()) << std::endl; + irccd_.get_log().debug(rule) << " origins: " << string_util::join(rule.get_origins()) << std::endl; + irccd_.get_log().debug(rule) << " plugins: " << string_util::join(rule.get_plugins()) << std::endl; + irccd_.get_log().debug(rule) << " events: " << string_util::join(rule.get_events()) << std::endl; + irccd_.get_log().debug(rule) << " action: " << action << std::endl; + + if (rule.match(server, channel, origin, plugin, event)) + result = rule.get_action() == rule::action::accept; + } + + return result; +} + +void rule_service::load(const config& cfg) noexcept +{ + rules_.clear(); + + for (const auto& section : cfg) { + if (section.key() != "rule") + continue; + + try { + rules_.push_back(rule_util::from_config(section)); + } catch (const std::exception& ex) { + irccd_.get_log().warning("rule", "") << ex.what() << std::endl; + } + } +} + +namespace logger { + +auto loggable_traits::get_category(const rule&) -> std::string_view +{ + return "rule"; +} + +auto loggable_traits::get_component(const rule&) -> std::string_view +{ + return ""; +} + +} // !logger + +} // !irccd diff -r 6d09b5fc82e8 -r c216d148558d libirccd/irccd/daemon/rule_service.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd/irccd/daemon/rule_service.hpp Sun Aug 05 15:47:10 2018 +0200 @@ -0,0 +1,152 @@ +/* + * rule_service.hpp -- rule service + * + * Copyright (c) 2013-2018 David Demelier + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_DAEMON_RULE_SERVICE_HPP +#define IRCCD_DAEMON_RULE_SERVICE_HPP + +/** + * \file rule_service.hpp + * \brief Rule service. + */ + +#include + +#include + +#include "rule.hpp" + +namespace irccd { + +class config; +class irccd; + +/** + * \brief Store and solve rules. + * \ingroup services + */ +class rule_service { +private: + irccd& irccd_; + std::vector rules_; + +public: + /** + * Create the rule service. + */ + rule_service(irccd& instance); + + /** + * Get the list of rules. + * + * \return the list of rules + */ + inline const std::vector& list() const noexcept + { + return rules_; + } + + /** + * Get the number of rules. + * + * \return the number of rules + */ + inline std::size_t length() const noexcept + { + return rules_.size(); + } + + /** + * Append a rule. + * + * \param rule the rule to append + */ + void add(rule rule); + + /** + * Insert a new rule at the specified position. + * + * \param rule the rule + * \param position the position + */ + void insert(rule rule, unsigned position); + + /** + * Remove a new rule from the specified position. + * + * \pre position must be valid + * \param position the position + */ + void remove(unsigned position); + + /** + * Get a rule at the specified index or throw an exception if not found. + * + * \param position the position + * \return the rule + * \throw std::out_of_range if position is invalid + */ + const rule& require(unsigned position) const; + + /** + * Overloaded function. + * + * \copydoc require + */ + rule& require(unsigned position); + + /** + * Resolve the action to execute with the specified list of rules. + * + * \param server the server name + * \param channel the channel name + * \param origin the origin + * \param plugin the plugin name + * \param event the event name (e.g onKick) + * \return true if the plugin must be called + */ + bool solve(std::string_view server, + std::string_view channel, + std::string_view origin, + std::string_view plugin, + std::string_view event) noexcept; + + /** + * Load rules from the configuration. + * + * \param cfg the config + */ + void load(const config& cfg) noexcept; +}; + +namespace logger { + +template +struct loggable_traits; + +template <> +struct loggable_traits { + static auto get_category(const rule& rule) -> std::string_view; + + static auto get_component(const rule& rule) -> std::string_view; +}; + +} // !logger + +} // !irccd + +#endif // !IRCCD_DAEMON_RULE_SERVICE_HPP diff -r 6d09b5fc82e8 -r c216d148558d libirccd/irccd/daemon/rule_util.cpp --- a/libirccd/irccd/daemon/rule_util.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/libirccd/irccd/daemon/rule_util.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -18,8 +18,7 @@ #include -#include - +#include "rule.hpp" #include "rule_util.hpp" namespace irccd { diff -r 6d09b5fc82e8 -r c216d148558d libirccd/irccd/daemon/server_service.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd/irccd/daemon/server_service.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -0,0 +1,690 @@ +/* + * server_service.cpp -- server service + * + * Copyright (c) 2013-2018 David Demelier + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include "irccd.hpp" +#include "logger.hpp" +#include "plugin_service.hpp" +#include "rule_service.hpp" +#include "server.hpp" +#include "server_service.hpp" +#include "server_util.hpp" +#include "transport_service.hpp" + +namespace irccd { + +namespace { + +class dispatcher { +private: + irccd& irccd_; + + template + void dispatch(std::string_view, std::string_view, std::string_view, EventNameFunc&&, ExecFunc); + +public: + dispatcher(irccd& irccd); + void operator()(const std::monostate&); + void operator()(const connect_event&); + void operator()(const disconnect_event&); + void operator()(const invite_event&); + void operator()(const join_event&); + void operator()(const kick_event&); + void operator()(const message_event&); + void operator()(const me_event&); + void operator()(const mode_event&); + void operator()(const names_event&); + void operator()(const nick_event&); + void operator()(const notice_event&); + void operator()(const part_event&); + void operator()(const topic_event&); + void operator()(const whois_event&); +}; + +template +void dispatcher::dispatch(std::string_view server, + std::string_view origin, + std::string_view target, + EventNameFunc&& name_func, + ExecFunc exec_func) +{ + for (const auto& plugin : irccd_.plugins().all()) { + const auto eventname = name_func(*plugin); + const auto allowed = irccd_.rules().solve(server, target, origin, plugin->get_name(), eventname); + + if (!allowed) { + irccd_.get_log().debug("rule", "") << "event skipped on match" << std::endl; + continue; + } + + irccd_.get_log().debug("rule", "") << "event allowed" << std::endl; + + try { + exec_func(*plugin); + } catch (const std::exception& ex) { + irccd_.get_log().warning(*plugin) << ex.what() << std::endl; + } + } +} + +dispatcher::dispatcher(irccd& irccd) + : irccd_(irccd) +{ +} + +void dispatcher::operator()(const std::monostate&) +{ +} + +void dispatcher::operator()(const connect_event& ev) +{ + irccd_.get_log().debug(*ev.server) << "event onConnect" << std::endl; + irccd_.transports().broadcast(nlohmann::json::object({ + { "event", "onConnect" }, + { "server", ev.server->get_id() } + })); + + dispatch(ev.server->get_id(), /* origin */ "", /* channel */ "", + [=] (plugin&) -> std::string { + return "onConnect"; + }, + [=] (plugin& plugin) { + plugin.handle_connect(irccd_, ev); + } + ); +} + +void dispatcher::operator()(const disconnect_event& ev) +{ + irccd_.get_log().debug(*ev.server) << "event onDisconnect" << std::endl; + irccd_.transports().broadcast(nlohmann::json::object({ + { "event", "onDisconnect" }, + { "server", ev.server->get_id() } + })); + + dispatch(ev.server->get_id(), /* origin */ "", /* channel */ "", + [=] (plugin&) -> std::string { + return "onDisconnect"; + }, + [=] (plugin& plugin) { + plugin.handle_disconnect(irccd_, ev); + } + ); +} + +void dispatcher::operator()(const invite_event& ev) +{ + irccd_.get_log().debug(*ev.server) << "event onInvite:" << std::endl; + irccd_.get_log().debug(*ev.server) << " origin: " << ev.origin << std::endl; + irccd_.get_log().debug(*ev.server) << " channel: " << ev.channel << std::endl; + irccd_.get_log().debug(*ev.server) << " target: " << ev.nickname << std::endl; + + irccd_.transports().broadcast(nlohmann::json::object({ + { "event", "onInvite" }, + { "server", ev.server->get_id() }, + { "origin", ev.origin }, + { "channel", ev.channel } + })); + + dispatch(ev.server->get_id(), ev.origin, ev.channel, + [=] (plugin&) -> std::string { + return "onInvite"; + }, + [=] (plugin& plugin) { + plugin.handle_invite(irccd_, ev); + } + ); +} + +void dispatcher::operator()(const join_event& ev) +{ + irccd_.get_log().debug(*ev.server) << "event onJoin:" << std::endl; + irccd_.get_log().debug(*ev.server) << " origin: " << ev.origin << std::endl; + irccd_.get_log().debug(*ev.server) << " channel: " << ev.channel << std::endl; + + irccd_.transports().broadcast(nlohmann::json::object({ + { "event", "onJoin" }, + { "server", ev.server->get_id() }, + { "origin", ev.origin }, + { "channel", ev.channel } + })); + + dispatch(ev.server->get_id(), ev.origin, ev.channel, + [=] (plugin&) -> std::string { + return "onJoin"; + }, + [=] (plugin& plugin) { + plugin.handle_join(irccd_, ev); + } + ); +} + +void dispatcher::operator()(const kick_event& ev) +{ + irccd_.get_log().debug(*ev.server) << "event onKick:" << std::endl; + irccd_.get_log().debug(*ev.server) << " origin: " << ev.origin << std::endl; + irccd_.get_log().debug(*ev.server) << " channel: " << ev.channel << std::endl; + irccd_.get_log().debug(*ev.server) << " target: " << ev.target << std::endl; + irccd_.get_log().debug(*ev.server) << " reason: " << ev.reason << std::endl; + + irccd_.transports().broadcast(nlohmann::json::object({ + { "event", "onKick" }, + { "server", ev.server->get_id() }, + { "origin", ev.origin }, + { "channel", ev.channel }, + { "target", ev.target }, + { "reason", ev.reason } + })); + + dispatch(ev.server->get_id(), ev.origin, ev.channel, + [=] (plugin&) -> std::string { + return "onKick"; + }, + [=] (plugin& plugin) { + plugin.handle_kick(irccd_, ev); + } + ); +} + +void dispatcher::operator()(const message_event& ev) +{ + irccd_.get_log().debug(*ev.server) << "event onMessage:" << std::endl; + irccd_.get_log().debug(*ev.server) << " origin: " << ev.origin << std::endl; + irccd_.get_log().debug(*ev.server) << " channel: " << ev.channel << std::endl; + irccd_.get_log().debug(*ev.server) << " message: " << ev.message << std::endl; + + irccd_.transports().broadcast(nlohmann::json::object({ + { "event", "onMessage" }, + { "server", ev.server->get_id() }, + { "origin", ev.origin }, + { "channel", ev.channel }, + { "message", ev.message } + })); + + dispatch(ev.server->get_id(), ev.origin, ev.channel, + [=] (plugin& plugin) -> std::string { + return server_util::parse_message( + ev.message, + ev.server->get_command_char(), + plugin.get_id() + ).type == server_util::message_pack::type::command ? "onCommand" : "onMessage"; + }, + [=] (plugin& plugin) mutable { + auto copy = ev; + auto pack = server_util::parse_message( + copy.message, + copy.server->get_command_char(), + plugin.get_id() + ); + + copy.message = pack.message; + + if (pack.type == server_util::message_pack::type::command) + plugin.handle_command(irccd_, copy); + else + plugin.handle_message(irccd_, copy); + } + ); +} + +void dispatcher::operator()(const me_event& ev) +{ + irccd_.get_log().debug(*ev.server) << "event onMe:" << std::endl; + irccd_.get_log().debug(*ev.server) << " origin: " << ev.origin << std::endl; + irccd_.get_log().debug(*ev.server) << " target: " << ev.channel << std::endl; + irccd_.get_log().debug(*ev.server) << " message: " << ev.message << std::endl; + + irccd_.transports().broadcast(nlohmann::json::object({ + { "event", "onMe" }, + { "server", ev.server->get_id() }, + { "origin", ev.origin }, + { "target", ev.channel }, + { "message", ev.message } + })); + + dispatch(ev.server->get_id(), ev.origin, ev.channel, + [=] (plugin&) -> std::string { + return "onMe"; + }, + [=] (plugin& plugin) { + plugin.handle_me(irccd_, ev); + } + ); +} + +void dispatcher::operator()(const mode_event& ev) +{ + irccd_.get_log().debug(*ev.server) << "event onMode" << std::endl; + irccd_.get_log().debug(*ev.server) << " origin: " << ev.origin << std::endl; + irccd_.get_log().debug(*ev.server) << " channel: " << ev.channel << std::endl; + irccd_.get_log().debug(*ev.server) << " mode: " << ev.mode << std::endl; + irccd_.get_log().debug(*ev.server) << " limit: " << ev.limit << std::endl; + irccd_.get_log().debug(*ev.server) << " user: " << ev.user << std::endl; + irccd_.get_log().debug(*ev.server) << " mask: " << ev.mask << std::endl; + + irccd_.transports().broadcast(nlohmann::json::object({ + { "event", "onMode" }, + { "server", ev.server->get_id() }, + { "origin", ev.origin }, + { "channel", ev.channel }, + { "mode", ev.mode }, + { "limit", ev.limit }, + { "user", ev.user }, + { "mask", ev.mask } + })); + + dispatch(ev.server->get_id(), ev.origin, /* channel */ "", + [=] (plugin &) -> std::string { + return "onMode"; + }, + [=] (plugin &plugin) { + plugin.handle_mode(irccd_, ev); + } + ); +} + +void dispatcher::operator()(const names_event& ev) +{ + irccd_.get_log().debug(*ev.server) << "event onNames:" << std::endl; + irccd_.get_log().debug(*ev.server) << " channel: " << ev.channel << std::endl; + irccd_.get_log().debug(*ev.server) << " names: " << string_util::join(ev.names.begin(), ev.names.end(), ", ") << std::endl; + + auto names = nlohmann::json::array(); + + for (const auto& v : ev.names) + names.push_back(v); + + irccd_.transports().broadcast(nlohmann::json::object({ + { "event", "onNames" }, + { "server", ev.server->get_id() }, + { "channel", ev.channel }, + { "names", std::move(names) } + })); + + dispatch(ev.server->get_id(), /* origin */ "", ev.channel, + [=] (plugin&) -> std::string { + return "onNames"; + }, + [=] (plugin& plugin) { + plugin.handle_names(irccd_, ev); + } + ); +} + +void dispatcher::operator()(const nick_event& ev) +{ + irccd_.get_log().debug(*ev.server) << "event onNick:" << std::endl; + irccd_.get_log().debug(*ev.server) << " origin: " << ev.origin << std::endl; + irccd_.get_log().debug(*ev.server) << " nickname: " << ev.nickname << std::endl; + + irccd_.transports().broadcast(nlohmann::json::object({ + { "event", "onNick" }, + { "server", ev.server->get_id() }, + { "origin", ev.origin }, + { "nickname", ev.nickname } + })); + + dispatch(ev.server->get_id(), ev.origin, /* channel */ "", + [=] (plugin&) -> std::string { + return "onNick"; + }, + [=] (plugin& plugin) { + plugin.handle_nick(irccd_, ev); + } + ); +} + +void dispatcher::operator()(const notice_event& ev) +{ + irccd_.get_log().debug(*ev.server) << "event onNotice:" << std::endl; + irccd_.get_log().debug(*ev.server) << " origin: " << ev.origin << std::endl; + irccd_.get_log().debug(*ev.server) << " channel: " << ev.channel << std::endl; + irccd_.get_log().debug(*ev.server) << " message: " << ev.message << std::endl; + + irccd_.transports().broadcast(nlohmann::json::object({ + { "event", "onNotice" }, + { "server", ev.server->get_id() }, + { "origin", ev.origin }, + { "channel", ev.channel }, + { "message", ev.message } + })); + + dispatch(ev.server->get_id(), ev.origin, /* channel */ "", + [=] (plugin&) -> std::string { + return "onNotice"; + }, + [=] (plugin& plugin) { + plugin.handle_notice(irccd_, ev); + } + ); +} + +void dispatcher::operator()(const part_event& ev) +{ + irccd_.get_log().debug(*ev.server) << "event onPart:" << std::endl; + irccd_.get_log().debug(*ev.server) << " origin: " << ev.origin << std::endl; + irccd_.get_log().debug(*ev.server) << " channel: " << ev.channel << std::endl; + irccd_.get_log().debug(*ev.server) << " reason: " << ev.reason << std::endl; + + irccd_.transports().broadcast(nlohmann::json::object({ + { "event", "onPart" }, + { "server", ev.server->get_id() }, + { "origin", ev.origin }, + { "channel", ev.channel }, + { "reason", ev.reason } + })); + + dispatch(ev.server->get_id(), ev.origin, ev.channel, + [=] (plugin&) -> std::string { + return "onPart"; + }, + [=] (plugin& plugin) { + plugin.handle_part(irccd_, ev); + } + ); +} + +void dispatcher::operator()(const topic_event& ev) +{ + irccd_.get_log().debug(*ev.server) << "event onTopic:" << std::endl; + irccd_.get_log().debug(*ev.server) << " origin: " << ev.origin << std::endl; + irccd_.get_log().debug(*ev.server) << " channel: " << ev.channel << std::endl; + irccd_.get_log().debug(*ev.server) << " topic: " << ev.topic << std::endl; + + irccd_.transports().broadcast(nlohmann::json::object({ + { "event", "onTopic" }, + { "server", ev.server->get_id() }, + { "origin", ev.origin }, + { "channel", ev.channel }, + { "topic", ev.topic } + })); + + dispatch(ev.server->get_id(), ev.origin, ev.channel, + [=] (plugin&) -> std::string { + return "onTopic"; + }, + [=] (plugin& plugin) { + plugin.handle_topic(irccd_, ev); + } + ); +} + +void dispatcher::operator()(const whois_event& ev) +{ + irccd_.get_log().debug(*ev.server) << "event onWhois" << std::endl; + irccd_.get_log().debug(*ev.server) << " nickname: " << ev.whois.nick << std::endl; + irccd_.get_log().debug(*ev.server) << " username: " << ev.whois.user << std::endl; + irccd_.get_log().debug(*ev.server) << " host: " << ev.whois.host << std::endl; + irccd_.get_log().debug(*ev.server) << " realname: " << ev.whois.realname << std::endl; + irccd_.get_log().debug(*ev.server) << " channels: " << string_util::join(ev.whois.channels, ", ") << std::endl; + + irccd_.transports().broadcast(nlohmann::json::object({ + { "event", "onWhois" }, + { "server", ev.server->get_id() }, + { "nickname", ev.whois.nick }, + { "username", ev.whois.user }, + { "host", ev.whois.host }, + { "realname", ev.whois.realname } + })); + + dispatch(ev.server->get_id(), /* origin */ "", /* channel */ "", + [=] (plugin&) -> std::string { + return "onWhois"; + }, + [=] (plugin& plugin) { + plugin.handle_whois(irccd_, ev); + } + ); +} + +} // !namespace + +void server_service::handle_error(const std::shared_ptr& server, + const std::error_code& code) +{ + assert(server); + + irccd_.get_log().warning(*server) << code.message() << std::endl; + + irccd_.get_log().warning(*server) << int(server->get_options()) << std::endl; + + if ((server->get_options() & server::options::auto_reconnect) != server::options::auto_reconnect) + remove(server->get_id()); + else { + irccd_.get_log().info(*server) << "reconnecting in " + << server->get_reconnect_delay() << " second(s)" << std::endl; + wait(server); + } +} + +void server_service::handle_wait(const std::shared_ptr& server, const std::error_code& code) +{ + /* + * The timer runs on his own control, it will complete either if the delay + * was reached, there was an error or if the io_context was called to cancel + * all pending operations. + * + * This means while the timer is running someone may already have ask a + * server for explicit reconnection (e.g. remote command, plugin). Thus we + * check for server state and if it is still present in service. + */ + if (code && code != std::errc::operation_canceled) { + irccd_.get_log().warning(*server) << code.message() << std::endl; + return; + } + + if (server->get_state() == server::state::connected || !has(server->get_id())) + return; + + connect(server); +} + +void server_service::handle_recv(const std::shared_ptr& server, + const std::error_code& code, + const event& event) +{ + assert(server); + + if (code) + handle_error(server, code); + else { + recv(server); + std::visit(dispatcher(irccd_), event); + } +} + +void server_service::handle_connect(const std::shared_ptr& server, const std::error_code& code) +{ + if (code) + handle_error(server, code); + else + recv(server); +} + +void server_service::wait(const std::shared_ptr& server) +{ + assert(server); + + auto timer = std::make_shared(irccd_.get_service()); + + timer->expires_from_now(boost::posix_time::seconds(server->get_reconnect_delay())); + timer->async_wait([this, server, timer] (auto code) { + handle_wait(server, code); + }); +} + +void server_service::recv(const std::shared_ptr& server) +{ + assert(server); + + server->recv([this, server] (auto code, auto event) { + handle_recv(server, code, event); + }); +} + +void server_service::connect(const std::shared_ptr& server) +{ + assert(server); + + server->connect([this, server] (auto code) { + handle_connect(server, code); + }); +} + +server_service::server_service(irccd &irccd) + : irccd_(irccd) +{ +} + +auto server_service::all() const noexcept -> const std::vector>& +{ + return servers_; +} + +auto server_service::has(const std::string& name) const noexcept -> bool +{ + return std::count_if(servers_.begin(), servers_.end(), [&] (const auto& server) { + return server->get_id() == name; + }) > 0; +} + +void server_service::add(std::shared_ptr server) +{ + assert(server); + assert(!has(server->get_id())); + + servers_.push_back(server); + connect(server); +} + +auto server_service::get(std::string_view name) const noexcept -> std::shared_ptr +{ + const auto it = std::find_if(servers_.begin(), servers_.end(), [&] (const auto& server) { + return server->get_id() == name; + }); + + if (it == servers_.end()) + return nullptr; + + return *it; +} + +auto server_service::require(std::string_view name) const -> std::shared_ptr +{ + if (!string_util::is_identifier(name)) + throw server_error(server_error::invalid_identifier); + + const auto s = get(name); + + if (!s) + throw server_error(server_error::not_found); + + return s; +} + +void server_service::disconnect(std::string_view id) +{ + const auto s = require(id); + + s->disconnect(); + dispatcher{irccd_}(disconnect_event{s}); +} + +void server_service::reconnect(std::string_view id) +{ + disconnect(id); + connect(require(id)); +} + +void server_service::reconnect() +{ + for (const auto& s : servers_) { + try { + s->disconnect(); + dispatcher{irccd_}(disconnect_event{s}); + connect(s); + } catch (const server_error& ex) { + irccd_.get_log().warning(*s) << ex.what() << std::endl; + } + } +} + +void server_service::remove(std::string_view name) +{ + const auto it = std::find_if(servers_.begin(), servers_.end(), [&] (const auto& server) { + return server->get_id() == name; + }); + + if (it != servers_.end()) { + (*it)->disconnect(); + servers_.erase(it); + } +} + +void server_service::clear() noexcept +{ + /* + * Copy the array, because disconnect() may trigger on_die signal which + * erase the server from itself. + */ + const auto save = servers_; + + for (const auto& server : save) + server->disconnect(); + + servers_.clear(); +} + +void server_service::load(const config& cfg) noexcept +{ + for (const auto& section : cfg) { + if (section.key() != "server") + continue; + + const auto id = section.get("name").value(); + + try { + auto server = server_util::from_config(irccd_.get_service(), cfg, section); + + if (has(server->get_id())) + throw server_error(server_error::already_exists); + + add(std::move(server)); + } catch (const std::exception& ex) { + irccd_.get_log().warning("server", id) << ex.what() << std::endl; + } + } +} + +namespace logger { + +auto loggable_traits::get_category(const server&) -> std::string_view +{ + return "server"; +} + +auto loggable_traits::get_component(const server& sv) -> std::string_view +{ + return sv.get_id(); +} + +} // !logger + +} // !irccd diff -r 6d09b5fc82e8 -r c216d148558d libirccd/irccd/daemon/server_service.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd/irccd/daemon/server_service.hpp Sun Aug 05 15:47:10 2018 +0200 @@ -0,0 +1,164 @@ +/* + * server_service.hpp -- server service + * + * Copyright (c) 2013-2018 David Demelier + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_DAEMON_SERVER_SERVICE_HPP +#define IRCCD_DAEMON_SERVER_SERVICE_HPP + +/** + * \file server_service.hpp + * \brief Server service. + */ + +#include +#include +#include + +#include "server.hpp" + +namespace irccd { + +class config; +class irccd; + +/** + * \brief Manage IRC servers. + * \ingroup services + */ +class server_service { +private: + irccd& irccd_; + std::vector> servers_; + + void handle_error(const std::shared_ptr&, const std::error_code&); + void handle_wait(const std::shared_ptr&, const std::error_code&); + void handle_recv(const std::shared_ptr&, const std::error_code&, const event&); + void handle_connect(const std::shared_ptr&, const std::error_code&); + + void wait(const std::shared_ptr&); + void recv(const std::shared_ptr&); + void connect(const std::shared_ptr&); + +public: + /** + * Create the server service. + */ + server_service(irccd& instance); + + /** + * Get the list of servers + * + * \return the servers + */ + auto all() const noexcept -> const std::vector>&; + + /** + * Check if a server exists. + * + * \param name the name + * \return true if exists + */ + auto has(const std::string& name) const noexcept -> bool; + + /** + * Add a new server to the application. + * + * \pre hasServer must return false + * \param sv the server + */ + void add(std::shared_ptr sv); + + /** + * Get a server or empty one if not found + * + * \param name the server name + * \return the server or empty one if not found + */ + auto get(std::string_view name) const noexcept -> std::shared_ptr; + + /** + * Find a server from a JSON object. + * + * \param name the server name + * \return the server + * \throw server_error on errors + */ + auto require(std::string_view name) const -> std::shared_ptr; + + /** + * Force disconnection, this also call plugin::handle_disconnect handler. + * + * \param id the server id + * \throw server_error on errors + */ + void disconnect(std::string_view id); + + /** + * Force reconnection, this also call plugin::handle_disconnect handler. + * + * \param id the server id + * \return the server + * \throw server_error on errors + */ + void reconnect(std::string_view id); + + /** + * Force reconnection of all servers. + */ + void reconnect(); + + /** + * Remove a server from the irccd instance. + * + * The server if any, will be disconnected. + * + * \param name the server name + */ + void remove(std::string_view name); + + /** + * Remove all servers. + * + * All servers will be disconnected. + */ + void clear() noexcept; + + /** + * Load servers from the configuration. + * + * \param cfg the config + */ + void load(const config& cfg) noexcept; +}; + +namespace logger { + +template +struct loggable_traits; + +template <> +struct loggable_traits { + static auto get_category(const server& server) -> std::string_view; + + static auto get_component(const server& server) -> std::string_view; +}; + +} // !logger + +} // !irccd + +#endif // !IRCCD_DAEMON_SERVER_SERVICE_HPP diff -r 6d09b5fc82e8 -r c216d148558d libirccd/irccd/daemon/server_util.cpp --- a/libirccd/irccd/daemon/server_util.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/libirccd/irccd/daemon/server_util.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -23,6 +23,7 @@ #include #include +#include "server.hpp" #include "server_util.hpp" namespace irccd { diff -r 6d09b5fc82e8 -r c216d148558d libirccd/irccd/daemon/server_util.hpp --- a/libirccd/irccd/daemon/server_util.hpp Sun Aug 05 12:14:16 2018 +0200 +++ b/libirccd/irccd/daemon/server_util.hpp Sun Aug 05 15:47:10 2018 +0200 @@ -30,8 +30,6 @@ #include -#include - namespace irccd { namespace ini { @@ -41,6 +39,7 @@ } // !ini class config; +class server; /** * \brief Server utilities. diff -r 6d09b5fc82e8 -r c216d148558d libirccd/irccd/daemon/service/plugin_service.cpp --- a/libirccd/irccd/daemon/service/plugin_service.cpp Sun Aug 05 12:14:16 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,266 +0,0 @@ -/* - * plugin_service.cpp -- plugin service - * - * Copyright (c) 2013-2018 David Demelier - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include - -#include -#include -#include - -#include -#include - -#include - -using boost::format; -using boost::str; - -namespace irccd { - -namespace { - -auto to_map(const config& conf, const std::string& section) -> plugin::map -{ - plugin::map ret; - - for (const auto& opt : conf.get(section)) - ret.emplace(opt.key(), opt.value()); - - return ret; -} - -} // !namespace - -plugin_service::plugin_service(irccd& irccd) noexcept - : irccd_(irccd) -{ -} - -plugin_service::~plugin_service() -{ - for (const auto& plg : plugins_) { - try { - plg->handle_unload(irccd_); - } catch (const std::exception& ex) { - irccd_.get_log().warning(*plg) << ex.what() << std::endl; - } - } -} - -auto plugin_service::all() const noexcept -> plugins -{ - return plugins_; -} - -auto plugin_service::has(std::string_view id) const noexcept -> bool -{ - return get(id) != nullptr; -} - -auto plugin_service::get(std::string_view id) const noexcept -> std::shared_ptr -{ - const auto find = [id] (const auto& plg) { - return plg->get_id() == id; - }; - - if (const auto it = std::find_if(plugins_.begin(), plugins_.end(), find); it != plugins_.end()) - return *it; - - return nullptr; -} - -auto plugin_service::require(std::string_view id) const -> std::shared_ptr -{ - auto plugin = get(id); - - if (!plugin) - throw plugin_error(plugin_error::not_found, id); - - return plugin; -} - -void plugin_service::add(std::shared_ptr plugin) -{ - assert(plugin); - - plugins_.push_back(std::move(plugin)); -} - -void plugin_service::add_loader(std::unique_ptr loader) -{ - assert(loader); - - loaders_.push_back(std::move(loader)); -} - -auto plugin_service::get_options(std::string_view id) -> plugin::map -{ - return to_map(irccd_.get_config(), str(format("plugin.%1%") % id)); -} - -auto plugin_service::get_formats(std::string_view id) -> plugin::map -{ - return to_map(irccd_.get_config(), str(format("format.%1%") % id)); -} - -auto plugin_service::get_paths(std::string_view id) -> plugin::map -{ - auto defaults = to_map(irccd_.get_config(), "paths"); - auto paths = to_map(irccd_.get_config(), str(format("paths.%1%") % id)); - - // Fill defaults paths. - if (!defaults.count("cache")) - defaults.emplace("cache", sys::cachedir().string()); - if (!defaults.count("data")) - defaults.emplace("data", sys::datadir().string()); - if (!defaults.count("config")) - defaults.emplace("config", sys::sysconfdir().string()); - - const auto join = [id] (auto path) { - return (boost::filesystem::path(path) / "plugin" / std::string(id)).string(); - }; - - // Now fill missing fields. - if (!paths.count("cache")) - paths.emplace("cache", join(defaults["cache"])); - if (!paths.count("data")) - paths.emplace("data", join(defaults["data"])); - if (!paths.count("config")) - paths.emplace("config", join(defaults["config"])); - - return paths; -} - -auto plugin_service::open(std::string_view id, std::string_view path) -> std::shared_ptr -{ - for (const auto& loader : loaders_) { - auto plugin = loader->open(id, path); - - if (plugin) - return plugin; - } - - return nullptr; -} - -auto plugin_service::find(std::string_view id) -> std::shared_ptr -{ - for (const auto& loader : loaders_) { - try { - auto plugin = loader->find(id); - - if (plugin) - return plugin; - } catch (const std::exception& ex) { - irccd_.get_log().warning("plugin", id) << ex.what() << std::endl; - } - } - - return nullptr; -} - -void plugin_service::load(std::string_view id, std::string_view path) -{ - if (has(id)) - throw plugin_error(plugin_error::already_exists, id); - - std::shared_ptr plugin; - - if (path.empty()) - plugin = find(id); - else - plugin = open(id, std::move(path)); - - if (!plugin) - throw plugin_error(plugin_error::not_found, id); - - plugin->set_options(get_options(id)); - plugin->set_formats(get_formats(id)); - plugin->set_paths(get_paths(id)); - - exec(plugin, &plugin::handle_load, irccd_); - add(std::move(plugin)); -} - -void plugin_service::reload(std::string_view id) -{ - auto plugin = get(id); - - if (!plugin) - throw plugin_error(plugin_error::not_found, id); - - exec(plugin, &plugin::handle_reload, irccd_); -} - -void plugin_service::unload(std::string_view id) -{ - const auto find = [id] (const auto& plg) { - return plg->get_id() == id; - }; - - const auto it = std::find_if(plugins_.begin(), plugins_.end(), find); - - if (it == plugins_.end()) - throw plugin_error(plugin_error::not_found, id); - - // Erase first, in case of throwing. - const auto save = *it; - - plugins_.erase(it); - exec(save, &plugin::handle_unload, irccd_); -} - -void plugin_service::load(const config& cfg) noexcept -{ - for (const auto& option : cfg.get("plugins")) { - if (!string_util::is_identifier(option.key())) - continue; - - auto id = option.key(); - auto p = get(id); - - // Reload the plugin if already loaded. - if (p) { - p->set_options(get_options(id)); - p->set_formats(get_formats(id)); - p->set_paths(get_paths(id)); - } else { - try { - load(id, option.value()); - } catch (const std::exception& ex) { - irccd_.get_log().warning("plugin", id) << ex.what() << std::endl; - } - } - } -} - -namespace logger { - -auto loggable_traits::get_category(const plugin&) -> std::string_view -{ - return "plugin"; -} - -auto loggable_traits::get_component(const plugin& plugin) -> std::string_view -{ - return plugin.get_id(); -} - -} // !logger - -} // !irccd diff -r 6d09b5fc82e8 -r c216d148558d libirccd/irccd/daemon/service/plugin_service.hpp --- a/libirccd/irccd/daemon/service/plugin_service.hpp Sun Aug 05 12:14:16 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,279 +0,0 @@ -/* - * plugin_service.hpp -- plugin service - * - * Copyright (c) 2013-2018 David Demelier - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_DAEMON_PLUGIN_SERVICE_HPP -#define IRCCD_DAEMON_PLUGIN_SERVICE_HPP - -/** - * \file plugin_service.hpp - * \brief Plugin service. - */ - -#include -#include -#include -#include -#include - -#include - -namespace irccd { - -class irccd; -class config; - -/** - * \brief Manage plugins. - * \ingroup services - */ -class plugin_service { -public: - /** - * \brief Map of plugins. - */ - using plugins = std::vector>; - - /** - * \brief List of loaders. - */ - using plugin_loaders = std::vector>; - -private: - irccd& irccd_; - plugins plugins_; - plugin_loaders loaders_; - -public: - /** - * Create the plugin service. - * - * \param irccd the irccd instance - */ - plugin_service(irccd& irccd) noexcept; - - /** - * Destroy plugins. - */ - virtual ~plugin_service(); - - /** - * Get the list of plugins. - * - * \return the list of plugins - */ - auto all() const noexcept -> plugins; - - /** - * Check if a plugin is loaded. - * - * \param id the plugin id - * \return true if has plugin - */ - auto has(std::string_view id) const noexcept -> bool; - - /** - * Get a loaded plugin or null if not found. - * - * \param id the plugin id - * \return the plugin or empty one if not found - */ - auto get(std::string_view id) const noexcept -> std::shared_ptr; - - /** - * Find a loaded plugin. - * - * \param id the plugin id - * \return the plugin - * \throw plugin_error on errors - */ - auto require(std::string_view id) const -> std::shared_ptr; - - /** - * Add the specified plugin to the registry. - * - * \pre plg != nullptr - * \param plg the plugin - * \note the plugin is only added to the list, no action is performed on it - */ - void add(std::shared_ptr plg); - - /** - * Add a loader. - * - * \pre loader != nullptr - * \param loader the loader - */ - void add_loader(std::unique_ptr loader); - - /** - * Get the configuration for the specified plugin. - * - * \param id the plugin id - * \return the configuration - */ - auto get_options(std::string_view id) -> plugin::map; - - /** - * Get the formats for the specified plugin. - * - * \param id the plugin id - * \return the formats - */ - auto get_formats(std::string_view id) -> plugin::map; - - /** - * Get the paths for the specified plugin. - * - * If none is defined, return the default ones. - * - * \param id the plugin id - * \return the paths - */ - auto get_paths(std::string_view id) -> plugin::map; - - /** - * Generic function for opening the plugin at the given path. - * - * This function will search for every pluginLoader and call open() on it, - * the first one that success will be returned. - * - * \param id the plugin id - * \param path the path to the file - * \return the plugin or nullptr on failures - */ - auto open(std::string_view id, std::string_view path) -> std::shared_ptr; - - /** - * Generic function for finding a plugin. - * - * \param id the plugin id - * \return the plugin or nullptr on failures - */ - auto find(std::string_view id) -> std::shared_ptr; - - /** - * Convenient wrapper that loads a plugin, call handle_load and add it to - * the registry. - * - * Any errors are printed using logger. - * - * \param id the plugin id - * \param path the optional path (searched if empty) - */ - void load(std::string_view name, std::string_view path = ""); - - /** - * Unload a plugin and remove it. - * - * \param id the plugin id - * \param name the plugin id - */ - void unload(std::string_view id); - - /** - * Reload a plugin by calling onReload. - * - * \param id the plugin id - * \throw std::exception on failures - */ - void reload(std::string_view id); - - /** - * Call a plugin function and throw an exception with the following errors: - * - * - plugin_error::not_found if not loaded - * - plugin_error::exec_error if function failed - * - * \pre plugin != nullptr - * \param plugin the plugin - * \param fn the plugin member function (pointer to member) - * \param args the arguments to pass - */ - template - void exec(std::shared_ptr plugin, Func fn, Args&&... args) - { - assert(plugin); - - // TODO: replace with C++17 std::invoke. - try { - ((*plugin).*(fn))(std::forward(args)...); - } catch (const std::exception& ex) { - throw plugin_error(plugin_error::exec_error, plugin->get_name(), ex.what()); - } catch (...) { - throw plugin_error(plugin_error::exec_error, plugin->get_name()); - } - } - - /** - * Overloaded function. - * - * \param name the plugin name - * \param fn the plugin member function (pointer to member) - * \param args the arguments to pass - */ - template - void exec(const std::string& name, Func fn, Args&&... args) - { - auto plugin = find(name); - - if (!plugin) - throw plugin_error(plugin_error::not_found, plugin->get_name()); - - exec(plugin, fn, std::forward(args)...); - } - - /** - * Load all plugins. - * - * \param cfg the config - */ - void load(const config& cfg) noexcept; -}; - -namespace logger { - -template -struct loggable_traits; - -/** - * \brief Implement Loggable traits for plugin. - */ -template <> -struct loggable_traits { - /** - * Return "plugin" - * - * \param plugin the plugin - * \return the category - */ - static auto get_category(const plugin& plugin) -> std::string_view; - - /** - * Return the plugin id. - * - * \param plugin the plugin - * \return the plugin id - */ - static auto get_component(const plugin& plugin) -> std::string_view; -}; - -} // !logger - -} // !irccd - -#endif // !IRCCD_DAEMON_PLUGIN_SERVICE_HPP diff -r 6d09b5fc82e8 -r c216d148558d libirccd/irccd/daemon/service/rule_service.cpp --- a/libirccd/irccd/daemon/service/rule_service.cpp Sun Aug 05 12:14:16 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,136 +0,0 @@ -/* - * rule_service.cpp -- rule service - * - * Copyright (c) 2013-2018 David Demelier - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include - -#include -#include - -#include -#include -#include - -#include - -namespace irccd { - -rule_service::rule_service(irccd &irccd) - : irccd_(irccd) -{ -} - -void rule_service::add(rule rule) -{ - rules_.push_back(std::move(rule)); -} - -void rule_service::insert(rule rule, unsigned position) -{ - assert(position <= rules_.size()); - - rules_.insert(rules_.begin() + position, std::move(rule)); -} - -void rule_service::remove(unsigned position) -{ - assert(position < rules_.size()); - - rules_.erase(rules_.begin() + position); -} - -const rule &rule_service::require(unsigned position) const -{ - if (position >= rules_.size()) - throw rule_error(rule_error::invalid_index); - - return rules_[position]; -} - -rule &rule_service::require(unsigned position) -{ - if (position >= rules_.size()) - throw rule_error(rule_error::invalid_index); - - return rules_[position]; -} - -bool rule_service::solve(std::string_view server, - std::string_view channel, - std::string_view origin, - std::string_view plugin, - std::string_view event) noexcept -{ - bool result = true; - - irccd_.get_log().debug("rule", "") - << "solving for server=" << server - << ", channel=" << channel - << ", origin=" << origin - << ", plugin=" << plugin - << ", event=" << event << std::endl; - - int i = 0; - for (const auto& rule : rules_) { - auto action = rule.get_action() == rule::action::accept ? "accept" : "drop"; - - irccd_.get_log().debug(rule) << "candidate " << i++ << ":" << std::endl; - irccd_.get_log().debug(rule) << " servers: " << string_util::join(rule.get_servers()) << std::endl; - irccd_.get_log().debug(rule) << " channels: " << string_util::join(rule.get_channels()) << std::endl; - irccd_.get_log().debug(rule) << " origins: " << string_util::join(rule.get_origins()) << std::endl; - irccd_.get_log().debug(rule) << " plugins: " << string_util::join(rule.get_plugins()) << std::endl; - irccd_.get_log().debug(rule) << " events: " << string_util::join(rule.get_events()) << std::endl; - irccd_.get_log().debug(rule) << " action: " << action << std::endl; - - if (rule.match(server, channel, origin, plugin, event)) - result = rule.get_action() == rule::action::accept; - } - - return result; -} - -void rule_service::load(const config& cfg) noexcept -{ - rules_.clear(); - - for (const auto& section : cfg) { - if (section.key() != "rule") - continue; - - try { - rules_.push_back(rule_util::from_config(section)); - } catch (const std::exception& ex) { - irccd_.get_log().warning("rule", "") << ex.what() << std::endl; - } - } -} - -namespace logger { - -auto loggable_traits::get_category(const rule&) -> std::string_view -{ - return "rule"; -} - -auto loggable_traits::get_component(const rule&) -> std::string_view -{ - return ""; -} - -} // !logger - -} // !irccd diff -r 6d09b5fc82e8 -r c216d148558d libirccd/irccd/daemon/service/rule_service.hpp --- a/libirccd/irccd/daemon/service/rule_service.hpp Sun Aug 05 12:14:16 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,152 +0,0 @@ -/* - * rule_service.hpp -- rule service - * - * Copyright (c) 2013-2018 David Demelier - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_DAEMON_RULE_SERVICE_HPP -#define IRCCD_DAEMON_RULE_SERVICE_HPP - -/** - * \file rule_service.hpp - * \brief Rule service. - */ - -#include - -#include - -#include - -namespace irccd { - -class config; -class irccd; - -/** - * \brief Store and solve rules. - * \ingroup services - */ -class rule_service { -private: - irccd& irccd_; - std::vector rules_; - -public: - /** - * Create the rule service. - */ - rule_service(irccd& instance); - - /** - * Get the list of rules. - * - * \return the list of rules - */ - inline const std::vector& list() const noexcept - { - return rules_; - } - - /** - * Get the number of rules. - * - * \return the number of rules - */ - inline std::size_t length() const noexcept - { - return rules_.size(); - } - - /** - * Append a rule. - * - * \param rule the rule to append - */ - void add(rule rule); - - /** - * Insert a new rule at the specified position. - * - * \param rule the rule - * \param position the position - */ - void insert(rule rule, unsigned position); - - /** - * Remove a new rule from the specified position. - * - * \pre position must be valid - * \param position the position - */ - void remove(unsigned position); - - /** - * Get a rule at the specified index or throw an exception if not found. - * - * \param position the position - * \return the rule - * \throw std::out_of_range if position is invalid - */ - const rule& require(unsigned position) const; - - /** - * Overloaded function. - * - * \copydoc require - */ - rule& require(unsigned position); - - /** - * Resolve the action to execute with the specified list of rules. - * - * \param server the server name - * \param channel the channel name - * \param origin the origin - * \param plugin the plugin name - * \param event the event name (e.g onKick) - * \return true if the plugin must be called - */ - bool solve(std::string_view server, - std::string_view channel, - std::string_view origin, - std::string_view plugin, - std::string_view event) noexcept; - - /** - * Load rules from the configuration. - * - * \param cfg the config - */ - void load(const config& cfg) noexcept; -}; - -namespace logger { - -template -struct loggable_traits; - -template <> -struct loggable_traits { - static auto get_category(const rule& rule) -> std::string_view; - - static auto get_component(const rule& rule) -> std::string_view; -}; - -} // !logger - -} // !irccd - -#endif // !IRCCD_DAEMON_RULE_SERVICE_HPP diff -r 6d09b5fc82e8 -r c216d148558d libirccd/irccd/daemon/service/server_service.cpp --- a/libirccd/irccd/daemon/service/server_service.cpp Sun Aug 05 12:14:16 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,690 +0,0 @@ -/* - * server_service.cpp -- server service - * - * Copyright (c) 2013-2018 David Demelier - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -namespace irccd { - -namespace { - -class dispatcher { -private: - irccd& irccd_; - - template - void dispatch(std::string_view, std::string_view, std::string_view, EventNameFunc&&, ExecFunc); - -public: - dispatcher(irccd& irccd); - void operator()(const std::monostate&); - void operator()(const connect_event&); - void operator()(const disconnect_event&); - void operator()(const invite_event&); - void operator()(const join_event&); - void operator()(const kick_event&); - void operator()(const message_event&); - void operator()(const me_event&); - void operator()(const mode_event&); - void operator()(const names_event&); - void operator()(const nick_event&); - void operator()(const notice_event&); - void operator()(const part_event&); - void operator()(const topic_event&); - void operator()(const whois_event&); -}; - -template -void dispatcher::dispatch(std::string_view server, - std::string_view origin, - std::string_view target, - EventNameFunc&& name_func, - ExecFunc exec_func) -{ - for (const auto& plugin : irccd_.plugins().all()) { - const auto eventname = name_func(*plugin); - const auto allowed = irccd_.rules().solve(server, target, origin, plugin->get_name(), eventname); - - if (!allowed) { - irccd_.get_log().debug("rule", "") << "event skipped on match" << std::endl; - continue; - } - - irccd_.get_log().debug("rule", "") << "event allowed" << std::endl; - - try { - exec_func(*plugin); - } catch (const std::exception& ex) { - irccd_.get_log().warning(*plugin) << ex.what() << std::endl; - } - } -} - -dispatcher::dispatcher(irccd& irccd) - : irccd_(irccd) -{ -} - -void dispatcher::operator()(const std::monostate&) -{ -} - -void dispatcher::operator()(const connect_event& ev) -{ - irccd_.get_log().debug(*ev.server) << "event onConnect" << std::endl; - irccd_.transports().broadcast(nlohmann::json::object({ - { "event", "onConnect" }, - { "server", ev.server->get_id() } - })); - - dispatch(ev.server->get_id(), /* origin */ "", /* channel */ "", - [=] (plugin&) -> std::string { - return "onConnect"; - }, - [=] (plugin& plugin) { - plugin.handle_connect(irccd_, ev); - } - ); -} - -void dispatcher::operator()(const disconnect_event& ev) -{ - irccd_.get_log().debug(*ev.server) << "event onDisconnect" << std::endl; - irccd_.transports().broadcast(nlohmann::json::object({ - { "event", "onDisconnect" }, - { "server", ev.server->get_id() } - })); - - dispatch(ev.server->get_id(), /* origin */ "", /* channel */ "", - [=] (plugin&) -> std::string { - return "onDisconnect"; - }, - [=] (plugin& plugin) { - plugin.handle_disconnect(irccd_, ev); - } - ); -} - -void dispatcher::operator()(const invite_event& ev) -{ - irccd_.get_log().debug(*ev.server) << "event onInvite:" << std::endl; - irccd_.get_log().debug(*ev.server) << " origin: " << ev.origin << std::endl; - irccd_.get_log().debug(*ev.server) << " channel: " << ev.channel << std::endl; - irccd_.get_log().debug(*ev.server) << " target: " << ev.nickname << std::endl; - - irccd_.transports().broadcast(nlohmann::json::object({ - { "event", "onInvite" }, - { "server", ev.server->get_id() }, - { "origin", ev.origin }, - { "channel", ev.channel } - })); - - dispatch(ev.server->get_id(), ev.origin, ev.channel, - [=] (plugin&) -> std::string { - return "onInvite"; - }, - [=] (plugin& plugin) { - plugin.handle_invite(irccd_, ev); - } - ); -} - -void dispatcher::operator()(const join_event& ev) -{ - irccd_.get_log().debug(*ev.server) << "event onJoin:" << std::endl; - irccd_.get_log().debug(*ev.server) << " origin: " << ev.origin << std::endl; - irccd_.get_log().debug(*ev.server) << " channel: " << ev.channel << std::endl; - - irccd_.transports().broadcast(nlohmann::json::object({ - { "event", "onJoin" }, - { "server", ev.server->get_id() }, - { "origin", ev.origin }, - { "channel", ev.channel } - })); - - dispatch(ev.server->get_id(), ev.origin, ev.channel, - [=] (plugin&) -> std::string { - return "onJoin"; - }, - [=] (plugin& plugin) { - plugin.handle_join(irccd_, ev); - } - ); -} - -void dispatcher::operator()(const kick_event& ev) -{ - irccd_.get_log().debug(*ev.server) << "event onKick:" << std::endl; - irccd_.get_log().debug(*ev.server) << " origin: " << ev.origin << std::endl; - irccd_.get_log().debug(*ev.server) << " channel: " << ev.channel << std::endl; - irccd_.get_log().debug(*ev.server) << " target: " << ev.target << std::endl; - irccd_.get_log().debug(*ev.server) << " reason: " << ev.reason << std::endl; - - irccd_.transports().broadcast(nlohmann::json::object({ - { "event", "onKick" }, - { "server", ev.server->get_id() }, - { "origin", ev.origin }, - { "channel", ev.channel }, - { "target", ev.target }, - { "reason", ev.reason } - })); - - dispatch(ev.server->get_id(), ev.origin, ev.channel, - [=] (plugin&) -> std::string { - return "onKick"; - }, - [=] (plugin& plugin) { - plugin.handle_kick(irccd_, ev); - } - ); -} - -void dispatcher::operator()(const message_event& ev) -{ - irccd_.get_log().debug(*ev.server) << "event onMessage:" << std::endl; - irccd_.get_log().debug(*ev.server) << " origin: " << ev.origin << std::endl; - irccd_.get_log().debug(*ev.server) << " channel: " << ev.channel << std::endl; - irccd_.get_log().debug(*ev.server) << " message: " << ev.message << std::endl; - - irccd_.transports().broadcast(nlohmann::json::object({ - { "event", "onMessage" }, - { "server", ev.server->get_id() }, - { "origin", ev.origin }, - { "channel", ev.channel }, - { "message", ev.message } - })); - - dispatch(ev.server->get_id(), ev.origin, ev.channel, - [=] (plugin& plugin) -> std::string { - return server_util::parse_message( - ev.message, - ev.server->get_command_char(), - plugin.get_id() - ).type == server_util::message_pack::type::command ? "onCommand" : "onMessage"; - }, - [=] (plugin& plugin) mutable { - auto copy = ev; - auto pack = server_util::parse_message( - copy.message, - copy.server->get_command_char(), - plugin.get_id() - ); - - copy.message = pack.message; - - if (pack.type == server_util::message_pack::type::command) - plugin.handle_command(irccd_, copy); - else - plugin.handle_message(irccd_, copy); - } - ); -} - -void dispatcher::operator()(const me_event& ev) -{ - irccd_.get_log().debug(*ev.server) << "event onMe:" << std::endl; - irccd_.get_log().debug(*ev.server) << " origin: " << ev.origin << std::endl; - irccd_.get_log().debug(*ev.server) << " target: " << ev.channel << std::endl; - irccd_.get_log().debug(*ev.server) << " message: " << ev.message << std::endl; - - irccd_.transports().broadcast(nlohmann::json::object({ - { "event", "onMe" }, - { "server", ev.server->get_id() }, - { "origin", ev.origin }, - { "target", ev.channel }, - { "message", ev.message } - })); - - dispatch(ev.server->get_id(), ev.origin, ev.channel, - [=] (plugin&) -> std::string { - return "onMe"; - }, - [=] (plugin& plugin) { - plugin.handle_me(irccd_, ev); - } - ); -} - -void dispatcher::operator()(const mode_event& ev) -{ - irccd_.get_log().debug(*ev.server) << "event onMode" << std::endl; - irccd_.get_log().debug(*ev.server) << " origin: " << ev.origin << std::endl; - irccd_.get_log().debug(*ev.server) << " channel: " << ev.channel << std::endl; - irccd_.get_log().debug(*ev.server) << " mode: " << ev.mode << std::endl; - irccd_.get_log().debug(*ev.server) << " limit: " << ev.limit << std::endl; - irccd_.get_log().debug(*ev.server) << " user: " << ev.user << std::endl; - irccd_.get_log().debug(*ev.server) << " mask: " << ev.mask << std::endl; - - irccd_.transports().broadcast(nlohmann::json::object({ - { "event", "onMode" }, - { "server", ev.server->get_id() }, - { "origin", ev.origin }, - { "channel", ev.channel }, - { "mode", ev.mode }, - { "limit", ev.limit }, - { "user", ev.user }, - { "mask", ev.mask } - })); - - dispatch(ev.server->get_id(), ev.origin, /* channel */ "", - [=] (plugin &) -> std::string { - return "onMode"; - }, - [=] (plugin &plugin) { - plugin.handle_mode(irccd_, ev); - } - ); -} - -void dispatcher::operator()(const names_event& ev) -{ - irccd_.get_log().debug(*ev.server) << "event onNames:" << std::endl; - irccd_.get_log().debug(*ev.server) << " channel: " << ev.channel << std::endl; - irccd_.get_log().debug(*ev.server) << " names: " << string_util::join(ev.names.begin(), ev.names.end(), ", ") << std::endl; - - auto names = nlohmann::json::array(); - - for (const auto& v : ev.names) - names.push_back(v); - - irccd_.transports().broadcast(nlohmann::json::object({ - { "event", "onNames" }, - { "server", ev.server->get_id() }, - { "channel", ev.channel }, - { "names", std::move(names) } - })); - - dispatch(ev.server->get_id(), /* origin */ "", ev.channel, - [=] (plugin&) -> std::string { - return "onNames"; - }, - [=] (plugin& plugin) { - plugin.handle_names(irccd_, ev); - } - ); -} - -void dispatcher::operator()(const nick_event& ev) -{ - irccd_.get_log().debug(*ev.server) << "event onNick:" << std::endl; - irccd_.get_log().debug(*ev.server) << " origin: " << ev.origin << std::endl; - irccd_.get_log().debug(*ev.server) << " nickname: " << ev.nickname << std::endl; - - irccd_.transports().broadcast(nlohmann::json::object({ - { "event", "onNick" }, - { "server", ev.server->get_id() }, - { "origin", ev.origin }, - { "nickname", ev.nickname } - })); - - dispatch(ev.server->get_id(), ev.origin, /* channel */ "", - [=] (plugin&) -> std::string { - return "onNick"; - }, - [=] (plugin& plugin) { - plugin.handle_nick(irccd_, ev); - } - ); -} - -void dispatcher::operator()(const notice_event& ev) -{ - irccd_.get_log().debug(*ev.server) << "event onNotice:" << std::endl; - irccd_.get_log().debug(*ev.server) << " origin: " << ev.origin << std::endl; - irccd_.get_log().debug(*ev.server) << " channel: " << ev.channel << std::endl; - irccd_.get_log().debug(*ev.server) << " message: " << ev.message << std::endl; - - irccd_.transports().broadcast(nlohmann::json::object({ - { "event", "onNotice" }, - { "server", ev.server->get_id() }, - { "origin", ev.origin }, - { "channel", ev.channel }, - { "message", ev.message } - })); - - dispatch(ev.server->get_id(), ev.origin, /* channel */ "", - [=] (plugin&) -> std::string { - return "onNotice"; - }, - [=] (plugin& plugin) { - plugin.handle_notice(irccd_, ev); - } - ); -} - -void dispatcher::operator()(const part_event& ev) -{ - irccd_.get_log().debug(*ev.server) << "event onPart:" << std::endl; - irccd_.get_log().debug(*ev.server) << " origin: " << ev.origin << std::endl; - irccd_.get_log().debug(*ev.server) << " channel: " << ev.channel << std::endl; - irccd_.get_log().debug(*ev.server) << " reason: " << ev.reason << std::endl; - - irccd_.transports().broadcast(nlohmann::json::object({ - { "event", "onPart" }, - { "server", ev.server->get_id() }, - { "origin", ev.origin }, - { "channel", ev.channel }, - { "reason", ev.reason } - })); - - dispatch(ev.server->get_id(), ev.origin, ev.channel, - [=] (plugin&) -> std::string { - return "onPart"; - }, - [=] (plugin& plugin) { - plugin.handle_part(irccd_, ev); - } - ); -} - -void dispatcher::operator()(const topic_event& ev) -{ - irccd_.get_log().debug(*ev.server) << "event onTopic:" << std::endl; - irccd_.get_log().debug(*ev.server) << " origin: " << ev.origin << std::endl; - irccd_.get_log().debug(*ev.server) << " channel: " << ev.channel << std::endl; - irccd_.get_log().debug(*ev.server) << " topic: " << ev.topic << std::endl; - - irccd_.transports().broadcast(nlohmann::json::object({ - { "event", "onTopic" }, - { "server", ev.server->get_id() }, - { "origin", ev.origin }, - { "channel", ev.channel }, - { "topic", ev.topic } - })); - - dispatch(ev.server->get_id(), ev.origin, ev.channel, - [=] (plugin&) -> std::string { - return "onTopic"; - }, - [=] (plugin& plugin) { - plugin.handle_topic(irccd_, ev); - } - ); -} - -void dispatcher::operator()(const whois_event& ev) -{ - irccd_.get_log().debug(*ev.server) << "event onWhois" << std::endl; - irccd_.get_log().debug(*ev.server) << " nickname: " << ev.whois.nick << std::endl; - irccd_.get_log().debug(*ev.server) << " username: " << ev.whois.user << std::endl; - irccd_.get_log().debug(*ev.server) << " host: " << ev.whois.host << std::endl; - irccd_.get_log().debug(*ev.server) << " realname: " << ev.whois.realname << std::endl; - irccd_.get_log().debug(*ev.server) << " channels: " << string_util::join(ev.whois.channels, ", ") << std::endl; - - irccd_.transports().broadcast(nlohmann::json::object({ - { "event", "onWhois" }, - { "server", ev.server->get_id() }, - { "nickname", ev.whois.nick }, - { "username", ev.whois.user }, - { "host", ev.whois.host }, - { "realname", ev.whois.realname } - })); - - dispatch(ev.server->get_id(), /* origin */ "", /* channel */ "", - [=] (plugin&) -> std::string { - return "onWhois"; - }, - [=] (plugin& plugin) { - plugin.handle_whois(irccd_, ev); - } - ); -} - -} // !namespace - -void server_service::handle_error(const std::shared_ptr& server, - const std::error_code& code) -{ - assert(server); - - irccd_.get_log().warning(*server) << code.message() << std::endl; - - irccd_.get_log().warning(*server) << int(server->get_options()) << std::endl; - - if ((server->get_options() & server::options::auto_reconnect) != server::options::auto_reconnect) - remove(server->get_id()); - else { - irccd_.get_log().info(*server) << "reconnecting in " - << server->get_reconnect_delay() << " second(s)" << std::endl; - wait(server); - } -} - -void server_service::handle_wait(const std::shared_ptr& server, const std::error_code& code) -{ - /* - * The timer runs on his own control, it will complete either if the delay - * was reached, there was an error or if the io_context was called to cancel - * all pending operations. - * - * This means while the timer is running someone may already have ask a - * server for explicit reconnection (e.g. remote command, plugin). Thus we - * check for server state and if it is still present in service. - */ - if (code && code != std::errc::operation_canceled) { - irccd_.get_log().warning(*server) << code.message() << std::endl; - return; - } - - if (server->get_state() == server::state::connected || !has(server->get_id())) - return; - - connect(server); -} - -void server_service::handle_recv(const std::shared_ptr& server, - const std::error_code& code, - const event& event) -{ - assert(server); - - if (code) - handle_error(server, code); - else { - recv(server); - std::visit(dispatcher(irccd_), event); - } -} - -void server_service::handle_connect(const std::shared_ptr& server, const std::error_code& code) -{ - if (code) - handle_error(server, code); - else - recv(server); -} - -void server_service::wait(const std::shared_ptr& server) -{ - assert(server); - - auto timer = std::make_shared(irccd_.get_service()); - - timer->expires_from_now(boost::posix_time::seconds(server->get_reconnect_delay())); - timer->async_wait([this, server, timer] (auto code) { - handle_wait(server, code); - }); -} - -void server_service::recv(const std::shared_ptr& server) -{ - assert(server); - - server->recv([this, server] (auto code, auto event) { - handle_recv(server, code, event); - }); -} - -void server_service::connect(const std::shared_ptr& server) -{ - assert(server); - - server->connect([this, server] (auto code) { - handle_connect(server, code); - }); -} - -server_service::server_service(irccd &irccd) - : irccd_(irccd) -{ -} - -auto server_service::all() const noexcept -> const std::vector>& -{ - return servers_; -} - -auto server_service::has(const std::string& name) const noexcept -> bool -{ - return std::count_if(servers_.begin(), servers_.end(), [&] (const auto& server) { - return server->get_id() == name; - }) > 0; -} - -void server_service::add(std::shared_ptr server) -{ - assert(server); - assert(!has(server->get_id())); - - servers_.push_back(server); - connect(server); -} - -auto server_service::get(std::string_view name) const noexcept -> std::shared_ptr -{ - const auto it = std::find_if(servers_.begin(), servers_.end(), [&] (const auto& server) { - return server->get_id() == name; - }); - - if (it == servers_.end()) - return nullptr; - - return *it; -} - -auto server_service::require(std::string_view name) const -> std::shared_ptr -{ - if (!string_util::is_identifier(name)) - throw server_error(server_error::invalid_identifier); - - const auto s = get(name); - - if (!s) - throw server_error(server_error::not_found); - - return s; -} - -void server_service::disconnect(std::string_view id) -{ - const auto s = require(id); - - s->disconnect(); - dispatcher{irccd_}(disconnect_event{s}); -} - -void server_service::reconnect(std::string_view id) -{ - disconnect(id); - connect(require(id)); -} - -void server_service::reconnect() -{ - for (const auto& s : servers_) { - try { - s->disconnect(); - dispatcher{irccd_}(disconnect_event{s}); - connect(s); - } catch (const server_error& ex) { - irccd_.get_log().warning(*s) << ex.what() << std::endl; - } - } -} - -void server_service::remove(std::string_view name) -{ - const auto it = std::find_if(servers_.begin(), servers_.end(), [&] (const auto& server) { - return server->get_id() == name; - }); - - if (it != servers_.end()) { - (*it)->disconnect(); - servers_.erase(it); - } -} - -void server_service::clear() noexcept -{ - /* - * Copy the array, because disconnect() may trigger on_die signal which - * erase the server from itself. - */ - const auto save = servers_; - - for (const auto& server : save) - server->disconnect(); - - servers_.clear(); -} - -void server_service::load(const config& cfg) noexcept -{ - for (const auto& section : cfg) { - if (section.key() != "server") - continue; - - const auto id = section.get("name").value(); - - try { - auto server = server_util::from_config(irccd_.get_service(), cfg, section); - - if (has(server->get_id())) - throw server_error(server_error::already_exists); - - add(std::move(server)); - } catch (const std::exception& ex) { - irccd_.get_log().warning("server", id) << ex.what() << std::endl; - } - } -} - -namespace logger { - -auto loggable_traits::get_category(const server&) -> std::string_view -{ - return "server"; -} - -auto loggable_traits::get_component(const server& sv) -> std::string_view -{ - return sv.get_id(); -} - -} // !logger - -} // !irccd diff -r 6d09b5fc82e8 -r c216d148558d libirccd/irccd/daemon/service/server_service.hpp --- a/libirccd/irccd/daemon/service/server_service.hpp Sun Aug 05 12:14:16 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,164 +0,0 @@ -/* - * server_service.hpp -- server service - * - * Copyright (c) 2013-2018 David Demelier - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_DAEMON_SERVER_SERVICE_HPP -#define IRCCD_DAEMON_SERVER_SERVICE_HPP - -/** - * \file server_service.hpp - * \brief Server service. - */ - -#include -#include -#include - -#include - -namespace irccd { - -class config; -class irccd; - -/** - * \brief Manage IRC servers. - * \ingroup services - */ -class server_service { -private: - irccd& irccd_; - std::vector> servers_; - - void handle_error(const std::shared_ptr&, const std::error_code&); - void handle_wait(const std::shared_ptr&, const std::error_code&); - void handle_recv(const std::shared_ptr&, const std::error_code&, const event&); - void handle_connect(const std::shared_ptr&, const std::error_code&); - - void wait(const std::shared_ptr&); - void recv(const std::shared_ptr&); - void connect(const std::shared_ptr&); - -public: - /** - * Create the server service. - */ - server_service(irccd& instance); - - /** - * Get the list of servers - * - * \return the servers - */ - auto all() const noexcept -> const std::vector>&; - - /** - * Check if a server exists. - * - * \param name the name - * \return true if exists - */ - auto has(const std::string& name) const noexcept -> bool; - - /** - * Add a new server to the application. - * - * \pre hasServer must return false - * \param sv the server - */ - void add(std::shared_ptr sv); - - /** - * Get a server or empty one if not found - * - * \param name the server name - * \return the server or empty one if not found - */ - auto get(std::string_view name) const noexcept -> std::shared_ptr; - - /** - * Find a server from a JSON object. - * - * \param name the server name - * \return the server - * \throw server_error on errors - */ - auto require(std::string_view name) const -> std::shared_ptr; - - /** - * Force disconnection, this also call plugin::handle_disconnect handler. - * - * \param id the server id - * \throw server_error on errors - */ - void disconnect(std::string_view id); - - /** - * Force reconnection, this also call plugin::handle_disconnect handler. - * - * \param id the server id - * \return the server - * \throw server_error on errors - */ - void reconnect(std::string_view id); - - /** - * Force reconnection of all servers. - */ - void reconnect(); - - /** - * Remove a server from the irccd instance. - * - * The server if any, will be disconnected. - * - * \param name the server name - */ - void remove(std::string_view name); - - /** - * Remove all servers. - * - * All servers will be disconnected. - */ - void clear() noexcept; - - /** - * Load servers from the configuration. - * - * \param cfg the config - */ - void load(const config& cfg) noexcept; -}; - -namespace logger { - -template -struct loggable_traits; - -template <> -struct loggable_traits { - static auto get_category(const server& server) -> std::string_view; - - static auto get_component(const server& server) -> std::string_view; -}; - -} // !logger - -} // !irccd - -#endif // !IRCCD_DAEMON_SERVER_SERVICE_HPP diff -r 6d09b5fc82e8 -r c216d148558d libirccd/irccd/daemon/service/transport_service.cpp --- a/libirccd/irccd/daemon/service/transport_service.cpp Sun Aug 05 12:14:16 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,140 +0,0 @@ -/* - * transport_service.cpp -- transport service - * - * Copyright (c) 2013-2018 David Demelier - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include - -#include - -#include - -#include -#include -#include -#include -#include - -#include "transport_service.hpp" - -namespace irccd { - -void transport_service::handle_command(std::shared_ptr tc, const nlohmann::json& object) -{ - assert(object.is_object()); - - const json_util::document doc(object); - const auto name = doc.get("command"); - - if (!name) { - tc->error(irccd_error::invalid_message); - return; - } - - const auto cmd = std::find_if(commands_.begin(), commands_.end(), [&] (const auto& cptr) { - return cptr->get_name() == *name; - }); - - if (cmd == commands_.end()) - tc->error(irccd_error::invalid_command, *name); - else { - try { - (*cmd)->exec(irccd_, *tc, doc); - } catch (const std::system_error& ex) { - tc->error(ex.code(), (*cmd)->get_name()); - } catch (const std::exception& ex) { - irccd_.get_log().warning("transport", "") - << "unknown error not reported: " - << ex.what() << std::endl; - } - } -} - -void transport_service::do_recv(std::shared_ptr tc) -{ - tc->read([this, tc] (auto code, auto json) { - switch (static_cast(code.value())) { - case std::errc::not_connected: - irccd_.get_log().info("transport", "") << "client disconnected" << std::endl; - break; - case std::errc::invalid_argument: - tc->error(irccd_error::invalid_message); - break; - default: - // Other error may still happen. - if (!code) { - handle_command(tc, json); - - if (tc->get_state() == transport_client::state_t::ready) - do_recv(std::move(tc)); - } - - break; - } - }); -} - -void transport_service::do_accept(transport_server& ts) -{ - ts.accept([this, &ts] (auto code, auto client) { - if (!code) { - do_accept(ts); - do_recv(std::move(client)); - - irccd_.get_log().info("transport", "") << "new client connected" << std::endl; - } - }); -} - -transport_service::transport_service(irccd& irccd) noexcept - : irccd_(irccd) -{ -} - -transport_service::~transport_service() noexcept = default; - -void transport_service::add(std::shared_ptr ts) -{ - assert(ts); - - do_accept(*ts); - servers_.push_back(std::move(ts)); -} - -void transport_service::broadcast(const nlohmann::json& json) -{ - assert(json.is_object()); - - for (const auto& servers : servers_) - for (const auto& client : servers->get_clients()) - client->write(json); -} - -void transport_service::load(const config& cfg) noexcept -{ - for (const auto& section : cfg) { - if (section.key() != "transport") - continue; - - try { - add(transport_util::from_config(irccd_.get_service(), section)); - } catch (const std::exception& ex) { - irccd_.get_log().warning("transport", "") << ex.what() << std::endl; - } - } -} - -} // !irccd diff -r 6d09b5fc82e8 -r c216d148558d libirccd/irccd/daemon/service/transport_service.hpp --- a/libirccd/irccd/daemon/service/transport_service.hpp Sun Aug 05 12:14:16 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,112 +0,0 @@ -/* - * transport_service.hpp -- transport service - * - * Copyright (c) 2013-2018 David Demelier - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_DAEMON_TRANSPORT_SERVICE_HPP -#define IRCCD_DAEMON_TRANSPORT_SERVICE_HPP - -#include -#include - -#include - -#include -#include - -namespace irccd { - -class command; -class config; -class irccd; - -/** - * \brief manage transport servers and clients. - * \ingroup services - */ -class transport_service { -public: - using commands_t = std::vector>; - using servers_t = std::vector>; - -private: - irccd& irccd_; - commands_t commands_; - servers_t servers_; - - void handle_command(std::shared_ptr, const nlohmann::json&); - void do_recv(std::shared_ptr); - void do_accept(transport_server&); - -public: - /** - * Create the transport service. - * - * \param irccd the irccd instance - */ - transport_service(irccd& irccd) noexcept; - - /** - * Default destructor. - */ - ~transport_service() noexcept; - - /** - * Get underlying commands. - * - * \return the commands - */ - inline const commands_t& get_commands() const noexcept - { - return commands_; - } - - /** - * Get underlying commands. - * - * \return the commands - */ - inline commands_t& get_commands() noexcept - { - return commands_; - } - - /** - * Add a transport server. - * - * \param ts the transport server - */ - void add(std::shared_ptr ts); - - /** - * Send data to all clients. - * - * \pre object.is_object() - * \param object the json object - */ - void broadcast(const nlohmann::json& object); - - /** - * Load transports from the configuration. - * - * \param cfg the config - */ - void load(const config& cfg) noexcept; -}; - -} // !irccd - -#endif // !IRCCD_DAEMON_TRANSPORT_SERVICE_HPP diff -r 6d09b5fc82e8 -r c216d148558d libirccd/irccd/daemon/transport_server.cpp --- a/libirccd/irccd/daemon/transport_server.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/libirccd/irccd/daemon/transport_server.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -24,6 +24,7 @@ #include #include "irccd.hpp" +#include "transport_client.hpp" #include "transport_server.hpp" namespace irccd { diff -r 6d09b5fc82e8 -r c216d148558d libirccd/irccd/daemon/transport_server.hpp --- a/libirccd/irccd/daemon/transport_server.hpp Sun Aug 05 12:14:16 2018 +0200 +++ b/libirccd/irccd/daemon/transport_server.hpp Sun Aug 05 15:47:10 2018 +0200 @@ -34,9 +34,9 @@ #include -#include "transport_client.hpp" +namespace irccd { -namespace irccd { +class transport_client; /** * \brief Abstract transport server class. diff -r 6d09b5fc82e8 -r c216d148558d libirccd/irccd/daemon/transport_service.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd/irccd/daemon/transport_service.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -0,0 +1,142 @@ +/* + * transport_service.cpp -- transport service + * + * Copyright (c) 2013-2018 David Demelier + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include + + +#include "transport_service.hpp" + +namespace irccd { + +void transport_service::handle_command(std::shared_ptr tc, const nlohmann::json& object) +{ + assert(object.is_object()); + + const json_util::document doc(object); + const auto name = doc.get("command"); + + if (!name) { + tc->error(irccd_error::invalid_message); + return; + } + + const auto cmd = std::find_if(commands_.begin(), commands_.end(), [&] (const auto& cptr) { + return cptr->get_name() == *name; + }); + + if (cmd == commands_.end()) + tc->error(irccd_error::invalid_command, *name); + else { + try { + (*cmd)->exec(irccd_, *tc, doc); + } catch (const std::system_error& ex) { + tc->error(ex.code(), (*cmd)->get_name()); + } catch (const std::exception& ex) { + irccd_.get_log().warning("transport", "") + << "unknown error not reported: " + << ex.what() << std::endl; + } + } +} + +void transport_service::do_recv(std::shared_ptr tc) +{ + tc->read([this, tc] (auto code, auto json) { + switch (static_cast(code.value())) { + case std::errc::not_connected: + irccd_.get_log().info("transport", "") << "client disconnected" << std::endl; + break; + case std::errc::invalid_argument: + tc->error(irccd_error::invalid_message); + break; + default: + // Other error may still happen. + if (!code) { + handle_command(tc, json); + + if (tc->get_state() == transport_client::state_t::ready) + do_recv(std::move(tc)); + } + + break; + } + }); +} + +void transport_service::do_accept(transport_server& ts) +{ + ts.accept([this, &ts] (auto code, auto client) { + if (!code) { + do_accept(ts); + do_recv(std::move(client)); + + irccd_.get_log().info("transport", "") << "new client connected" << std::endl; + } + }); +} + +transport_service::transport_service(irccd& irccd) noexcept + : irccd_(irccd) +{ +} + +transport_service::~transport_service() noexcept = default; + +void transport_service::add(std::shared_ptr ts) +{ + assert(ts); + + do_accept(*ts); + servers_.push_back(std::move(ts)); +} + +void transport_service::broadcast(const nlohmann::json& json) +{ + assert(json.is_object()); + + for (const auto& servers : servers_) + for (const auto& client : servers->get_clients()) + client->write(json); +} + +void transport_service::load(const config& cfg) noexcept +{ + for (const auto& section : cfg) { + if (section.key() != "transport") + continue; + + try { + add(transport_util::from_config(irccd_.get_service(), section)); + } catch (const std::exception& ex) { + irccd_.get_log().warning("transport", "") << ex.what() << std::endl; + } + } +} + +} // !irccd diff -r 6d09b5fc82e8 -r c216d148558d libirccd/irccd/daemon/transport_service.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd/irccd/daemon/transport_service.hpp Sun Aug 05 15:47:10 2018 +0200 @@ -0,0 +1,111 @@ +/* + * transport_service.hpp -- transport service + * + * Copyright (c) 2013-2018 David Demelier + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_DAEMON_TRANSPORT_SERVICE_HPP +#define IRCCD_DAEMON_TRANSPORT_SERVICE_HPP + +#include +#include + +#include + +namespace irccd { + +class command; +class config; +class irccd; +class transport_client; +class transport_server; + +/** + * \brief manage transport servers and clients. + * \ingroup services + */ +class transport_service { +public: + using commands_t = std::vector>; + using servers_t = std::vector>; + +private: + irccd& irccd_; + commands_t commands_; + servers_t servers_; + + void handle_command(std::shared_ptr, const nlohmann::json&); + void do_recv(std::shared_ptr); + void do_accept(transport_server&); + +public: + /** + * Create the transport service. + * + * \param irccd the irccd instance + */ + transport_service(irccd& irccd) noexcept; + + /** + * Default destructor. + */ + ~transport_service() noexcept; + + /** + * Get underlying commands. + * + * \return the commands + */ + inline const commands_t& get_commands() const noexcept + { + return commands_; + } + + /** + * Get underlying commands. + * + * \return the commands + */ + inline commands_t& get_commands() noexcept + { + return commands_; + } + + /** + * Add a transport server. + * + * \param ts the transport server + */ + void add(std::shared_ptr ts); + + /** + * Send data to all clients. + * + * \pre object.is_object() + * \param object the json object + */ + void broadcast(const nlohmann::json& object); + + /** + * Load transports from the configuration. + * + * \param cfg the config + */ + void load(const config& cfg) noexcept; +}; + +} // !irccd + +#endif // !IRCCD_DAEMON_TRANSPORT_SERVICE_HPP diff -r 6d09b5fc82e8 -r c216d148558d tests/src/libirccd-js/js-plugin/main.cpp --- a/tests/src/libirccd-js/js-plugin/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/tests/src/libirccd-js/js-plugin/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include diff -r 6d09b5fc82e8 -r c216d148558d tests/src/libirccd/command-plugin-config/main.cpp --- a/tests/src/libirccd/command-plugin-config/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/tests/src/libirccd/command-plugin-config/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -19,7 +19,7 @@ #define BOOST_TEST_MODULE "plugin-config" #include -#include +#include #include #include diff -r 6d09b5fc82e8 -r c216d148558d tests/src/libirccd/command-plugin-info/main.cpp --- a/tests/src/libirccd/command-plugin-info/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/tests/src/libirccd/command-plugin-info/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -19,7 +19,7 @@ #define BOOST_TEST_MODULE "plugin-info" #include -#include +#include #include #include diff -r 6d09b5fc82e8 -r c216d148558d tests/src/libirccd/command-plugin-list/main.cpp --- a/tests/src/libirccd/command-plugin-list/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/tests/src/libirccd/command-plugin-list/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -19,7 +19,7 @@ #define BOOST_TEST_MODULE "plugin-list" #include -#include +#include #include #include diff -r 6d09b5fc82e8 -r c216d148558d tests/src/libirccd/command-plugin-load/main.cpp --- a/tests/src/libirccd/command-plugin-load/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/tests/src/libirccd/command-plugin-load/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -19,7 +19,7 @@ #define BOOST_TEST_MODULE "plugin-load" #include -#include +#include #include #include diff -r 6d09b5fc82e8 -r c216d148558d tests/src/libirccd/command-plugin-reload/main.cpp --- a/tests/src/libirccd/command-plugin-reload/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/tests/src/libirccd/command-plugin-reload/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -19,7 +19,7 @@ #define BOOST_TEST_MODULE "plugin-reload" #include -#include +#include #include #include diff -r 6d09b5fc82e8 -r c216d148558d tests/src/libirccd/command-plugin-unload/main.cpp --- a/tests/src/libirccd/command-plugin-unload/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/tests/src/libirccd/command-plugin-unload/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -19,7 +19,7 @@ #define BOOST_TEST_MODULE "plugin-unload" #include -#include +#include #include #include diff -r 6d09b5fc82e8 -r c216d148558d tests/src/libirccd/command-rule-add/main.cpp --- a/tests/src/libirccd/command-rule-add/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/tests/src/libirccd/command-rule-add/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -21,7 +21,7 @@ #include -#include +#include #include diff -r 6d09b5fc82e8 -r c216d148558d tests/src/libirccd/command-rule-edit/main.cpp --- a/tests/src/libirccd/command-rule-edit/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/tests/src/libirccd/command-rule-edit/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -21,7 +21,7 @@ #include -#include +#include #include diff -r 6d09b5fc82e8 -r c216d148558d tests/src/libirccd/command-rule-info/main.cpp --- a/tests/src/libirccd/command-rule-info/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/tests/src/libirccd/command-rule-info/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -21,7 +21,7 @@ #include -#include +#include #include diff -r 6d09b5fc82e8 -r c216d148558d tests/src/libirccd/command-rule-list/main.cpp --- a/tests/src/libirccd/command-rule-list/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/tests/src/libirccd/command-rule-list/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -21,7 +21,7 @@ #include -#include +#include #include diff -r 6d09b5fc82e8 -r c216d148558d tests/src/libirccd/command-rule-move/main.cpp --- a/tests/src/libirccd/command-rule-move/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/tests/src/libirccd/command-rule-move/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -21,7 +21,7 @@ #include -#include +#include #include diff -r 6d09b5fc82e8 -r c216d148558d tests/src/libirccd/command-rule-remove/main.cpp --- a/tests/src/libirccd/command-rule-remove/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/tests/src/libirccd/command-rule-remove/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -21,7 +21,7 @@ #include -#include +#include #include diff -r 6d09b5fc82e8 -r c216d148558d tests/src/libirccd/command-server-connect/main.cpp --- a/tests/src/libirccd/command-server-connect/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/tests/src/libirccd/command-server-connect/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -19,7 +19,7 @@ #define BOOST_TEST_MODULE "server-connect" #include -#include +#include #include #include diff -r 6d09b5fc82e8 -r c216d148558d tests/src/libirccd/command-server-disconnect/main.cpp --- a/tests/src/libirccd/command-server-disconnect/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/tests/src/libirccd/command-server-disconnect/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -19,7 +19,7 @@ #define BOOST_TEST_MODULE "server-disconnect" #include -#include +#include #include #include diff -r 6d09b5fc82e8 -r c216d148558d tests/src/libirccd/command-server-info/main.cpp --- a/tests/src/libirccd/command-server-info/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/tests/src/libirccd/command-server-info/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -19,7 +19,7 @@ #define BOOST_TEST_MODULE "server-info" #include -#include +#include #include #include diff -r 6d09b5fc82e8 -r c216d148558d tests/src/libirccd/command-server-invite/main.cpp --- a/tests/src/libirccd/command-server-invite/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/tests/src/libirccd/command-server-invite/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -19,7 +19,7 @@ #define BOOST_TEST_MODULE "server-invite" #include -#include +#include #include #include diff -r 6d09b5fc82e8 -r c216d148558d tests/src/libirccd/command-server-join/main.cpp --- a/tests/src/libirccd/command-server-join/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/tests/src/libirccd/command-server-join/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -19,7 +19,7 @@ #define BOOST_TEST_MODULE "server-join" #include -#include +#include #include #include diff -r 6d09b5fc82e8 -r c216d148558d tests/src/libirccd/command-server-kick/main.cpp --- a/tests/src/libirccd/command-server-kick/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/tests/src/libirccd/command-server-kick/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -19,7 +19,7 @@ #define BOOST_TEST_MODULE "server-kick" #include -#include +#include #include #include diff -r 6d09b5fc82e8 -r c216d148558d tests/src/libirccd/command-server-list/main.cpp --- a/tests/src/libirccd/command-server-list/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/tests/src/libirccd/command-server-list/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -19,7 +19,7 @@ #define BOOST_TEST_MODULE "server-list" #include -#include +#include #include #include diff -r 6d09b5fc82e8 -r c216d148558d tests/src/libirccd/command-server-me/main.cpp --- a/tests/src/libirccd/command-server-me/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/tests/src/libirccd/command-server-me/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -19,7 +19,7 @@ #define BOOST_TEST_MODULE "server-me" #include -#include +#include #include #include diff -r 6d09b5fc82e8 -r c216d148558d tests/src/libirccd/command-server-message/main.cpp --- a/tests/src/libirccd/command-server-message/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/tests/src/libirccd/command-server-message/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -19,7 +19,7 @@ #define BOOST_TEST_MODULE "server-message" #include -#include +#include #include #include diff -r 6d09b5fc82e8 -r c216d148558d tests/src/libirccd/command-server-mode/main.cpp --- a/tests/src/libirccd/command-server-mode/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/tests/src/libirccd/command-server-mode/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -19,7 +19,7 @@ #define BOOST_TEST_MODULE "server-mode" #include -#include +#include #include #include diff -r 6d09b5fc82e8 -r c216d148558d tests/src/libirccd/command-server-nick/main.cpp --- a/tests/src/libirccd/command-server-nick/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/tests/src/libirccd/command-server-nick/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -19,7 +19,7 @@ #define BOOST_TEST_MODULE "server-nick" #include -#include +#include #include #include diff -r 6d09b5fc82e8 -r c216d148558d tests/src/libirccd/command-server-notice/main.cpp --- a/tests/src/libirccd/command-server-notice/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/tests/src/libirccd/command-server-notice/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -19,7 +19,7 @@ #define BOOST_TEST_MODULE "server-notice" #include -#include +#include #include #include diff -r 6d09b5fc82e8 -r c216d148558d tests/src/libirccd/command-server-part/main.cpp --- a/tests/src/libirccd/command-server-part/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/tests/src/libirccd/command-server-part/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -19,7 +19,7 @@ #define BOOST_TEST_MODULE "server-part" #include -#include +#include #include #include diff -r 6d09b5fc82e8 -r c216d148558d tests/src/libirccd/command-server-reconnect/main.cpp --- a/tests/src/libirccd/command-server-reconnect/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/tests/src/libirccd/command-server-reconnect/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -19,7 +19,7 @@ #define BOOST_TEST_MODULE "server-reconnect" #include -#include +#include #include #include diff -r 6d09b5fc82e8 -r c216d148558d tests/src/libirccd/command-server-topic/main.cpp --- a/tests/src/libirccd/command-server-topic/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/tests/src/libirccd/command-server-topic/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -19,7 +19,7 @@ #define BOOST_TEST_MODULE "server-topic" #include -#include +#include #include #include diff -r 6d09b5fc82e8 -r c216d148558d tests/src/libirccd/rules/main.cpp --- a/tests/src/libirccd/rules/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/tests/src/libirccd/rules/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -21,7 +21,7 @@ #include #include -#include +#include namespace irccd { diff -r 6d09b5fc82e8 -r c216d148558d tests/src/plugins/plugin/main.cpp --- a/tests/src/plugins/plugin/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/tests/src/plugins/plugin/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -23,8 +23,8 @@ #include #include +#include #include -#include #include diff -r 6d09b5fc82e8 -r c216d148558d tests/src/plugins/tictactoe/main.cpp --- a/tests/src/plugins/tictactoe/main.cpp Sun Aug 05 12:14:16 2018 +0200 +++ b/tests/src/plugins/tictactoe/main.cpp Sun Aug 05 15:47:10 2018 +0200 @@ -22,8 +22,8 @@ #include #include +#include #include -#include #include