Mercurial > irccd
changeset 128:2d8343b86e2e
Irccd: implement PluginService, #499
author | David Demelier <markand@malikania.fr> |
---|---|
date | Wed, 11 May 2016 13:58:42 +0200 |
parents | 77f950caab35 |
children | 49d1a5eeef6f |
files | irccd/main.cpp lib/irccd/CMakeSources.cmake lib/irccd/cmd-plugin-info.cpp lib/irccd/cmd-plugin-list.cpp lib/irccd/cmd-plugin-load.cpp lib/irccd/cmd-plugin-reload.cpp lib/irccd/cmd-plugin-unload.cpp lib/irccd/irccd.cpp lib/irccd/irccd.hpp lib/irccd/js-plugin.cpp lib/irccd/server-event.cpp lib/irccd/service-plugin.cpp lib/irccd/service-plugin.hpp lib/irccd/service-server.cpp tests/js-timer/main.cpp |
diffstat | 15 files changed, 365 insertions(+), 294 deletions(-) [+] |
line wrap: on
line diff
--- a/irccd/main.cpp Wed May 11 13:27:39 2016 +0200 +++ b/irccd/main.cpp Wed May 11 13:58:42 2016 +0200 @@ -37,6 +37,7 @@ #include <irccd/logger.hpp> #include <irccd/options.hpp> #include <irccd/path.hpp> +#include <irccd/service-plugin.hpp> #include <irccd/service-rule.hpp> #include <irccd/service-server.hpp> #include <irccd/service-transport.hpp> @@ -245,7 +246,7 @@ // [plugin] section. for (const auto &plugin : config.loadPlugins()) { - instance->addPlugin(plugin); + instance->pluginService().add(plugin); } }
--- a/lib/irccd/CMakeSources.cmake Wed May 11 13:27:39 2016 +0200 +++ b/lib/irccd/CMakeSources.cmake Wed May 11 13:58:42 2016 +0200 @@ -1,8 +1,5 @@ set( HEADERS - ${COMMAND_HEADERS} - ${JS_HEADERS} - ${PRIVATE_HEADERS} ${CMAKE_CURRENT_LIST_DIR}/alias.hpp ${CMAKE_CURRENT_LIST_DIR}/application.hpp ${CMAKE_CURRENT_LIST_DIR}/connection.hpp @@ -64,6 +61,7 @@ ${CMAKE_CURRENT_LIST_DIR}/server-state-disconnected.hpp ${CMAKE_CURRENT_LIST_DIR}/service.hpp ${CMAKE_CURRENT_LIST_DIR}/service-interrupt.hpp + ${CMAKE_CURRENT_LIST_DIR}/service-plugin.hpp ${CMAKE_CURRENT_LIST_DIR}/service-rule.hpp ${CMAKE_CURRENT_LIST_DIR}/service-server.hpp ${CMAKE_CURRENT_LIST_DIR}/service-transport.hpp @@ -135,6 +133,7 @@ ${CMAKE_CURRENT_LIST_DIR}/server-state-connecting.cpp ${CMAKE_CURRENT_LIST_DIR}/server-state-disconnected.cpp ${CMAKE_CURRENT_LIST_DIR}/service-interrupt.cpp + ${CMAKE_CURRENT_LIST_DIR}/service-plugin.cpp ${CMAKE_CURRENT_LIST_DIR}/service-rule.cpp ${CMAKE_CURRENT_LIST_DIR}/service-server.cpp ${CMAKE_CURRENT_LIST_DIR}/service-transport.cpp
--- a/lib/irccd/cmd-plugin-info.cpp Wed May 11 13:27:39 2016 +0200 +++ b/lib/irccd/cmd-plugin-info.cpp Wed May 11 13:58:42 2016 +0200 @@ -20,6 +20,8 @@ #include "cmd-plugin-info.hpp" #include "irccd.hpp" +#include "plugin.hpp" +#include "service-plugin.hpp" #include "sysconfig.hpp" namespace irccd { @@ -49,7 +51,7 @@ json::Value PluginInfo::exec(Irccd &irccd, const json::Value &request) const { #if defined(WITH_JS) - auto plugin = irccd.requirePlugin(request.at("plugin").toString()); + auto plugin = irccd.pluginService().require(request.at("plugin").toString()); return json::object({ { "author", plugin->author() },
--- a/lib/irccd/cmd-plugin-list.cpp Wed May 11 13:27:39 2016 +0200 +++ b/lib/irccd/cmd-plugin-list.cpp Wed May 11 13:58:42 2016 +0200 @@ -20,6 +20,8 @@ #include "cmd-plugin-list.hpp" #include "irccd.hpp" +#include "plugin.hpp" +#include "service-plugin.hpp" #include "sysconfig.hpp" namespace irccd { @@ -42,7 +44,7 @@ json::Value response = RemoteCommand::exec(irccd, request); json::Value list = json::array({}); - for (const auto &plugin : irccd.plugins()) { + for (const auto &plugin : irccd.pluginService().plugins()) { list.append(plugin->name()); }
--- a/lib/irccd/cmd-plugin-load.cpp Wed May 11 13:27:39 2016 +0200 +++ b/lib/irccd/cmd-plugin-load.cpp Wed May 11 13:58:42 2016 +0200 @@ -18,6 +18,7 @@ #include "cmd-plugin-load.hpp" #include "irccd.hpp" +#include "service-plugin.hpp" #include "sysconfig.hpp" namespace irccd { @@ -44,7 +45,7 @@ #if defined(WITH_JS) auto name = request.at("plugin").toString(); - irccd.loadPlugin(name, name, true); + irccd.pluginService().load(name, name, true); return RemoteCommand::exec(irccd, request); #else
--- a/lib/irccd/cmd-plugin-reload.cpp Wed May 11 13:27:39 2016 +0200 +++ b/lib/irccd/cmd-plugin-reload.cpp Wed May 11 13:58:42 2016 +0200 @@ -18,6 +18,8 @@ #include "cmd-plugin-reload.hpp" #include "irccd.hpp" +#include "plugin.hpp" +#include "service-plugin.hpp" #include "sysconfig.hpp" namespace irccd { @@ -42,7 +44,7 @@ json::Value PluginReload::exec(Irccd &irccd, const json::Value &request) const { #if defined(WITH_JS) - irccd.requirePlugin(request.at("plugin").toString())->onReload(); + irccd.pluginService().require(request.at("plugin").toString())->onReload(); return RemoteCommand::exec(irccd, request); #else
--- a/lib/irccd/cmd-plugin-unload.cpp Wed May 11 13:27:39 2016 +0200 +++ b/lib/irccd/cmd-plugin-unload.cpp Wed May 11 13:58:42 2016 +0200 @@ -18,6 +18,7 @@ #include "cmd-plugin-unload.hpp" #include "irccd.hpp" +#include "service-plugin.hpp" #include "sysconfig.hpp" namespace irccd { @@ -42,7 +43,7 @@ json::Value PluginUnload::exec(Irccd &irccd, const json::Value &request) const { #if defined(WITH_JS) - irccd.unloadPlugin(request.at("plugin").toString()); + irccd.pluginService().unload(request.at("plugin").toString()); return RemoteCommand::exec(irccd, request); #else
--- a/lib/irccd/irccd.cpp Wed May 11 13:27:39 2016 +0200 +++ b/lib/irccd/irccd.cpp Wed May 11 13:58:42 2016 +0200 @@ -16,27 +16,19 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <algorithm> -#include <stdexcept> - -#include <format.h> - -#include "fs.hpp" #include "irccd.hpp" #include "logger.hpp" -#include "path.hpp" #include "service-interrupt.hpp" +#include "service-plugin.hpp" #include "service-rule.hpp" #include "service-server.hpp" #include "service-transport.hpp" -#include "util.hpp" +#include "sockets.hpp" using namespace std; using namespace std::placeholders; using namespace std::string_literals; -using namespace fmt::literals; - namespace irccd { Irccd::Irccd() @@ -44,6 +36,7 @@ , m_serverService(std::make_shared<ServerService>(*this)) , m_transportService(std::make_shared<TransportService>(*this)) , m_ruleService(std::make_shared<RuleService>()) + , m_pluginService(std::make_shared<PluginService>(*this)) { m_services.push_back(m_interruptService); m_services.push_back(m_serverService); @@ -58,163 +51,6 @@ m_interruptService->interrupt(); } -#if defined(WITH_JS) - -std::shared_ptr<Plugin> Irccd::getPlugin(const std::string &name) const noexcept -{ - auto it = std::find_if(m_plugins.begin(), m_plugins.end(), [&] (const auto &plugin) { - return plugin->name() == name; - }); - - if (it == m_plugins.end()) { - return nullptr; - } - - return *it; -} - -std::shared_ptr<Plugin> Irccd::requirePlugin(const std::string &name) const -{ - auto plugin = getPlugin(name); - - if (!plugin) { - throw std::invalid_argument("plugin {} not found"_format(name)); - } - - return plugin; -} - -void Irccd::addPlugin(std::shared_ptr<Plugin> plugin) -{ - std::weak_ptr<Plugin> ptr(plugin); - - plugin->onTimerSignal.connect(std::bind(&Irccd::handleTimerSignal, this, ptr, _1)); - plugin->onTimerEnd.connect(std::bind(&Irccd::handleTimerEnd, this, ptr, _1)); - - /* Store reference to irccd */ - duk::putGlobal(plugin->context(), "\xff""\xff""irccd", duk::RawPointer<Irccd>{this}); - - /* Initial load now */ - try { - plugin->onLoad(); - m_plugins.push_back(std::move(plugin)); - } catch (const std::exception &ex) { - log::warning("plugin {}: {}"_format(plugin->name(), ex.what())); - } -} - -void Irccd::loadPlugin(std::string name, const std::string &source, bool find) -{ - // TODO: change with Plugin::find - auto it = std::find_if(m_plugins.begin(), m_plugins.end(), [&] (const auto &plugin) { - return plugin->name() == name; - }); - - if (it != m_plugins.end()) { - throw std::invalid_argument("plugin already loaded"); - } - - std::vector<string> paths; - std::shared_ptr<Plugin> plugin; - - if (find) { - for (const std::string &dir : path::list(path::PathPlugins)) { - paths.push_back(dir + source + ".js"); - } - } else { - paths.push_back(source); - } - - /* Iterate over all paths */ - log::info("plugin {}: trying to load:"_format(name)); - - for (const auto &path : paths) { - log::info() << " from " << path << std::endl; - - try { - plugin = std::make_shared<Plugin>(name, path /*, m_pluginConf[name] */); - break; - } catch (const std::exception &ex) { - log::info(fmt::format(" error: {}", ex.what())); - } - } - - if (plugin) { - addPlugin(std::move(plugin)); - } else { - throw std::runtime_error("no suitable plugin found"); - } -} - -void Irccd::reloadPlugin(const std::string &name) -{ - auto plugin = getPlugin(name); - - if (plugin) { - plugin->onReload(); - } -} - -void Irccd::unloadPlugin(const std::string &name) -{ - auto it = std::find_if(m_plugins.begin(), m_plugins.end(), [&] (const auto &plugin) { - return plugin->name() == name; - }); - - if (it != m_plugins.end()) { - (*it)->onUnload(); - m_plugins.erase(it); - } -} - -#endif // !WITH_JS - -/* - * Timer slots - * ------------------------------------------------------------------ - * - * These slots are called from timer threads. - */ - -#if defined(WITH_JS) - -void Irccd::handleTimerSignal(std::weak_ptr<Plugin> ptr, std::shared_ptr<Timer> timer) -{ - post([this, ptr, timer] (Irccd &) { - auto plugin = ptr.lock(); - - if (!plugin) { - return; - } - - auto &ctx = plugin->context(); - - duk::StackAssert sa(ctx); - - // TODO: improve this - try { - duk::getGlobal<void>(ctx, "\xff""\xff""timer-" + std::to_string(reinterpret_cast<std::intptr_t>(timer.get()))); - duk::pcall(ctx, 0); - duk::pop(ctx); - } catch (const std::exception &) { - } - }); -} - -void Irccd::handleTimerEnd(std::weak_ptr<Plugin> ptr, std::shared_ptr<Timer> timer) -{ - post([this, ptr, timer] (Irccd &) { - auto plugin = ptr.lock(); - - if (plugin) { - log::debug() << "timer: finished, removing from plugin `" << plugin->name() << "'" << std::endl; - plugin->removeTimer(timer); - } - }); -} - -#endif - void Irccd::run() { while (m_running) {
--- a/lib/irccd/irccd.hpp Wed May 11 13:27:39 2016 +0200 +++ b/lib/irccd/irccd.hpp Wed May 11 13:58:42 2016 +0200 @@ -31,19 +31,13 @@ #include <mutex> #include <vector> -#include "sysconfig.hpp" - -#if defined(WITH_JS) -# include "plugin.hpp" -#endif - #include "application.hpp" namespace irccd { class InterruptService; class Irccd; -class Plugin; +class PluginService; class RuleService; class ServerService; class Service; @@ -60,30 +54,14 @@ std::mutex m_mutex; std::vector<std::function<void (Irccd &)>> m_events; - // Optional plugins. -#if defined(WITH_JS) - std::vector<std::shared_ptr<Plugin>> m_plugins; -#endif - // Services. std::shared_ptr<InterruptService> m_interruptService; std::shared_ptr<ServerService> m_serverService; std::shared_ptr<TransportService> m_transportService; std::shared_ptr<RuleService> m_ruleService; + std::shared_ptr<PluginService> m_pluginService; std::vector<std::shared_ptr<Service>> m_services; - /* - * Plugin timers slots - * ---------------------------------------------------------- - * - * These handlers catch the timer signals and call the plugin function or remove the timer from the plugin. - */ - -#if defined(WITH_JS) - void handleTimerSignal(std::weak_ptr<Plugin>, std::shared_ptr<Timer>); - void handleTimerEnd(std::weak_ptr<Plugin>, std::shared_ptr<Timer>); -#endif - // Not copyable and not movable because services has references to irccd. Irccd(const Irccd &) = delete; Irccd(Irccd &&) = delete; @@ -138,6 +116,16 @@ } /** + * Access the plugin service. + * + * \return the service + */ + inline PluginService &pluginService() noexcept + { + return *m_pluginService; + } + + /** * Add an event to the queue. This will immediately signals the event loop to interrupt itself to dispatch * the pending events. * @@ -146,92 +134,6 @@ */ void post(std::function<void (Irccd &)> ev) noexcept; - /* - * Plugin management - * ---------------------------------------------------------- - * - * Functions for loading JavaScript plugins. - */ - -#if defined(WITH_JS) - /** - * Check if a plugin is loaded. - * - * \param name the plugin id - * \return true if has plugin - */ - inline bool hasPlugin(const std::string &name) const noexcept - { - return std::count_if(m_plugins.cbegin(), m_plugins.cend(), [&] (const auto &plugin) { - return plugin->name() == name; - }) > 0; - } - - /** - * Get a plugin or empty one if not found. - * - * \param name the plugin id - * \return the plugin or empty one if not found - */ - std::shared_ptr<Plugin> getPlugin(const std::string &name) const noexcept; - - /** - * Find a plugin. - * - * \param name the plugin id - * \return the plugin - * \throws std::out_of_range if not found - */ - std::shared_ptr<Plugin> requirePlugin(const std::string &name) const; - - /** - * Add a loaded plugin. - * - * Plugins signals will be connected to the irccd main loop. The onLoad function will also be called and the - * plugin is not added on errors. - * - * \pre plugin must not be empty - * \param plugin the plugin - */ - void addPlugin(std::shared_ptr<Plugin> plugin); - - /** - * Load a plugin by path or by searching through directories. - * - * TODO: Move this somewhere else (e.g. Plugin::find). - * - * \param source the path or the plugin id to search - * \param find set to true for searching by id - */ - void loadPlugin(std::string name, const std::string &source, bool find); - - /** - * Unload a plugin and remove it. - * - * \param name the plugin id - */ - void unloadPlugin(const std::string &name); - - /** - * Reload a plugin by calling onReload. - * - * \param name the plugin name - * \throw std::exception on failures - */ - void reloadPlugin(const std::string &name); - - /** - * Get the map of plugins. - * - * \return the map of plugins - */ - inline const std::vector<std::shared_ptr<Plugin>> &plugins() const noexcept - { - return m_plugins; - } - -#endif // !WITH_JS - /** * Loop forever by calling poll() and dispatch() indefinitely. */
--- a/lib/irccd/js-plugin.cpp Wed May 11 13:27:39 2016 +0200 +++ b/lib/irccd/js-plugin.cpp Wed May 11 13:58:42 2016 +0200 @@ -17,6 +17,8 @@ */ #include "irccd.hpp" +#include "plugin.hpp" +#include "service-plugin.hpp" #include "js-plugin.hpp" namespace irccd { @@ -70,7 +72,7 @@ Plugin *plugin = nullptr; if (duk::top(ctx) >= 1) { - plugin = duk::getGlobal<duk::RawPointer<Irccd>>(ctx, "\xff""\xff""irccd")->getPlugin(duk::require<std::string>(ctx, 0)).get(); + plugin = duk::getGlobal<duk::RawPointer<Irccd>>(ctx, "\xff""\xff""irccd")->pluginService().get(duk::require<std::string>(ctx, 0)).get(); } else { plugin = duk::getGlobal<duk::RawPointer<Plugin>>(ctx, "\xff""\xff""plugin"); } @@ -103,7 +105,7 @@ duk::push(ctx, duk::Array{}); int i = 0; - for (const auto &plugin : duk::getGlobal<duk::RawPointer<Irccd>>(ctx, "\xff""\xff""irccd")->plugins()) { + for (const auto &plugin : duk::getGlobal<duk::RawPointer<Irccd>>(ctx, "\xff""\xff""irccd")->pluginService().plugins()) { duk::putProperty(ctx, -1, i++, plugin->name()); } @@ -125,7 +127,7 @@ duk::Ret load(duk::ContextPtr ctx) { return wrap(ctx, 0, [&] (Irccd &irccd, const std::string &name) { - irccd.loadPlugin(name, name, true); + irccd.pluginService().load(name, name, true); }); } @@ -144,7 +146,7 @@ duk::Ret reload(duk::ContextPtr ctx) { return wrap(ctx, 0, [&] (Irccd &irccd, const std::string &name) { - irccd.reloadPlugin(name); + irccd.pluginService().reload(name); }); } @@ -163,7 +165,7 @@ duk::Ret unload(duk::ContextPtr ctx) { return wrap(ctx, 0, [&] (Irccd &irccd, const std::string &name) { - irccd.unloadPlugin(name); + irccd.pluginService().unload(name); }); }
--- a/lib/irccd/server-event.cpp Wed May 11 13:27:39 2016 +0200 +++ b/lib/irccd/server-event.cpp Wed May 11 13:58:42 2016 +0200 @@ -18,7 +18,9 @@ #include "irccd.hpp" #include "logger.hpp" +#include "plugin.hpp" #include "server-event.hpp" +#include "service-plugin.hpp" #include "service-rule.hpp" namespace irccd { @@ -38,7 +40,7 @@ void ServerEvent::operator()(Irccd &irccd) const { - for (auto &plugin : irccd.plugins()) { + for (auto &plugin : irccd.pluginService().plugins()) { auto eventname = m_plugin_function_name(*plugin); auto allowed = irccd.ruleService().solve(m_server, m_target, m_origin, plugin->name(), eventname);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/service-plugin.cpp Wed May 11 13:58:42 2016 +0200 @@ -0,0 +1,190 @@ +/* + * service-plugin.cpp -- manage plugins + * + * Copyright (c) 2013-2016 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 <algorithm> +#include <functional> +#include <stdexcept> + +#include <format.h> + +#include "irccd.hpp" +#include "logger.hpp" +#include "plugin.hpp" +#include "service-plugin.hpp" + +using namespace fmt::literals; + +namespace irccd { + +PluginService::PluginService(Irccd &irccd) noexcept + : m_irccd(irccd) +{ +} + +bool PluginService::has(const std::string &name) const noexcept +{ + return std::count_if(m_plugins.cbegin(), m_plugins.cend(), [&] (const auto &plugin) { + return plugin->name() == name; + }) > 0; +} + +std::shared_ptr<Plugin> PluginService::get(const std::string &name) const noexcept +{ + auto it = std::find_if(m_plugins.begin(), m_plugins.end(), [&] (const auto &plugin) { + return plugin->name() == name; + }); + + if (it == m_plugins.end()) { + return nullptr; + } + + return *it; +} + +std::shared_ptr<Plugin> PluginService::require(const std::string &name) const +{ + auto plugin = get(name); + + if (!plugin) { + throw std::invalid_argument("plugin {} not found"_format(name)); + } + + return plugin; +} + +void PluginService::add(std::shared_ptr<Plugin> plugin) +{ + using namespace std::placeholders; + + std::weak_ptr<Plugin> ptr(plugin); + + plugin->onTimerSignal.connect(std::bind(&PluginService::handleTimerSignal, this, ptr, _1)); + plugin->onTimerEnd.connect(std::bind(&PluginService::handleTimerEnd, this, ptr, _1)); + + // Store reference to irccd. + duk::putGlobal(plugin->context(), "\xff""\xff""irccd", duk::RawPointer<Irccd>{&m_irccd}); + + // Initial load now. + try { + plugin->onLoad(); + m_plugins.push_back(std::move(plugin)); + } catch (const std::exception &ex) { + log::warning("plugin {}: {}"_format(plugin->name(), ex.what())); + } +} + +void PluginService::load(std::string name, const std::string &source, bool find) +{ + // TODO: change with Plugin::find + auto it = std::find_if(m_plugins.begin(), m_plugins.end(), [&] (const auto &plugin) { + return plugin->name() == name; + }); + + if (it != m_plugins.end()) { + throw std::invalid_argument("plugin already loaded"); + } + + std::vector<std::string> paths; + std::shared_ptr<Plugin> plugin; + + if (find) { + for (const std::string &dir : path::list(path::PathPlugins)) { + paths.push_back(dir + source + ".js"); + } + } else { + paths.push_back(source); + } + + // Iterate over all paths. + log::info("plugin {}: trying to load:"_format(name)); + + for (const auto &path : paths) { + log::info() << " from " << path << std::endl; + + try { + plugin = std::make_shared<Plugin>(name, path /*, m_pluginConf[name] */); + break; + } catch (const std::exception &ex) { + log::info(fmt::format(" error: {}", ex.what())); + } + } + + if (plugin) { + add(std::move(plugin)); + } else { + throw std::runtime_error("no suitable plugin found"); + } +} + +void PluginService::reload(const std::string &name) +{ + auto plugin = get(name); + + if (plugin) { + plugin->onReload(); + } +} + +void PluginService::unload(const std::string &name) +{ + auto it = std::find_if(m_plugins.begin(), m_plugins.end(), [&] (const auto &plugin) { + return plugin->name() == name; + }); + + if (it != m_plugins.end()) { + (*it)->onUnload(); + m_plugins.erase(it); + } +} + +void PluginService::handleTimerSignal(std::weak_ptr<Plugin> ptr, std::shared_ptr<Timer> timer) +{ + m_irccd.post([this, ptr, timer] (Irccd &) { + auto plugin = ptr.lock(); + + if (!plugin) { + return; + } + + auto &ctx = plugin->context(); + + duk::StackAssert sa(ctx); + + // TODO: improve this + try { + duk::getGlobal<void>(ctx, "\xff""\xff""timer-" + std::to_string(reinterpret_cast<std::intptr_t>(timer.get()))); + duk::pcall(ctx, 0); + duk::pop(ctx); + } catch (const std::exception &) { + } + }); +} + +void PluginService::handleTimerEnd(std::weak_ptr<Plugin> ptr, std::shared_ptr<Timer> timer) +{ + m_irccd.post([this, ptr, timer] (Irccd &) { + auto plugin = ptr.lock(); + + if (plugin) { + log::debug() << "timer: finished, removing from plugin `" << plugin->name() << "'" << std::endl; + plugin->removeTimer(timer); + } + }); +} + +} // !irccd
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/service-plugin.hpp Wed May 11 13:58:42 2016 +0200 @@ -0,0 +1,128 @@ +/* + * service-plugin.hpp -- manage plugins + * + * Copyright (c) 2013-2016 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_SERVICE_PLUGIN_HPP +#define IRCCD_SERVICE_PLUGIN_HPP + +/** + * \file service-plugin.hpp + * \brief Manage plugins. + */ + +#include <memory> +#include <vector> + +namespace irccd { + +class Irccd; +class Plugin; +class Timer; + +/** + * \brief Manage plugins. + */ +class PluginService { +private: + Irccd &m_irccd; + std::vector<std::shared_ptr<Plugin>> m_plugins; + + // TODO: get rid of this with future JavaScript modules. + void handleTimerSignal(std::weak_ptr<Plugin>, std::shared_ptr<Timer>); + void handleTimerEnd(std::weak_ptr<Plugin>, std::shared_ptr<Timer>); + +public: + /** + * Create the plugin service. + * + * \param irccd the irccd instance + */ + PluginService(Irccd &irccd) noexcept; + + /** + * Get the list of plugins. + * + * \return the list of plugins + */ + inline const std::vector<std::shared_ptr<Plugin>> &plugins() const noexcept + { + return m_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 plugin or empty one 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 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 a loaded plugin. + * + * Plugins signals will be connected to the irccd main loop. The onLoad function will also be called and the + * plugin is not added on errors. + * + * \pre plugin must not be empty + * \param plugin the plugin + */ + void add(std::shared_ptr<Plugin> plugin); + + /** + * Load a plugin by path or by searching through directories. + * + * \param source the path or the plugin id to search + * \param find set to true for searching by id + */ + void load(std::string name, const std::string &source, bool find); + + /** + * 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); +}; + +} // !irccd + +#endif // !IRCCD_SERVICE_PLUGIN_HPP
--- a/lib/irccd/service-server.cpp Wed May 11 13:27:39 2016 +0200 +++ b/lib/irccd/service-server.cpp Wed May 11 13:58:42 2016 +0200 @@ -22,6 +22,7 @@ #include "irccd.hpp" #include "logger.hpp" +#include "plugin.hpp" #include "server.hpp" #include "server-event.hpp" #include "service-server.hpp"
--- a/tests/js-timer/main.cpp Wed May 11 13:27:39 2016 +0200 +++ b/tests/js-timer/main.cpp Wed May 11 13:58:42 2016 +0200 @@ -21,6 +21,8 @@ #include <irccd/elapsed-timer.hpp> #include <irccd/irccd.hpp> #include <irccd/logger.hpp> +#include <irccd/plugin.hpp> +#include <irccd/service-plugin.hpp> #include <irccd/system.hpp> using namespace irccd; @@ -32,7 +34,7 @@ auto plugin = std::make_shared<Plugin>("timer", IRCCD_TESTS_DIRECTORY "/timer-single.js"); - irccd.addPlugin(plugin); + irccd.pluginService().add(plugin); while (timer.elapsed() < 3000) { irccd.poll(); @@ -49,7 +51,7 @@ auto plugin = std::make_shared<Plugin>("timer", IRCCD_TESTS_DIRECTORY "/timer-repeat.js"); - irccd.addPlugin(plugin); + irccd.pluginService().add(plugin); while (timer.elapsed() < 3000) { irccd.poll();