Mercurial > irccd
changeset 131:77c90336ba56
Irccd: initial Plugin split, #501
author | David Demelier <markand@malikania.fr> |
---|---|
date | Thu, 12 May 2016 15:06:11 +0200 |
parents | 483c862b5a52 |
children | 105287c768ba |
files | lib/irccd/CMakeSources.cmake lib/irccd/config.cpp lib/irccd/js-timer.cpp lib/irccd/plugin-js.cpp lib/irccd/plugin-js.hpp lib/irccd/plugin.cpp lib/irccd/plugin.hpp lib/irccd/service-plugin.cpp lib/irccd/service-plugin.hpp tests/js-timer/main.cpp |
diffstat | 10 files changed, 1013 insertions(+), 562 deletions(-) [+] |
line wrap: on
line diff
--- a/lib/irccd/CMakeSources.cmake Wed May 11 21:09:10 2016 +0200 +++ b/lib/irccd/CMakeSources.cmake Thu May 12 15:06:11 2016 +0200 @@ -51,6 +51,7 @@ ${CMAKE_CURRENT_LIST_DIR}/options.hpp ${CMAKE_CURRENT_LIST_DIR}/path.hpp ${CMAKE_CURRENT_LIST_DIR}/plugin.hpp + ${CMAKE_CURRENT_LIST_DIR}/plugin-js.hpp ${CMAKE_CURRENT_LIST_DIR}/rule.hpp ${CMAKE_CURRENT_LIST_DIR}/server.hpp ${CMAKE_CURRENT_LIST_DIR}/server-event.hpp @@ -126,6 +127,7 @@ ${CMAKE_CURRENT_LIST_DIR}/options.cpp ${CMAKE_CURRENT_LIST_DIR}/path.cpp ${CMAKE_CURRENT_LIST_DIR}/plugin.cpp + ${CMAKE_CURRENT_LIST_DIR}/plugin-js.cpp ${CMAKE_CURRENT_LIST_DIR}/rule.cpp ${CMAKE_CURRENT_LIST_DIR}/server.cpp ${CMAKE_CURRENT_LIST_DIR}/server-event.cpp
--- a/lib/irccd/config.cpp Wed May 11 21:09:10 2016 +0200 +++ b/lib/irccd/config.cpp Thu May 12 15:06:11 2016 +0200 @@ -25,6 +25,7 @@ #include "irccd.hpp" #include "logger.hpp" #include "path.hpp" +#include "plugin-js.hpp" #include "rule.hpp" #include "server.hpp" #include "sysconfig.hpp" @@ -631,7 +632,7 @@ plugins.push_back(Plugin::find(name, findPluginConfig(name))); } else { log::info("plugin {}: trying {}"_format(name, path)); - plugins.push_back(std::make_shared<Plugin>(name, path, findPluginConfig(name))); + plugins.push_back(std::make_shared<JsPlugin>(name, path, findPluginConfig(name))); } } catch (const duk::ErrorInfo &ex) { log::warning("plugin {}: {}"_format(option.key(), ex.what()));
--- a/lib/irccd/js-timer.cpp Wed May 11 21:09:10 2016 +0200 +++ b/lib/irccd/js-timer.cpp Thu May 12 15:06:11 2016 +0200 @@ -20,7 +20,7 @@ #include <cstdint> #include "js.hpp" -#include "plugin.hpp" +#include "plugin-js.hpp" namespace irccd { @@ -107,7 +107,7 @@ auto timer = std::make_shared<Timer>(static_cast<TimerType>(type), delay); /* Add this timer to the underlying plugin */ - duk::getGlobal<duk::RawPointer<Plugin>>(ctx, "\xff""\xff""plugin")->addTimer(timer); + duk::getGlobal<duk::RawPointer<JsPlugin>>(ctx, "\xff""\xff""plugin")->addTimer(timer); /* Construct object */ duk::construct(ctx, duk::Shared<Timer>{timer});
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/plugin-js.cpp Thu May 12 15:06:11 2016 +0200 @@ -0,0 +1,495 @@ +/* + * plugin-js.cpp -- JavaScript plugins for irccd + * + * 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 "sysconfig.hpp" + +#if defined(HAVE_STAT) +# include <sys/stat.h> +# include <cerrno> +# include <cstring> +#endif + +#include "fs.hpp" +#include "js-directory.hpp" +#include "js-elapsed-timer.hpp" +#include "js-file.hpp" +#include "js-irccd.hpp" +#include "js-logger.hpp" +#include "js-plugin.hpp" +#include "js-server.hpp" +#include "js-system.hpp" +#include "js-timer.hpp" +#include "js-unicode.hpp" +#include "js-util.hpp" +#include "logger.hpp" +#include "plugin-js.hpp" + +namespace irccd { + +void JsPlugin::call(const std::string &name, unsigned nargs) +{ + duk::getGlobal<void>(m_context, name); + + if (duk::type(m_context, -1) == DUK_TYPE_UNDEFINED) { + /* Function not defined, remove the undefined value and all arguments */ + duk::pop(m_context, nargs + 1); + } else { + /* Call the function and discard the result */ + duk::insert(m_context, -nargs - 1); + + if (duk::pcall(m_context, nargs) != 0) { + auto error = duk::error(m_context, -1); + + duk::pop(m_context); + + throw error; + } else { + duk::pop(m_context); + } + } +} + +void JsPlugin::putVars() +{ + duk::StackAssert sa(m_context); + + /* Save a reference to this */ + duk::putGlobal(m_context, "\xff""\xff""plugin", duk::RawPointer<JsPlugin>{this}); + duk::putGlobal(m_context, "\xff""\xff""name", name()); + duk::putGlobal(m_context, "\xff""\xff""path", path()); +} + +void JsPlugin::putPath(const std::string &varname, const std::string &append, path::Path type) +{ + duk::StackAssert sa(m_context); + + bool found = true; + std::string foundpath; + + /* + * Use the first existing directory available. + */ + for (const std::string &p : path::list(type)) { + foundpath = path::clean(p + append); + + if (fs::exists(foundpath)) { + found = true; + break; + } + } + + /* Use the system as default */ + if (!found) { + foundpath = path::clean(path::get(type, path::OwnerSystem) + append); + } + + duk::getGlobal<void>(m_context, "Irccd"); + duk::getProperty<void>(m_context, -1, "Plugin"); + duk::putProperty(m_context, -1, varname, foundpath); + duk::pop(m_context, 2); +} + +void JsPlugin::putPaths() +{ + duk::StackAssert sa(m_context); + + /* + * dataPath: DATA + plugin/name (e.g ~/.local/share/irccd/plugins/<name>/) + * configPath: CONFIG + plugin/name (e.g ~/.config/irccd/plugin/<name>/) + */ + putPath("dataPath", "plugin/" + name(), path::PathData); + putPath("configPath", "plugin/" + name(), path::PathConfig); + putPath("cachePath", "plugin/" + name(), path::PathCache); +} + +void JsPlugin::putConfig(const PluginConfig &config) +{ + duk::StackAssert sa(m_context); + + // TODO: override dataPath, configPath, cachePath + + /* Store plugin configuration into Irccd.Plugin.config */ + duk::getGlobal<void>(m_context, "Irccd"); + duk::getProperty<void>(m_context, -1, "Plugin"); + duk::getProperty<void>(m_context, -1, "config"); + + if (duk::type(m_context, -1) != DUK_TYPE_OBJECT) { + duk::pop(m_context); + duk::push(m_context, duk::Object{}); + } + + for (const auto &pair : config) { + duk::putProperty(m_context, -1, pair.first, pair.second); + } + + duk::putProperty(m_context, -2, "config"); + duk::pop(m_context, 2); +} + +JsPlugin::JsPlugin(std::string name, std::string path, const PluginConfig &config) + : Plugin(name, path, config) +{ + duk::StackAssert sa(m_context); + + /* + * Duktape currently emit useless warnings when a file do + * not exists so we do a homemade access. + */ +#if defined(HAVE_STAT) + struct stat st; + + if (::stat(path.c_str(), &st) < 0) { + throw std::runtime_error(std::strerror(errno)); + } +#endif + + // TODO: change with future modules + // Load standard irccd API. + loadJsIrccd(m_context); + loadJsDirectory(m_context); + loadJsElapsedTimer(m_context); + loadJsFile(m_context); + loadJsLogger(m_context); + loadJsPlugin(m_context); + loadJsServer(m_context); + loadJsSystem(m_context); + loadJsTimer(m_context); + loadJsUnicode(m_context); + loadJsUtil(m_context); + + putVars(); + putPaths(); + + /* Try to load the file (does not call onLoad yet) */ + if (duk::pevalFile(m_context, path) != 0) { + throw duk::error(m_context, -1); + } + + duk::pop(m_context); + + /* Initialize user defined options after loading to allow the plugin to define default values */ + putConfig(config); + + /* Read metadata */ + duk::getGlobal<void>(m_context, "info"); + + if (duk::type(m_context, -1) == DUK_TYPE_OBJECT) { + setAuthor(duk::optionalProperty<std::string>(m_context, -1, "author", author())); + setLicense(duk::optionalProperty<std::string>(m_context, -1, "license", license())); + setSummary(duk::optionalProperty<std::string>(m_context, -1, "summary", summary())); + setVersion(duk::optionalProperty<std::string>(m_context, -1, "version", version())); + } + + duk::pop(m_context); + + log::debug() << "plugin " << name << ": " << std::endl; + log::debug() << " author: " << author() << std::endl; + log::debug() << " license: " << license() << std::endl; + log::debug() << " summary: " << summary() << std::endl; + log::debug() << " version: " << version() << std::endl; +} + +JsPlugin::~JsPlugin() +{ + for (auto &timer : m_timers) { + timer->stop(); + } +} + +void JsPlugin::addTimer(std::shared_ptr<Timer> timer) noexcept +{ + std::weak_ptr<Timer> ptr(timer); + + /* + * These signals are called from the Timer thread and are transmitted to irccd so that it can + * calls appropriate timer functions. + */ + timer->onSignal.connect([this, ptr] () { + auto timer = ptr.lock(); + + if (timer) { + onTimerSignal(move(timer)); + } + }); + timer->onEnd.connect([this, ptr] () { + auto timer = ptr.lock(); + + if (timer) { + onTimerEnd(move(timer)); + } + }); + + m_timers.insert(move(timer)); +} + +void JsPlugin::removeTimer(const std::shared_ptr<Timer> &timer) noexcept +{ + duk::StackAssert sa(m_context); + + /* Remove the JavaScript function */ + duk::push(m_context, duk::Null{}); + duk::putGlobal(m_context, "\xff""\xff""timer-" + std::to_string(reinterpret_cast<std::intptr_t>(timer.get()))); + + /* Remove from list */ + m_timers.erase(timer); +} + +void JsPlugin::onChannelMode(const std::shared_ptr<Server> &server, + const std::string &origin, + const std::string &channel, + const std::string &mode, + const std::string &arg) +{ + duk::StackAssert sa(m_context); + + duk::push(m_context, duk::Shared<Server>{server}); + duk::push(m_context, origin); + duk::push(m_context, channel); + duk::push(m_context, mode); + duk::push(m_context, arg); + call("onChannelMode", 5); +} + +void JsPlugin::onChannelNotice(const std::shared_ptr<Server> &server, + const std::string &origin, + const std::string &channel, + const std::string ¬ice) +{ + duk::StackAssert sa(m_context); + + duk::push(m_context, duk::Shared<Server>{server}); + duk::push(m_context, origin); + duk::push(m_context, channel); + duk::push(m_context, notice); + call("onChannelNotice", 4); +} + +void JsPlugin::onCommand(const std::shared_ptr<Server> &server, + const std::string &origin, + const std::string &channel, + const std::string &message) +{ + duk::StackAssert sa(m_context); + + duk::push(m_context, duk::Shared<Server>{server}); + duk::push(m_context, origin); + duk::push(m_context, channel); + duk::push(m_context, message); + call("onCommand", 4); +} + +void JsPlugin::onConnect(const std::shared_ptr<Server> &server) +{ + duk::StackAssert sa(m_context); + + duk::push(m_context, duk::Shared<Server>{server}); + call("onConnect", 1); +} + +void JsPlugin::onInvite(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &channel) +{ + duk::StackAssert sa(m_context); + + duk::push(m_context, duk::Shared<Server>{server}); + duk::push(m_context, origin); + duk::push(m_context, channel); + call("onInvite", 3); +} + +void JsPlugin::onJoin(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &channel) +{ + duk::StackAssert sa(m_context); + + duk::push(m_context, duk::Shared<Server>{server}); + duk::push(m_context, origin); + duk::push(m_context, channel); + call("onJoin", 3); +} + +void JsPlugin::onKick(const std::shared_ptr<Server> &server, + const std::string &origin, + const std::string &channel, + const std::string &target, + const std::string &reason) +{ + duk::StackAssert sa(m_context); + + duk::push(m_context, duk::Shared<Server>{server}); + duk::push(m_context, origin); + duk::push(m_context, channel); + duk::push(m_context, target); + duk::push(m_context, reason); + call("onKick", 5); +} + +void JsPlugin::onLoad() +{ + duk::StackAssert sa(m_context); + + call("onLoad", 0); +} + +void JsPlugin::onMessage(const std::shared_ptr<Server> &server, + const std::string &origin, + const std::string &channel, + const std::string &message) +{ + duk::StackAssert sa(m_context); + + duk::push(m_context, duk::Shared<Server>{server}); + duk::push(m_context, origin); + duk::push(m_context, channel); + duk::push(m_context, message); + call("onMessage", 4); +} + +void JsPlugin::onMe(const std::shared_ptr<Server> &server, + const std::string &origin, + const std::string &channel, + const std::string &message) +{ + duk::StackAssert sa(m_context); + + duk::push(m_context, duk::Shared<Server>{server}); + duk::push(m_context, origin); + duk::push(m_context, channel); + duk::push(m_context, message); + call("onMe", 4); +} + +void JsPlugin::onMode(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &mode) +{ + duk::StackAssert sa(m_context); + + duk::push(m_context, duk::Shared<Server>{server}); + duk::push(m_context, origin); + duk::push(m_context, mode); + call("onMode", 3); +} + +void JsPlugin::onNames(const std::shared_ptr<Server> &server, const std::string &channel, const std::vector<std::string> &names) +{ + duk::StackAssert sa(m_context); + + duk::push(m_context, duk::Shared<Server>{server}); + duk::push(m_context, channel); + duk::push(m_context, names); + call("onNames", 3); +} + +void JsPlugin::onNick(const std::shared_ptr<Server> &server, const std::string &oldnick, const std::string &newnick) +{ + duk::StackAssert sa(m_context); + + duk::push(m_context, duk::Shared<Server>{server}); + duk::push(m_context, oldnick); + duk::push(m_context, newnick); + call("onNick", 3); +} + +void JsPlugin::onNotice(const std::shared_ptr<Server> &server, const std::string &origin, const std::string ¬ice) +{ + duk::StackAssert sa(m_context); + + duk::push(m_context, duk::Shared<Server>{server}); + duk::push(m_context, origin); + duk::push(m_context, notice); + call("onNotice", 3); +} + +void JsPlugin::onPart(const std::shared_ptr<Server> &server, + const std::string &origin, + const std::string &channel, + const std::string &reason) +{ + duk::StackAssert sa(m_context); + + duk::push(m_context, duk::Shared<Server>{server}); + duk::push(m_context, origin); + duk::push(m_context, channel); + duk::push(m_context, reason); + call("onPart", 4); +} + +void JsPlugin::onQuery(const std::shared_ptr<Server> &server, + const std::string &origin, + const std::string &message) +{ + duk::StackAssert sa(m_context); + + duk::push(m_context, duk::Shared<Server>{server}); + duk::push(m_context, origin); + duk::push(m_context, message); + call("onQuery", 3); +} + +void JsPlugin::onQueryCommand(const std::shared_ptr<Server> &server, + const std::string &origin, + const std::string &message) +{ + duk::StackAssert sa(m_context); + + duk::push(m_context, duk::Shared<Server>{server}); + duk::push(m_context, origin); + duk::push(m_context, message); + call("onQueryCommand", 3); +} + +void JsPlugin::onReload() +{ + duk::StackAssert sa(m_context); + + call("onReload"); +} + +void JsPlugin::onTopic(const std::shared_ptr<Server> &server, + const std::string &origin, + const std::string &channel, + const std::string &topic) +{ + duk::StackAssert sa(m_context); + + duk::push(m_context, duk::Shared<Server>{server}); + duk::push(m_context, origin); + duk::push(m_context, channel); + duk::push(m_context, topic); + call("onTopic", 4); +} + +void JsPlugin::onUnload() +{ + duk::StackAssert sa(m_context); + + call("onUnload"); +} + +void JsPlugin::onWhois(const std::shared_ptr<Server> &server, const ServerWhois &whois) +{ + duk::StackAssert sa(m_context); + + duk::push(m_context, duk::Shared<Server>{server}); + duk::push(m_context, duk::Object{}); + duk::putProperty(m_context, -1, "nickname", whois.nick); + duk::putProperty(m_context, -1, "username", whois.user); + duk::putProperty(m_context, -1, "realname", whois.realname); + duk::putProperty(m_context, -1, "host", whois.host); + duk::putProperty(m_context, 1, "channels", whois.channels); + call("onWhois", 2); +} + +} // !irccd
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/plugin-js.hpp Thu May 12 15:06:11 2016 +0200 @@ -0,0 +1,333 @@ +/* + * plugin-js.hpp -- JavaScript plugins for irccd + * + * 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_PLUGIN_JS_HPP +#define IRCCD_PLUGIN_JS_HPP + +/** + * \file plugin-hs.hpp + * \brief JavaScript plugins for irccd. + */ + +#include "plugin.hpp" + +namespace irccd { + +/** + * \brief Timers that a plugin owns. + */ +using PluginTimers = std::unordered_set<std::shared_ptr<Timer>>; + +/** + * \brief JavaScript plugins for irccd. + */ +class JsPlugin : public Plugin { +public: + // TODO: remove with future modules + + /** + * Signal: onTimerSignal + * ------------------------------------------------ + * + * When a timer expires. + * + * Arguments: + * - the timer object + */ + Signal<std::shared_ptr<Timer>> onTimerSignal; + + /** + * Signal: onTimerEnd + * ------------------------------------------------ + * + * When a timer is finished. + * + * Arguments: + * - the timer object + */ + Signal<std::shared_ptr<Timer>> onTimerEnd; + +private: + // JavaScript context + duk::Context m_context; + + // Plugin info and its timers + PluginTimers m_timers; + + // Private helpers + void call(const std::string &name, unsigned nargs = 0); + void putVars(); + void putPath(const std::string &varname, const std::string &append, path::Path type); + void putPaths(); + void putConfig(const PluginConfig &config); + +public: + /** + * Constructor. + * + * \param name the plugin name + * \param path the path to the plugin + * \param config the configuration + */ + JsPlugin(std::string name, std::string path, const PluginConfig &config = PluginConfig()); + + /** + * Close timers. + */ + ~JsPlugin(); + + /** + * Add a timer to the plugin. + * + * \param timer the timer to add + */ + void addTimer(std::shared_ptr<Timer> timer) noexcept; + + /** + * Remove a timer from a plugin. + * + * \param timer + */ + void removeTimer(const std::shared_ptr<Timer> &timer) noexcept; + + /** + * Access the Duktape context. + * + * \return the context + */ + inline duk::Context &context() noexcept + { + return m_context; + } + + /** + * On channel message. This event will call onMessage or + * onCommand if the messages starts with the command character + * plus the plugin name. + * + * \param server the server + * \param origin the user who sent the message + * \param channel the channel + * \param message the message or command + */ + void onCommand(const std::shared_ptr<Server> &server, + const std::string &origin, + const std::string &channel, + const std::string &message) override; + + /** + * On successful connection. + * + * \param server the server + */ + void onConnect(const std::shared_ptr<Server> &server) override; + + /** + * On channel mode. + * + * \param server the server + * \param origin the ouser who has changed the mode + * \param channel the channel + * \param mode the mode + * \param arg the optional mode argument + */ + void onChannelMode(const std::shared_ptr<Server> &server, + const std::string &origin, + const std::string &channel, + const std::string &mode, + const std::string &arg) override; + + /** + * On a channel notice. + * + * \param server the server + * \param origin the user who sent the notice + * \param channel on which channel + * \param notice the message + */ + void onChannelNotice(const std::shared_ptr<Server> &server, + const std::string &origin, + const std::string &channel, + const std::string ¬ice) override; + + /** + * On invitation. + * + * \param server the server + * \param origin the user who invited you + * \param channel the channel + */ + void onInvite(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &channel) override; + + /** + * On join. + * + * \param server the server + * \param origin the user who joined + * \param channel the channel + */ + void onJoin(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &channel) override; + + /** + * On kick. + * + * \param server the server + * \param origin the user who kicked the target + * \param channel the channel + * \param target the kicked target + * \param reason the optional reason + */ + void onKick(const std::shared_ptr<Server> &server, + const std::string &origin, + const std::string &channel, + const std::string &target, + const std::string &reason) override; + + /** + * On load. + */ + void onLoad() override; + + /** + * On channel message. + * + * \param server the server + * \param origin the user who sent the message + * \param channel the channel + * \param message the message or command + */ + void onMessage(const std::shared_ptr<Server> &server, + const std::string &origin, + const std::string &channel, + const std::string &message) override; + + /** + * On CTCP Action. + * + * \param server the server + * \param origin the user who sent the message + * \param channel the channel (may also be your nickname) + * \param message the message + */ + void onMe(const std::shared_ptr<Server> &server, + const std::string &origin, + const std::string &channel, + const std::string &message) override; + + /** + * On user mode change. + * + * \param server the server + * \param origin the person who changed the mode + * \param mode the new mode + */ + void onMode(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &mode) override; + + /** + * On names listing. + * + * \param server the server + * \param channel the channel + * \param list the list of nicknames + */ + void onNames(const std::shared_ptr<Server> &server, const std::string &channel, const std::vector<std::string> &list) override; + + /** + * On nick change. + * + * \param server the server + * \param origin the user that changed its nickname + * \param nick the new nickname + */ + void onNick(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &nick) override; + + /** + * On user notice. + * + * \param server the server + * \param origin the user who sent the notice + * \param notice the notice + */ + void onNotice(const std::shared_ptr<Server> &server, const std::string &origin, const std::string ¬ice) override; + + /** + * On part. + * + * \param server the server + * \param origin the user who left + * \param channel the channel + * \param reason the optional reason + */ + void onPart(const std::shared_ptr<Server> &server, + const std::string &origin, + const std::string &channel, + const std::string &reason) override; + + /** + * On user query. + * + * \param server the server + * \param origin the user who sent the query + * \param message the message + */ + void onQuery(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &message) override; + + /** + * On user query command. + * + * \param server the server + * \param origin the user who sent the query + * \param message the message + */ + void onQueryCommand(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &message) override; + + /** + * On reload. + */ + void onReload() override; + + /** + * On topic change. + * + * \param server the server + * \param origin the user who sent the topic + * \param channel the channel + * \param topic the new topic + */ + void onTopic(const std::shared_ptr<Server> &server, + const std::string &origin, + const std::string &channel, + const std::string &topic) override; + + /** + * On unload. + */ + void onUnload() override; + + /** + * On whois information. + * + * \param server the server + * \param info the info + */ + void onWhois(const std::shared_ptr<Server> &server, const ServerWhois &info) override; +}; + +} // !irccd + +#endif // !IRCCD_PLUGIN_JS_HPP
--- a/lib/irccd/plugin.cpp Wed May 11 21:09:10 2016 +0200 +++ b/lib/irccd/plugin.cpp Thu May 12 15:06:11 2016 +0200 @@ -20,29 +20,10 @@ #include <format.h> -#include "sysconfig.hpp" - -#if defined(HAVE_STAT) -# include <sys/stat.h> -# include <cerrno> -# include <cstring> -#endif - #include "fs.hpp" -#include "js-directory.hpp" -#include "js-elapsed-timer.hpp" -#include "js-file.hpp" -#include "js-irccd.hpp" -#include "js-logger.hpp" -#include "js-plugin.hpp" -#include "js-server.hpp" -#include "js-system.hpp" -#include "js-timer.hpp" -#include "js-unicode.hpp" -#include "js-util.hpp" #include "logger.hpp" #include "path.hpp" -#include "plugin.hpp" +#include "plugin-js.hpp" #include "server.hpp" #include "util.hpp" @@ -52,106 +33,6 @@ namespace irccd { -void Plugin::call(const std::string &name, unsigned nargs) -{ - duk::getGlobal<void>(m_context, name); - - if (duk::type(m_context, -1) == DUK_TYPE_UNDEFINED) { - /* Function not defined, remove the undefined value and all arguments */ - duk::pop(m_context, nargs + 1); - } else { - /* Call the function and discard the result */ - duk::insert(m_context, -nargs - 1); - - if (duk::pcall(m_context, nargs) != 0) { - auto error = duk::error(m_context, -1); - - duk::pop(m_context); - - throw error; - } else { - duk::pop(m_context); - } - } -} - -void Plugin::putVars() -{ - duk::StackAssert sa(m_context); - - /* Save a reference to this */ - duk::putGlobal(m_context, "\xff""\xff""plugin", duk::RawPointer<Plugin>{this}); - duk::putGlobal(m_context, "\xff""\xff""name", m_name); - duk::putGlobal(m_context, "\xff""\xff""path", m_path); -} - -void Plugin::putPath(const std::string &varname, const std::string &append, path::Path type) -{ - duk::StackAssert sa(m_context); - - bool found = true; - std::string foundpath; - - /* - * Use the first existing directory available. - */ - for (const std::string &p : path::list(type)) { - foundpath = path::clean(p + append); - - if (fs::exists(foundpath)) { - found = true; - break; - } - } - - /* Use the system as default */ - if (!found) { - foundpath = path::clean(path::get(type, path::OwnerSystem) + append); - } - - duk::getGlobal<void>(m_context, "Irccd"); - duk::getProperty<void>(m_context, -1, "Plugin"); - duk::putProperty(m_context, -1, varname, foundpath); - duk::pop(m_context, 2); -} - -void Plugin::putPaths() -{ - duk::StackAssert sa(m_context); - - /* - * dataPath: DATA + plugin/name (e.g ~/.local/share/irccd/plugins/<name>/) - * configPath: CONFIG + plugin/name (e.g ~/.config/irccd/plugin/<name>/) - */ - putPath("dataPath", "plugin/" + m_name, path::PathData); - putPath("configPath", "plugin/" + m_name, path::PathConfig); - putPath("cachePath", "plugin/" + m_name, path::PathCache); -} - -void Plugin::putConfig(const PluginConfig &config) -{ - duk::StackAssert sa(m_context); - - // TODO: override dataPath, configPath, cachePath - - /* Store plugin configuration into Irccd.Plugin.config */ - duk::getGlobal<void>(m_context, "Irccd"); - duk::getProperty<void>(m_context, -1, "Plugin"); - duk::getProperty<void>(m_context, -1, "config"); - - if (duk::type(m_context, -1) != DUK_TYPE_OBJECT) { - duk::pop(m_context); - duk::push(m_context, duk::Object{}); - } - - for (const auto &pair : config) { - duk::putProperty(m_context, -1, pair.first, pair.second); - } - - duk::putProperty(m_context, -2, "config"); - duk::pop(m_context, 2); -} - std::shared_ptr<Plugin> Plugin::find(const std::string &name, const PluginConfig &config) { log::info("plugin {}: searching {}.js"_format(name, name)); @@ -166,7 +47,7 @@ log::info("plugin {}: trying {}"_format(name, fullpath)); try { - return std::make_shared<Plugin>(name, fullpath, config); + return std::make_shared<JsPlugin>(name, fullpath, config); } catch (const std::exception &ex) { throw std::runtime_error("{}: {}"_format(fullpath, ex.what())); } @@ -175,343 +56,4 @@ throw std::runtime_error("no suitable plugin found"); } -Plugin::Plugin(std::string name, std::string path, const PluginConfig &config) - : m_name(std::move(name)) - , m_path(std::move(path)) -{ - duk::StackAssert sa(m_context); - - /* - * Duktape currently emit useless warnings when a file do - * not exists so we do a homemade access. - */ -#if defined(HAVE_STAT) - struct stat st; - - if (stat(m_path.c_str(), &st) < 0) { - throw std::runtime_error(std::strerror(errno)); - } -#endif - -#if 0 - // TODO: not enabled now - - /* - * Store the base path to the plugin, it is required for - * Duktape.modSearch to find external modules and other - * sources. - * - * If path is absolute, the parent is the directory name, otherwise - * we use the current working directory (needed for some tests). - */ - if (fs::isAbsolute(m_info.path)) { - m_info.parent = fs::dirName(m_info.path); - } else { - m_info.parent = fs::cwd(); - } -#endif - - /* Load standard irccd API */ - loadJsIrccd(m_context); - loadJsDirectory(m_context); - loadJsElapsedTimer(m_context); - loadJsFile(m_context); - loadJsLogger(m_context); - loadJsPlugin(m_context); - loadJsServer(m_context); - loadJsSystem(m_context); - loadJsTimer(m_context); - loadJsUnicode(m_context); - loadJsUtil(m_context); - - putVars(); - putPaths(); - - /* Try to load the file (does not call onLoad yet) */ - if (duk::pevalFile(m_context, m_path) != 0) { - throw duk::error(m_context, -1); - } - - duk::pop(m_context); - - /* Initialize user defined options after loading to allow the plugin to define default values */ - putConfig(config); - - /* Read metadata */ - duk::getGlobal<void>(m_context, "info"); - - if (duk::type(m_context, -1) == DUK_TYPE_OBJECT) { - m_author = duk::optionalProperty<std::string>(m_context, -1, "author", m_author); - m_license = duk::optionalProperty<std::string>(m_context, -1, "license", m_license); - m_summary = duk::optionalProperty<std::string>(m_context, -1, "summary", m_summary); - m_version = duk::optionalProperty<std::string>(m_context, -1, "version", m_version); - } - - duk::pop(m_context); - - log::debug() << "plugin " << m_name << ": " << std::endl; - log::debug() << " author: " << m_author << std::endl; - log::debug() << " license: " << m_license << std::endl; - log::debug() << " summary: " << m_summary << std::endl; - log::debug() << " version: " << m_version << std::endl; -} - -Plugin::~Plugin() -{ - for (auto &timer : m_timers) { - timer->stop(); - } -} - -void Plugin::addTimer(std::shared_ptr<Timer> timer) noexcept -{ - std::weak_ptr<Timer> ptr(timer); - - /* - * These signals are called from the Timer thread and are transmitted to irccd so that it can - * calls appropriate timer functions. - */ - timer->onSignal.connect([this, ptr] () { - auto timer = ptr.lock(); - - if (timer) { - onTimerSignal(move(timer)); - } - }); - timer->onEnd.connect([this, ptr] () { - auto timer = ptr.lock(); - - if (timer) { - onTimerEnd(move(timer)); - } - }); - - m_timers.insert(move(timer)); -} - -void Plugin::removeTimer(const std::shared_ptr<Timer> &timer) noexcept -{ - duk::StackAssert sa(m_context); - - /* Remove the JavaScript function */ - duk::push(m_context, duk::Null{}); - duk::putGlobal(m_context, "\xff""\xff""timer-" + std::to_string(reinterpret_cast<std::intptr_t>(timer.get()))); - - /* Remove from list */ - m_timers.erase(timer); -} - -void Plugin::onChannelMode(std::shared_ptr<Server> server, std::string origin, std::string channel, std::string mode, std::string arg) -{ - duk::StackAssert sa(m_context); - - duk::push(m_context, duk::Shared<Server>{server}); - duk::push(m_context, move(origin)); - duk::push(m_context, move(channel)); - duk::push(m_context, move(mode)); - duk::push(m_context, move(arg)); - call("onChannelMode", 5); -} - -void Plugin::onChannelNotice(std::shared_ptr<Server> server, std::string origin, std::string channel, std::string notice) -{ - duk::StackAssert sa(m_context); - - duk::push(m_context, duk::Shared<Server>{server}); - duk::push(m_context, move(origin)); - duk::push(m_context, move(channel)); - duk::push(m_context, move(notice)); - call("onChannelNotice", 4); -} - -void Plugin::onCommand(std::shared_ptr<Server> server, std::string origin, std::string channel, std::string message) -{ - duk::StackAssert sa(m_context); - - duk::push(m_context, duk::Shared<Server>{server}); - duk::push(m_context, move(origin)); - duk::push(m_context, move(channel)); - duk::push(m_context, move(message)); - call("onCommand", 4); -} - -void Plugin::onConnect(std::shared_ptr<Server> server) -{ - duk::StackAssert sa(m_context); - - duk::push(m_context, duk::Shared<Server>{server}); - call("onConnect", 1); -} - -void Plugin::onInvite(std::shared_ptr<Server> server, std::string origin, std::string channel) -{ - duk::StackAssert sa(m_context); - - duk::push(m_context, duk::Shared<Server>{server}); - duk::push(m_context, move(origin)); - duk::push(m_context, move(channel)); - call("onInvite", 3); -} - -void Plugin::onJoin(std::shared_ptr<Server> server, std::string origin, std::string channel) -{ - duk::StackAssert sa(m_context); - - duk::push(m_context, duk::Shared<Server>{server}); - duk::push(m_context, move(origin)); - duk::push(m_context, move(channel)); - call("onJoin", 3); -} - -void Plugin::onKick(std::shared_ptr<Server> server, std::string origin, std::string channel, std::string target, std::string reason) -{ - duk::StackAssert sa(m_context); - - duk::push(m_context, duk::Shared<Server>{server}); - duk::push(m_context, move(origin)); - duk::push(m_context, move(channel)); - duk::push(m_context, move(target)); - duk::push(m_context, move(reason)); - call("onKick", 5); -} - -void Plugin::onLoad() -{ - duk::StackAssert sa(m_context); - - call("onLoad", 0); -} - -void Plugin::onMessage(std::shared_ptr<Server> server, std::string origin, std::string channel, std::string message) -{ - duk::StackAssert sa(m_context); - - duk::push(m_context, duk::Shared<Server>{server}); - duk::push(m_context, move(origin)); - duk::push(m_context, move(channel)); - duk::push(m_context, move(message)); - call("onMessage", 4); -} - -void Plugin::onMe(std::shared_ptr<Server> server, std::string origin, std::string channel, std::string message) -{ - duk::StackAssert sa(m_context); - - duk::push(m_context, duk::Shared<Server>{server}); - duk::push(m_context, move(origin)); - duk::push(m_context, move(channel)); - duk::push(m_context, move(message)); - call("onMe", 4); -} - -void Plugin::onMode(std::shared_ptr<Server> server, std::string origin, std::string mode) -{ - duk::StackAssert sa(m_context); - - duk::push(m_context, duk::Shared<Server>{server}); - duk::push(m_context, move(origin)); - duk::push(m_context, move(mode)); - call("onMode", 3); -} - -void Plugin::onNames(std::shared_ptr<Server> server, std::string channel, std::vector<std::string> names) -{ - duk::StackAssert sa(m_context); - - duk::push(m_context, duk::Shared<Server>{server}); - duk::push(m_context, move(channel)); - duk::push(m_context, move(names)); - call("onNames", 3); -} - -void Plugin::onNick(std::shared_ptr<Server> server, std::string oldnick, std::string newnick) -{ - duk::StackAssert sa(m_context); - - duk::push(m_context, duk::Shared<Server>{server}); - duk::push(m_context, move(oldnick)); - duk::push(m_context, move(newnick)); - call("onNick", 3); -} - -void Plugin::onNotice(std::shared_ptr<Server> server, std::string origin, std::string notice) -{ - duk::StackAssert sa(m_context); - - duk::push(m_context, duk::Shared<Server>{server}); - duk::push(m_context, move(origin)); - duk::push(m_context, move(notice)); - call("onNotice", 3); -} - -void Plugin::onPart(std::shared_ptr<Server> server, std::string origin, std::string channel, std::string reason) -{ - duk::StackAssert sa(m_context); - - duk::push(m_context, duk::Shared<Server>{server}); - duk::push(m_context, move(origin)); - duk::push(m_context, move(channel)); - duk::push(m_context, move(reason)); - call("onPart", 4); -} - -void Plugin::onQuery(std::shared_ptr<Server> server, std::string origin, std::string message) -{ - duk::StackAssert sa(m_context); - - duk::push(m_context, duk::Shared<Server>{server}); - duk::push(m_context, move(origin)); - duk::push(m_context, move(message)); - call("onQuery", 3); -} - -void Plugin::onQueryCommand(std::shared_ptr<Server> server, std::string origin, std::string message) -{ - duk::StackAssert sa(m_context); - - duk::push(m_context, duk::Shared<Server>{server}); - duk::push(m_context, move(origin)); - duk::push(m_context, move(message)); - call("onQueryCommand", 3); -} - -void Plugin::onReload() -{ - duk::StackAssert sa(m_context); - - call("onReload"); -} - -void Plugin::onTopic(std::shared_ptr<Server> server, std::string origin, std::string channel, std::string topic) -{ - duk::StackAssert sa(m_context); - - duk::push(m_context, duk::Shared<Server>{server}); - duk::push(m_context, move(origin)); - duk::push(m_context, move(channel)); - duk::push(m_context, move(topic)); - call("onTopic", 4); -} - -void Plugin::onUnload() -{ - duk::StackAssert sa(m_context); - - call("onUnload"); -} - -void Plugin::onWhois(std::shared_ptr<Server> server, ServerWhois whois) -{ - duk::StackAssert sa(m_context); - - duk::push(m_context, duk::Shared<Server>{server}); - duk::push(m_context, duk::Object{}); - duk::putProperty(m_context, -1, "nickname", whois.nick); - duk::putProperty(m_context, -1, "username", whois.user); - duk::putProperty(m_context, -1, "realname", whois.realname); - duk::putProperty(m_context, -1, "host", whois.host); - duk::putProperty(m_context, 1, "channels", whois.channels); - call("onWhois", 2); -} - } // !irccd
--- a/lib/irccd/plugin.hpp Wed May 11 21:09:10 2016 +0200 +++ b/lib/irccd/plugin.hpp Thu May 12 15:06:11 2016 +0200 @@ -46,11 +46,6 @@ using PluginConfig = std::unordered_map<std::string, std::string>; /** - * Timers that a plugin owns. - */ -using PluginTimers = std::unordered_set<std::shared_ptr<Timer>>; - -/** * \class Plugin * \brief JavaScript plugin * @@ -58,29 +53,6 @@ * at runtime. */ class Plugin { -public: - /** - * Signal: onTimerSignal - * ------------------------------------------------ - * - * When a timer expires. - * - * Arguments: - * - the timer object - */ - Signal<std::shared_ptr<Timer>> onTimerSignal; - - /** - * Signal: onTimerEnd - * ------------------------------------------------ - * - * When a timer is finished. - * - * Arguments: - * - the timer object - */ - Signal<std::shared_ptr<Timer>> onTimerEnd; - private: // Plugin information std::string m_name; @@ -92,18 +64,7 @@ std::string m_summary{"unknown"}; std::string m_version{"unknown"}; - // JavaScript context - duk::Context m_context; - - // Plugin info and its timers - PluginTimers m_timers; - - // Private helpers - void call(const std::string &name, unsigned nargs = 0); - void putVars(); - void putPath(const std::string &varname, const std::string &append, path::Path type); - void putPaths(); - void putConfig(const PluginConfig &config); + PluginConfig m_config; public: /** @@ -122,12 +83,17 @@ * \param config the plugin configuration * \throws std::runtime_error on errors */ - Plugin(std::string name, std::string path, const PluginConfig &config = PluginConfig()); + inline Plugin(std::string name, std::string path, PluginConfig config = PluginConfig()) noexcept + : m_name(std::move(name)) + , m_path(std::move(path)) + , m_config(std::move(config)) + { + } /** * Temporary, close all timers. */ - ~Plugin(); + virtual ~Plugin() = default; /** * Get the plugin name. @@ -231,30 +197,6 @@ } /** - * Add a timer to the plugin. - * - * \param timer the timer to add - */ - void addTimer(std::shared_ptr<Timer> timer) noexcept; - - /** - * Remove a timer from a plugin. - * - * \param timer - */ - void removeTimer(const std::shared_ptr<Timer> &timer) noexcept; - - /** - * Access the Duktape context. - * - * \return the context - */ - inline duk::Context &context() noexcept - { - return m_context; - } - - /** * On channel message. This event will call onMessage or * onCommand if the messages starts with the command character * plus the plugin name. @@ -264,14 +206,26 @@ * \param channel the channel * \param message the message or command */ - void onCommand(std::shared_ptr<Server> server, std::string origin, std::string channel, std::string message); + virtual void onCommand(const std::shared_ptr<Server> &server, + const std::string &origin, + const std::string &channel, + const std::string &message) + { + (void)server; + (void)origin; + (void)channel; + (void)message; + } /** * On successful connection. * * \param server the server */ - void onConnect(std::shared_ptr<Server> server); + virtual void onConnect(const std::shared_ptr<Server> &server) + { + (void)server; + } /** * On channel mode. @@ -282,7 +236,18 @@ * \param mode the mode * \param arg the optional mode argument */ - void onChannelMode(std::shared_ptr<Server> server, std::string origin, std::string channel, std::string mode, std::string arg); + virtual void onChannelMode(const std::shared_ptr<Server> &server, + const std::string &origin, + const std::string &channel, + const std::string &mode, + const std::string &arg) + { + (void)server; + (void)origin; + (void)channel; + (void)mode; + (void)arg; + } /** * On a channel notice. @@ -292,7 +257,16 @@ * \param channel on which channel * \param notice the message */ - void onChannelNotice(std::shared_ptr<Server> server, std::string origin, std::string channel, std::string notice); + virtual void onChannelNotice(const std::shared_ptr<Server> &server, + const std::string &origin, + const std::string &channel, + const std::string ¬ice) + { + (void)server; + (void)origin; + (void)channel; + (void)notice; + } /** * On invitation. @@ -301,7 +275,12 @@ * \param origin the user who invited you * \param channel the channel */ - void onInvite(std::shared_ptr<Server> server, std::string origin, std::string channel); + virtual void onInvite(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &channel) + { + (void)server; + (void)origin; + (void)channel; + } /** * On join. @@ -310,7 +289,12 @@ * \param origin the user who joined * \param channel the channel */ - void onJoin(std::shared_ptr<Server> server, std::string origin, std::string channel); + virtual void onJoin(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &channel) + { + (void)server; + (void)origin; + (void)channel; + } /** * On kick. @@ -321,12 +305,25 @@ * \param target the kicked target * \param reason the optional reason */ - void onKick(std::shared_ptr<Server> server, std::string origin, std::string channel, std::string target, std::string reason); + virtual void onKick(const std::shared_ptr<Server> &server, + const std::string &origin, + const std::string &channel, + const std::string &target, + const std::string &reason) + { + (void)server; + (void)origin; + (void)channel; + (void)target; + (void)reason; + } /** * On load. */ - void onLoad(); + virtual void onLoad() + { + } /** * On channel message. @@ -336,7 +333,16 @@ * \param channel the channel * \param message the message or command */ - void onMessage(std::shared_ptr<Server> server, std::string origin, std::string channel, std::string message); + virtual void onMessage(const std::shared_ptr<Server> &server, + const std::string &origin, + const std::string &channel, + const std::string &message) + { + (void)server; + (void)origin; + (void)channel; + (void)message; + } /** * On CTCP Action. @@ -346,7 +352,16 @@ * \param channel the channel (may also be your nickname) * \param message the message */ - void onMe(std::shared_ptr<Server> server, std::string origin, std::string channel, std::string message); + virtual void onMe(const std::shared_ptr<Server> &server, + const std::string &origin, + const std::string &channel, + const std::string &message) + { + (void)server; + (void)origin; + (void)channel; + (void)message; + } /** * On user mode change. @@ -355,7 +370,12 @@ * \param origin the person who changed the mode * \param mode the new mode */ - void onMode(std::shared_ptr<Server> server, std::string origin, std::string mode); + virtual void onMode(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &mode) + { + (void)server; + (void)origin; + (void)mode; + } /** * On names listing. @@ -364,7 +384,12 @@ * \param channel the channel * \param list the list of nicknames */ - void onNames(std::shared_ptr<Server> server, std::string channel, std::vector<std::string> list); + virtual void onNames(const std::shared_ptr<Server> &server, const std::string &channel, const std::vector<std::string> &list) + { + (void)server; + (void)channel; + (void)list; + } /** * On nick change. @@ -373,7 +398,12 @@ * \param origin the user that changed its nickname * \param nick the new nickname */ - void onNick(std::shared_ptr<Server> server, std::string origin, std::string nick); + virtual void onNick(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &nick) + { + (void)server; + (void)origin; + (void)nick; + } /** * On user notice. @@ -382,7 +412,12 @@ * \param origin the user who sent the notice * \param notice the notice */ - void onNotice(std::shared_ptr<Server> server, std::string origin, std::string notice); + virtual void onNotice(const std::shared_ptr<Server> &server, const std::string &origin, const std::string ¬ice) + { + (void)server; + (void)origin; + (void)notice; + } /** * On part. @@ -392,7 +427,16 @@ * \param channel the channel * \param reason the optional reason */ - void onPart(std::shared_ptr<Server> server, std::string origin, std::string channel, std::string reason); + virtual void onPart(const std::shared_ptr<Server> &server, + const std::string &origin, + const std::string &channel, + const std::string &reason) + { + (void)server; + (void)origin; + (void)channel; + (void)reason; + } /** * On user query. @@ -401,7 +445,12 @@ * \param origin the user who sent the query * \param message the message */ - void onQuery(std::shared_ptr<Server> server, std::string origin, std::string message); + virtual void onQuery(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &message) + { + (void)server; + (void)origin; + (void)message; + } /** * On user query command. @@ -410,12 +459,19 @@ * \param origin the user who sent the query * \param message the message */ - void onQueryCommand(std::shared_ptr<Server> server, std::string origin, std::string message); + virtual void onQueryCommand(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &message) + { + (void)server; + (void)origin; + (void)message; + } /** * On reload. */ - void onReload(); + virtual void onReload() + { + } /** * On topic change. @@ -425,12 +481,23 @@ * \param channel the channel * \param topic the new topic */ - void onTopic(std::shared_ptr<Server> server, std::string origin, std::string channel, std::string topic); + virtual void onTopic(const std::shared_ptr<Server> &server, + const std::string &origin, + const std::string &channel, + const std::string &topic) + { + (void)server; + (void)origin; + (void)channel; + (void)topic; + } /** * On unload. */ - void onUnload(); + virtual void onUnload() + { + } /** * On whois information. @@ -438,7 +505,11 @@ * \param server the server * \param info the info */ - void onWhois(std::shared_ptr<Server> server, ServerWhois info); + virtual void onWhois(const std::shared_ptr<Server> &server, const ServerWhois &info) + { + (void)server; + (void)info; + } }; } // !irccd
--- a/lib/irccd/service-plugin.cpp Wed May 11 21:09:10 2016 +0200 +++ b/lib/irccd/service-plugin.cpp Thu May 12 15:06:11 2016 +0200 @@ -25,6 +25,7 @@ #include "irccd.hpp" #include "logger.hpp" #include "plugin.hpp" +#include "plugin-js.hpp" #include "service-plugin.hpp" using namespace fmt::literals; @@ -71,13 +72,18 @@ { using namespace std::placeholders; - std::weak_ptr<Plugin> ptr(plugin); + // TODO: REMOVE WHEN WE GET THE JAVASCRIPT MODULES + std::shared_ptr<JsPlugin> jsp = std::dynamic_pointer_cast<JsPlugin>(plugin); + + if (jsp) { + std::weak_ptr<JsPlugin> ptr(jsp); - plugin->onTimerSignal.connect(std::bind(&PluginService::handleTimerSignal, this, ptr, _1)); - plugin->onTimerEnd.connect(std::bind(&PluginService::handleTimerEnd, this, ptr, _1)); + jsp->onTimerSignal.connect(std::bind(&PluginService::handleTimerSignal, this, ptr, _1)); + jsp->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}); + // Store reference to irccd. + duk::putGlobal(jsp->context(), "\xff""\xff""irccd", duk::RawPointer<Irccd>{&m_irccd}); + } // Initial load now. try { @@ -152,7 +158,7 @@ } } -void PluginService::handleTimerSignal(std::weak_ptr<Plugin> ptr, std::shared_ptr<Timer> timer) +void PluginService::handleTimerSignal(std::weak_ptr<JsPlugin> ptr, std::shared_ptr<Timer> timer) { m_irccd.post([this, ptr, timer] (Irccd &) { auto plugin = ptr.lock(); @@ -175,7 +181,7 @@ }); } -void PluginService::handleTimerEnd(std::weak_ptr<Plugin> ptr, std::shared_ptr<Timer> timer) +void PluginService::handleTimerEnd(std::weak_ptr<JsPlugin> ptr, std::shared_ptr<Timer> timer) { m_irccd.post([this, ptr, timer] (Irccd &) { auto plugin = ptr.lock();
--- a/lib/irccd/service-plugin.hpp Wed May 11 21:09:10 2016 +0200 +++ b/lib/irccd/service-plugin.hpp Thu May 12 15:06:11 2016 +0200 @@ -31,6 +31,7 @@ class Irccd; class Plugin; +class JsPlugin; class Timer; /** @@ -42,8 +43,8 @@ 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>); + void handleTimerSignal(std::weak_ptr<JsPlugin>, std::shared_ptr<Timer>); + void handleTimerEnd(std::weak_ptr<JsPlugin>, std::shared_ptr<Timer>); public: /**
--- a/tests/js-timer/main.cpp Wed May 11 21:09:10 2016 +0200 +++ b/tests/js-timer/main.cpp Thu May 12 15:06:11 2016 +0200 @@ -21,7 +21,7 @@ #include <irccd/elapsed-timer.hpp> #include <irccd/irccd.hpp> #include <irccd/logger.hpp> -#include <irccd/plugin.hpp> +#include <irccd/plugin-js.hpp> #include <irccd/service-plugin.hpp> #include <irccd/system.hpp> @@ -32,7 +32,7 @@ Irccd irccd; ElapsedTimer timer; - auto plugin = std::make_shared<Plugin>("timer", IRCCD_TESTS_DIRECTORY "/timer-single.js"); + auto plugin = std::make_shared<JsPlugin>("timer", IRCCD_TESTS_DIRECTORY "/timer-single.js"); irccd.pluginService().add(plugin); @@ -49,7 +49,7 @@ Irccd irccd; ElapsedTimer timer; - auto plugin = std::make_shared<Plugin>("timer", IRCCD_TESTS_DIRECTORY "/timer-repeat.js"); + auto plugin = std::make_shared<JsPlugin>("timer", IRCCD_TESTS_DIRECTORY "/timer-repeat.js"); irccd.pluginService().add(plugin);