Mercurial > irccd
changeset 630:711e0bd01eaf
Irccd: move services to service folder
line wrap: on
line diff
--- a/irccd-test/main.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/irccd-test/main.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -36,8 +36,9 @@ #include <irccd/daemon/dynlib_plugin.hpp> #include <irccd/daemon/irccd.hpp> -#include <irccd/daemon/plugin_service.hpp> -#include <irccd/daemon/server_service.hpp> + +#include <irccd/daemon/service/plugin_service.hpp> +#include <irccd/daemon/service/server_service.hpp> #include <irccd/test/debug_server.hpp>
--- a/irccd/main.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/irccd/main.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -38,7 +38,6 @@ #include <irccd/string_util.hpp> #include <irccd/system.hpp> -#include <irccd/daemon/command_service.hpp> #include <irccd/daemon/irccd.hpp> #include <irccd/daemon/logger.hpp> #include <irccd/daemon/plugin_config_command.hpp> @@ -47,7 +46,6 @@ #include <irccd/daemon/plugin_list_command.hpp> #include <irccd/daemon/plugin_load_command.hpp> #include <irccd/daemon/plugin_reload_command.hpp> -#include <irccd/daemon/plugin_service.hpp> #include <irccd/daemon/plugin_unload_command.hpp> #include <irccd/daemon/rule_add_command.hpp> #include <irccd/daemon/rule_edit_command.hpp> @@ -55,7 +53,6 @@ #include <irccd/daemon/rule_list_command.hpp> #include <irccd/daemon/rule_move_command.hpp> #include <irccd/daemon/rule_remove_command.hpp> -#include <irccd/daemon/rule_service.hpp> #include <irccd/daemon/server_connect_command.hpp> #include <irccd/daemon/server_disconnect_command.hpp> #include <irccd/daemon/server_info_command.hpp> @@ -70,9 +67,12 @@ #include <irccd/daemon/server_notice_command.hpp> #include <irccd/daemon/server_part_command.hpp> #include <irccd/daemon/server_reconnect_command.hpp> -#include <irccd/daemon/server_service.hpp> #include <irccd/daemon/server_topic_command.hpp> -#include <irccd/daemon/transport_service.hpp> + +#include <irccd/daemon/service/plugin_service.hpp> +#include <irccd/daemon/service/rule_service.hpp> +#include <irccd/daemon/service/server_service.hpp> +#include <irccd/daemon/service/transport_service.hpp> #if defined(HAVE_JS) # include <irccd/js/js_plugin.hpp> @@ -202,33 +202,33 @@ auto options = parse(argc, argv); - instance->commands().add(std::make_unique<plugin_config_command>()); - instance->commands().add(std::make_unique<plugin_info_command>()); - instance->commands().add(std::make_unique<plugin_list_command>()); - instance->commands().add(std::make_unique<plugin_load_command>()); - instance->commands().add(std::make_unique<plugin_reload_command>()); - instance->commands().add(std::make_unique<plugin_unload_command>()); - instance->commands().add(std::make_unique<server_connect_command>()); - instance->commands().add(std::make_unique<server_disconnect_command>()); - instance->commands().add(std::make_unique<server_info_command>()); - instance->commands().add(std::make_unique<server_invite_command>()); - instance->commands().add(std::make_unique<server_join_command>()); - instance->commands().add(std::make_unique<server_kick_command>()); - instance->commands().add(std::make_unique<server_list_command>()); - instance->commands().add(std::make_unique<server_me_command>()); - instance->commands().add(std::make_unique<server_message_command>()); - instance->commands().add(std::make_unique<server_mode_command>()); - instance->commands().add(std::make_unique<server_nick_command>()); - instance->commands().add(std::make_unique<server_notice_command>()); - instance->commands().add(std::make_unique<server_part_command>()); - instance->commands().add(std::make_unique<server_reconnect_command>()); - instance->commands().add(std::make_unique<server_topic_command>()); - instance->commands().add(std::make_unique<rule_add_command>()); - instance->commands().add(std::make_unique<rule_edit_command>()); - instance->commands().add(std::make_unique<rule_info_command>()); - instance->commands().add(std::make_unique<rule_list_command>()); - instance->commands().add(std::make_unique<rule_move_command>()); - instance->commands().add(std::make_unique<rule_remove_command>()); + instance->transports().get_commands().push_back(std::make_unique<plugin_config_command>()); + instance->transports().get_commands().push_back(std::make_unique<plugin_info_command>()); + instance->transports().get_commands().push_back(std::make_unique<plugin_list_command>()); + instance->transports().get_commands().push_back(std::make_unique<plugin_load_command>()); + instance->transports().get_commands().push_back(std::make_unique<plugin_reload_command>()); + instance->transports().get_commands().push_back(std::make_unique<plugin_unload_command>()); + instance->transports().get_commands().push_back(std::make_unique<server_connect_command>()); + instance->transports().get_commands().push_back(std::make_unique<server_disconnect_command>()); + instance->transports().get_commands().push_back(std::make_unique<server_info_command>()); + instance->transports().get_commands().push_back(std::make_unique<server_invite_command>()); + instance->transports().get_commands().push_back(std::make_unique<server_join_command>()); + instance->transports().get_commands().push_back(std::make_unique<server_kick_command>()); + instance->transports().get_commands().push_back(std::make_unique<server_list_command>()); + instance->transports().get_commands().push_back(std::make_unique<server_me_command>()); + instance->transports().get_commands().push_back(std::make_unique<server_message_command>()); + instance->transports().get_commands().push_back(std::make_unique<server_mode_command>()); + instance->transports().get_commands().push_back(std::make_unique<server_nick_command>()); + instance->transports().get_commands().push_back(std::make_unique<server_notice_command>()); + instance->transports().get_commands().push_back(std::make_unique<server_part_command>()); + instance->transports().get_commands().push_back(std::make_unique<server_reconnect_command>()); + instance->transports().get_commands().push_back(std::make_unique<server_topic_command>()); + instance->transports().get_commands().push_back(std::make_unique<rule_add_command>()); + instance->transports().get_commands().push_back(std::make_unique<rule_edit_command>()); + instance->transports().get_commands().push_back(std::make_unique<rule_info_command>()); + instance->transports().get_commands().push_back(std::make_unique<rule_list_command>()); + instance->transports().get_commands().push_back(std::make_unique<rule_move_command>()); + instance->transports().get_commands().push_back(std::make_unique<rule_remove_command>()); #if defined(HAVE_JS) instance->plugins().add_loader(js_plugin_loader::defaults(*instance));
--- a/libirccd-js/irccd/js/plugin_jsapi.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd-js/irccd/js/plugin_jsapi.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -17,7 +17,8 @@ */ #include <irccd/daemon/irccd.hpp> -#include <irccd/daemon/plugin_service.hpp> + +#include <irccd/daemon/service/plugin_service.hpp> #include "irccd_jsapi.hpp" #include "js_plugin.hpp"
--- a/libirccd-js/irccd/js/server_jsapi.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd-js/irccd/js/server_jsapi.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -21,7 +21,8 @@ #include <unordered_map> #include <irccd/daemon/irccd.hpp> -#include <irccd/daemon/server_service.hpp> + +#include <irccd/daemon/service/server_service.hpp> #include "duktape_vector.hpp" #include "irccd_jsapi.hpp"
--- a/libirccd-test/irccd/test/command_test.hpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd-test/irccd/test/command_test.hpp Wed Mar 07 17:49:56 2018 +0100 @@ -21,11 +21,10 @@ #include <memory> -#include <irccd/daemon/command_service.hpp> #include <irccd/daemon/ip_transport_server.hpp> #include <irccd/daemon/irccd.hpp> #include <irccd/daemon/logger.hpp> -#include <irccd/daemon/transport_service.hpp> +#include <irccd/daemon/service/transport_service.hpp> #include <irccd/ctl/ip_connection.hpp> #include <irccd/ctl/controller.hpp> @@ -38,7 +37,7 @@ template <typename Command> inline void add() { - daemon_->commands().add(std::make_unique<Command>()); + daemon_->transports().get_commands().push_back(std::make_unique<Command>()); } template <typename C1, typename C2, typename... Tail>
--- a/libirccd-test/irccd/test/plugin_test.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd-test/irccd/test/plugin_test.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -19,8 +19,9 @@ #include <cassert> #include <irccd/daemon/logger.hpp> -#include <irccd/daemon/plugin_service.hpp> -#include <irccd/daemon/server_service.hpp> + +#include <irccd/daemon/service/plugin_service.hpp> +#include <irccd/daemon/service/server_service.hpp> #include <irccd/js/directory_jsapi.hpp> #include <irccd/js/elapsed_timer_jsapi.hpp>
--- a/libirccd/CMakeLists.txt Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd/CMakeLists.txt Wed Mar 07 17:49:56 2018 +0100 @@ -25,7 +25,6 @@ ${libirccd_SOURCE_DIR}/irccd/daemon/basic_transport_client.hpp ${libirccd_SOURCE_DIR}/irccd/daemon/basic_transport_server.hpp ${libirccd_SOURCE_DIR}/irccd/daemon/command.hpp - ${libirccd_SOURCE_DIR}/irccd/daemon/command_service.hpp ${libirccd_SOURCE_DIR}/irccd/daemon/dynlib_plugin.hpp ${libirccd_SOURCE_DIR}/irccd/daemon/ip_transport_server.hpp ${libirccd_SOURCE_DIR}/irccd/daemon/irccd.hpp @@ -39,7 +38,6 @@ ${libirccd_SOURCE_DIR}/irccd/daemon/plugin_list_command.hpp ${libirccd_SOURCE_DIR}/irccd/daemon/plugin_load_command.hpp ${libirccd_SOURCE_DIR}/irccd/daemon/plugin_reload_command.hpp - ${libirccd_SOURCE_DIR}/irccd/daemon/plugin_service.hpp ${libirccd_SOURCE_DIR}/irccd/daemon/plugin_unload_command.hpp ${libirccd_SOURCE_DIR}/irccd/daemon/rule_add_command.hpp ${libirccd_SOURCE_DIR}/irccd/daemon/rule_edit_command.hpp @@ -48,7 +46,6 @@ ${libirccd_SOURCE_DIR}/irccd/daemon/rule_list_command.hpp ${libirccd_SOURCE_DIR}/irccd/daemon/rule_move_command.hpp ${libirccd_SOURCE_DIR}/irccd/daemon/rule_remove_command.hpp - ${libirccd_SOURCE_DIR}/irccd/daemon/rule_service.hpp ${libirccd_SOURCE_DIR}/irccd/daemon/server_connect_command.hpp ${libirccd_SOURCE_DIR}/irccd/daemon/server_disconnect_command.hpp ${libirccd_SOURCE_DIR}/irccd/daemon/server.hpp @@ -64,17 +61,18 @@ ${libirccd_SOURCE_DIR}/irccd/daemon/server_notice_command.hpp ${libirccd_SOURCE_DIR}/irccd/daemon/server_part_command.hpp ${libirccd_SOURCE_DIR}/irccd/daemon/server_reconnect_command.hpp - ${libirccd_SOURCE_DIR}/irccd/daemon/server_service.hpp ${libirccd_SOURCE_DIR}/irccd/daemon/server_topic_command.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 $<$<BOOL:${HAVE_SSL}>:${libirccd_SOURCE_DIR}/irccd/daemon/tls_transport_server.hpp> ) set( SOURCES - ${libirccd_SOURCE_DIR}/irccd/daemon/command_service.cpp ${libirccd_SOURCE_DIR}/irccd/daemon/dynlib_plugin.cpp ${libirccd_SOURCE_DIR}/irccd/daemon/irccd.cpp ${libirccd_SOURCE_DIR}/irccd/daemon/irc.cpp @@ -85,7 +83,6 @@ ${libirccd_SOURCE_DIR}/irccd/daemon/plugin_list_command.cpp ${libirccd_SOURCE_DIR}/irccd/daemon/plugin_load_command.cpp ${libirccd_SOURCE_DIR}/irccd/daemon/plugin_reload_command.cpp - ${libirccd_SOURCE_DIR}/irccd/daemon/plugin_service.cpp ${libirccd_SOURCE_DIR}/irccd/daemon/plugin_unload_command.cpp ${libirccd_SOURCE_DIR}/irccd/daemon/rule_add_command.cpp ${libirccd_SOURCE_DIR}/irccd/daemon/rule.cpp @@ -94,7 +91,6 @@ ${libirccd_SOURCE_DIR}/irccd/daemon/rule_list_command.cpp ${libirccd_SOURCE_DIR}/irccd/daemon/rule_move_command.cpp ${libirccd_SOURCE_DIR}/irccd/daemon/rule_remove_command.cpp - ${libirccd_SOURCE_DIR}/irccd/daemon/rule_service.cpp ${libirccd_SOURCE_DIR}/irccd/daemon/server_connect_command.cpp ${libirccd_SOURCE_DIR}/irccd/daemon/server.cpp ${libirccd_SOURCE_DIR}/irccd/daemon/server_disconnect_command.cpp @@ -110,11 +106,13 @@ ${libirccd_SOURCE_DIR}/irccd/daemon/server_notice_command.cpp ${libirccd_SOURCE_DIR}/irccd/daemon/server_part_command.cpp ${libirccd_SOURCE_DIR}/irccd/daemon/server_reconnect_command.cpp - ${libirccd_SOURCE_DIR}/irccd/daemon/server_service.cpp ${libirccd_SOURCE_DIR}/irccd/daemon/server_topic_command.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 $<$<BOOL:${HAVE_SSL}>:${libirccd_SOURCE_DIR}/irccd/daemon/tls_transport_server.cpp> )
--- a/libirccd/irccd/daemon/command_service.cpp Mon Jan 15 13:37:32 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* - * command_service.cpp -- command service - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * 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 "command_service.hpp" - -namespace irccd { - -bool command_service::contains(const std::string& name) const noexcept -{ - return find(name) != nullptr; -} - -std::shared_ptr<command> command_service::find(const std::string& name) const noexcept -{ - auto it = std::find_if(commands_.begin(), commands_.end(), [&] (const auto& cmd) { - return cmd->get_name() == name; - }); - - return it == commands_.end() ? nullptr : *it; -} - -void command_service::add(std::shared_ptr<command> command) -{ - auto it = std::find_if(commands_.begin(), commands_.end(), [&] (const auto& cmd) { - return cmd->get_name() == command->get_name(); - }); - - if (it != commands_.end()) - *it = std::move(command); - else - commands_.push_back(std::move(command)); -} - -} // !irccd
--- a/libirccd/irccd/daemon/command_service.hpp Mon Jan 15 13:37:32 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ -/* - * command_service.hpp -- command service - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * 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_COMMAND_SERVICE_HPP -#define IRCCD_DAEMON_COMMAND_SERVICE_HPP - -/** - * \file command_service.hpp - * \brief Command service. - */ - -#include <memory> -#include <vector> - -#include "command.hpp" - -namespace irccd { - -/** - * \brief Store remote commands. - * \ingroup services - */ -class command_service { -private: - std::vector<std::shared_ptr<command>> commands_; - -public: - /** - * Get all commands. - * - * \return the list of commands. - */ - inline const std::vector<std::shared_ptr<command>>& commands() const noexcept - { - return commands_; - } - - /** - * Tells if a command exists. - * - * \param name the command name - * \return true if the command exists - */ - bool contains(const std::string& name) const noexcept; - - /** - * Find a command by name. - * - * \param name the command name - * \return the command or empty one if not found - */ - std::shared_ptr<command> find(const std::string& name) const noexcept; - - /** - * Add a command or replace existing one. - * - * \pre command != nullptr - * \param command the command name - */ - void add(std::shared_ptr<command> command); -}; - -} // !irccd - -#endif // !IRCCD_DAEMON_COMMAND_SERVICE_HPP
--- a/libirccd/irccd/daemon/irccd.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd/irccd/daemon/irccd.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -19,13 +19,13 @@ #include <irccd/string_util.hpp> #include <irccd/system.hpp> -#include "command_service.hpp" #include "irccd.hpp" #include "logger.hpp" -#include "plugin_service.hpp" -#include "rule_service.hpp" -#include "server_service.hpp" -#include "transport_service.hpp" + +#include "service/plugin_service.hpp" +#include "service/rule_service.hpp" +#include "service/server_service.hpp" +#include "service/transport_service.hpp" namespace irccd { @@ -211,7 +211,6 @@ : config_(std::move(config)) , service_(service) , logger_(std::make_unique<console_logger>()) - , command_service_(std::make_unique<command_service>()) , server_service_(std::make_unique<server_service>(*this)) , tpt_service_(std::make_unique<transport_service>(*this)) , rule_service_(std::make_unique<rule_service>(*this))
--- a/libirccd/irccd/daemon/irccd.hpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd/irccd/daemon/irccd.hpp Wed Mar 07 17:49:56 2018 +0100 @@ -37,7 +37,6 @@ */ namespace irccd { -class command_service; class logger; class plugin_service; class rule_service; @@ -62,7 +61,6 @@ std::unique_ptr<logger> logger_; // Services. - std::shared_ptr<command_service> command_service_; std::shared_ptr<server_service> server_service_; std::shared_ptr<transport_service> tpt_service_; std::shared_ptr<rule_service> rule_service_; @@ -167,16 +165,6 @@ void set_log(std::unique_ptr<logger> logger) noexcept; /** - * Access the command service. - * - * \return the service - */ - inline command_service& commands() noexcept - { - return *command_service_; - } - - /** * Access the server service. * * \return the service
--- a/libirccd/irccd/daemon/plugin_config_command.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd/irccd/daemon/plugin_config_command.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -20,9 +20,10 @@ #include "irccd.hpp" #include "plugin_config_command.hpp" -#include "plugin_service.hpp" #include "transport_client.hpp" +#include <irccd/daemon/service/plugin_service.hpp> + namespace irccd { namespace {
--- a/libirccd/irccd/daemon/plugin_info_command.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd/irccd/daemon/plugin_info_command.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -20,9 +20,10 @@ #include "irccd.hpp" #include "plugin_info_command.hpp" -#include "plugin_service.hpp" #include "transport_client.hpp" +#include <irccd/daemon/service/plugin_service.hpp> + namespace irccd { std::string plugin_info_command::get_name() const noexcept
--- a/libirccd/irccd/daemon/plugin_list_command.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd/irccd/daemon/plugin_list_command.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -18,9 +18,10 @@ #include "irccd.hpp" #include "plugin_list_command.hpp" -#include "plugin_service.hpp" #include "transport_client.hpp" +#include <irccd/daemon/service/plugin_service.hpp> + namespace irccd { std::string plugin_list_command::get_name() const noexcept
--- a/libirccd/irccd/daemon/plugin_load_command.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd/irccd/daemon/plugin_load_command.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -20,9 +20,10 @@ #include "irccd.hpp" #include "plugin_load_command.hpp" -#include "plugin_service.hpp" #include "transport_client.hpp" +#include <irccd/daemon/service/plugin_service.hpp> + namespace irccd { std::string plugin_load_command::get_name() const noexcept
--- a/libirccd/irccd/daemon/plugin_reload_command.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd/irccd/daemon/plugin_reload_command.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -20,9 +20,10 @@ #include "irccd.hpp" #include "plugin_reload_command.hpp" -#include "plugin_service.hpp" #include "transport_client.hpp" +#include <irccd/daemon/service/plugin_service.hpp> + namespace irccd { std::string plugin_reload_command::get_name() const noexcept
--- a/libirccd/irccd/daemon/plugin_service.cpp Mon Jan 15 13:37:32 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,231 +0,0 @@ -/* - * plugin_service.cpp -- plugin service - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * 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 <irccd/config.hpp> -#include <irccd/string_util.hpp> -#include <irccd/system.hpp> - -#include "irccd.hpp" -#include "logger.hpp" -#include "plugin_service.hpp" - -namespace irccd { - -namespace { - -template <typename Map> -Map to_map(const config& conf, const std::string& section) -{ - Map ret; - - for (const auto& opt : conf.doc().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& plugin : plugins_) { - try { - plugin->on_unload(irccd_); - } catch (const std::exception& ex) { - irccd_.log().warning() << "plugin: " << plugin->name() << ": " << ex.what() << std::endl; - } - } -} - -bool plugin_service::has(const std::string& name) const noexcept -{ - return std::count_if(plugins_.cbegin(), plugins_.cend(), [&] (const auto& plugin) { - return plugin->name() == name; - }) > 0; -} - -std::shared_ptr<plugin> plugin_service::get(const std::string& name) const noexcept -{ - auto it = std::find_if(plugins_.begin(), plugins_.end(), [&] (const auto& plugin) { - return plugin->name() == name; - }); - - if (it == plugins_.end()) - return nullptr; - - return *it; -} - -std::shared_ptr<plugin> plugin_service::require(const std::string& name) const -{ - auto plugin = get(name); - - if (!plugin) - throw plugin_error(plugin_error::not_found, name); - - return plugin; -} - -void plugin_service::add(std::shared_ptr<plugin> plugin) -{ - plugins_.push_back(std::move(plugin)); -} - -void plugin_service::add_loader(std::unique_ptr<plugin_loader> loader) -{ - loaders_.push_back(std::move(loader)); -} - -plugin_config plugin_service::config(const std::string& id) -{ - return to_map<plugin_config>(irccd_.config(), string_util::sprintf("plugin.%s", id)); -} - -plugin_formats plugin_service::formats(const std::string& id) -{ - return to_map<plugin_formats>(irccd_.config(), string_util::sprintf("format.%s", id)); -} - -plugin_paths plugin_service::paths(const std::string& id) -{ - auto defaults = to_map<plugin_paths>(irccd_.config(), "paths"); - auto paths = to_map<plugin_paths>(irccd_.config(), string_util::sprintf("paths.%s", id)); - - // Fill defaults paths. - if (!defaults.count("cache")) - defaults.emplace("cache", sys::cachedir() + "/plugin/" + id); - if (!defaults.count("data")) - paths.emplace("data", sys::datadir() + "/plugin/" + id); - if (!defaults.count("config")) - paths.emplace("config", sys::sysconfigdir() + "/plugin/" + id); - - // Now fill missing fields. - if (!paths.count("cache")) - paths.emplace("cache", defaults["cache"]); - if (!paths.count("data")) - paths.emplace("data", defaults["data"]); - if (!paths.count("config")) - paths.emplace("config", defaults["config"]); - - return paths; -} - -std::shared_ptr<plugin> plugin_service::open(const std::string& id, - const std::string& path) -{ - for (const auto& loader : loaders_) { - auto plugin = loader->open(id, path); - - if (plugin) - return plugin; - } - - return nullptr; -} - -std::shared_ptr<plugin> plugin_service::find(const std::string& id) -{ - for (const auto& loader : loaders_) { - auto plugin = loader->find(id); - - if (plugin) - return plugin; - } - - return nullptr; -} - -void plugin_service::load(std::string name, std::string path) -{ - if (has(name)) - throw plugin_error(plugin_error::already_exists, name); - - std::shared_ptr<plugin> plugin; - - if (path.empty()) - plugin = find(name); - else - plugin = open(name, std::move(path)); - - if (!plugin) - throw plugin_error(plugin_error::not_found, name); - - plugin->set_config(config(name)); - plugin->set_formats(formats(name)); - plugin->set_paths(paths(name)); - - exec(plugin, &plugin::on_load, irccd_); - add(std::move(plugin)); -} - -void plugin_service::reload(const std::string& name) -{ - auto plugin = get(name); - - if (!plugin) - throw plugin_error(plugin_error::not_found, name); - - exec(plugin, &plugin::on_reload, irccd_); -} - -void plugin_service::unload(const std::string& name) -{ - auto it = std::find_if(plugins_.begin(), plugins_.end(), [&] (const auto& plugin) { - return plugin->name() == name; - }); - - if (it == plugins_.end()) - throw plugin_error(plugin_error::not_found, name); - - // Erase first, in case of throwing. - auto save = *it; - - plugins_.erase(it); - exec(save, &plugin::on_unload, irccd_); -} - -void plugin_service::load(const class config& cfg) noexcept -{ - for (const auto& option : cfg.section("plugins")) { - if (!string_util::is_identifier(option.key())) - continue; - - auto name = option.key(); - auto p = get(name); - - // Reload the plugin if already loaded. - if (p) { - p->set_config(config(name)); - p->set_formats(formats(name)); - p->set_paths(paths(name)); - } else { - try { - load(name, option.value()); - } catch (const std::exception& ex) { - irccd_.log().warning(ex.what()); - } - } - } -} - -} // !irccd
--- a/libirccd/irccd/daemon/plugin_service.hpp Mon Jan 15 13:37:32 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,237 +0,0 @@ -/* - * plugin_service.hpp -- plugin service - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * 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 <cassert> -#include <memory> -#include <string> -#include <vector> - -#include "plugin.hpp" - -namespace irccd { - -class irccd; -class config; - -/** - * \brief Manage plugins. - * \ingroup services - */ -class plugin_service { -private: - irccd& irccd_; - std::vector<std::shared_ptr<plugin>> plugins_; - std::vector<std::unique_ptr<plugin_loader>> loaders_; - -public: - /** - * Create the plugin service. - * - * \param irccd the irccd instance - */ - plugin_service(irccd& irccd) noexcept; - - /** - * Destroy plugins. - */ - ~plugin_service(); - - /** - * Get the list of plugins. - * - * \return the list of plugins - */ - inline const std::vector<std::shared_ptr<plugin>>& list() const noexcept - { - return plugins_; - } - - /** - * Check if a plugin is loaded. - * - * \param name the plugin id - * \return true if has plugin - */ - bool has(const std::string& name) const noexcept; - - /** - * Get a loaded plugin or null if not found. - * - * \param name the plugin id - * \return the plugin or empty one if not found - */ - std::shared_ptr<plugin> get(const std::string& name) const noexcept; - - /** - * Find a loaded plugin. - * - * \param name the plugin id - * \return the plugin - * \throws std::out_of_range if not found - */ - std::shared_ptr<plugin> require(const std::string& name) const; - - /** - * Add the specified plugin to the registry. - * - * \pre plugin != nullptr - * \param plugin the plugin - * \note the plugin is only added to the list, no action is performed on it - */ - void add(std::shared_ptr<plugin> plugin); - - /** - * Add a loader. - * - * \param loader the loader - */ - void add_loader(std::unique_ptr<plugin_loader> loader); - - /** - * Get the configuration for the specified plugin. - * - * \return the configuration - */ - plugin_config config(const std::string& id); - - /** - * Get the formats for the specified plugin. - * - * \return the formats - */ - plugin_formats formats(const std::string& id); - - /** - * Get the paths for the specified plugin. - * - * If none is defined, return the default ones. - * - * \return the paths - */ - plugin_paths paths(const std::string& id); - - /** - * 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 - */ - std::shared_ptr<plugin> open(const std::string& id, - const std::string& path); - - /** - * Generic function for finding a plugin. - * - * \param id the plugin id - * \return the plugin or nullptr on failures - */ - std::shared_ptr<plugin> find(const std::string& id); - - /** - * Convenient wrapper that loads a plugin, call onLoad and add it to the - * registry. - * - * Any errors are printed using logger. - * - * \param name the name - * \param path the optional path (searched if empty) - */ - void load(std::string name, std::string path = ""); - - /** - * Unload a plugin and remove it. - * - * \param name the plugin id - */ - void unload(const std::string& name); - - /** - * Reload a plugin by calling onReload. - * - * \param name the plugin name - * \throw std::exception on failures - */ - void reload(const std::string& name); - - /** - * 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 <typename Func, typename... Args> - void exec(std::shared_ptr<plugin> plugin, Func fn, Args&&... args) - { - assert(plugin); - - // TODO: replace with C++17 std::invoke. - try { - ((*plugin).*(fn))(std::forward<Args>(args)...); - } catch (const std::exception& ex) { - throw plugin_error(plugin_error::exec_error, plugin->name(), ex.what()); - } catch (...) { - throw plugin_error(plugin_error::exec_error, plugin->name()); - } - } - - /** - * Overloaded function. - * - * \param name the plugin name - * \param fn the plugin member function (pointer to member) - * \param args the arguments to pass - */ - template <typename Func, typename... Args> - void exec(const std::string& name, Func fn, Args&&... args) - { - auto plugin = find(name); - - if (!plugin) - throw plugin_error(plugin_error::not_found, plugin->name()); - - exec(plugin, fn, std::forward<Args>(args)...); - } - - /** - * Load all plugins. - * - * \param cfg the config - */ - void load(const class config& cfg) noexcept; -}; - -} // !irccd - -#endif // !IRCCD_DAEMON_PLUGIN_SERVICE_HPP
--- a/libirccd/irccd/daemon/plugin_unload_command.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd/irccd/daemon/plugin_unload_command.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -19,10 +19,11 @@ #include <irccd/json_util.hpp> #include "irccd.hpp" -#include "plugin_service.hpp" #include "plugin_unload_command.hpp" #include "transport_client.hpp" +#include <irccd/daemon/service/plugin_service.hpp> + namespace irccd { std::string plugin_unload_command::get_name() const noexcept
--- a/libirccd/irccd/daemon/rule_add_command.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd/irccd/daemon/rule_add_command.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -20,9 +20,10 @@ #include "irccd.hpp" #include "rule_add_command.hpp" -#include "rule_service.hpp" #include "transport_client.hpp" +#include <irccd/daemon/service/rule_service.hpp> + namespace irccd { std::string rule_add_command::get_name() const noexcept
--- a/libirccd/irccd/daemon/rule_edit_command.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd/irccd/daemon/rule_edit_command.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -18,9 +18,10 @@ #include "irccd.hpp" #include "rule_edit_command.hpp" -#include "rule_service.hpp" #include "transport_client.hpp" +#include <irccd/daemon/service/rule_service.hpp> + using namespace std::string_literals; namespace irccd {
--- a/libirccd/irccd/daemon/rule_info_command.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd/irccd/daemon/rule_info_command.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -18,9 +18,10 @@ #include "irccd.hpp" #include "rule_info_command.hpp" -#include "rule_service.hpp" #include "transport_client.hpp" +#include <irccd/daemon/service/rule_service.hpp> + namespace irccd { std::string rule_info_command::get_name() const noexcept
--- a/libirccd/irccd/daemon/rule_list_command.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd/irccd/daemon/rule_list_command.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -18,9 +18,10 @@ #include "irccd.hpp" #include "rule_list_command.hpp" -#include "rule_service.hpp" #include "transport_client.hpp" +#include <irccd/daemon/service/rule_service.hpp> + namespace irccd { std::string rule_list_command::get_name() const noexcept
--- a/libirccd/irccd/daemon/rule_move_command.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd/irccd/daemon/rule_move_command.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -18,9 +18,10 @@ #include "irccd.hpp" #include "rule_move_command.hpp" -#include "rule_service.hpp" #include "transport_client.hpp" +#include <irccd/daemon/service/rule_service.hpp> + namespace irccd { std::string rule_move_command::get_name() const noexcept
--- a/libirccd/irccd/daemon/rule_remove_command.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd/irccd/daemon/rule_remove_command.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -18,9 +18,10 @@ #include "irccd.hpp" #include "rule_remove_command.hpp" -#include "rule_service.hpp" #include "transport_client.hpp" +#include <irccd/daemon/service/rule_service.hpp> + namespace irccd { std::string rule_remove_command::get_name() const noexcept
--- a/libirccd/irccd/daemon/rule_service.cpp Mon Jan 15 13:37:32 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,240 +0,0 @@ -/* - * rule_service.cpp -- rule service - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * 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 <stdexcept> - -#include <irccd/config.hpp> -#include <irccd/string_util.hpp> - -#include "irccd.hpp" -#include "logger.hpp" -#include "rule_service.hpp" - -namespace irccd { - -namespace { - -rule load_rule(const ini::section& sc) -{ - assert(sc.key() == "rule"); - - // Simple converter from std::vector to std::unordered_set. - auto toset = [] (const auto& v) { - return std::unordered_set<std::string>(v.begin(), v.end()); - }; - - rule::set servers, channels, origins, plugins, events; - rule::action action = rule::action::accept; - - // Get the sets. - ini::section::const_iterator it; - - if ((it = sc.find("servers")) != sc.end()) - servers = toset(*it); - if ((it = sc.find("channels")) != sc.end()) - channels = toset(*it); - if ((it = sc.find("origins")) != sc.end()) - origins = toset(*it); - if ((it = sc.find("plugins")) != sc.end()) - plugins = toset(*it); - if ((it = sc.find("channels")) != sc.end()) - channels = toset(*it); - - // Get the action. - auto actionstr = sc.get("action").value(); - - if (actionstr == "drop") - action = rule::action::drop; - else if (actionstr == "accept") - action = rule::action::accept; - else - throw rule_error(rule_error::invalid_action); - - return { - std::move(servers), - std::move(channels), - std::move(origins), - std::move(plugins), - std::move(events), - action - }; -} - -} // !namespace - -rule rule_service::from_json(const nlohmann::json& json) -{ - auto toset = [] (auto object, auto name) { - rule::set result; - - for (const auto& s : object[name]) - if (s.is_string()) - result.insert(s.template get<std::string>()); - - return result; - }; - auto toaction = [] (auto object, auto name) { - auto v = object[name]; - - if (!v.is_string()) - throw rule_error(rule_error::invalid_action); - - auto s = v.template get<std::string>(); - if (s == "accept") - return rule::action::accept; - if (s == "drop") - return rule::action::drop; - - throw rule_error(rule_error::invalid_action); - }; - - return { - toset(json, "servers"), - toset(json, "channels"), - toset(json, "origins"), - toset(json, "plugins"), - toset(json, "events"), - toaction(json, "action") - }; -} - -unsigned rule_service::get_index(const nlohmann::json& json, const std::string& key) -{ - auto index = json.find(key); - - if (index == json.end() || !index->is_number_integer() || index->get<int>() < 0) - throw rule_error(rule_error::invalid_index); - - return index->get<int>(); -} - -nlohmann::json rule_service::to_json(const rule& rule) -{ - auto join = [] (const auto& set) { - auto array = nlohmann::json::array(); - - for (const auto& entry : set) - array.push_back(entry); - - return array; - }; - auto str = [] (auto action) { - switch (action) { - case rule::action::accept: - return "accept"; - default: - return "drop"; - } - }; - - return { - { "servers", join(rule.get_servers()) }, - { "channels", join(rule.get_channels()) }, - { "plugins", join(rule.get_plugins()) }, - { "events", join(rule.get_events()) }, - { "action", str(rule.get_action()) } - }; -} - -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(const std::string& server, - const std::string& channel, - const std::string& origin, - const std::string& plugin, - const std::string& event) noexcept -{ - bool result = true; - - irccd_.log().debug(string_util::sprintf("rule: solving for server=%s, channel=%s, origin=%s, plugin=%s, event=%s", - server, channel, origin, plugin, event)); - - int i = 0; - for (const auto& rule : rules_) { - auto action = rule.get_action() == rule::action::accept ? "accept" : "drop"; - - irccd_.log().debug() << " candidate " << i++ << ":\n" - << " servers: " << string_util::join(rule.get_servers()) << "\n" - << " channels: " << string_util::join(rule.get_channels()) << "\n" - << " origins: " << string_util::join(rule.get_origins()) << "\n" - << " plugins: " << string_util::join(rule.get_plugins()) << "\n" - << " events: " << string_util::join(rule.get_events()) << "\n" - << " 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.doc()) { - if (section.key() != "rule") - continue; - - try { - rules_.push_back(load_rule(section)); - } catch (const std::exception& ex) { - irccd_.log().warning() << "rule: " << ex.what() << std::endl; - } - } -} - -} // !irccd
--- a/libirccd/irccd/daemon/rule_service.hpp Mon Jan 15 13:37:32 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,169 +0,0 @@ -/* - * rule_service.hpp -- rule service - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * 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 <vector> - -#include <json.hpp> - -#include "rule.hpp" - -namespace irccd { - -class config; -class irccd; - -/** - * \brief Store and solve rules. - * \ingroup services - */ -class rule_service { -private: - irccd& irccd_; - std::vector<rule> rules_; - -public: - /** - * Load a rule from a JSON object. - * - * For possible use in transport commands or Javascript API. - * - * \pre json.is_object() - * \param json the JSON object - * \return the new rule - * \throw rule_error on errors - */ - static rule from_json(const nlohmann::json& json); - - /** - * Helper to get rule index in a JSON object. - * - * \pre json.is_object() - * \param json the JSON object - * \param key the index property - * \return the index - * \throw rule_error on errors - */ - static unsigned get_index(const nlohmann::json& json, const std::string& key = "index"); - - /** - * Convert a rule into a JSON object. - * - * \param rule the rule - * \throw the JSON representation - */ - static nlohmann::json to_json(const rule& rule); - - /** - * Create the rule service. - */ - rule_service(irccd& instance); - - /** - * Get the list of rules. - * - * \return the list of rules - */ - inline const std::vector<rule>& 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(const std::string& server, - const std::string& channel, - const std::string& origin, - const std::string& plugin, - const std::string& event) noexcept; - - /** - * Load rules from the configuration. - * - * \param cfg the config - */ - void load(const config& cfg) noexcept; -}; - -} // !irccd - -#endif // !IRCCD_DAEMON_RULE_SERVICE_HPP
--- a/libirccd/irccd/daemon/server_connect_command.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd/irccd/daemon/server_connect_command.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -18,9 +18,10 @@ #include "irccd.hpp" #include "server_connect_command.hpp" -#include "server_service.hpp" #include "transport_client.hpp" +#include <irccd/daemon/service/server_service.hpp> + namespace irccd { std::string server_connect_command::get_name() const noexcept
--- a/libirccd/irccd/daemon/server_disconnect_command.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd/irccd/daemon/server_disconnect_command.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -18,9 +18,10 @@ #include "irccd.hpp" #include "server_disconnect_command.hpp" -#include "server_service.hpp" #include "transport_client.hpp" +#include <irccd/daemon/service/server_service.hpp> + namespace irccd { std::string server_disconnect_command::get_name() const noexcept
--- a/libirccd/irccd/daemon/server_info_command.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd/irccd/daemon/server_info_command.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -18,9 +18,10 @@ #include "irccd.hpp" #include "server_info_command.hpp" -#include "server_service.hpp" #include "transport_client.hpp" +#include <irccd/daemon/service/server_service.hpp> + namespace irccd { std::string server_info_command::get_name() const noexcept
--- a/libirccd/irccd/daemon/server_invite_command.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd/irccd/daemon/server_invite_command.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -20,9 +20,10 @@ #include "irccd.hpp" #include "server_invite_command.hpp" -#include "server_service.hpp" #include "transport_client.hpp" +#include <irccd/daemon/service/server_service.hpp> + namespace irccd { std::string server_invite_command::get_name() const noexcept
--- a/libirccd/irccd/daemon/server_join_command.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd/irccd/daemon/server_join_command.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -20,9 +20,10 @@ #include "irccd.hpp" #include "server_join_command.hpp" -#include "server_service.hpp" #include "transport_client.hpp" +#include <irccd/daemon/service/server_service.hpp> + namespace irccd { std::string server_join_command::get_name() const noexcept
--- a/libirccd/irccd/daemon/server_kick_command.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd/irccd/daemon/server_kick_command.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -20,9 +20,10 @@ #include "irccd.hpp" #include "server_kick_command.hpp" -#include "server_service.hpp" #include "transport_client.hpp" +#include <irccd/daemon/service/server_service.hpp> + namespace irccd { std::string server_kick_command::get_name() const noexcept
--- a/libirccd/irccd/daemon/server_list_command.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd/irccd/daemon/server_list_command.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -18,9 +18,10 @@ #include "irccd.hpp" #include "server_list_command.hpp" -#include "server_service.hpp" #include "transport_client.hpp" +#include <irccd/daemon/service/server_service.hpp> + namespace irccd { std::string server_list_command::get_name() const noexcept
--- a/libirccd/irccd/daemon/server_me_command.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd/irccd/daemon/server_me_command.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -20,9 +20,10 @@ #include "irccd.hpp" #include "server_me_command.hpp" -#include "server_service.hpp" #include "transport_client.hpp" +#include <irccd/daemon/service/server_service.hpp> + namespace irccd { std::string server_me_command::get_name() const noexcept
--- a/libirccd/irccd/daemon/server_message_command.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd/irccd/daemon/server_message_command.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -20,9 +20,10 @@ #include "irccd.hpp" #include "server_message_command.hpp" -#include "server_service.hpp" #include "transport_client.hpp" +#include <irccd/daemon/service/server_service.hpp> + namespace irccd { std::string server_message_command::get_name() const noexcept
--- a/libirccd/irccd/daemon/server_mode_command.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd/irccd/daemon/server_mode_command.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -20,9 +20,10 @@ #include "irccd.hpp" #include "server_mode_command.hpp" -#include "server_service.hpp" #include "transport_client.hpp" +#include <irccd/daemon/service/server_service.hpp> + namespace irccd { std::string server_mode_command::get_name() const noexcept
--- a/libirccd/irccd/daemon/server_nick_command.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd/irccd/daemon/server_nick_command.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -20,9 +20,10 @@ #include "irccd.hpp" #include "server_nick_command.hpp" -#include "server_service.hpp" #include "transport_client.hpp" +#include <irccd/daemon/service/server_service.hpp> + namespace irccd { std::string server_nick_command::get_name() const noexcept
--- a/libirccd/irccd/daemon/server_notice_command.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd/irccd/daemon/server_notice_command.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -20,9 +20,10 @@ #include "irccd.hpp" #include "server_notice_command.hpp" -#include "server_service.hpp" #include "transport_client.hpp" +#include <irccd/daemon/service/server_service.hpp> + namespace irccd { std::string server_notice_command::get_name() const noexcept
--- a/libirccd/irccd/daemon/server_part_command.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd/irccd/daemon/server_part_command.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -20,9 +20,10 @@ #include "irccd.hpp" #include "server_part_command.hpp" -#include "server_service.hpp" #include "transport_client.hpp" +#include <irccd/daemon/service/server_service.hpp> + namespace irccd { std::string server_part_command::get_name() const noexcept
--- a/libirccd/irccd/daemon/server_reconnect_command.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd/irccd/daemon/server_reconnect_command.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -20,9 +20,10 @@ #include "irccd.hpp" #include "server_reconnect_command.hpp" -#include "server_service.hpp" #include "transport_client.hpp" +#include <irccd/daemon/service/server_service.hpp> + namespace irccd { std::string server_reconnect_command::get_name() const noexcept
--- a/libirccd/irccd/daemon/server_service.cpp Mon Jan 15 13:37:32 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,727 +0,0 @@ -/* - * server_service.hpp -- server service - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * 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 <irccd/json_util.hpp> -#include <irccd/string_util.hpp> - -#include "irccd.hpp" -#include "logger.hpp" -#include "plugin_service.hpp" -#include "rule_service.hpp" -#include "server_service.hpp" -#include "transport_service.hpp" - -namespace irccd { - -namespace { - -template <typename EventNameFunc, typename ExecFunc> -void dispatch(irccd& daemon, - const std::string& server, - const std::string& origin, - const std::string& target, - EventNameFunc&& name_func, - ExecFunc exec_func) -{ - for (auto& plugin : daemon.plugins().list()) { - auto eventname = name_func(*plugin); - auto allowed = daemon.rules().solve(server, target, origin, plugin->name(), eventname); - - if (!allowed) { - daemon.log().debug("rule: event skipped on match"); - continue; - } - - daemon.log().debug("rule: event allowed"); - - try { - exec_func(*plugin); - } catch (const std::exception& ex) { - daemon.log().warning() << "plugin " << plugin->name() << ": error: " - << ex.what() << std::endl; - } - } -} - -template <typename T> -T to_int(const std::string& value, const std::string& name, server_error::error errc) -{ - try { - return string_util::to_int<T>(value); - } catch (...) { - throw server_error(errc, name); - } -} - -template <typename T> -T to_uint(const std::string& value, const std::string& name, server_error::error errc) -{ - try { - return string_util::to_uint<T>(value); - } catch (...) { - throw server_error(errc, name); - } -} - -template <typename T> -T to_uint(const nlohmann::json& value, const std::string& name, server_error::error errc) -{ - if (!value.is_number()) - throw server_error(errc, name); - - auto n = value.get<unsigned>(); - - if (n > std::numeric_limits<T>::max()) - throw server_error(errc, name); - - return static_cast<T>(n); -} - -std::string to_id(const ini::section& sc) -{ - auto id = sc.get("name"); - - if (!string_util::is_identifier(id.value())) - throw server_error(server_error::invalid_identifier, ""); - - return id.value(); -} - -std::string to_id(const nlohmann::json& object) -{ - auto id = json_util::get_string(object, "name"); - - if (!string_util::is_identifier(id)) - throw server_error(server_error::invalid_identifier, ""); - - return id; -} - -std::string to_host(const ini::section& sc, const std::string& name) -{ - auto value = sc.get("host"); - - if (value.empty()) - throw server_error(server_error::invalid_hostname, name); - - return value.value(); -} - -std::string to_host(const nlohmann::json& object, const std::string& name) -{ - auto value = json_util::get_string(object, "host"); - - if (value.empty()) - throw server_error(server_error::invalid_hostname, name); - - return value; -} - -void load_server_identity(std::shared_ptr<server>& server, - const config& cfg, - const std::string& identity) -{ - auto sc = std::find_if(cfg.doc().begin(), cfg.doc().end(), [&] (const auto& sc) { - if (sc.key() != "identity") - return false; - - auto name = sc.find("name"); - - return name != sc.end() && name->value() == identity; - }); - - if (sc == cfg.doc().end()) - return; - - ini::section::const_iterator it; - - if ((it = sc->find("username")) != sc->end()) - server->set_username(it->value()); - if ((it = sc->find("realname")) != sc->end()) - server->set_realname(it->value()); - if ((it = sc->find("nickname")) != sc->end()) - server->set_nickname(it->value()); - if ((it = sc->find("ctcp-version")) != sc->end()) - server->set_ctcp_version(it->value()); -} - -std::shared_ptr<server> load_server(boost::asio::io_service& service, - const config& cfg, - const ini::section& sc) -{ - assert(sc.key() == "server"); - - auto sv = std::make_shared<server>(service, to_id(sc)); - - // Mandatory fields. - sv->set_host(to_host(sc, sv->name())); - - // Optional fields. - ini::section::const_iterator it; - - if ((it = sc.find("password")) != sc.end()) - sv->set_password(it->value()); - - // Optional flags - if ((it = sc.find("ipv6")) != sc.end() && string_util::is_boolean(it->value())) - sv->set_flags(sv->flags() | server::ipv6); - - if ((it = sc.find("ssl")) != sc.end() && string_util::is_boolean(it->value())) { -#if defined(HAVE_SSL) - sv->set_flags(sv->flags() | server::ssl); -#else - throw server_error(server_error::ssl_disabled, sv->name()); -#endif - } - - if ((it = sc.find("ssl-verify")) != sc.end() && string_util::is_boolean(it->value())) - sv->set_flags(sv->flags() | server::ssl_verify); - - // Optional identity - if ((it = sc.find("identity")) != sc.end()) - load_server_identity(sv, cfg, it->value()); - - // Options - if ((it = sc.find("auto-rejoin")) != sc.end() && string_util::is_boolean(it->value())) - sv->set_flags(sv->flags() | server::auto_rejoin); - if ((it = sc.find("join-invite")) != sc.end() && string_util::is_boolean(it->value())) - sv->set_flags(sv->flags() | server::join_invite); - - // Channels - if ((it = sc.find("channels")) != sc.end()) { - for (const auto& s : *it) { - channel channel; - - if (auto pos = s.find(":") != std::string::npos) { - channel.name = s.substr(0, pos); - channel.password = s.substr(pos + 1); - } else - channel.name = s; - - sv->join(channel.name, channel.password); - } - } - if ((it = sc.find("command-char")) != sc.end()) - sv->set_command_char(it->value()); - - // Reconnect and ping timeout - if ((it = sc.find("port")) != sc.end()) - sv->set_port(to_uint<std::uint16_t>(it->value(), - sv->name(), server_error::invalid_port)); - - if ((it = sc.find("reconnect-tries")) != sc.end()) - sv->set_reconnect_tries(to_int<std::int8_t>(it->value(), - sv->name(), server_error::invalid_reconnect_tries)); - - if ((it = sc.find("reconnect-timeout")) != sc.end()) - sv->set_reconnect_delay(to_uint<std::uint16_t>(it->value(), - sv->name(), server_error::invalid_reconnect_timeout)); - - if ((it = sc.find("ping-timeout")) != sc.end()) - sv->set_ping_timeout(to_uint<std::uint16_t>(it->value(), - sv->name(), server_error::invalid_ping_timeout)); - - return sv; -} - -} // !namespace - -void server_service::handle_connect(const connect_event& ev) -{ - irccd_.log().debug() << "server " << ev.server->name() << ": event onConnect" << std::endl; - - irccd_.transports().broadcast(nlohmann::json::object({ - { "event", "onConnect" }, - { "server", ev.server->name() } - })); - - dispatch(irccd_, ev.server->name(), /* origin */ "", /* channel */ "", - [=] (plugin&) -> std::string { - return "onConnect"; - }, - [=] (plugin& plugin) { - plugin.on_connect(irccd_, ev); - } - ); -} - -void server_service::handle_invite(const invite_event& ev) -{ - irccd_.log().debug() << "server " << ev.server->name() << ": event onInvite:\n"; - irccd_.log().debug() << " origin: " << ev.origin << "\n"; - irccd_.log().debug() << " channel: " << ev.channel << "\n"; - irccd_.log().debug() << " target: " << ev.nickname << std::endl; - - irccd_.transports().broadcast(nlohmann::json::object({ - { "event", "onInvite" }, - { "server", ev.server->name() }, - { "origin", ev.origin }, - { "channel", ev.channel } - })); - - dispatch(irccd_, ev.server->name(), ev.origin, ev.channel, - [=] (plugin&) -> std::string { - return "onInvite"; - }, - [=] (plugin& plugin) { - plugin.on_invite(irccd_, ev); - } - ); -} - -void server_service::handle_join(const join_event& ev) -{ - irccd_.log().debug() << "server " << ev.server->name() << ": event onJoin:\n"; - irccd_.log().debug() << " origin: " << ev.origin << "\n"; - irccd_.log().debug() << " channel: " << ev.channel << std::endl; - - irccd_.transports().broadcast(nlohmann::json::object({ - { "event", "onJoin" }, - { "server", ev.server->name() }, - { "origin", ev.origin }, - { "channel", ev.channel } - })); - - dispatch(irccd_, ev.server->name(), ev.origin, ev.channel, - [=] (plugin&) -> std::string { - return "onJoin"; - }, - [=] (plugin& plugin) { - plugin.on_join(irccd_, ev); - } - ); -} - -void server_service::handle_kick(const kick_event& ev) -{ - irccd_.log().debug() << "server " << ev.server->name() << ": event onKick:\n"; - irccd_.log().debug() << " origin: " << ev.origin << "\n"; - irccd_.log().debug() << " channel: " << ev.channel << "\n"; - irccd_.log().debug() << " target: " << ev.target << "\n"; - irccd_.log().debug() << " reason: " << ev.reason << std::endl; - - irccd_.transports().broadcast(nlohmann::json::object({ - { "event", "onKick" }, - { "server", ev.server->name() }, - { "origin", ev.origin }, - { "channel", ev.channel }, - { "target", ev.target }, - { "reason", ev.reason } - })); - - dispatch(irccd_, ev.server->name(), ev.origin, ev.channel, - [=] (plugin&) -> std::string { - return "onKick"; - }, - [=] (plugin& plugin) { - plugin.on_kick(irccd_, ev); - } - ); -} - -void server_service::handle_message(const message_event& ev) -{ - irccd_.log().debug() << "server " << ev.server->name() << ": event onMessage:\n"; - irccd_.log().debug() << " origin: " << ev.origin << "\n"; - irccd_.log().debug() << " channel: " << ev.channel << "\n"; - irccd_.log().debug() << " message: " << ev.message << std::endl; - - irccd_.transports().broadcast(nlohmann::json::object({ - { "event", "onMessage" }, - { "server", ev.server->name() }, - { "origin", ev.origin }, - { "channel", ev.channel }, - { "message", ev.message } - })); - - dispatch(irccd_, ev.server->name(), ev.origin, ev.channel, - [=] (plugin& plugin) -> std::string { - return string_util::parse_message( - ev.message, - ev.server->command_char(), - plugin.name() - ).type == string_util::message_pack::type::command ? "onCommand" : "onMessage"; - }, - [=] (plugin& plugin) mutable { - auto copy = ev; - auto pack = string_util::parse_message(copy.message, copy.server->command_char(), plugin.name()); - - copy.message = pack.message; - - if (pack.type == string_util::message_pack::type::command) - plugin.on_command(irccd_, copy); - else - plugin.on_message(irccd_, copy); - } - ); -} - -void server_service::handle_me(const me_event& ev) -{ - irccd_.log().debug() << "server " << ev.server->name() << ": event onMe:\n"; - irccd_.log().debug() << " origin: " << ev.origin << "\n"; - irccd_.log().debug() << " target: " << ev.channel << "\n"; - irccd_.log().debug() << " message: " << ev.message << std::endl; - - irccd_.transports().broadcast(nlohmann::json::object({ - { "event", "onMe" }, - { "server", ev.server->name() }, - { "origin", ev.origin }, - { "target", ev.channel }, - { "message", ev.message } - })); - - dispatch(irccd_, ev.server->name(), ev.origin, ev.channel, - [=] (plugin&) -> std::string { - return "onMe"; - }, - [=] (plugin& plugin) { - plugin.on_me(irccd_, ev); - } - ); -} - -void server_service::handle_mode(const mode_event& ev) -{ - irccd_.log().debug() << "server " << ev.server->name() << ": event onMode\n"; - irccd_.log().debug() << " origin: " << ev.origin << "\n"; - irccd_.log().debug() << " channel: " << ev.channel << "\n"; - irccd_.log().debug() << " mode: " << ev.mode << "\n"; - irccd_.log().debug() << " limit: " << ev.limit << "\n"; - irccd_.log().debug() << " user: " << ev.user << "\n"; - irccd_.log().debug() << " mask: " << ev.mask << std::endl; - - irccd_.transports().broadcast(nlohmann::json::object({ - { "event", "onMode" }, - { "server", ev.server->name() }, - { "origin", ev.origin }, - { "channel", ev.channel }, - { "mode", ev.mode }, - { "limit", ev.limit }, - { "user", ev.user }, - { "mask", ev.mask } - })); - - dispatch(irccd_, ev.server->name(), ev.origin, /* channel */ "", - [=] (plugin &) -> std::string { - return "onMode"; - }, - [=] (plugin &plugin) { - plugin.on_mode(irccd_, ev); - } - ); -} - -void server_service::handle_names(const names_event& ev) -{ - irccd_.log().debug() << "server " << ev.server->name() << ": event onNames:\n"; - irccd_.log().debug() << " channel: " << ev.channel << "\n"; - irccd_.log().debug() << " 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->name() }, - { "channel", ev.channel }, - { "names", std::move(names) } - })); - - dispatch(irccd_, ev.server->name(), /* origin */ "", ev.channel, - [=] (plugin&) -> std::string { - return "onNames"; - }, - [=] (plugin& plugin) { - plugin.on_names(irccd_, ev); - } - ); -} - -void server_service::handle_nick(const nick_event& ev) -{ - irccd_.log().debug() << "server " << ev.server->name() << ": event onNick:\n"; - irccd_.log().debug() << " origin: " << ev.origin << "\n"; - irccd_.log().debug() << " nickname: " << ev.nickname << std::endl; - - irccd_.transports().broadcast(nlohmann::json::object({ - { "event", "onNick" }, - { "server", ev.server->name() }, - { "origin", ev.origin }, - { "nickname", ev.nickname } - })); - - dispatch(irccd_, ev.server->name(), ev.origin, /* channel */ "", - [=] (plugin&) -> std::string { - return "onNick"; - }, - [=] (plugin& plugin) { - plugin.on_nick(irccd_, ev); - } - ); -} - -void server_service::handle_notice(const notice_event& ev) -{ - irccd_.log().debug() << "server " << ev.server->name() << ": event onNotice:\n"; - irccd_.log().debug() << " origin: " << ev.origin << "\n"; - irccd_.log().debug() << " channel: " << ev.channel << "\n"; - irccd_.log().debug() << " message: " << ev.message << std::endl; - - irccd_.transports().broadcast(nlohmann::json::object({ - { "event", "onNotice" }, - { "server", ev.server->name() }, - { "origin", ev.origin }, - { "channel", ev.channel }, - { "message", ev.message } - })); - - dispatch(irccd_, ev.server->name(), ev.origin, /* channel */ "", - [=] (plugin&) -> std::string { - return "onNotice"; - }, - [=] (plugin& plugin) { - plugin.on_notice(irccd_, ev); - } - ); -} - -void server_service::handle_part(const part_event& ev) -{ - irccd_.log().debug() << "server " << ev.server->name() << ": event onPart:\n"; - irccd_.log().debug() << " origin: " << ev.origin << "\n"; - irccd_.log().debug() << " channel: " << ev.channel << "\n"; - irccd_.log().debug() << " reason: " << ev.reason << std::endl; - - irccd_.transports().broadcast(nlohmann::json::object({ - { "event", "onPart" }, - { "server", ev.server->name() }, - { "origin", ev.origin }, - { "channel", ev.channel }, - { "reason", ev.reason } - })); - - dispatch(irccd_, ev.server->name(), ev.origin, ev.channel, - [=] (plugin&) -> std::string { - return "onPart"; - }, - [=] (plugin& plugin) { - plugin.on_part(irccd_, ev); - } - ); -} - -void server_service::handle_topic(const topic_event& ev) -{ - irccd_.log().debug() << "server " << ev.server->name() << ": event onTopic:\n"; - irccd_.log().debug() << " origin: " << ev.origin << "\n"; - irccd_.log().debug() << " channel: " << ev.channel << "\n"; - irccd_.log().debug() << " topic: " << ev.topic << std::endl; - - irccd_.transports().broadcast(nlohmann::json::object({ - { "event", "onTopic" }, - { "server", ev.server->name() }, - { "origin", ev.origin }, - { "channel", ev.channel }, - { "topic", ev.topic } - })); - - dispatch(irccd_, ev.server->name(), ev.origin, ev.channel, - [=] (plugin&) -> std::string { - return "onTopic"; - }, - [=] (plugin& plugin) { - plugin.on_topic(irccd_, ev); - } - ); -} - -void server_service::handle_whois(const whois_event& ev) -{ - irccd_.log().debug() << "server " << ev.server->name() << ": event onWhois\n"; - irccd_.log().debug() << " nickname: " << ev.whois.nick << "\n"; - irccd_.log().debug() << " username: " << ev.whois.user << "\n"; - irccd_.log().debug() << " host: " << ev.whois.host << "\n"; - irccd_.log().debug() << " realname: " << ev.whois.realname << "\n"; - irccd_.log().debug() << " channels: " << string_util::join(ev.whois.channels, ", ") << std::endl; - - irccd_.transports().broadcast(nlohmann::json::object({ - { "event", "onWhois" }, - { "server", ev.server->name() }, - { "nickname", ev.whois.nick }, - { "username", ev.whois.user }, - { "host", ev.whois.host }, - { "realname", ev.whois.realname } - })); - - dispatch(irccd_, ev.server->name(), /* origin */ "", /* channel */ "", - [=] (plugin&) -> std::string { - return "onWhois"; - }, - [=] (plugin& plugin) { - plugin.on_whois(irccd_, ev); - } - ); -} - -std::shared_ptr<server> server_service::from_json(boost::asio::io_service& service, const nlohmann::json& object) -{ - // TODO: move this function in server_service. - auto sv = std::make_shared<server>(service, to_id(object)); - - // Mandatory fields. - sv->set_host(to_host(object, sv->name())); - - // Optional fields. - if (object.count("port")) - sv->set_port(to_uint<std::uint16_t>(object["port"], sv->name(), server_error::invalid_port)); - sv->set_password(json_util::get_string(object, "password")); - sv->set_nickname(json_util::get_string(object, "nickname", sv->nickname())); - sv->set_realname(json_util::get_string(object, "realname", sv->realname())); - sv->set_username(json_util::get_string(object, "username", sv->username())); - sv->set_ctcp_version(json_util::get_string(object, "ctcpVersion", sv->ctcp_version())); - sv->set_command_char(json_util::get_string(object, "commandChar", sv->command_char())); - - if (json_util::get_bool(object, "ipv6")) - sv->set_flags(sv->flags() | server::ipv6); - if (json_util::get_bool(object, "sslVerify")) - sv->set_flags(sv->flags() | server::ssl_verify); - if (json_util::get_bool(object, "autoRejoin")) - sv->set_flags(sv->flags() | server::auto_rejoin); - if (json_util::get_bool(object, "joinInvite")) - sv->set_flags(sv->flags() | server::join_invite); - - if (json_util::get_bool(object, "ssl")) -#if defined(HAVE_SSL) - sv->set_flags(sv->flags() | server::ssl); -#else - throw server_error(server_error::ssl_disabled, sv->name()); -#endif - - return sv; -} - -server_service::server_service(irccd &irccd) - : irccd_(irccd) -{ -} - -bool server_service::has(const std::string& name) const noexcept -{ - return std::count_if(servers_.begin(), servers_.end(), [&] (const auto& server) { - return server->name() == name; - }) > 0; -} - -void server_service::add(std::shared_ptr<server> server) -{ - assert(!has(server->name())); - - std::weak_ptr<class server> ptr(server); - - server->on_connect.connect(boost::bind(&server_service::handle_connect, this, _1)); - server->on_invite.connect(boost::bind(&server_service::handle_invite, this, _1)); - server->on_join.connect(boost::bind(&server_service::handle_join, this, _1)); - server->on_kick.connect(boost::bind(&server_service::handle_kick, this, _1)); - server->on_message.connect(boost::bind(&server_service::handle_message, this, _1)); - server->on_me.connect(boost::bind(&server_service::handle_me, this, _1)); - server->on_mode.connect(boost::bind(&server_service::handle_mode, this, _1)); - server->on_names.connect(boost::bind(&server_service::handle_names, this, _1)); - server->on_nick.connect(boost::bind(&server_service::handle_nick, this, _1)); - server->on_notice.connect(boost::bind(&server_service::handle_notice, this, _1)); - server->on_part.connect(boost::bind(&server_service::handle_part, this, _1)); - server->on_topic.connect(boost::bind(&server_service::handle_topic, this, _1)); - server->on_whois.connect(boost::bind(&server_service::handle_whois, this, _1)); - server->on_die.connect([this, ptr] () { - auto server = ptr.lock(); - - if (server) { - irccd_.log().info(string_util::sprintf("server %s: removed", server->name())); - servers_.erase(std::find(servers_.begin(), servers_.end(), server)); - } - }); - - server->connect(); - servers_.push_back(std::move(server)); -} - -std::shared_ptr<server> server_service::get(const std::string& name) const noexcept -{ - auto it = std::find_if(servers_.begin(), servers_.end(), [&] (const auto& server) { - return server->name() == name; - }); - - if (it == servers_.end()) - return nullptr; - - return *it; -} - -std::shared_ptr<server> server_service::require(const nlohmann::json& args, const std::string& key) -{ - auto id = json_util::get_string(args, key); - - if (!string_util::is_identifier(id)) - throw server_error(server_error::invalid_identifier, ""); - - auto server = get(id); - - if (!server) - throw server_error(server_error::not_found, id); - - return server; -} - -void server_service::remove(const std::string& name) -{ - auto it = std::find_if(servers_.begin(), servers_.end(), [&] (const auto& server) { - return server->name() == name; - }); - - if (it != servers_.end()) { - (*it)->disconnect(); - servers_.erase(it); - } -} - -void server_service::clear() noexcept -{ - for (auto &server : servers_) - server->disconnect(); - - servers_.clear(); -} - -void server_service::load(const config& cfg) noexcept -{ - for (const auto& section : cfg.doc()) { - if (section.key() != "server") - continue; - - try { - add(load_server(irccd_.service(), cfg, section)); - } catch (const std::exception& ex) { - irccd_.log().warning() << "server " << section.get("name").value() << ": " - << ex.what() << std::endl; - } - } -} - -} // !irccd
--- a/libirccd/irccd/daemon/server_service.hpp Mon Jan 15 13:37:32 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,149 +0,0 @@ -/* - * server_service.hpp -- server service - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * 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 <memory> -#include <vector> - -#include "server.hpp" - -namespace irccd { - -class config; -class irccd; - -/** - * \brief Manage IRC servers. - * \ingroup services - */ -class server_service { -private: - irccd& irccd_; - std::vector<std::shared_ptr<server>> servers_; - - void handle_connect(const connect_event&); - void handle_invite(const invite_event&); - void handle_join(const join_event&); - void handle_kick(const kick_event&); - void handle_message(const message_event&); - void handle_me(const me_event&); - void handle_mode(const mode_event&); - void handle_names(const names_event&); - void handle_nick(const nick_event&); - void handle_notice(const notice_event&); - void handle_part(const part_event&); - void handle_query(const query_event&); - void handle_topic(const topic_event&); - void handle_whois(const whois_event&); - -public: - /** - * Convert a JSON object as a server. - * - * Used in JavaScript API and transport commands. - * - * \param service the io service - * \param object the object - * \return the server - * \throw std::exception on failures - */ - static std::shared_ptr<server> from_json(boost::asio::io_service& service, const nlohmann::json& object); - - /** - * Create the server service. - */ - server_service(irccd& instance); - - /** - * Get the list of servers - * - * \return the servers - */ - inline const std::vector<std::shared_ptr<server>>& servers() const noexcept - { - return servers_; - } - - /** - * Check if a server exists. - * - * \param name the name - * \return true if exists - */ - bool has(const std::string& name) const noexcept; - - /** - * Add a new server to the application. - * - * \pre hasServer must return false - * \param sv the server - */ - void add(std::shared_ptr<server> sv); - - /** - * Get a server or empty one if not found - * - * \param name the server name - * \return the server or empty one if not found - */ - std::shared_ptr<server> get(const std::string& name) const noexcept; - - /** - * Find a server from a JSON object. - * - * \pre json.is_object() - * \param json the JSON object - * \param key the server identifier property - * \throw server_error on errors - */ - std::shared_ptr<server> require(const nlohmann::json& json, const std::string& key = "server"); - - /** - * Remove a server from the irccd instance. - * - * The server if any, will be disconnected. - * - * \param name the server name - */ - void remove(const std::string& 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; -}; - -} // !irccd - -#endif // !IRCCD_DAEMON_SERVER_SERVICE_HPP
--- a/libirccd/irccd/daemon/server_topic_command.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/libirccd/irccd/daemon/server_topic_command.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -19,10 +19,11 @@ #include <irccd/json_util.hpp> #include "irccd.hpp" -#include "server_service.hpp" #include "server_topic_command.hpp" #include "transport_client.hpp" +#include <irccd/daemon/service/server_service.hpp> + namespace irccd { std::string server_topic_command::get_name() const noexcept
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd/irccd/daemon/service/plugin_service.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -0,0 +1,232 @@ +/* + * plugin_service.cpp -- plugin service + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * 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 <irccd/config.hpp> +#include <irccd/string_util.hpp> +#include <irccd/system.hpp> + +#include <irccd/daemon/irccd.hpp> +#include <irccd/daemon/logger.hpp> + +#include <irccd/daemon/service/plugin_service.hpp> + +namespace irccd { + +namespace { + +template <typename Map> +Map to_map(const config& conf, const std::string& section) +{ + Map ret; + + for (const auto& opt : conf.doc().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& plugin : plugins_) { + try { + plugin->on_unload(irccd_); + } catch (const std::exception& ex) { + irccd_.log().warning() << "plugin: " << plugin->name() << ": " << ex.what() << std::endl; + } + } +} + +bool plugin_service::has(const std::string& name) const noexcept +{ + return std::count_if(plugins_.cbegin(), plugins_.cend(), [&] (const auto& plugin) { + return plugin->name() == name; + }) > 0; +} + +std::shared_ptr<plugin> plugin_service::get(const std::string& name) const noexcept +{ + auto it = std::find_if(plugins_.begin(), plugins_.end(), [&] (const auto& plugin) { + return plugin->name() == name; + }); + + if (it == plugins_.end()) + return nullptr; + + return *it; +} + +std::shared_ptr<plugin> plugin_service::require(const std::string& name) const +{ + auto plugin = get(name); + + if (!plugin) + throw plugin_error(plugin_error::not_found, name); + + return plugin; +} + +void plugin_service::add(std::shared_ptr<plugin> plugin) +{ + plugins_.push_back(std::move(plugin)); +} + +void plugin_service::add_loader(std::unique_ptr<plugin_loader> loader) +{ + loaders_.push_back(std::move(loader)); +} + +plugin_config plugin_service::config(const std::string& id) +{ + return to_map<plugin_config>(irccd_.config(), string_util::sprintf("plugin.%s", id)); +} + +plugin_formats plugin_service::formats(const std::string& id) +{ + return to_map<plugin_formats>(irccd_.config(), string_util::sprintf("format.%s", id)); +} + +plugin_paths plugin_service::paths(const std::string& id) +{ + auto defaults = to_map<plugin_paths>(irccd_.config(), "paths"); + auto paths = to_map<plugin_paths>(irccd_.config(), string_util::sprintf("paths.%s", id)); + + // Fill defaults paths. + if (!defaults.count("cache")) + defaults.emplace("cache", sys::cachedir() + "/plugin/" + id); + if (!defaults.count("data")) + paths.emplace("data", sys::datadir() + "/plugin/" + id); + if (!defaults.count("config")) + paths.emplace("config", sys::sysconfigdir() + "/plugin/" + id); + + // Now fill missing fields. + if (!paths.count("cache")) + paths.emplace("cache", defaults["cache"]); + if (!paths.count("data")) + paths.emplace("data", defaults["data"]); + if (!paths.count("config")) + paths.emplace("config", defaults["config"]); + + return paths; +} + +std::shared_ptr<plugin> plugin_service::open(const std::string& id, + const std::string& path) +{ + for (const auto& loader : loaders_) { + auto plugin = loader->open(id, path); + + if (plugin) + return plugin; + } + + return nullptr; +} + +std::shared_ptr<plugin> plugin_service::find(const std::string& id) +{ + for (const auto& loader : loaders_) { + auto plugin = loader->find(id); + + if (plugin) + return plugin; + } + + return nullptr; +} + +void plugin_service::load(std::string name, std::string path) +{ + if (has(name)) + throw plugin_error(plugin_error::already_exists, name); + + std::shared_ptr<plugin> plugin; + + if (path.empty()) + plugin = find(name); + else + plugin = open(name, std::move(path)); + + if (!plugin) + throw plugin_error(plugin_error::not_found, name); + + plugin->set_config(config(name)); + plugin->set_formats(formats(name)); + plugin->set_paths(paths(name)); + + exec(plugin, &plugin::on_load, irccd_); + add(std::move(plugin)); +} + +void plugin_service::reload(const std::string& name) +{ + auto plugin = get(name); + + if (!plugin) + throw plugin_error(plugin_error::not_found, name); + + exec(plugin, &plugin::on_reload, irccd_); +} + +void plugin_service::unload(const std::string& name) +{ + auto it = std::find_if(plugins_.begin(), plugins_.end(), [&] (const auto& plugin) { + return plugin->name() == name; + }); + + if (it == plugins_.end()) + throw plugin_error(plugin_error::not_found, name); + + // Erase first, in case of throwing. + auto save = *it; + + plugins_.erase(it); + exec(save, &plugin::on_unload, irccd_); +} + +void plugin_service::load(const class config& cfg) noexcept +{ + for (const auto& option : cfg.section("plugins")) { + if (!string_util::is_identifier(option.key())) + continue; + + auto name = option.key(); + auto p = get(name); + + // Reload the plugin if already loaded. + if (p) { + p->set_config(config(name)); + p->set_formats(formats(name)); + p->set_paths(paths(name)); + } else { + try { + load(name, option.value()); + } catch (const std::exception& ex) { + irccd_.log().warning(ex.what()); + } + } + } +} + +} // !irccd
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd/irccd/daemon/service/plugin_service.hpp Wed Mar 07 17:49:56 2018 +0100 @@ -0,0 +1,237 @@ +/* + * plugin_service.hpp -- plugin service + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * 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 <cassert> +#include <memory> +#include <string> +#include <vector> + +#include <irccd/daemon/plugin.hpp> + +namespace irccd { + +class irccd; +class config; + +/** + * \brief Manage plugins. + * \ingroup services + */ +class plugin_service { +private: + irccd& irccd_; + std::vector<std::shared_ptr<plugin>> plugins_; + std::vector<std::unique_ptr<plugin_loader>> loaders_; + +public: + /** + * Create the plugin service. + * + * \param irccd the irccd instance + */ + plugin_service(irccd& irccd) noexcept; + + /** + * Destroy plugins. + */ + ~plugin_service(); + + /** + * Get the list of plugins. + * + * \return the list of plugins + */ + inline const std::vector<std::shared_ptr<plugin>>& list() const noexcept + { + return plugins_; + } + + /** + * Check if a plugin is loaded. + * + * \param name the plugin id + * \return true if has plugin + */ + bool has(const std::string& name) const noexcept; + + /** + * Get a loaded plugin or null if not found. + * + * \param name the plugin id + * \return the plugin or empty one if not found + */ + std::shared_ptr<plugin> get(const std::string& name) const noexcept; + + /** + * Find a loaded plugin. + * + * \param name the plugin id + * \return the plugin + * \throws std::out_of_range if not found + */ + std::shared_ptr<plugin> require(const std::string& name) const; + + /** + * Add the specified plugin to the registry. + * + * \pre plugin != nullptr + * \param plugin the plugin + * \note the plugin is only added to the list, no action is performed on it + */ + void add(std::shared_ptr<plugin> plugin); + + /** + * Add a loader. + * + * \param loader the loader + */ + void add_loader(std::unique_ptr<plugin_loader> loader); + + /** + * Get the configuration for the specified plugin. + * + * \return the configuration + */ + plugin_config config(const std::string& id); + + /** + * Get the formats for the specified plugin. + * + * \return the formats + */ + plugin_formats formats(const std::string& id); + + /** + * Get the paths for the specified plugin. + * + * If none is defined, return the default ones. + * + * \return the paths + */ + plugin_paths paths(const std::string& id); + + /** + * 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 + */ + std::shared_ptr<plugin> open(const std::string& id, + const std::string& path); + + /** + * Generic function for finding a plugin. + * + * \param id the plugin id + * \return the plugin or nullptr on failures + */ + std::shared_ptr<plugin> find(const std::string& id); + + /** + * Convenient wrapper that loads a plugin, call onLoad and add it to the + * registry. + * + * Any errors are printed using logger. + * + * \param name the name + * \param path the optional path (searched if empty) + */ + void load(std::string name, std::string path = ""); + + /** + * Unload a plugin and remove it. + * + * \param name the plugin id + */ + void unload(const std::string& name); + + /** + * Reload a plugin by calling onReload. + * + * \param name the plugin name + * \throw std::exception on failures + */ + void reload(const std::string& name); + + /** + * 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 <typename Func, typename... Args> + void exec(std::shared_ptr<plugin> plugin, Func fn, Args&&... args) + { + assert(plugin); + + // TODO: replace with C++17 std::invoke. + try { + ((*plugin).*(fn))(std::forward<Args>(args)...); + } catch (const std::exception& ex) { + throw plugin_error(plugin_error::exec_error, plugin->name(), ex.what()); + } catch (...) { + throw plugin_error(plugin_error::exec_error, plugin->name()); + } + } + + /** + * Overloaded function. + * + * \param name the plugin name + * \param fn the plugin member function (pointer to member) + * \param args the arguments to pass + */ + template <typename Func, typename... Args> + void exec(const std::string& name, Func fn, Args&&... args) + { + auto plugin = find(name); + + if (!plugin) + throw plugin_error(plugin_error::not_found, plugin->name()); + + exec(plugin, fn, std::forward<Args>(args)...); + } + + /** + * Load all plugins. + * + * \param cfg the config + */ + void load(const class config& cfg) noexcept; +}; + +} // !irccd + +#endif // !IRCCD_DAEMON_PLUGIN_SERVICE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd/irccd/daemon/service/rule_service.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -0,0 +1,241 @@ +/* + * rule_service.cpp -- rule service + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * 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 <stdexcept> + +#include <irccd/config.hpp> +#include <irccd/string_util.hpp> + +#include <irccd/daemon/irccd.hpp> +#include <irccd/daemon/logger.hpp> + +#include <irccd/daemon/service/rule_service.hpp> + +namespace irccd { + +namespace { + +rule load_rule(const ini::section& sc) +{ + assert(sc.key() == "rule"); + + // Simple converter from std::vector to std::unordered_set. + auto toset = [] (const auto& v) { + return std::unordered_set<std::string>(v.begin(), v.end()); + }; + + rule::set servers, channels, origins, plugins, events; + rule::action action = rule::action::accept; + + // Get the sets. + ini::section::const_iterator it; + + if ((it = sc.find("servers")) != sc.end()) + servers = toset(*it); + if ((it = sc.find("channels")) != sc.end()) + channels = toset(*it); + if ((it = sc.find("origins")) != sc.end()) + origins = toset(*it); + if ((it = sc.find("plugins")) != sc.end()) + plugins = toset(*it); + if ((it = sc.find("channels")) != sc.end()) + channels = toset(*it); + + // Get the action. + auto actionstr = sc.get("action").value(); + + if (actionstr == "drop") + action = rule::action::drop; + else if (actionstr == "accept") + action = rule::action::accept; + else + throw rule_error(rule_error::invalid_action); + + return { + std::move(servers), + std::move(channels), + std::move(origins), + std::move(plugins), + std::move(events), + action + }; +} + +} // !namespace + +rule rule_service::from_json(const nlohmann::json& json) +{ + auto toset = [] (auto object, auto name) { + rule::set result; + + for (const auto& s : object[name]) + if (s.is_string()) + result.insert(s.template get<std::string>()); + + return result; + }; + auto toaction = [] (auto object, auto name) { + auto v = object[name]; + + if (!v.is_string()) + throw rule_error(rule_error::invalid_action); + + auto s = v.template get<std::string>(); + if (s == "accept") + return rule::action::accept; + if (s == "drop") + return rule::action::drop; + + throw rule_error(rule_error::invalid_action); + }; + + return { + toset(json, "servers"), + toset(json, "channels"), + toset(json, "origins"), + toset(json, "plugins"), + toset(json, "events"), + toaction(json, "action") + }; +} + +unsigned rule_service::get_index(const nlohmann::json& json, const std::string& key) +{ + auto index = json.find(key); + + if (index == json.end() || !index->is_number_integer() || index->get<int>() < 0) + throw rule_error(rule_error::invalid_index); + + return index->get<int>(); +} + +nlohmann::json rule_service::to_json(const rule& rule) +{ + auto join = [] (const auto& set) { + auto array = nlohmann::json::array(); + + for (const auto& entry : set) + array.push_back(entry); + + return array; + }; + auto str = [] (auto action) { + switch (action) { + case rule::action::accept: + return "accept"; + default: + return "drop"; + } + }; + + return { + { "servers", join(rule.get_servers()) }, + { "channels", join(rule.get_channels()) }, + { "plugins", join(rule.get_plugins()) }, + { "events", join(rule.get_events()) }, + { "action", str(rule.get_action()) } + }; +} + +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(const std::string& server, + const std::string& channel, + const std::string& origin, + const std::string& plugin, + const std::string& event) noexcept +{ + bool result = true; + + irccd_.log().debug(string_util::sprintf("rule: solving for server=%s, channel=%s, origin=%s, plugin=%s, event=%s", + server, channel, origin, plugin, event)); + + int i = 0; + for (const auto& rule : rules_) { + auto action = rule.get_action() == rule::action::accept ? "accept" : "drop"; + + irccd_.log().debug() << " candidate " << i++ << ":\n" + << " servers: " << string_util::join(rule.get_servers()) << "\n" + << " channels: " << string_util::join(rule.get_channels()) << "\n" + << " origins: " << string_util::join(rule.get_origins()) << "\n" + << " plugins: " << string_util::join(rule.get_plugins()) << "\n" + << " events: " << string_util::join(rule.get_events()) << "\n" + << " 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.doc()) { + if (section.key() != "rule") + continue; + + try { + rules_.push_back(load_rule(section)); + } catch (const std::exception& ex) { + irccd_.log().warning() << "rule: " << ex.what() << std::endl; + } + } +} + +} // !irccd
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd/irccd/daemon/service/rule_service.hpp Wed Mar 07 17:49:56 2018 +0100 @@ -0,0 +1,169 @@ +/* + * rule_service.hpp -- rule service + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * 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 <vector> + +#include <json.hpp> + +#include <irccd/daemon/rule.hpp> + +namespace irccd { + +class config; +class irccd; + +/** + * \brief Store and solve rules. + * \ingroup services + */ +class rule_service { +private: + irccd& irccd_; + std::vector<rule> rules_; + +public: + /** + * Load a rule from a JSON object. + * + * For possible use in transport commands or Javascript API. + * + * \pre json.is_object() + * \param json the JSON object + * \return the new rule + * \throw rule_error on errors + */ + static rule from_json(const nlohmann::json& json); + + /** + * Helper to get rule index in a JSON object. + * + * \pre json.is_object() + * \param json the JSON object + * \param key the index property + * \return the index + * \throw rule_error on errors + */ + static unsigned get_index(const nlohmann::json& json, const std::string& key = "index"); + + /** + * Convert a rule into a JSON object. + * + * \param rule the rule + * \throw the JSON representation + */ + static nlohmann::json to_json(const rule& rule); + + /** + * Create the rule service. + */ + rule_service(irccd& instance); + + /** + * Get the list of rules. + * + * \return the list of rules + */ + inline const std::vector<rule>& 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(const std::string& server, + const std::string& channel, + const std::string& origin, + const std::string& plugin, + const std::string& event) noexcept; + + /** + * Load rules from the configuration. + * + * \param cfg the config + */ + void load(const config& cfg) noexcept; +}; + +} // !irccd + +#endif // !IRCCD_DAEMON_RULE_SERVICE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd/irccd/daemon/service/server_service.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -0,0 +1,728 @@ +/* + * server_service.hpp -- server service + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * 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 <irccd/json_util.hpp> +#include <irccd/string_util.hpp> + +#include <irccd/daemon/irccd.hpp> +#include <irccd/daemon/logger.hpp> + +#include <irccd/daemon/service/plugin_service.hpp> +#include <irccd/daemon/service/rule_service.hpp> +#include <irccd/daemon/service/server_service.hpp> +#include <irccd/daemon/service/transport_service.hpp> + +namespace irccd { + +namespace { + +template <typename EventNameFunc, typename ExecFunc> +void dispatch(irccd& daemon, + const std::string& server, + const std::string& origin, + const std::string& target, + EventNameFunc&& name_func, + ExecFunc exec_func) +{ + for (auto& plugin : daemon.plugins().list()) { + auto eventname = name_func(*plugin); + auto allowed = daemon.rules().solve(server, target, origin, plugin->name(), eventname); + + if (!allowed) { + daemon.log().debug("rule: event skipped on match"); + continue; + } + + daemon.log().debug("rule: event allowed"); + + try { + exec_func(*plugin); + } catch (const std::exception& ex) { + daemon.log().warning() << "plugin " << plugin->name() << ": error: " + << ex.what() << std::endl; + } + } +} + +template <typename T> +T to_int(const std::string& value, const std::string& name, server_error::error errc) +{ + try { + return string_util::to_int<T>(value); + } catch (...) { + throw server_error(errc, name); + } +} + +template <typename T> +T to_uint(const std::string& value, const std::string& name, server_error::error errc) +{ + try { + return string_util::to_uint<T>(value); + } catch (...) { + throw server_error(errc, name); + } +} + +template <typename T> +T to_uint(const nlohmann::json& value, const std::string& name, server_error::error errc) +{ + if (!value.is_number()) + throw server_error(errc, name); + + auto n = value.get<unsigned>(); + + if (n > std::numeric_limits<T>::max()) + throw server_error(errc, name); + + return static_cast<T>(n); +} + +std::string to_id(const ini::section& sc) +{ + auto id = sc.get("name"); + + if (!string_util::is_identifier(id.value())) + throw server_error(server_error::invalid_identifier, ""); + + return id.value(); +} + +std::string to_id(const nlohmann::json& object) +{ + auto id = json_util::get_string(object, "name"); + + if (!string_util::is_identifier(id)) + throw server_error(server_error::invalid_identifier, ""); + + return id; +} + +std::string to_host(const ini::section& sc, const std::string& name) +{ + auto value = sc.get("host"); + + if (value.empty()) + throw server_error(server_error::invalid_hostname, name); + + return value.value(); +} + +std::string to_host(const nlohmann::json& object, const std::string& name) +{ + auto value = json_util::get_string(object, "host"); + + if (value.empty()) + throw server_error(server_error::invalid_hostname, name); + + return value; +} + +void load_server_identity(std::shared_ptr<server>& server, + const config& cfg, + const std::string& identity) +{ + auto sc = std::find_if(cfg.doc().begin(), cfg.doc().end(), [&] (const auto& sc) { + if (sc.key() != "identity") + return false; + + auto name = sc.find("name"); + + return name != sc.end() && name->value() == identity; + }); + + if (sc == cfg.doc().end()) + return; + + ini::section::const_iterator it; + + if ((it = sc->find("username")) != sc->end()) + server->set_username(it->value()); + if ((it = sc->find("realname")) != sc->end()) + server->set_realname(it->value()); + if ((it = sc->find("nickname")) != sc->end()) + server->set_nickname(it->value()); + if ((it = sc->find("ctcp-version")) != sc->end()) + server->set_ctcp_version(it->value()); +} + +std::shared_ptr<server> load_server(boost::asio::io_service& service, + const config& cfg, + const ini::section& sc) +{ + assert(sc.key() == "server"); + + auto sv = std::make_shared<server>(service, to_id(sc)); + + // Mandatory fields. + sv->set_host(to_host(sc, sv->name())); + + // Optional fields. + ini::section::const_iterator it; + + if ((it = sc.find("password")) != sc.end()) + sv->set_password(it->value()); + + // Optional flags + if ((it = sc.find("ipv6")) != sc.end() && string_util::is_boolean(it->value())) + sv->set_flags(sv->flags() | server::ipv6); + + if ((it = sc.find("ssl")) != sc.end() && string_util::is_boolean(it->value())) { +#if defined(HAVE_SSL) + sv->set_flags(sv->flags() | server::ssl); +#else + throw server_error(server_error::ssl_disabled, sv->name()); +#endif + } + + if ((it = sc.find("ssl-verify")) != sc.end() && string_util::is_boolean(it->value())) + sv->set_flags(sv->flags() | server::ssl_verify); + + // Optional identity + if ((it = sc.find("identity")) != sc.end()) + load_server_identity(sv, cfg, it->value()); + + // Options + if ((it = sc.find("auto-rejoin")) != sc.end() && string_util::is_boolean(it->value())) + sv->set_flags(sv->flags() | server::auto_rejoin); + if ((it = sc.find("join-invite")) != sc.end() && string_util::is_boolean(it->value())) + sv->set_flags(sv->flags() | server::join_invite); + + // Channels + if ((it = sc.find("channels")) != sc.end()) { + for (const auto& s : *it) { + channel channel; + + if (auto pos = s.find(":") != std::string::npos) { + channel.name = s.substr(0, pos); + channel.password = s.substr(pos + 1); + } else + channel.name = s; + + sv->join(channel.name, channel.password); + } + } + if ((it = sc.find("command-char")) != sc.end()) + sv->set_command_char(it->value()); + + // Reconnect and ping timeout + if ((it = sc.find("port")) != sc.end()) + sv->set_port(to_uint<std::uint16_t>(it->value(), + sv->name(), server_error::invalid_port)); + + if ((it = sc.find("reconnect-tries")) != sc.end()) + sv->set_reconnect_tries(to_int<std::int8_t>(it->value(), + sv->name(), server_error::invalid_reconnect_tries)); + + if ((it = sc.find("reconnect-timeout")) != sc.end()) + sv->set_reconnect_delay(to_uint<std::uint16_t>(it->value(), + sv->name(), server_error::invalid_reconnect_timeout)); + + if ((it = sc.find("ping-timeout")) != sc.end()) + sv->set_ping_timeout(to_uint<std::uint16_t>(it->value(), + sv->name(), server_error::invalid_ping_timeout)); + + return sv; +} + +} // !namespace + +void server_service::handle_connect(const connect_event& ev) +{ + irccd_.log().debug() << "server " << ev.server->name() << ": event onConnect" << std::endl; + + irccd_.transports().broadcast(nlohmann::json::object({ + { "event", "onConnect" }, + { "server", ev.server->name() } + })); + + dispatch(irccd_, ev.server->name(), /* origin */ "", /* channel */ "", + [=] (plugin&) -> std::string { + return "onConnect"; + }, + [=] (plugin& plugin) { + plugin.on_connect(irccd_, ev); + } + ); +} + +void server_service::handle_invite(const invite_event& ev) +{ + irccd_.log().debug() << "server " << ev.server->name() << ": event onInvite:\n"; + irccd_.log().debug() << " origin: " << ev.origin << "\n"; + irccd_.log().debug() << " channel: " << ev.channel << "\n"; + irccd_.log().debug() << " target: " << ev.nickname << std::endl; + + irccd_.transports().broadcast(nlohmann::json::object({ + { "event", "onInvite" }, + { "server", ev.server->name() }, + { "origin", ev.origin }, + { "channel", ev.channel } + })); + + dispatch(irccd_, ev.server->name(), ev.origin, ev.channel, + [=] (plugin&) -> std::string { + return "onInvite"; + }, + [=] (plugin& plugin) { + plugin.on_invite(irccd_, ev); + } + ); +} + +void server_service::handle_join(const join_event& ev) +{ + irccd_.log().debug() << "server " << ev.server->name() << ": event onJoin:\n"; + irccd_.log().debug() << " origin: " << ev.origin << "\n"; + irccd_.log().debug() << " channel: " << ev.channel << std::endl; + + irccd_.transports().broadcast(nlohmann::json::object({ + { "event", "onJoin" }, + { "server", ev.server->name() }, + { "origin", ev.origin }, + { "channel", ev.channel } + })); + + dispatch(irccd_, ev.server->name(), ev.origin, ev.channel, + [=] (plugin&) -> std::string { + return "onJoin"; + }, + [=] (plugin& plugin) { + plugin.on_join(irccd_, ev); + } + ); +} + +void server_service::handle_kick(const kick_event& ev) +{ + irccd_.log().debug() << "server " << ev.server->name() << ": event onKick:\n"; + irccd_.log().debug() << " origin: " << ev.origin << "\n"; + irccd_.log().debug() << " channel: " << ev.channel << "\n"; + irccd_.log().debug() << " target: " << ev.target << "\n"; + irccd_.log().debug() << " reason: " << ev.reason << std::endl; + + irccd_.transports().broadcast(nlohmann::json::object({ + { "event", "onKick" }, + { "server", ev.server->name() }, + { "origin", ev.origin }, + { "channel", ev.channel }, + { "target", ev.target }, + { "reason", ev.reason } + })); + + dispatch(irccd_, ev.server->name(), ev.origin, ev.channel, + [=] (plugin&) -> std::string { + return "onKick"; + }, + [=] (plugin& plugin) { + plugin.on_kick(irccd_, ev); + } + ); +} + +void server_service::handle_message(const message_event& ev) +{ + irccd_.log().debug() << "server " << ev.server->name() << ": event onMessage:\n"; + irccd_.log().debug() << " origin: " << ev.origin << "\n"; + irccd_.log().debug() << " channel: " << ev.channel << "\n"; + irccd_.log().debug() << " message: " << ev.message << std::endl; + + irccd_.transports().broadcast(nlohmann::json::object({ + { "event", "onMessage" }, + { "server", ev.server->name() }, + { "origin", ev.origin }, + { "channel", ev.channel }, + { "message", ev.message } + })); + + dispatch(irccd_, ev.server->name(), ev.origin, ev.channel, + [=] (plugin& plugin) -> std::string { + return string_util::parse_message( + ev.message, + ev.server->command_char(), + plugin.name() + ).type == string_util::message_pack::type::command ? "onCommand" : "onMessage"; + }, + [=] (plugin& plugin) mutable { + auto copy = ev; + auto pack = string_util::parse_message(copy.message, copy.server->command_char(), plugin.name()); + + copy.message = pack.message; + + if (pack.type == string_util::message_pack::type::command) + plugin.on_command(irccd_, copy); + else + plugin.on_message(irccd_, copy); + } + ); +} + +void server_service::handle_me(const me_event& ev) +{ + irccd_.log().debug() << "server " << ev.server->name() << ": event onMe:\n"; + irccd_.log().debug() << " origin: " << ev.origin << "\n"; + irccd_.log().debug() << " target: " << ev.channel << "\n"; + irccd_.log().debug() << " message: " << ev.message << std::endl; + + irccd_.transports().broadcast(nlohmann::json::object({ + { "event", "onMe" }, + { "server", ev.server->name() }, + { "origin", ev.origin }, + { "target", ev.channel }, + { "message", ev.message } + })); + + dispatch(irccd_, ev.server->name(), ev.origin, ev.channel, + [=] (plugin&) -> std::string { + return "onMe"; + }, + [=] (plugin& plugin) { + plugin.on_me(irccd_, ev); + } + ); +} + +void server_service::handle_mode(const mode_event& ev) +{ + irccd_.log().debug() << "server " << ev.server->name() << ": event onMode\n"; + irccd_.log().debug() << " origin: " << ev.origin << "\n"; + irccd_.log().debug() << " channel: " << ev.channel << "\n"; + irccd_.log().debug() << " mode: " << ev.mode << "\n"; + irccd_.log().debug() << " limit: " << ev.limit << "\n"; + irccd_.log().debug() << " user: " << ev.user << "\n"; + irccd_.log().debug() << " mask: " << ev.mask << std::endl; + + irccd_.transports().broadcast(nlohmann::json::object({ + { "event", "onMode" }, + { "server", ev.server->name() }, + { "origin", ev.origin }, + { "channel", ev.channel }, + { "mode", ev.mode }, + { "limit", ev.limit }, + { "user", ev.user }, + { "mask", ev.mask } + })); + + dispatch(irccd_, ev.server->name(), ev.origin, /* channel */ "", + [=] (plugin &) -> std::string { + return "onMode"; + }, + [=] (plugin &plugin) { + plugin.on_mode(irccd_, ev); + } + ); +} + +void server_service::handle_names(const names_event& ev) +{ + irccd_.log().debug() << "server " << ev.server->name() << ": event onNames:\n"; + irccd_.log().debug() << " channel: " << ev.channel << "\n"; + irccd_.log().debug() << " 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->name() }, + { "channel", ev.channel }, + { "names", std::move(names) } + })); + + dispatch(irccd_, ev.server->name(), /* origin */ "", ev.channel, + [=] (plugin&) -> std::string { + return "onNames"; + }, + [=] (plugin& plugin) { + plugin.on_names(irccd_, ev); + } + ); +} + +void server_service::handle_nick(const nick_event& ev) +{ + irccd_.log().debug() << "server " << ev.server->name() << ": event onNick:\n"; + irccd_.log().debug() << " origin: " << ev.origin << "\n"; + irccd_.log().debug() << " nickname: " << ev.nickname << std::endl; + + irccd_.transports().broadcast(nlohmann::json::object({ + { "event", "onNick" }, + { "server", ev.server->name() }, + { "origin", ev.origin }, + { "nickname", ev.nickname } + })); + + dispatch(irccd_, ev.server->name(), ev.origin, /* channel */ "", + [=] (plugin&) -> std::string { + return "onNick"; + }, + [=] (plugin& plugin) { + plugin.on_nick(irccd_, ev); + } + ); +} + +void server_service::handle_notice(const notice_event& ev) +{ + irccd_.log().debug() << "server " << ev.server->name() << ": event onNotice:\n"; + irccd_.log().debug() << " origin: " << ev.origin << "\n"; + irccd_.log().debug() << " channel: " << ev.channel << "\n"; + irccd_.log().debug() << " message: " << ev.message << std::endl; + + irccd_.transports().broadcast(nlohmann::json::object({ + { "event", "onNotice" }, + { "server", ev.server->name() }, + { "origin", ev.origin }, + { "channel", ev.channel }, + { "message", ev.message } + })); + + dispatch(irccd_, ev.server->name(), ev.origin, /* channel */ "", + [=] (plugin&) -> std::string { + return "onNotice"; + }, + [=] (plugin& plugin) { + plugin.on_notice(irccd_, ev); + } + ); +} + +void server_service::handle_part(const part_event& ev) +{ + irccd_.log().debug() << "server " << ev.server->name() << ": event onPart:\n"; + irccd_.log().debug() << " origin: " << ev.origin << "\n"; + irccd_.log().debug() << " channel: " << ev.channel << "\n"; + irccd_.log().debug() << " reason: " << ev.reason << std::endl; + + irccd_.transports().broadcast(nlohmann::json::object({ + { "event", "onPart" }, + { "server", ev.server->name() }, + { "origin", ev.origin }, + { "channel", ev.channel }, + { "reason", ev.reason } + })); + + dispatch(irccd_, ev.server->name(), ev.origin, ev.channel, + [=] (plugin&) -> std::string { + return "onPart"; + }, + [=] (plugin& plugin) { + plugin.on_part(irccd_, ev); + } + ); +} + +void server_service::handle_topic(const topic_event& ev) +{ + irccd_.log().debug() << "server " << ev.server->name() << ": event onTopic:\n"; + irccd_.log().debug() << " origin: " << ev.origin << "\n"; + irccd_.log().debug() << " channel: " << ev.channel << "\n"; + irccd_.log().debug() << " topic: " << ev.topic << std::endl; + + irccd_.transports().broadcast(nlohmann::json::object({ + { "event", "onTopic" }, + { "server", ev.server->name() }, + { "origin", ev.origin }, + { "channel", ev.channel }, + { "topic", ev.topic } + })); + + dispatch(irccd_, ev.server->name(), ev.origin, ev.channel, + [=] (plugin&) -> std::string { + return "onTopic"; + }, + [=] (plugin& plugin) { + plugin.on_topic(irccd_, ev); + } + ); +} + +void server_service::handle_whois(const whois_event& ev) +{ + irccd_.log().debug() << "server " << ev.server->name() << ": event onWhois\n"; + irccd_.log().debug() << " nickname: " << ev.whois.nick << "\n"; + irccd_.log().debug() << " username: " << ev.whois.user << "\n"; + irccd_.log().debug() << " host: " << ev.whois.host << "\n"; + irccd_.log().debug() << " realname: " << ev.whois.realname << "\n"; + irccd_.log().debug() << " channels: " << string_util::join(ev.whois.channels, ", ") << std::endl; + + irccd_.transports().broadcast(nlohmann::json::object({ + { "event", "onWhois" }, + { "server", ev.server->name() }, + { "nickname", ev.whois.nick }, + { "username", ev.whois.user }, + { "host", ev.whois.host }, + { "realname", ev.whois.realname } + })); + + dispatch(irccd_, ev.server->name(), /* origin */ "", /* channel */ "", + [=] (plugin&) -> std::string { + return "onWhois"; + }, + [=] (plugin& plugin) { + plugin.on_whois(irccd_, ev); + } + ); +} + +std::shared_ptr<server> server_service::from_json(boost::asio::io_service& service, const nlohmann::json& object) +{ + // TODO: move this function in server_service. + auto sv = std::make_shared<server>(service, to_id(object)); + + // Mandatory fields. + sv->set_host(to_host(object, sv->name())); + + // Optional fields. + if (object.count("port")) + sv->set_port(to_uint<std::uint16_t>(object["port"], sv->name(), server_error::invalid_port)); + sv->set_password(json_util::get_string(object, "password")); + sv->set_nickname(json_util::get_string(object, "nickname", sv->nickname())); + sv->set_realname(json_util::get_string(object, "realname", sv->realname())); + sv->set_username(json_util::get_string(object, "username", sv->username())); + sv->set_ctcp_version(json_util::get_string(object, "ctcpVersion", sv->ctcp_version())); + sv->set_command_char(json_util::get_string(object, "commandChar", sv->command_char())); + + if (json_util::get_bool(object, "ipv6")) + sv->set_flags(sv->flags() | server::ipv6); + if (json_util::get_bool(object, "sslVerify")) + sv->set_flags(sv->flags() | server::ssl_verify); + if (json_util::get_bool(object, "autoRejoin")) + sv->set_flags(sv->flags() | server::auto_rejoin); + if (json_util::get_bool(object, "joinInvite")) + sv->set_flags(sv->flags() | server::join_invite); + + if (json_util::get_bool(object, "ssl")) +#if defined(HAVE_SSL) + sv->set_flags(sv->flags() | server::ssl); +#else + throw server_error(server_error::ssl_disabled, sv->name()); +#endif + + return sv; +} + +server_service::server_service(irccd &irccd) + : irccd_(irccd) +{ +} + +bool server_service::has(const std::string& name) const noexcept +{ + return std::count_if(servers_.begin(), servers_.end(), [&] (const auto& server) { + return server->name() == name; + }) > 0; +} + +void server_service::add(std::shared_ptr<server> server) +{ + assert(!has(server->name())); + + std::weak_ptr<class server> ptr(server); + + server->on_connect.connect(boost::bind(&server_service::handle_connect, this, _1)); + server->on_invite.connect(boost::bind(&server_service::handle_invite, this, _1)); + server->on_join.connect(boost::bind(&server_service::handle_join, this, _1)); + server->on_kick.connect(boost::bind(&server_service::handle_kick, this, _1)); + server->on_message.connect(boost::bind(&server_service::handle_message, this, _1)); + server->on_me.connect(boost::bind(&server_service::handle_me, this, _1)); + server->on_mode.connect(boost::bind(&server_service::handle_mode, this, _1)); + server->on_names.connect(boost::bind(&server_service::handle_names, this, _1)); + server->on_nick.connect(boost::bind(&server_service::handle_nick, this, _1)); + server->on_notice.connect(boost::bind(&server_service::handle_notice, this, _1)); + server->on_part.connect(boost::bind(&server_service::handle_part, this, _1)); + server->on_topic.connect(boost::bind(&server_service::handle_topic, this, _1)); + server->on_whois.connect(boost::bind(&server_service::handle_whois, this, _1)); + server->on_die.connect([this, ptr] () { + auto server = ptr.lock(); + + if (server) { + irccd_.log().info(string_util::sprintf("server %s: removed", server->name())); + servers_.erase(std::find(servers_.begin(), servers_.end(), server)); + } + }); + + server->connect(); + servers_.push_back(std::move(server)); +} + +std::shared_ptr<server> server_service::get(const std::string& name) const noexcept +{ + auto it = std::find_if(servers_.begin(), servers_.end(), [&] (const auto& server) { + return server->name() == name; + }); + + if (it == servers_.end()) + return nullptr; + + return *it; +} + +std::shared_ptr<server> server_service::require(const nlohmann::json& args, const std::string& key) +{ + auto id = json_util::get_string(args, key); + + if (!string_util::is_identifier(id)) + throw server_error(server_error::invalid_identifier, ""); + + auto server = get(id); + + if (!server) + throw server_error(server_error::not_found, id); + + return server; +} + +void server_service::remove(const std::string& name) +{ + auto it = std::find_if(servers_.begin(), servers_.end(), [&] (const auto& server) { + return server->name() == name; + }); + + if (it != servers_.end()) { + (*it)->disconnect(); + servers_.erase(it); + } +} + +void server_service::clear() noexcept +{ + for (auto &server : servers_) + server->disconnect(); + + servers_.clear(); +} + +void server_service::load(const config& cfg) noexcept +{ + for (const auto& section : cfg.doc()) { + if (section.key() != "server") + continue; + + try { + add(load_server(irccd_.service(), cfg, section)); + } catch (const std::exception& ex) { + irccd_.log().warning() << "server " << section.get("name").value() << ": " + << ex.what() << std::endl; + } + } +} + +} // !irccd
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd/irccd/daemon/service/server_service.hpp Wed Mar 07 17:49:56 2018 +0100 @@ -0,0 +1,149 @@ +/* + * server_service.hpp -- server service + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * 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 <memory> +#include <vector> + +#include <irccd/daemon/server.hpp> + +namespace irccd { + +class config; +class irccd; + +/** + * \brief Manage IRC servers. + * \ingroup services + */ +class server_service { +private: + irccd& irccd_; + std::vector<std::shared_ptr<server>> servers_; + + void handle_connect(const connect_event&); + void handle_invite(const invite_event&); + void handle_join(const join_event&); + void handle_kick(const kick_event&); + void handle_message(const message_event&); + void handle_me(const me_event&); + void handle_mode(const mode_event&); + void handle_names(const names_event&); + void handle_nick(const nick_event&); + void handle_notice(const notice_event&); + void handle_part(const part_event&); + void handle_query(const query_event&); + void handle_topic(const topic_event&); + void handle_whois(const whois_event&); + +public: + /** + * Convert a JSON object as a server. + * + * Used in JavaScript API and transport commands. + * + * \param service the io service + * \param object the object + * \return the server + * \throw std::exception on failures + */ + static std::shared_ptr<server> from_json(boost::asio::io_service& service, const nlohmann::json& object); + + /** + * Create the server service. + */ + server_service(irccd& instance); + + /** + * Get the list of servers + * + * \return the servers + */ + inline const std::vector<std::shared_ptr<server>>& servers() const noexcept + { + return servers_; + } + + /** + * Check if a server exists. + * + * \param name the name + * \return true if exists + */ + bool has(const std::string& name) const noexcept; + + /** + * Add a new server to the application. + * + * \pre hasServer must return false + * \param sv the server + */ + void add(std::shared_ptr<server> sv); + + /** + * Get a server or empty one if not found + * + * \param name the server name + * \return the server or empty one if not found + */ + std::shared_ptr<server> get(const std::string& name) const noexcept; + + /** + * Find a server from a JSON object. + * + * \pre json.is_object() + * \param json the JSON object + * \param key the server identifier property + * \throw server_error on errors + */ + std::shared_ptr<server> require(const nlohmann::json& json, const std::string& key = "server"); + + /** + * Remove a server from the irccd instance. + * + * The server if any, will be disconnected. + * + * \param name the server name + */ + void remove(const std::string& 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; +}; + +} // !irccd + +#endif // !IRCCD_DAEMON_SERVER_SERVICE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd/irccd/daemon/service/transport_service.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -0,0 +1,284 @@ +/* + * transport_service.cpp -- transport service + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * 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 <irccd/sysconfig.hpp> + +#include <cassert> + +#include <irccd/string_util.hpp> + +#include <irccd/daemon/command.hpp> +#include <irccd/daemon/ip_transport_server.hpp> +#include <irccd/daemon/irccd.hpp> +#include <irccd/daemon/logger.hpp> +#include <irccd/daemon/transport_client.hpp> + +#include <irccd/daemon/service/transport_service.hpp> + +#if !defined(IRCCD_SYSTEM_WINDOWS) +# include <irccd/daemon/local_transport_server.hpp> +#endif + +#if defined(HAVE_SSL) +# include <irccd/daemon/tls_transport_server.hpp> +#endif + +namespace irccd { + +namespace { + +std::unique_ptr<transport_server> load_transport_ip(boost::asio::io_service& service, const ini::section& sc) +{ + assert(sc.key() == "transport"); + + std::unique_ptr<transport_server> transport; + ini::section::const_iterator it; + + // Port. + if ((it = sc.find("port")) == sc.cend()) + throw std::invalid_argument("missing 'port' parameter"); + + auto port = string_util::to_uint<std::uint16_t>(it->value()); + + // Address. + std::string address = "*"; + + if ((it = sc.find("address")) != sc.end()) + address = it->value(); + + // 0011 + // ^ define IPv4 + // ^ define IPv6 + auto mode = 1U; + + /* + * Documentation stated family but code checked for 'domain' option. + * + * As irccdctl uses domain, accept both and unify the option name to 'family'. + * + * See #637 + */ + if ((it = sc.find("domain")) != sc.end() || (it = sc.find("family")) != sc.end()) { + mode = 0U; + + for (const auto& v : *it) { + if (v == "ipv4") + mode |= (1U << 0); + if (v == "ipv6") + mode |= (1U << 1); + } + } + + if (mode == 0U) + throw std::invalid_argument("family must at least have ipv4 or ipv6"); + + auto protocol = (mode & 0x2U) + ? boost::asio::ip::tcp::v4() + : boost::asio::ip::tcp::v6(); + + // Optional SSL. + std::string pkey; + std::string cert; + + if ((it = sc.find("ssl")) != sc.end() && string_util::is_boolean(it->value())) { + if ((it = sc.find("certificate")) == sc.end()) + throw std::invalid_argument("missing 'certificate' parameter"); + + cert = it->value(); + + if ((it = sc.find("key")) == sc.end()) + throw std::invalid_argument("missing 'key' parameter"); + + pkey = it->value(); + } + + auto endpoint = (address == "*") + ? boost::asio::ip::tcp::endpoint(protocol, port) + : boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port); + + boost::asio::ip::tcp::acceptor acceptor(service, endpoint, true); + + if (pkey.empty()) + return std::make_unique<ip_transport_server>(std::move(acceptor)); + +#if defined(HAVE_SSL) + boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23); + + ctx.use_private_key_file(pkey, boost::asio::ssl::context::pem); + ctx.use_certificate_file(cert, boost::asio::ssl::context::pem); + + return std::make_unique<tls_transport_server>(std::move(acceptor), std::move(ctx)); +#else + throw std::invalid_argument("SSL disabled"); +#endif +} + +std::unique_ptr<transport_server> load_transport_unix(boost::asio::io_service& service, const ini::section& sc) +{ + using boost::asio::local::stream_protocol; + + assert(sc.key() == "transport"); + +#if !defined(IRCCD_SYSTEM_WINDOWS) + ini::section::const_iterator it = sc.find("path"); + + if (it == sc.end()) + throw std::invalid_argument("missing 'path' parameter"); + + // Remove the file first. + std::remove(it->value().c_str()); + + stream_protocol::endpoint endpoint(it->value()); + stream_protocol::acceptor acceptor(service, std::move(endpoint)); + + return std::make_unique<local_transport_server>(std::move(acceptor)); +#else + (void)sc; + + throw std::invalid_argument("unix transports not supported on on this platform"); +#endif +} + +std::unique_ptr<transport_server> load_transport(boost::asio::io_service& service, const ini::section& sc) +{ + assert(sc.key() == "transport"); + + std::unique_ptr<transport_server> transport; + ini::section::const_iterator it = sc.find("type"); + + if (it == sc.end()) + throw std::invalid_argument("missing 'type' parameter"); + + if (it->value() == "ip") + transport = load_transport_ip(service, sc); + else if (it->value() == "unix") + transport = load_transport_unix(service, sc); + else + throw std::invalid_argument(string_util::sprintf("invalid type given: %s", it->value())); + + if ((it = sc.find("password")) != sc.end()) + transport->set_password(it->value()); + + return transport; +} + +} // !namespace + +void transport_service::handle_command(std::shared_ptr<transport_client> tc, const nlohmann::json& object) +{ + assert(object.is_object()); + + auto name = object.find("command"); + + if (name == object.end() || !name->is_string()) { + tc->error(irccd_error::invalid_message); + return; + } + + auto cmd = std::find_if(commands_.begin(), commands_.end(), [&] (const auto& cptr) { + return cptr->get_name() == name->template get<std::string>(); + }); + + if (cmd == commands_.end()) + tc->error(irccd_error::invalid_command, name->get<std::string>()); + else { + try { + (*cmd)->exec(irccd_, *tc, object); + } catch (const boost::system::system_error& ex) { + tc->error(ex.code(), (*cmd)->get_name()); + } catch (const std::exception& ex) { + irccd_.log().warning() << "transport: unknown error not reported" << std::endl; + irccd_.log().warning() << "transport: " << ex.what() << std::endl; + } + } +} + +void transport_service::do_recv(std::shared_ptr<transport_client> tc) +{ + tc->recv([this, tc] (auto code, auto json) { + switch (code.value()) { + case boost::system::errc::network_down: + irccd_.log().warning("transport: client disconnected"); + break; + case boost::system::errc::invalid_argument: + tc->error(irccd_error::invalid_message); + break; + default: + handle_command(tc, json); + + if (tc->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) + irccd_.log().warning() << "transport: new client error: " << code.message() << std::endl; + else { + do_accept(ts); + do_recv(std::move(client)); + + irccd_.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::unique_ptr<transport_server> 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->clients()) + client->send(json); +} + +void transport_service::load(const config& cfg) noexcept +{ + for (const auto& section : cfg.doc()) { + if (section.key() != "transport") + continue; + + try { + add(load_transport(irccd_.service(), section)); + } catch (const std::exception& ex) { + irccd_.log().warning() << "transport: " << ex.what() << std::endl; + } + } +} + +} // !irccd
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd/irccd/daemon/service/transport_service.hpp Wed Mar 07 17:49:56 2018 +0100 @@ -0,0 +1,111 @@ +/* + * transport_service.hpp -- transport service + * + * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> + * + * 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 <memory> +#include <vector> + +#include <json.hpp> + +#include <irccd/daemon/transport_client.hpp> +#include <irccd/daemon/transport_server.hpp> + +namespace irccd { + +class command; +class config; + +/** + * \brief manage transport servers and clients. + * \ingroup services + */ +class transport_service { +public: + using commands_t = std::vector<std::unique_ptr<command>>; + using servers_t = std::vector<std::unique_ptr<transport_server>>; + +private: + irccd& irccd_; + commands_t commands_; + servers_t servers_; + + void handle_command(std::shared_ptr<transport_client>, const nlohmann::json&); + void do_recv(std::shared_ptr<transport_client>); + 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::unique_ptr<transport_server> 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
--- a/libirccd/irccd/daemon/transport_service.cpp Mon Jan 15 13:37:32 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,281 +0,0 @@ -/* - * transport_service.cpp -- transport service - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * 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 <irccd/sysconfig.hpp> - -#include <cassert> - -#include <irccd/string_util.hpp> - -#include "command_service.hpp" -#include "ip_transport_server.hpp" -#include "irccd.hpp" -#include "logger.hpp" -#include "transport_client.hpp" -#include "transport_service.hpp" - -#if !defined(IRCCD_SYSTEM_WINDOWS) -# include "local_transport_server.hpp" -#endif - -#if defined(HAVE_SSL) -# include "tls_transport_server.hpp" -#endif - -namespace irccd { - -namespace { - -std::unique_ptr<transport_server> load_transport_ip(boost::asio::io_service& service, const ini::section& sc) -{ - assert(sc.key() == "transport"); - - std::unique_ptr<transport_server> transport; - ini::section::const_iterator it; - - // Port. - if ((it = sc.find("port")) == sc.cend()) - throw std::invalid_argument("missing 'port' parameter"); - - auto port = string_util::to_uint<std::uint16_t>(it->value()); - - // Address. - std::string address = "*"; - - if ((it = sc.find("address")) != sc.end()) - address = it->value(); - - // 0011 - // ^ define IPv4 - // ^ define IPv6 - auto mode = 1U; - - /* - * Documentation stated family but code checked for 'domain' option. - * - * As irccdctl uses domain, accept both and unify the option name to 'family'. - * - * See #637 - */ - if ((it = sc.find("domain")) != sc.end() || (it = sc.find("family")) != sc.end()) { - mode = 0U; - - for (const auto& v : *it) { - if (v == "ipv4") - mode |= (1U << 0); - if (v == "ipv6") - mode |= (1U << 1); - } - } - - if (mode == 0U) - throw std::invalid_argument("family must at least have ipv4 or ipv6"); - - auto protocol = (mode & 0x2U) - ? boost::asio::ip::tcp::v4() - : boost::asio::ip::tcp::v6(); - - // Optional SSL. - std::string pkey; - std::string cert; - - if ((it = sc.find("ssl")) != sc.end() && string_util::is_boolean(it->value())) { - if ((it = sc.find("certificate")) == sc.end()) - throw std::invalid_argument("missing 'certificate' parameter"); - - cert = it->value(); - - if ((it = sc.find("key")) == sc.end()) - throw std::invalid_argument("missing 'key' parameter"); - - pkey = it->value(); - } - - auto endpoint = (address == "*") - ? boost::asio::ip::tcp::endpoint(protocol, port) - : boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port); - - boost::asio::ip::tcp::acceptor acceptor(service, endpoint, true); - - if (pkey.empty()) - return std::make_unique<ip_transport_server>(std::move(acceptor)); - -#if defined(HAVE_SSL) - boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23); - - ctx.use_private_key_file(pkey, boost::asio::ssl::context::pem); - ctx.use_certificate_file(cert, boost::asio::ssl::context::pem); - - return std::make_unique<tls_transport_server>(std::move(acceptor), std::move(ctx)); -#else - throw std::invalid_argument("SSL disabled"); -#endif -} - -std::unique_ptr<transport_server> load_transport_unix(boost::asio::io_service& service, const ini::section& sc) -{ - using boost::asio::local::stream_protocol; - - assert(sc.key() == "transport"); - -#if !defined(IRCCD_SYSTEM_WINDOWS) - ini::section::const_iterator it = sc.find("path"); - - if (it == sc.end()) - throw std::invalid_argument("missing 'path' parameter"); - - // Remove the file first. - std::remove(it->value().c_str()); - - stream_protocol::endpoint endpoint(it->value()); - stream_protocol::acceptor acceptor(service, std::move(endpoint)); - - return std::make_unique<local_transport_server>(std::move(acceptor)); -#else - (void)sc; - - throw std::invalid_argument("unix transports not supported on on this platform"); -#endif -} - -std::unique_ptr<transport_server> load_transport(boost::asio::io_service& service, const ini::section& sc) -{ - assert(sc.key() == "transport"); - - std::unique_ptr<transport_server> transport; - ini::section::const_iterator it = sc.find("type"); - - if (it == sc.end()) - throw std::invalid_argument("missing 'type' parameter"); - - if (it->value() == "ip") - transport = load_transport_ip(service, sc); - else if (it->value() == "unix") - transport = load_transport_unix(service, sc); - else - throw std::invalid_argument(string_util::sprintf("invalid type given: %s", it->value())); - - if ((it = sc.find("password")) != sc.end()) - transport->set_password(it->value()); - - return transport; -} - -} // !namespace - -void transport_service::handle_command(std::shared_ptr<transport_client> tc, const nlohmann::json& object) -{ - assert(object.is_object()); - - auto name = object.find("command"); - - if (name == object.end() || !name->is_string()) { - tc->error(irccd_error::invalid_message); - return; - } - - auto cmd = irccd_.commands().find(*name); - - if (!cmd) - tc->error(irccd_error::invalid_command, name->get<std::string>()); - else { - try { - cmd->exec(irccd_, *tc, object); - } catch (const boost::system::system_error& ex) { - tc->error(ex.code(), cmd->get_name()); - } catch (const std::exception& ex) { - irccd_.log().warning() << "transport: unknown error not reported" << std::endl; - irccd_.log().warning() << "transport: " << ex.what() << std::endl; - } - } -} - -void transport_service::do_recv(std::shared_ptr<transport_client> tc) -{ - tc->recv([this, tc] (auto code, auto json) { - switch (code.value()) { - case boost::system::errc::network_down: - irccd_.log().warning("transport: client disconnected"); - break; - case boost::system::errc::invalid_argument: - tc->error(irccd_error::invalid_message); - break; - default: - handle_command(tc, json); - - if (tc->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) - irccd_.log().warning() << "transport: new client error: " << code.message() << std::endl; - else { - do_accept(ts); - do_recv(std::move(client)); - - irccd_.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::unique_ptr<transport_server> 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->clients()) - client->send(json); -} - -void transport_service::load(const config& cfg) noexcept -{ - for (const auto& section : cfg.doc()) { - if (section.key() != "transport") - continue; - - try { - add(load_transport(irccd_.service(), section)); - } catch (const std::exception& ex) { - irccd_.log().warning() << "transport: " << ex.what() << std::endl; - } - } -} - -} // !irccd
--- a/libirccd/irccd/daemon/transport_service.hpp Mon Jan 15 13:37:32 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -/* - * transport_service.hpp -- transport service - * - * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> - * - * 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 <memory> -#include <vector> - -#include <json.hpp> - -#include "transport_client.hpp" -#include "transport_server.hpp" - -namespace irccd { - -class config; - -/** - * \brief manage transport servers and clients. - * \ingroup services - */ -class transport_service { -public: - using servers_t = std::vector<std::unique_ptr<transport_server>>; - -private: - irccd& irccd_; - servers_t servers_; - - void handle_command(std::shared_ptr<transport_client>, const nlohmann::json&); - void do_recv(std::shared_ptr<transport_client>); - 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; - - /** - * Add a transport server. - * - * \param ts the transport server - */ - void add(std::unique_ptr<transport_server> 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
--- a/tests/src/libirccd-js/js-plugin/main.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/tests/src/libirccd-js/js-plugin/main.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -21,7 +21,7 @@ #include <boost/test/unit_test.hpp> #include <irccd/daemon/irccd.hpp> -#include <irccd/daemon/plugin_service.hpp> +#include <irccd/daemon/service/plugin_service.hpp> #include <irccd/js/irccd_jsapi.hpp> #include <irccd/js/js_plugin.hpp>
--- a/tests/src/libirccd/command-plugin-config/main.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/tests/src/libirccd/command-plugin-config/main.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -20,7 +20,7 @@ #include <boost/test/unit_test.hpp> #include <irccd/daemon/plugin_config_command.hpp> -#include <irccd/daemon/plugin_service.hpp> +#include <irccd/daemon/service/plugin_service.hpp> #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-plugin-info/main.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/tests/src/libirccd/command-plugin-info/main.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -20,7 +20,7 @@ #include <boost/test/unit_test.hpp> #include <irccd/daemon/plugin_info_command.hpp> -#include <irccd/daemon/plugin_service.hpp> +#include <irccd/daemon/service/plugin_service.hpp> #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-plugin-list/main.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/tests/src/libirccd/command-plugin-list/main.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -20,7 +20,7 @@ #include <boost/test/unit_test.hpp> #include <irccd/daemon/plugin_list_command.hpp> -#include <irccd/daemon/plugin_service.hpp> +#include <irccd/daemon/service/plugin_service.hpp> #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-plugin-load/main.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/tests/src/libirccd/command-plugin-load/main.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -20,7 +20,7 @@ #include <boost/test/unit_test.hpp> #include <irccd/daemon/plugin_load_command.hpp> -#include <irccd/daemon/plugin_service.hpp> +#include <irccd/daemon/service/plugin_service.hpp> #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-plugin-reload/main.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/tests/src/libirccd/command-plugin-reload/main.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -20,7 +20,7 @@ #include <boost/test/unit_test.hpp> #include <irccd/daemon/plugin_reload_command.hpp> -#include <irccd/daemon/plugin_service.hpp> +#include <irccd/daemon/service/plugin_service.hpp> #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-plugin-unload/main.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/tests/src/libirccd/command-plugin-unload/main.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -19,8 +19,8 @@ #define BOOST_TEST_MODULE "plugin-unload" #include <boost/test/unit_test.hpp> -#include <irccd/daemon/plugin_service.hpp> #include <irccd/daemon/plugin_unload_command.hpp> +#include <irccd/daemon/service/plugin_service.hpp> #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-rule-add/main.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/tests/src/libirccd/command-rule-add/main.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -23,7 +23,7 @@ #include <irccd/daemon/rule_add_command.hpp> #include <irccd/daemon/rule_list_command.hpp> -#include <irccd/daemon/rule_service.hpp> +#include <irccd/daemon/service/rule_service.hpp> #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-rule-edit/main.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/tests/src/libirccd/command-rule-edit/main.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -23,7 +23,7 @@ #include <irccd/daemon/rule_edit_command.hpp> #include <irccd/daemon/rule_info_command.hpp> -#include <irccd/daemon/rule_service.hpp> +#include <irccd/daemon/service/rule_service.hpp> #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-rule-info/main.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/tests/src/libirccd/command-rule-info/main.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -22,7 +22,7 @@ #include <irccd/json_util.hpp> #include <irccd/daemon/rule_info_command.hpp> -#include <irccd/daemon/rule_service.hpp> +#include <irccd/daemon/service/rule_service.hpp> #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-rule-list/main.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/tests/src/libirccd/command-rule-list/main.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -22,7 +22,7 @@ #include <irccd/json_util.hpp> #include <irccd/daemon/rule_list_command.hpp> -#include <irccd/daemon/rule_service.hpp> +#include <irccd/daemon/service/rule_service.hpp> #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-rule-move/main.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/tests/src/libirccd/command-rule-move/main.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -23,7 +23,7 @@ #include <irccd/daemon/rule_list_command.hpp> #include <irccd/daemon/rule_move_command.hpp> -#include <irccd/daemon/rule_service.hpp> +#include <irccd/daemon/service/rule_service.hpp> #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-rule-remove/main.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/tests/src/libirccd/command-rule-remove/main.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -23,7 +23,7 @@ #include <irccd/daemon/rule_remove_command.hpp> #include <irccd/daemon/rule_list_command.hpp> -#include <irccd/daemon/rule_service.hpp> +#include <irccd/daemon/service/rule_service.hpp> #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-server-connect/main.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/tests/src/libirccd/command-server-connect/main.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -19,8 +19,8 @@ #define BOOST_TEST_MODULE "server-connect" #include <boost/test/unit_test.hpp> -#include <irccd/daemon/server_service.hpp> #include <irccd/daemon/server_connect_command.hpp> +#include <irccd/daemon/service/server_service.hpp> #include <irccd/test/command_test.hpp> #include <irccd/test/journal_server.hpp>
--- a/tests/src/libirccd/command-server-disconnect/main.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/tests/src/libirccd/command-server-disconnect/main.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -20,7 +20,7 @@ #include <boost/test/unit_test.hpp> #include <irccd/daemon/server_disconnect_command.hpp> -#include <irccd/daemon/server_service.hpp> +#include <irccd/daemon/service/server_service.hpp> #include <irccd/test/journal_server.hpp> #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-server-info/main.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/tests/src/libirccd/command-server-info/main.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -20,7 +20,7 @@ #include <boost/test/unit_test.hpp> #include <irccd/daemon/server_info_command.hpp> -#include <irccd/daemon/server_service.hpp> +#include <irccd/daemon/service/server_service.hpp> #include <irccd/test/command_test.hpp> #include <irccd/test/journal_server.hpp>
--- a/tests/src/libirccd/command-server-invite/main.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/tests/src/libirccd/command-server-invite/main.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -20,7 +20,7 @@ #include <boost/test/unit_test.hpp> #include <irccd/daemon/server_invite_command.hpp> -#include <irccd/daemon/server_service.hpp> +#include <irccd/daemon/service/server_service.hpp> #include <irccd/test/command_test.hpp> #include <irccd/test/journal_server.hpp>
--- a/tests/src/libirccd/command-server-join/main.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/tests/src/libirccd/command-server-join/main.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -20,7 +20,7 @@ #include <boost/test/unit_test.hpp> #include <irccd/daemon/server_join_command.hpp> -#include <irccd/daemon/server_service.hpp> +#include <irccd/daemon/service/server_service.hpp> #include <irccd/test/command_test.hpp> #include <irccd/test/journal_server.hpp>
--- a/tests/src/libirccd/command-server-kick/main.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/tests/src/libirccd/command-server-kick/main.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -19,8 +19,8 @@ #define BOOST_TEST_MODULE "server-kick" #include <boost/test/unit_test.hpp> -#include <irccd/daemon/server_service.hpp> #include <irccd/daemon/server_kick_command.hpp> +#include <irccd/daemon/service/server_service.hpp> #include <irccd/test/command_test.hpp> #include <irccd/test/journal_server.hpp>
--- a/tests/src/libirccd/command-server-list/main.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/tests/src/libirccd/command-server-list/main.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -19,8 +19,8 @@ #define BOOST_TEST_MODULE "server-list" #include <boost/test/unit_test.hpp> -#include <irccd/daemon/server_service.hpp> #include <irccd/daemon/server_list_command.hpp> +#include <irccd/daemon/service/server_service.hpp> #include <irccd/test/command_test.hpp> #include <irccd/test/journal_server.hpp>
--- a/tests/src/libirccd/command-server-me/main.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/tests/src/libirccd/command-server-me/main.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -19,8 +19,8 @@ #define BOOST_TEST_MODULE "server-me" #include <boost/test/unit_test.hpp> -#include <irccd/daemon/server_service.hpp> #include <irccd/daemon/server_me_command.hpp> +#include <irccd/daemon/service/server_service.hpp> #include <irccd/test/command_test.hpp> #include <irccd/test/journal_server.hpp>
--- a/tests/src/libirccd/command-server-message/main.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/tests/src/libirccd/command-server-message/main.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -19,8 +19,8 @@ #define BOOST_TEST_MODULE "server-message" #include <boost/test/unit_test.hpp> -#include <irccd/daemon/server_service.hpp> #include <irccd/daemon/server_message_command.hpp> +#include <irccd/daemon/service/server_service.hpp> #include <irccd/test/command_test.hpp> #include <irccd/test/journal_server.hpp>
--- a/tests/src/libirccd/command-server-mode/main.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/tests/src/libirccd/command-server-mode/main.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -19,8 +19,8 @@ #define BOOST_TEST_MODULE "server-mode" #include <boost/test/unit_test.hpp> -#include <irccd/daemon/server_service.hpp> #include <irccd/daemon/server_mode_command.hpp> +#include <irccd/daemon/service/server_service.hpp> #include <irccd/test/command_test.hpp> #include <irccd/test/journal_server.hpp>
--- a/tests/src/libirccd/command-server-nick/main.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/tests/src/libirccd/command-server-nick/main.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -19,8 +19,8 @@ #define BOOST_TEST_MODULE "server-nick" #include <boost/test/unit_test.hpp> -#include <irccd/daemon/server_service.hpp> #include <irccd/daemon/server_nick_command.hpp> +#include <irccd/daemon/service/server_service.hpp> #include <irccd/test/command_test.hpp> #include <irccd/test/journal_server.hpp>
--- a/tests/src/libirccd/command-server-notice/main.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/tests/src/libirccd/command-server-notice/main.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -19,8 +19,8 @@ #define BOOST_TEST_MODULE "server-notice" #include <boost/test/unit_test.hpp> -#include <irccd/daemon/server_service.hpp> #include <irccd/daemon/server_notice_command.hpp> +#include <irccd/daemon/service/server_service.hpp> #include <irccd/test/command_test.hpp> #include <irccd/test/journal_server.hpp>
--- a/tests/src/libirccd/command-server-part/main.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/tests/src/libirccd/command-server-part/main.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -19,8 +19,8 @@ #define BOOST_TEST_MODULE "server-part" #include <boost/test/unit_test.hpp> -#include <irccd/daemon/server_service.hpp> #include <irccd/daemon/server_part_command.hpp> +#include <irccd/daemon/service/server_service.hpp> #include <irccd/test/command_test.hpp> #include <irccd/test/journal_server.hpp>
--- a/tests/src/libirccd/command-server-reconnect/main.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/tests/src/libirccd/command-server-reconnect/main.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -19,8 +19,8 @@ #define BOOST_TEST_MODULE "server-reconnect" #include <boost/test/unit_test.hpp> -#include <irccd/daemon/server_service.hpp> #include <irccd/daemon/server_reconnect_command.hpp> +#include <irccd/daemon/service/server_service.hpp> #include <irccd/test/command_test.hpp> #include <irccd/test/journal_server.hpp>
--- a/tests/src/libirccd/command-server-topic/main.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/tests/src/libirccd/command-server-topic/main.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -19,8 +19,8 @@ #define BOOST_TEST_MODULE "server-topic" #include <boost/test/unit_test.hpp> -#include <irccd/daemon/server_service.hpp> #include <irccd/daemon/server_topic_command.hpp> +#include <irccd/daemon/service/server_service.hpp> #include <irccd/test/command_test.hpp> #include <irccd/test/journal_server.hpp>
--- a/tests/src/libirccd/rules/main.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/tests/src/libirccd/rules/main.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -21,7 +21,7 @@ #include <irccd/daemon/irccd.hpp> #include <irccd/daemon/logger.hpp> -#include <irccd/daemon/rule_service.hpp> +#include <irccd/daemon/service/rule_service.hpp> namespace irccd {
--- a/tests/src/plugins/plugin/main.cpp Mon Jan 15 13:37:32 2018 +0100 +++ b/tests/src/plugins/plugin/main.cpp Wed Mar 07 17:49:56 2018 +0100 @@ -22,8 +22,8 @@ #include <irccd/string_util.hpp> #include <irccd/daemon/irccd.hpp> -#include <irccd/daemon/plugin_service.hpp> #include <irccd/daemon/server.hpp> +#include <irccd/daemon/service/plugin_service.hpp> #include <irccd/test/plugin_test.hpp>