comparison libirccd-js/irccd/mod-plugin.cpp @ 292:671612cbc721

Irccd: split lib into libirccd-js, #564
author David Demelier <markand@malikania.fr>
date Wed, 05 Oct 2016 20:32:27 +0200
parents
children 45065955ba2d
comparison
equal deleted inserted replaced
291:b490853404d9 292:671612cbc721
1 /*
2 * js-plugin.cpp -- Irccd.Plugin API
3 *
4 * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include "irccd.hpp"
20 #include "plugin-js.hpp"
21 #include "service-plugin.hpp"
22 #include "mod-irccd.hpp"
23 #include "mod-plugin.hpp"
24
25 namespace irccd {
26
27 namespace {
28
29 const char PluginGlobal[] = "\xff""\xff""irccd-plugin-ptr";
30
31 /*
32 * wrap
33 * ------------------------------------------------------------------
34 *
35 * Wrap function for these functions because they all takes the same arguments.
36 *
37 * - load,
38 * - reload,
39 * - unload.
40 */
41 template <typename Func>
42 duk_idx_t wrap(duk_context *ctx, int nret, Func &&func)
43 {
44 std::string name = duk_require_string(ctx, 0);
45
46 try {
47 func(dukx_get_irccd(ctx), name);
48 } catch (const std::out_of_range &ex) {
49 dukx_throw(ctx, ReferenceError(ex.what()));
50 } catch (const std::exception &ex) {
51 dukx_throw(ctx, Error(ex.what()));
52 }
53
54 return nret;
55 }
56
57 /*
58 * set
59 * ------------------------------------------------------------------
60 *
61 * This setter is used to replace the Irccd.Plugin.(config|format) property when
62 * the plugin assign a new one.
63 *
64 * Because the plugin configuration always has higher priority, when a new
65 * object is assigned to 'config' or to the 'format' property, the plugin
66 * configuration is merged to the assigned one, adding or replacing any values.
67 *
68 * Example:
69 *
70 * Plugin 'xyz' does:
71 *
72 * Irccd.Plugin.config = {
73 * mode: "simple",
74 * level: "123"
75 * };
76 *
77 * The user configuration is:
78 *
79 * [plugin.xyz]
80 * mode = "hard"
81 * path = "/var"
82 *
83 * The final user table looks like this:
84 *
85 * Irccd.Plugin.config = {
86 * mode: "hard",
87 * level: "123",
88 * path: "/var"
89 */
90 duk_ret_t set(duk_context *ctx, const char *name)
91 {
92 if (!duk_is_object(ctx, 0))
93 duk_error(ctx, DUK_ERR_TYPE_ERROR, "'%s' property must be object", name);
94
95 // Merge old table with new one.
96 duk_get_global_string(ctx, name);
97 duk_enum(ctx, -1, 0);
98
99 while (duk_next(ctx, -1, true))
100 duk_put_prop(ctx, 0);
101
102 // Pop enum and old table.
103 duk_pop_2(ctx);
104
105 // Replace the old table with the new assigned one.
106 duk_put_global_string(ctx, name);
107
108 return 0;
109 }
110
111 /*
112 * get
113 * ------------------------------------------------------------------
114 *
115 * Get the Irccd.Plugin.(config|format) property.
116 */
117 duk_ret_t get(duk_context *ctx, const char *name)
118 {
119 duk_get_global_string(ctx, name);
120
121 return 1;
122 }
123
124 /*
125 * setConfig
126 * ------------------------------------------------------------------
127 *
128 * Wrap setter for Irccd.Plugin.config property.
129 */
130 duk_ret_t setConfig(duk_context *ctx)
131 {
132 return set(ctx, JsPlugin::ConfigProperty);
133 }
134
135 /*
136 * getConfig
137 * ------------------------------------------------------------------
138 *
139 * Wrap getter for Irccd.Plugin.config property.
140 */
141 duk_ret_t getConfig(duk_context *ctx)
142 {
143 return get(ctx, JsPlugin::ConfigProperty);
144 }
145
146 /*
147 * setFormat
148 * ------------------------------------------------------------------
149 *
150 * Wrap setter for Irccd.Plugin.format property.
151 */
152 duk_ret_t setFormat(duk_context *ctx)
153 {
154 return set(ctx, JsPlugin::FormatProperty);
155 }
156
157 /*
158 * getFormat
159 * ------------------------------------------------------------------
160 *
161 * Wrap getter for Irccd.Plugin.format property.
162 */
163 duk_ret_t getFormat(duk_context *ctx)
164 {
165 return get(ctx, JsPlugin::FormatProperty);
166 }
167
168 /*
169 * Function: Irccd.Plugin.info([name])
170 * ------------------------------------------------------------------
171 *
172 * Get information about a plugin.
173 *
174 * The returned object as the following properties:
175 *
176 * - name: (string) the plugin identifier,
177 * - author: (string) the author,
178 * - license: (string) the license,
179 * - summary: (string) a short description,
180 * - version: (string) the version
181 *
182 * Arguments:
183 * - name, the plugin identifier, if not specified the current plugin is
184 * selected.
185 * Returns:
186 * The plugin information or undefined if the plugin was not found.
187 */
188 duk_idx_t info(duk_context *ctx)
189 {
190 std::shared_ptr<Plugin> plugin;
191
192 if (duk_get_top(ctx) >= 1)
193 plugin = dukx_get_irccd(ctx).plugins().get(duk_require_string(ctx, 0));
194 else
195 plugin = dukx_get_plugin(ctx);
196
197 if (!plugin)
198 return 0;
199
200 duk_push_object(ctx);
201 dukx_push_std_string(ctx, plugin->name());
202 duk_put_prop_string(ctx, -2, "name");
203 dukx_push_std_string(ctx, plugin->author());
204 duk_put_prop_string(ctx, -2, "author");
205 dukx_push_std_string(ctx, plugin->license());
206 duk_put_prop_string(ctx, -2, "license");
207 dukx_push_std_string(ctx, plugin->summary());
208 duk_put_prop_string(ctx, -2, "summary");
209 dukx_push_std_string(ctx, plugin->version());
210 duk_put_prop_string(ctx, -2, "version");
211
212 return 1;
213 }
214
215 /*
216 * Function: Irccd.Plugin.list()
217 * ------------------------------------------------------------------
218 *
219 * Get the list of plugins, the array returned contains all plugin names.
220 *
221 * Returns:
222 * The list of all plugin names.
223 */
224 duk_idx_t list(duk_context *ctx)
225 {
226 dukx_push_array(ctx, dukx_get_irccd(ctx).plugins().list(), [] (auto ctx, auto plugin) {
227 dukx_push_std_string(ctx, plugin->name());
228 });
229
230 return 1;
231 }
232
233 /*
234 * Function: Irccd.Plugin.load(name)
235 * ------------------------------------------------------------------
236 *
237 * Load a plugin by name. This function will search through the standard
238 * directories.
239 *
240 * Arguments:
241 * - name, the plugin identifier.
242 * Throws:
243 * - Error on errors,
244 * - ReferenceError if the plugin was not found.
245 */
246 duk_idx_t load(duk_context *ctx)
247 {
248 return wrap(ctx, 0, [&] (Irccd &irccd, const std::string &name) {
249 irccd.plugins().load(name);
250 });
251 }
252
253 /*
254 * Function: Irccd.Plugin.reload(name)
255 * ------------------------------------------------------------------
256 *
257 * Reload a plugin by name.
258 *
259 * Arguments:
260 * - name, the plugin identifier.
261 * Throws:
262 * - Error on errors,
263 * - ReferenceError if the plugin was not found.
264 */
265 duk_idx_t reload(duk_context *ctx)
266 {
267 return wrap(ctx, 0, [&] (Irccd &irccd, const std::string &name) {
268 irccd.plugins().reload(name);
269 });
270 }
271
272 /*
273 * Function: Irccd.Plugin.unload(name)
274 * ------------------------------------------------------------------
275 *
276 * Unload a plugin by name.
277 *
278 * Arguments:
279 * - name, the plugin identifier.
280 * Throws:
281 * - Error on errors,
282 * - ReferenceError if the plugin was not found.
283 */
284 duk_idx_t unload(duk_context *ctx)
285 {
286 return wrap(ctx, 0, [&] (Irccd &irccd, const std::string &name) {
287 irccd.plugins().unload(name);
288 });
289 }
290
291 const duk_function_list_entry functions[] = {
292 { "info", info, DUK_VARARGS },
293 { "list", list, 0 },
294 { "load", load, 1 },
295 { "reload", reload, 1 },
296 { "unload", unload, 1 },
297 { nullptr, nullptr, 0 }
298 };
299
300 } // !namespace
301
302 PluginModule::PluginModule() noexcept
303 : Module("Irccd.Plugin")
304 {
305 }
306
307 void PluginModule::load(Irccd &, const std::shared_ptr<JsPlugin> &plugin)
308 {
309 StackAssert sa(plugin->context());
310
311 duk_push_pointer(plugin->context(), new std::shared_ptr<JsPlugin>(plugin));
312 duk_put_global_string(plugin->context(), PluginGlobal);
313 duk_get_global_string(plugin->context(), "Irccd");
314 duk_push_object(plugin->context());
315 duk_put_function_list(plugin->context(), -1, functions);
316
317 // 'config' property.
318 duk_push_string(plugin->context(), "config");
319 duk_push_c_function(plugin->context(), getConfig, 0);
320 duk_push_c_function(plugin->context(), setConfig, 1);
321 duk_def_prop(plugin->context(), -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER);
322
323 // 'format' property.
324 duk_push_string(plugin->context(), "format");
325 duk_push_c_function(plugin->context(), getFormat, 0);
326 duk_push_c_function(plugin->context(), setFormat, 1);
327 duk_def_prop(plugin->context(), -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER);
328
329 duk_put_prop_string(plugin->context(), -2, "Plugin");
330 duk_pop(plugin->context());
331 }
332
333 void PluginModule::unload(Irccd &, const std::shared_ptr<JsPlugin> &plugin)
334 {
335 StackAssert sa(plugin->context());
336
337 duk_push_global_object(plugin->context());
338 duk_get_prop_string(plugin->context(), -1, PluginGlobal);
339 delete static_cast<std::shared_ptr<JsPlugin> *>(duk_to_pointer(plugin->context(), -1));
340 duk_pop(plugin->context());
341 duk_del_prop_string(plugin->context(), -1, PluginGlobal);
342 duk_pop(plugin->context());
343 }
344
345 std::shared_ptr<JsPlugin> dukx_get_plugin(duk_context *ctx)
346 {
347 StackAssert sa(ctx);
348
349 duk_get_global_string(ctx, PluginGlobal);
350 auto plugin = static_cast<std::shared_ptr<JsPlugin> *>(duk_to_pointer(ctx, -1));
351 duk_pop(ctx);
352
353 return *plugin;
354 }
355
356 } // !irccd