Mercurial > irccd
changeset 684:8d93e415c3b4
Irccd: load directly native plugin instead of wrapping it, closes #790 @1h
The boost::dll::import function support importing variables as
boost::shared_ptr, instead of wrapping all individual function, just load the
plugin from the shared object and return it as a std::shared_ptr.
author | David Demelier <markand@malikania.fr> |
---|---|
date | Fri, 13 Apr 2018 07:32:10 +0200 |
parents | d30793525261 |
children | e81c6badede3 |
files | libirccd/irccd/daemon/dynlib_plugin.cpp libirccd/irccd/daemon/dynlib_plugin.hpp tests/src/libirccd/dynlib-plugin/CMakeLists.txt tests/src/libirccd/dynlib-plugin/main.cpp tests/src/libirccd/dynlib-plugin/test_plugin.cpp |
diffstat | 5 files changed, 135 insertions(+), 343 deletions(-) [+] |
line wrap: on
line diff
--- a/libirccd/irccd/daemon/dynlib_plugin.cpp Thu Apr 12 19:30:43 2018 +0200 +++ b/libirccd/irccd/daemon/dynlib_plugin.cpp Fri Apr 13 07:32:10 2018 +0200 @@ -19,7 +19,7 @@ #include <cctype> #include <algorithm> -#include <boost/filesystem.hpp> +#include <boost/dll.hpp> #include <irccd/string_util.hpp> @@ -35,126 +35,23 @@ namespace irccd { -dynlib_plugin::dynlib_plugin(std::string name, std::string path) - : plugin(name, path) - , dso_(path) -{ - using load_t = std::unique_ptr<plugin>(std::string, std::string); - - /* - * Function name is determined from the plugin filename where all non - * alphabetic characters are removed. - * - * Example: foo_bar-baz___.so becomes irccd_foobarbaz_load. - */ - auto base = boost::filesystem::path(path).stem().string(); - auto need_remove = [] (auto c) { - return !std::isalnum(c); - }; - - base.erase(std::remove_if(base.begin(), base.end(), need_remove), base.end()); - - auto fname = string_util::sprintf("irccd_%s_load", base); - auto load = dso_.get<load_t>(fname); - - if (!load) - throw std::runtime_error(string_util::sprintf("missing plugin entry function '%s'", fname)); - - plugin_ = load(name, path); +namespace { - if (!plugin_) - throw std::runtime_error("plugin returned null"); -} - -void dynlib_plugin::handle_command(irccd& irccd, const message_event& ev) +std::string symbol(std::string id) noexcept { - plugin_->handle_command(irccd, ev); -} - -void dynlib_plugin::handle_connect(irccd& irccd, const connect_event& ev) -{ - plugin_->handle_connect(irccd, ev); -} + std::transform(id.begin(), id.end(), id.begin(), [] (auto c) { + return c == '-' ? '_' : c; + }); -void dynlib_plugin::handle_disconnect(irccd& irccd, const disconnect_event& ev) -{ - plugin_->handle_disconnect(irccd, ev); -} - -void dynlib_plugin::handle_invite(irccd& irccd, const invite_event& ev) -{ - plugin_->handle_invite(irccd, ev); -} - -void dynlib_plugin::handle_join(irccd& irccd, const join_event& ev) -{ - plugin_->handle_join(irccd, ev); + return string_util::sprintf("irccd_plugin_%s", id); } -void dynlib_plugin::handle_kick(irccd& irccd, const kick_event& ev) -{ - plugin_->handle_kick(irccd, ev); -} - -void dynlib_plugin::handle_load(irccd& irccd) -{ - plugin_->handle_load(irccd); -} - -void dynlib_plugin::handle_message(irccd& irccd, const message_event& ev) +std::shared_ptr<plugin> wrap(boost::shared_ptr<plugin> ptr) noexcept { - plugin_->handle_message(irccd, ev); -} - -void dynlib_plugin::handle_me(irccd& irccd, const me_event& ev) -{ - plugin_->handle_me(irccd, ev); -} - -void dynlib_plugin::handle_mode(irccd& irccd, const mode_event& ev) -{ - plugin_->handle_mode(irccd, ev); -} - -void dynlib_plugin::handle_names(irccd& irccd, const names_event& ev) -{ - plugin_->handle_names(irccd, ev); + return std::shared_ptr<plugin>(ptr.get(), [ptr] (auto) mutable { ptr.reset(); }); } -void dynlib_plugin::handle_nick(irccd& irccd, const nick_event& ev) -{ - plugin_->handle_nick(irccd, ev); -} - -void dynlib_plugin::handle_notice(irccd& irccd, const notice_event& ev) -{ - plugin_->handle_notice(irccd, ev); -} - -void dynlib_plugin::handle_part(irccd& irccd, const part_event& ev) -{ - plugin_->handle_part(irccd, ev); -} - -void dynlib_plugin::handle_reload(irccd& irccd) -{ - plugin_->handle_reload(irccd); -} - -void dynlib_plugin::handle_topic(irccd& irccd, const topic_event& ev) -{ - plugin_->handle_topic(irccd, ev); -} - -void dynlib_plugin::handle_unload(irccd& irccd) -{ - plugin_->handle_unload(irccd); -} - -void dynlib_plugin::handle_whois(irccd& irccd, const whois_event& ev) -{ - plugin_->handle_whois(irccd, ev); -} +} // !namespace dynlib_plugin_loader::dynlib_plugin_loader(std::vector<std::string> directories) noexcept : plugin_loader(std::move(directories), { DYNLIB_EXTENSION }) @@ -164,7 +61,7 @@ std::shared_ptr<plugin> dynlib_plugin_loader::open(const std::string& id, const std::string& path) noexcept { - return std::make_unique<dynlib_plugin>(id, path); + return wrap(boost::dll::import<plugin>(path, symbol(id))); } } // !irccd
--- a/libirccd/irccd/daemon/dynlib_plugin.hpp Thu Apr 12 19:30:43 2018 +0200 +++ b/libirccd/irccd/daemon/dynlib_plugin.hpp Fri Apr 13 07:32:10 2018 +0200 @@ -31,116 +31,6 @@ namespace irccd { /** - * \brief Dynlib based plugin. - * \ingroup plugins - */ -class dynlib_plugin : public plugin { -private: - boost::dll::shared_library dso_; - std::unique_ptr<plugin> plugin_; - -public: - /** - * Construct the plugin. - * - * \param name the name - * \param path the fully resolved path (must be absolute) - * \throw std::exception on failures - */ - dynlib_plugin(std::string name, std::string path); - - /** - * \copydoc plugin::handle_command - */ - void handle_command(irccd& irccd, const message_event& event) override; - - /** - * \copydoc plugin::handle_connect - */ - void handle_connect(irccd& irccd, const connect_event& event) override; - - /** - * \copydoc plugin::handle_disconnect - */ - void handle_disconnect(irccd& irccd, const disconnect_event& event) override; - - /** - * \copydoc plugin::handle_invite - */ - void handle_invite(irccd& irccd, const invite_event& event) override; - - /** - * \copydoc plugin::handle_join - */ - void handle_join(irccd& irccd, const join_event& event) override; - - /** - * \copydoc plugin::handle_kick - */ - void handle_kick(irccd& irccd, const kick_event& event) override; - - /** - * \copydoc plugin::handle_load - */ - void handle_load(irccd& irccd) override; - - /** - * \copydoc plugin::handle_message - */ - void handle_message(irccd& irccd, const message_event& event) override; - - /** - * \copydoc plugin::handle_me - */ - void handle_me(irccd& irccd, const me_event& event) override; - - /** - * \copydoc plugin::handle_mode - */ - void handle_mode(irccd& irccd, const mode_event& event) override; - - /** - * \copydoc plugin::handle_names - */ - void handle_names(irccd& irccd, const names_event& event) override; - - /** - * \copydoc plugin::handle_nick - */ - void handle_nick(irccd& irccd, const nick_event& event) override; - - /** - * \copydoc plugin::handle_notice - */ - void handle_notice(irccd& irccd, const notice_event& event) override; - - /** - * \copydoc plugin::handle_part - */ - void handle_part(irccd& irccd, const part_event& event) override; - - /** - * \copydoc plugin::handle_reload - */ - void handle_reload(irccd& irccd) override; - - /** - * \copydoc plugin::handle_topic - */ - void handle_topic(irccd& irccd, const topic_event& event) override; - - /** - * \copydoc plugin::handle_unload - */ - void handle_unload(irccd& irccd) override; - - /** - * \copydoc plugin::handle_whois - */ - void handle_whois(irccd& irccd, const whois_event& event) override; -}; - -/** * \brief Implementation for searching native plugins. */ class dynlib_plugin_loader : public plugin_loader {
--- a/tests/src/libirccd/dynlib-plugin/CMakeLists.txt Thu Apr 12 19:30:43 2018 +0200 +++ b/tests/src/libirccd/dynlib-plugin/CMakeLists.txt Fri Apr 13 07:32:10 2018 +0200 @@ -40,4 +40,5 @@ NAME dynlib-plugin SOURCES main.cpp LIBRARIES libirccd libirccd-test + DEPENDS test-plugin )
--- a/tests/src/libirccd/dynlib-plugin/main.cpp Thu Apr 12 19:30:43 2018 +0200 +++ b/tests/src/libirccd/dynlib-plugin/main.cpp Fri Apr 13 07:32:10 2018 +0200 @@ -20,31 +20,22 @@ #include <boost/test/unit_test.hpp> /* - * For this test, we open a plugin written in C++ and pass a journal_server - * class for each of the plugin function. - * - * Then we verify that the appropriate function has been called correctly. - * - * Functions load, unload and reload can not be tested though. + * For this test, we update internal plugin configuration each time a function + * is called and check if it has been called correctly using get_config. */ #include <irccd/daemon/dynlib_plugin.hpp> #include <irccd/daemon/irccd.hpp> -#include <irccd/test/journal_server.hpp> - namespace irccd { class fixture { protected: boost::asio::io_service service_; - std::shared_ptr<journal_server> server_; std::shared_ptr<plugin> plugin_; - irccd irccd_; + irccd irccd_{service_}; inline fixture() - : server_(std::make_shared<journal_server>(service_, "test")) - , irccd_(service_) { plugin_ = dynlib_plugin_loader({CMAKE_CURRENT_BINARY_DIR}).find("test-plugin"); @@ -57,142 +48,138 @@ BOOST_AUTO_TEST_CASE(handle_command) { - plugin_->handle_command(irccd_, {server_, "", "", ""}); + plugin_->handle_command(irccd_, {}); - BOOST_TEST(server_->cqueue().size() == 1U); - BOOST_TEST(server_->cqueue()[0]["command"].get<std::string>() == "message"); - BOOST_TEST(server_->cqueue()[0]["message"].get<std::string>() == "handle_command"); - BOOST_TEST(server_->cqueue()[0]["target"].get<std::string>() == "test"); + BOOST_TEST(plugin_->get_config().size() == 1U); + BOOST_TEST(plugin_->get_config()["command"] == "true"); } BOOST_AUTO_TEST_CASE(handle_connect) { - plugin_->handle_connect(irccd_, {server_}); + plugin_->handle_connect(irccd_, {}); - BOOST_TEST(server_->cqueue().size() == 1U); - BOOST_TEST(server_->cqueue()[0]["command"].get<std::string>() == "message"); - BOOST_TEST(server_->cqueue()[0]["message"].get<std::string>() == "handle_connect"); - BOOST_TEST(server_->cqueue()[0]["target"].get<std::string>() == "test"); + BOOST_TEST(plugin_->get_config().size() == 1U); + BOOST_TEST(plugin_->get_config()["connect"] == "true"); } BOOST_AUTO_TEST_CASE(handle_invite) { - plugin_->handle_invite(irccd_, {server_, "", "", ""}); + plugin_->handle_invite(irccd_, {}); - BOOST_TEST(server_->cqueue().size() == 1U); - BOOST_TEST(server_->cqueue()[0]["command"].get<std::string>() == "message"); - BOOST_TEST(server_->cqueue()[0]["message"].get<std::string>() == "handle_invite"); - BOOST_TEST(server_->cqueue()[0]["target"].get<std::string>() == "test"); + BOOST_TEST(plugin_->get_config().size() == 1U); + BOOST_TEST(plugin_->get_config()["invite"] == "true"); } BOOST_AUTO_TEST_CASE(handle_join) { - plugin_->handle_join(irccd_, {server_, "", ""}); + plugin_->handle_join(irccd_, {}); - BOOST_TEST(server_->cqueue().size() == 1U); - BOOST_TEST(server_->cqueue()[0]["command"].get<std::string>() == "message"); - BOOST_TEST(server_->cqueue()[0]["message"].get<std::string>() == "handle_join"); - BOOST_TEST(server_->cqueue()[0]["target"].get<std::string>() == "test"); + BOOST_TEST(plugin_->get_config().size() == 1U); + BOOST_TEST(plugin_->get_config()["join"] == "true"); } BOOST_AUTO_TEST_CASE(handle_kick) { - plugin_->handle_kick(irccd_, {server_, "", "", "", ""}); + plugin_->handle_kick(irccd_, {}); + + BOOST_TEST(plugin_->get_config().size() == 1U); + BOOST_TEST(plugin_->get_config()["kick"] == "true"); +} - BOOST_TEST(server_->cqueue().size() == 1U); - BOOST_TEST(server_->cqueue()[0]["command"].get<std::string>() == "message"); - BOOST_TEST(server_->cqueue()[0]["message"].get<std::string>() == "handle_kick"); - BOOST_TEST(server_->cqueue()[0]["target"].get<std::string>() == "test"); +BOOST_AUTO_TEST_CASE(handle_load) +{ + plugin_->handle_load(irccd_); + + BOOST_TEST(plugin_->get_config().size() == 1U); + BOOST_TEST(plugin_->get_config()["load"] == "true"); } BOOST_AUTO_TEST_CASE(handle_message) { - plugin_->handle_message(irccd_, {server_, "", "", ""}); + plugin_->handle_message(irccd_, {}); - BOOST_TEST(server_->cqueue().size() == 1U); - BOOST_TEST(server_->cqueue()[0]["command"].get<std::string>() == "message"); - BOOST_TEST(server_->cqueue()[0]["message"].get<std::string>() == "handle_message"); - BOOST_TEST(server_->cqueue()[0]["target"].get<std::string>() == "test"); + BOOST_TEST(plugin_->get_config().size() == 1U); + BOOST_TEST(plugin_->get_config()["message"] == "true"); } BOOST_AUTO_TEST_CASE(handle_me) { - plugin_->handle_me(irccd_, {server_, "", "", ""}); + plugin_->handle_me(irccd_, {}); - BOOST_TEST(server_->cqueue().size() == 1U); - BOOST_TEST(server_->cqueue()[0]["command"].get<std::string>() == "message"); - BOOST_TEST(server_->cqueue()[0]["message"].get<std::string>() == "handle_me"); - BOOST_TEST(server_->cqueue()[0]["target"].get<std::string>() == "test"); + BOOST_TEST(plugin_->get_config().size() == 1U); + BOOST_TEST(plugin_->get_config()["me"] == "true"); } BOOST_AUTO_TEST_CASE(handle_mode) { - plugin_->handle_mode(irccd_, {server_, "", "", "", "", "", ""}); + plugin_->handle_mode(irccd_, {}); - BOOST_TEST(server_->cqueue().size() == 1U); - BOOST_TEST(server_->cqueue()[0]["command"].get<std::string>() == "message"); - BOOST_TEST(server_->cqueue()[0]["message"].get<std::string>() == "handle_mode"); - BOOST_TEST(server_->cqueue()[0]["target"].get<std::string>() == "test"); + BOOST_TEST(plugin_->get_config().size() == 1U); + BOOST_TEST(plugin_->get_config()["mode"] == "true"); } BOOST_AUTO_TEST_CASE(handle_names) { - plugin_->handle_names(irccd_, {server_, "", {}}); + plugin_->handle_names(irccd_, {}); - BOOST_TEST(server_->cqueue().size() == 1U); - BOOST_TEST(server_->cqueue()[0]["command"].get<std::string>() == "message"); - BOOST_TEST(server_->cqueue()[0]["message"].get<std::string>() == "handle_names"); - BOOST_TEST(server_->cqueue()[0]["target"].get<std::string>() == "test"); + BOOST_TEST(plugin_->get_config().size() == 1U); + BOOST_TEST(plugin_->get_config()["names"] == "true"); } BOOST_AUTO_TEST_CASE(handle_nick) { - plugin_->handle_nick(irccd_, {server_, "", ""}); + plugin_->handle_nick(irccd_, {}); - BOOST_TEST(server_->cqueue().size() == 1U); - BOOST_TEST(server_->cqueue()[0]["command"].get<std::string>() == "message"); - BOOST_TEST(server_->cqueue()[0]["message"].get<std::string>() == "handle_nick"); - BOOST_TEST(server_->cqueue()[0]["target"].get<std::string>() == "test"); + BOOST_TEST(plugin_->get_config().size() == 1U); + BOOST_TEST(plugin_->get_config()["nick"] == "true"); } BOOST_AUTO_TEST_CASE(handle_notice) { - plugin_->handle_notice(irccd_, {server_, "", "", ""}); + plugin_->handle_notice(irccd_, {}); - BOOST_TEST(server_->cqueue().size() == 1U); - BOOST_TEST(server_->cqueue()[0]["command"].get<std::string>() == "message"); - BOOST_TEST(server_->cqueue()[0]["message"].get<std::string>() == "handle_notice"); - BOOST_TEST(server_->cqueue()[0]["target"].get<std::string>() == "test"); + BOOST_TEST(plugin_->get_config().size() == 1U); + BOOST_TEST(plugin_->get_config()["notice"] == "true"); } BOOST_AUTO_TEST_CASE(handle_part) { - plugin_->handle_part(irccd_, {server_, "", "", ""}); + plugin_->handle_part(irccd_, {}); + + BOOST_TEST(plugin_->get_config().size() == 1U); + BOOST_TEST(plugin_->get_config()["part"] == "true"); +} - BOOST_TEST(server_->cqueue().size() == 1U); - BOOST_TEST(server_->cqueue()[0]["command"].get<std::string>() == "message"); - BOOST_TEST(server_->cqueue()[0]["message"].get<std::string>() == "handle_part"); - BOOST_TEST(server_->cqueue()[0]["target"].get<std::string>() == "test"); +BOOST_AUTO_TEST_CASE(handle_reload) +{ + plugin_->handle_reload(irccd_); + + BOOST_TEST(plugin_->get_config().size() == 1U); + BOOST_TEST(plugin_->get_config()["reload"] == "true"); } BOOST_AUTO_TEST_CASE(handle_topic) { - plugin_->handle_topic(irccd_, {server_, "", "", ""}); + plugin_->handle_topic(irccd_, {}); + + BOOST_TEST(plugin_->get_config().size() == 1U); + BOOST_TEST(plugin_->get_config()["topic"] == "true"); +} - BOOST_TEST(server_->cqueue().size() == 1U); - BOOST_TEST(server_->cqueue()[0]["command"].get<std::string>() == "message"); - BOOST_TEST(server_->cqueue()[0]["message"].get<std::string>() == "handle_topic"); - BOOST_TEST(server_->cqueue()[0]["target"].get<std::string>() == "test"); +BOOST_AUTO_TEST_CASE(handle_unload) +{ + plugin_->handle_unload(irccd_); + + BOOST_TEST(plugin_->get_config().size() == 1U); + BOOST_TEST(plugin_->get_config()["unload"] == "true"); } BOOST_AUTO_TEST_CASE(handle_whois) { - plugin_->handle_whois(irccd_, {server_, {"", "", "", "", {}}}); + plugin_->handle_whois(irccd_, {}); - BOOST_TEST(server_->cqueue().size() == 1U); - BOOST_TEST(server_->cqueue()[0]["command"].get<std::string>() == "message"); - BOOST_TEST(server_->cqueue()[0]["message"].get<std::string>() == "handle_whois"); - BOOST_TEST(server_->cqueue()[0]["target"].get<std::string>() == "test"); + BOOST_TEST(plugin_->get_config().size() == 1U); + BOOST_TEST(plugin_->get_config()["whois"] == "true"); } BOOST_AUTO_TEST_SUITE_END()
--- a/tests/src/libirccd/dynlib-plugin/test_plugin.cpp Thu Apr 12 19:30:43 2018 +0200 +++ b/tests/src/libirccd/dynlib-plugin/test_plugin.cpp Fri Apr 13 07:32:10 2018 +0200 @@ -23,88 +23,105 @@ namespace irccd { class test_plugin : public plugin { +private: + plugin_config config_; + public: using plugin::plugin; - void handle_command(irccd&, const message_event& event) override + plugin_config get_config() override { - event.server->message("test", "handle_command"); + return config_; } - void handle_connect(irccd&, const connect_event& event) override + void handle_command(irccd&, const message_event&) override { - event.server->message("test", "handle_connect"); + config_["command"] = "true"; + } + + void handle_connect(irccd&, const connect_event&) override + { + config_["connect"] = "true"; } - void handle_invite(irccd&, const invite_event& event) override + void handle_invite(irccd&, const invite_event&) override { - event.server->message("test", "handle_invite"); + config_["invite"] = "true"; + } + + void handle_join(irccd&, const join_event&) override + { + config_["join"] = "true"; } - void handle_join(irccd&, const join_event& event) override + void handle_kick(irccd&, const kick_event&) override { - event.server->message("test", "handle_join"); + config_["kick"] = "true"; } - void handle_kick(irccd&, const kick_event& event) override + void handle_load(irccd&) override { - event.server->message("test", "handle_kick"); + config_["load"] = "true"; } - void handle_message(irccd&, const message_event& event) override + void handle_message(irccd&, const message_event&) override { - event.server->message("test", "handle_message"); + config_["message"] = "true"; } - void handle_me(irccd&, const me_event& event) override + void handle_me(irccd&, const me_event&) override { - event.server->message("test", "handle_me"); + config_["me"] = "true"; } - void handle_mode(irccd&, const mode_event& event) override + void handle_mode(irccd&, const mode_event&) override { - event.server->message("test", "handle_mode"); + config_["mode"] = "true"; } - void handle_names(irccd&, const names_event& event) override + void handle_names(irccd&, const names_event&) override { - event.server->message("test", "handle_names"); + config_["names"] = "true"; + } + + void handle_nick(irccd&, const nick_event&) override + { + config_["nick"] = "true"; } - void handle_nick(irccd&, const nick_event& event) override + void handle_notice(irccd&, const notice_event&) override { - event.server->message("test", "handle_nick"); + config_["notice"] = "true"; } - void handle_notice(irccd&, const notice_event& event) override + void handle_part(irccd&, const part_event&) override { - event.server->message("test", "handle_notice"); + config_["part"] = "true"; } - void handle_part(irccd&, const part_event& event) override + void handle_reload(irccd&) override { - event.server->message("test", "handle_part"); + config_["reload"] = "true"; } - void handle_topic(irccd&, const topic_event& event) override + void handle_topic(irccd&, const topic_event&) override { - event.server->message("test", "handle_topic"); + config_["topic"] = "true"; } - void handle_whois(irccd&, const whois_event& event) override + void handle_unload(irccd&) override { - event.server->message("test", "handle_whois"); + config_["unload"] = "true"; + } + + void handle_whois(irccd&, const whois_event&) override + { + config_["whois"] = "true"; } }; -} // !irccd - -extern "C" { +extern "C" BOOST_SYMBOL_EXPORT test_plugin irccd_plugin_test_plugin; -BOOST_SYMBOL_EXPORT -std::unique_ptr<irccd::plugin> irccd_testplugin_load(std::string name, std::string path) -{ - return std::make_unique<irccd::test_plugin>(name, path); -} +test_plugin irccd_plugin_test_plugin("test", ""); -} // !C +} // !irccd