changeset 212:b224b85a6ebf

Irccd: change the way JavaScript plugin configuration is accessed When user assign a new table to the Irccd.Plugin.config or format property, we need to merge the old table with the new one so accessing them will give a union of all properties. Thus, using irccdctl plugin-config will return both plugin variables and user variables.
author David Demelier <markand@malikania.fr>
date Thu, 23 Jun 2016 07:35:41 +0200
parents c8c831d9f4bf
children 68831a43b1ab
files lib/irccd/mod-plugin.cpp lib/irccd/mod-plugin.hpp lib/irccd/plugin-js.cpp
diffstat 3 files changed, 143 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/lib/irccd/mod-plugin.cpp	Wed Jun 22 13:02:39 2016 +0200
+++ b/lib/irccd/mod-plugin.cpp	Thu Jun 23 07:35:41 2016 +0200
@@ -26,9 +26,12 @@
 
 namespace {
 
-const char *PluginGlobal("\xff""\xff""irccd-plugin-ptr");
+const char PluginGlobal[] = "\xff""\xff""irccd-plugin-ptr";
 
 /*
+ * wrap
+ * ------------------------------------------------------------------
+ *
  * Wrap function for these functions because they all takes the same arguments.
  *
  * - load,
@@ -52,6 +55,115 @@
 }
 
 /*
+ * set
+ * ------------------------------------------------------------------
+ *
+ * This setter is used to replace the Irccd.Plugin.(config|format) property when the plugin assign a new one.
+ *
+ * Because the plugin configuration always has higher priority, when a new object is assigned to 'config' or to the 'format' property,
+ * the plugin configuration is merged to the assigned one, adding or replacing any values.
+ *
+ * Example:
+ *
+ * Plugin 'xyz' does:
+ *
+ * Irccd.Plugin.config = {
+ *      mode: "simple",
+ *      level: "123"
+ * };
+ *
+ * The user configuration is:
+ *
+ * [plugin.xyz]
+ * mode = "hard"
+ * path = "/var"
+ *
+ * The final user table looks like this:
+ *
+ * Irccd.Plugin.config = {
+ *      mode: "hard",
+ *      level: "123",
+ *      path: "/var"
+ */
+duk_ret_t set(duk_context *ctx, const char *name)
+{
+    if (!duk_is_object(ctx, 0))
+        duk_error(ctx, DUK_ERR_TYPE_ERROR, "'%s' property must be object", name);
+
+    // Merge old table with new one.
+    duk_get_global_string(ctx, name);
+    duk_enum(ctx, -1, 0);
+
+    while (duk_next(ctx, -1, true))
+        duk_put_prop(ctx, 0);
+
+    // Pop enum and old table.
+    duk_pop_2(ctx);
+
+    // Replace the old table with the new assigned one.
+    duk_put_global_string(ctx, name);
+
+    return 0;
+}
+
+/*
+ * get
+ * ------------------------------------------------------------------
+ *
+ * Get the Irccd.Plugin.(config|format) property.
+ */
+duk_ret_t get(duk_context *ctx, const char *name)
+{
+    duk_get_global_string(ctx, name);
+
+    return 1;
+}
+
+/*
+ * setConfig
+ * ------------------------------------------------------------------
+ *
+ * Wrap setter for Irccd.Plugin.config property.
+ */
+duk_ret_t setConfig(duk_context *ctx)
+{
+    return set(ctx, PluginConfigProperty);
+}
+
+/*
+ * getConfig
+ * ------------------------------------------------------------------
+ *
+ * Wrap getter for Irccd.Plugin.config property.
+ */
+duk_ret_t getConfig(duk_context *ctx)
+{
+    return get(ctx, PluginConfigProperty);
+}
+
+/*
+ * setFormat
+ * ------------------------------------------------------------------
+ *
+ * Wrap setter for Irccd.Plugin.format property.
+ */
+duk_ret_t setFormat(duk_context *ctx)
+{
+    return set(ctx, PluginFormatProperty);
+}
+
+/*
+ * getFormat
+ * ------------------------------------------------------------------
+ *
+ * Wrap getter for Irccd.Plugin.format property.
+ */
+duk_ret_t getFormat(duk_context *ctx)
+{
+    return get(ctx, PluginFormatProperty);
+}
+
+/*
  * Function: Irccd.Plugin.info([name])
  * ------------------------------------------------------------------
  *
@@ -197,10 +309,19 @@
     duk_get_global_string(plugin->context(), "Irccd");
     duk_push_object(plugin->context());
     duk_put_function_list(plugin->context(), -1, functions);
-    duk_get_global_string(plugin->context(), "\xff""\xff""irccd-plugin-config");
-    duk_put_prop_string(plugin->context(), -2, "config");
-    duk_get_global_string(plugin->context(), "\xff""\xff""irccd-plugin-format");
-    duk_put_prop_string(plugin->context(), -2, "format");
+
+    // 'config' property.
+    duk_push_string(plugin->context(), "config");
+    duk_push_c_function(plugin->context(), getConfig, 0);
+    duk_push_c_function(plugin->context(), setConfig, 1);
+    duk_def_prop(plugin->context(), -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER);
+
+    // 'format' property.
+    duk_push_string(plugin->context(), "format");
+    duk_push_c_function(plugin->context(), getFormat, 0);
+    duk_push_c_function(plugin->context(), setFormat, 1);
+    duk_def_prop(plugin->context(), -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER);
+
     duk_put_prop_string(plugin->context(), -2, "Plugin");
     duk_pop(plugin->context());
 }
--- a/lib/irccd/mod-plugin.hpp	Wed Jun 22 13:02:39 2016 +0200
+++ b/lib/irccd/mod-plugin.hpp	Thu Jun 23 07:35:41 2016 +0200
@@ -30,6 +30,16 @@
 namespace irccd {
 
 /**
+ * Global property where to read/write plugin configuration.
+ */
+const char PluginConfigProperty[] = "\xff""\xff""irccd-plugin-config";
+
+/**
+ * Global property where to read/write plugin formats.
+ */
+const char PluginFormatProperty[] = "\xff""\xff""irccd-plugin-format";
+
+/**
  * \brief Irccd.Plugin JavaScript API.
  * \ingroup modules
  */
--- a/lib/irccd/plugin-js.cpp	Wed Jun 22 13:02:39 2016 +0200
+++ b/lib/irccd/plugin-js.cpp	Thu Jun 23 07:35:41 2016 +0200
@@ -27,6 +27,7 @@
 #include "fs.hpp"
 #include "irccd.hpp"
 #include "logger.hpp"
+#include "mod-plugin.hpp"
 #include "mod-server.hpp"
 #include "plugin-js.hpp"
 #include "service-module.hpp"
@@ -35,13 +36,6 @@
 
 namespace irccd {
 
-namespace {
-
-const char *ConfigGlobal("\xff""\xff""irccd-plugin-config");
-const char *FormatGlobal("\xff""\xff""irccd-plugin-format");
-
-} // !namespace
-
 std::unordered_map<std::string, std::string> JsPlugin::getTable(const char *name) const
 {
     StackAssert sa(m_context);
@@ -148,30 +142,29 @@
      * In mod-plugin.cpp.
      */
     duk_push_object(m_context);
-    duk_put_global_string(m_context, ConfigGlobal);
+    duk_put_global_string(m_context, PluginConfigProperty);
     duk_push_object(m_context);
-    duk_put_global_string(m_context, FormatGlobal);
+    duk_put_global_string(m_context, PluginFormatProperty);
 }
 
 PluginConfig JsPlugin::config()
 {
-    return getTable(ConfigGlobal);
+    return getTable(PluginConfigProperty);
 }
 
 void JsPlugin::setConfig(PluginConfig config)
 {
-    printf("%s\n", config["collaborative"].c_str());
-    putTable(ConfigGlobal, config);
+    putTable(PluginConfigProperty, config);
 }
 
 PluginFormats JsPlugin::formats()
 {
-    return getTable(FormatGlobal);
+    return getTable(PluginFormatProperty);
 }
 
 void JsPlugin::setFormats(PluginFormats formats)
 {
-    putTable(FormatGlobal, formats);
+    putTable(PluginFormatProperty, formats);
 }
 
 void JsPlugin::onChannelMode(Irccd &, const ChannelModeEvent &event)