changeset 981:e4fc051e2d94

irccd: add brand new Irccd.Hook API
author David Demelier <markand@malikania.fr>
date Tue, 09 Feb 2021 21:15:51 +0100
parents 3afd375f308b
children 0e9e09941f5a
files CHANGES.md irccd/CMakeLists.txt irccd/js-plugin.c irccd/jsapi-chrono.c irccd/jsapi-hook.c irccd/jsapi-hook.h irccd/jsapi-irccd.c irccd/jsapi-logger.c irccd/jsapi-plugin.c irccd/jsapi-rule.c irccd/jsapi-system.c irccd/jsapi-timer.c irccd/jsapi-unicode.c lib/irccd/hook.c lib/irccd/server.c
diffstat 15 files changed, 196 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES.md	Tue Feb 09 21:34:00 2021 +0100
+++ b/CHANGES.md	Tue Feb 09 21:15:51 2021 +0100
@@ -35,6 +35,7 @@
 javascript API:
 
 - Brand new Irccd.Rule API to inspect and manage rules.
+- Brand new Irccd.Hook API to inspect and manage hooks.
 
 irccd 3.1.1 2021-01-04
 ----------------------
--- a/irccd/CMakeLists.txt	Tue Feb 09 21:34:00 2021 +0100
+++ b/irccd/CMakeLists.txt	Tue Feb 09 21:15:51 2021 +0100
@@ -39,6 +39,8 @@
 		${irccd_SOURCE_DIR}/jsapi-directory.h
 		${irccd_SOURCE_DIR}/jsapi-file.c
 		${irccd_SOURCE_DIR}/jsapi-file.h
+		${irccd_SOURCE_DIR}/jsapi-hook.c
+		${irccd_SOURCE_DIR}/jsapi-hook.h
 		${irccd_SOURCE_DIR}/jsapi-irccd.c
 		${irccd_SOURCE_DIR}/jsapi-irccd.h
 		${irccd_SOURCE_DIR}/jsapi-logger.c
--- a/irccd/js-plugin.c	Tue Feb 09 21:34:00 2021 +0100
+++ b/irccd/js-plugin.c	Tue Feb 09 21:15:51 2021 +0100
@@ -35,6 +35,7 @@
 #include "jsapi-chrono.h"
 #include "jsapi-directory.h"
 #include "jsapi-file.h"
+#include "jsapi-hook.h"
 #include "jsapi-irccd.h"
 #include "jsapi-logger.h"
 #include "jsapi-plugin.h"
@@ -452,6 +453,7 @@
 	jsapi_chrono_load(js->ctx);
 	jsapi_directory_load(js->ctx);
 	jsapi_file_load(js->ctx);
+	jsapi_hook_load(js->ctx);
 	jsapi_logger_load(js->ctx);
 	jsapi_plugin_load(js->ctx, &js->plugin);
 	jsapi_rule_load(js->ctx);
--- a/irccd/jsapi-chrono.c	Tue Feb 09 21:34:00 2021 +0100
+++ b/irccd/jsapi-chrono.c	Tue Feb 09 21:15:51 2021 +0100
@@ -16,6 +16,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <assert.h>
 #include <time.h>
 
 #include <duktape.h>
@@ -107,6 +108,8 @@
 void
 jsapi_chrono_load(duk_context *ctx)
 {
+	assert(ctx);
+
 	duk_get_global_string(ctx, "Irccd");
 	duk_push_c_function(ctx, Chrono_constructor, 0);
 	duk_push_object(ctx);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/irccd/jsapi-hook.c	Tue Feb 09 21:15:51 2021 +0100
@@ -0,0 +1,85 @@
+/*
+ * jsapi-hook.c -- Irccd.Hook API
+ *
+ * Copyright (c) 2013-2021 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 <assert.h>
+
+#include <irccd/hook.h>
+#include <irccd/irccd.h>
+
+#include "jsapi-hook.h"
+
+static int
+Hook_add(duk_context *ctx)
+{
+	const char *name = duk_require_string(ctx, 0);
+	const char *path = duk_require_string(ctx, 1);
+
+	if (irc_bot_hook_get(name))
+		return duk_error(ctx, DUK_ERR_ERROR, "hook %s already exists", name);
+
+	irc_bot_hook_add(irc_hook_new(name, path));
+
+	return 0;
+}
+
+static int
+Hook_list(duk_context *ctx)
+{
+	struct irc_hook *h;
+	size_t i = 0;
+
+	duk_push_array(ctx);
+
+	LIST_FOREACH(h, &irc.hooks, link) {
+		duk_push_object(ctx);
+		duk_push_string(ctx, h->name);
+		duk_put_prop_string(ctx, -2, "name");
+		duk_push_string(ctx, h->path);
+		duk_put_prop_string(ctx, -2, "path");
+		duk_put_prop_index(ctx, -2, i++);
+	}
+
+	return 1;
+}
+
+static int
+Hook_remove(duk_context *ctx)
+{
+	irc_bot_hook_remove(duk_require_string(ctx, 0));
+
+	return 0;
+}
+
+static const duk_function_list_entry functions[] = {
+	{ "add",        Hook_add,       2 },
+	{ "list",       Hook_list,      0 },
+	{ "remove",     Hook_remove,    1 },
+	{ NULL,         NULL,           0 }
+};
+
+void
+jsapi_hook_load(duk_context *ctx)
+{
+	assert(ctx);
+
+	duk_get_global_string(ctx, "Irccd");
+	duk_push_object(ctx);
+	duk_put_function_list(ctx, -1, functions);
+	duk_put_prop_string(ctx, -2, "Hook");
+	duk_pop(ctx);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/irccd/jsapi-hook.h	Tue Feb 09 21:15:51 2021 +0100
@@ -0,0 +1,27 @@
+/*
+ * jsapi-hook.h -- Irccd.Hook API
+ *
+ * Copyright (c) 2013-2021 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_JSAPI_HOOK_H
+#define IRCCD_JSAPI_HOOK_H
+
+#include <duktape.h>
+
+void
+jsapi_hook_load(duk_context *);
+
+#endif /* !IRCCD_JSAPI_HOOK_H */
--- a/irccd/jsapi-irccd.c	Tue Feb 09 21:34:00 2021 +0100
+++ b/irccd/jsapi-irccd.c	Tue Feb 09 21:15:51 2021 +0100
@@ -16,6 +16,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <assert.h>
 #include <errno.h>
 #include <string.h>
 
@@ -295,6 +296,8 @@
 void
 jsapi_load(duk_context *ctx)
 {
+	assert(ctx);
+
 	/* Irccd (global object) */
 	duk_push_object(ctx);
 
--- a/irccd/jsapi-logger.c	Tue Feb 09 21:34:00 2021 +0100
+++ b/irccd/jsapi-logger.c	Tue Feb 09 21:15:51 2021 +0100
@@ -16,6 +16,8 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <assert.h>
+
 #include <duktape.h>
 
 #include <irccd/plugin.h>
@@ -66,6 +68,8 @@
 void
 jsapi_logger_load(duk_context *ctx)
 {
+	assert(ctx);
+
 	duk_get_global_string(ctx, "Irccd");
 	duk_push_object(ctx);
 	duk_put_function_list(ctx, -1, functions);
--- a/irccd/jsapi-plugin.c	Tue Feb 09 21:34:00 2021 +0100
+++ b/irccd/jsapi-plugin.c	Tue Feb 09 21:15:51 2021 +0100
@@ -16,6 +16,8 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <assert.h>
+
 #include <irccd/irccd.h>
 #include <irccd/plugin.h>
 
@@ -214,6 +216,9 @@
 void
 jsapi_plugin_load(duk_context *ctx, struct irc_plugin *p)
 {
+	assert(ctx);
+	assert(p);
+
 	/* Store plugin. */
 	duk_push_pointer(ctx, p);
 	duk_put_global_string(ctx, SIGNATURE);
@@ -247,6 +252,8 @@
 struct irc_plugin *
 jsapi_plugin_self(duk_context *ctx)
 {
+	assert(ctx);
+
 	struct irc_plugin *p;
 
 	duk_get_global_string(ctx, SIGNATURE);
--- a/irccd/jsapi-rule.c	Tue Feb 09 21:34:00 2021 +0100
+++ b/irccd/jsapi-rule.c	Tue Feb 09 21:15:51 2021 +0100
@@ -18,6 +18,7 @@
 
 #include <compat.h>
 
+#include <assert.h>
 #include <string.h>
 
 #include <irccd/irccd.h>
@@ -153,6 +154,8 @@
 void
 jsapi_rule_load(duk_context *ctx)
 {
+	assert(ctx);
+
 	duk_get_global_string(ctx, "Irccd");
 	duk_push_object(ctx);
 	duk_put_number_list(ctx, -1, actions);
--- a/irccd/jsapi-system.c	Tue Feb 09 21:34:00 2021 +0100
+++ b/irccd/jsapi-system.c	Tue Feb 09 21:15:51 2021 +0100
@@ -16,6 +16,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <assert.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -229,6 +230,8 @@
 void
 jsapi_system_raise(duk_context *ctx)
 {
+	assert(ctx);
+
 	duk_get_global_string(ctx, "Irccd");
 	duk_get_prop_string(ctx, -1, "SystemError");
 	duk_remove(ctx, -2);
@@ -242,6 +245,8 @@
 void
 jsapi_system_load(duk_context *ctx)
 {
+	assert(ctx);
+
 	duk_get_global_string(ctx, "Irccd");
 	duk_push_object(ctx);
 	duk_put_function_list(ctx, -1, functions);
--- a/irccd/jsapi-timer.c	Tue Feb 09 21:34:00 2021 +0100
+++ b/irccd/jsapi-timer.c	Tue Feb 09 21:15:51 2021 +0100
@@ -16,6 +16,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <assert.h>
 #include <pthread.h>
 #include <stdatomic.h>
 #include <time.h>
@@ -308,6 +309,8 @@
 void
 jsapi_timer_load(duk_context *ctx)
 {
+	assert(ctx);
+
 	duk_get_global_string(ctx, "Irccd");
 	duk_push_c_function(ctx, Timer_constructor, 3);
 	duk_put_number_list(ctx, -1, constants);
--- a/irccd/jsapi-unicode.c	Tue Feb 09 21:34:00 2021 +0100
+++ b/irccd/jsapi-unicode.c	Tue Feb 09 21:15:51 2021 +0100
@@ -16,6 +16,8 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <assert.h>
+
 #include "jsapi-unicode.h"
 #include "unicode.h"
 
@@ -80,6 +82,8 @@
 void
 jsapi_unicode_load(duk_context *ctx)
 {
+	assert(ctx);
+
 	duk_get_global_string(ctx, "Irccd");
 	duk_push_object(ctx);
 	duk_put_function_list(ctx, -1, functions);
--- a/lib/irccd/hook.c	Tue Feb 09 21:34:00 2021 +0100
+++ b/lib/irccd/hook.c	Tue Feb 09 21:15:51 2021 +0100
@@ -129,6 +129,9 @@
 void
 irc_hook_invoke(struct irc_hook *h, const struct irc_event *ev)
 {
+	assert(h);
+	assert(ev);
+
 	char **args;
 	pid_t child;
 
@@ -142,6 +145,7 @@
 	case 0:
 		execv(h->path, args);
 		irc_log_warn("hook %s: %s", h->name, strerror(errno));
+		exit(1);
 		break;
 	default:
 		/* We wait for signal handler using SIGCHLD. */
@@ -154,5 +158,7 @@
 void
 irc_hook_finish(struct irc_hook *h)
 {
+	assert(h);
+
 	free(h);
 }
--- a/lib/irccd/server.c	Tue Feb 09 21:34:00 2021 +0100
+++ b/lib/irccd/server.c	Tue Feb 09 21:15:51 2021 +0100
@@ -42,6 +42,25 @@
 #define DELAY   30      /* Seconds to wait before reconnecting. */
 #define TIMEOUT 1800    /* Seconds before marking a server as dead. */
 
+static inline const char *
+statename(enum irc_server_state st)
+{
+	switch (st) {
+	case IRC_SERVER_STATE_NONE:
+		return "none";
+	case IRC_SERVER_STATE_DISCONNECTED:
+		return "disconnected";
+	case IRC_SERVER_STATE_CONNECTING:
+		return "connecting";
+	case IRC_SERVER_STATE_CONNECTED:
+		return "connected";
+	case IRC_SERVER_STATE_WAITING:
+		return "waiting";
+	default:
+		return "unknown";
+	}
+}
+
 static inline void
 clear_channels(struct irc_server *s, int free)
 {
@@ -181,10 +200,15 @@
 	clear_server(s);
 
 	if (s->flags & IRC_SERVER_FLAGS_AUTO_RECO) {
+		irc_log_debug("server %s: state %s -> %s", s->name,
+		    statename(s->state), statename(IRC_SERVER_STATE_WAITING));
 		irc_log_info("server %s: waiting %u seconds before reconnecting", s->name, DELAY);
 		s->state = IRC_SERVER_STATE_WAITING;
-	} else
+	} else {
+		irc_log_debug("server %s: state %s -> %s", s->name,
+		    statename(s->state), statename(IRC_SERVER_STATE_DISCONNECTED));
 		s->state = IRC_SERVER_STATE_DISCONNECTED;
+	}
 
 	/* Time point when we lose signal from the server. */
 	s->lost_tp = time(NULL);
@@ -201,6 +225,8 @@
 	LIST_FOREACH(ch, &s->channels, link)
 		irc_server_join(s, ch->name, ch->password);
 
+	irc_log_debug("server %s: state %s -> %s", s->name,
+	    statename(s->state), statename(IRC_SERVER_STATE_CONNECTED));
 	s->state = IRC_SERVER_STATE_CONNECTED;
 	ev->type = IRC_EVENT_CONNECT;
 
@@ -589,6 +615,9 @@
 static void
 auth(struct irc_server *s)
 {
+	irc_log_debug("server %s: state %s -> %s", s->name,
+	    statename(s->state), statename(IRC_SERVER_STATE_CONNECTED));
+
 	s->state = IRC_SERVER_STATE_CONNECTED;
 
 	if (s->ident.password[0])
@@ -645,8 +674,11 @@
 
 	if (irc_conn_connect(&s->conn) < 0)
 		fail(s);
-	else
+	else {
+		irc_log_debug("server %s: state %s -> %s", s->name,
+		    statename(s->state), statename(IRC_SERVER_STATE_CONNECTING));
 		s->state = IRC_SERVER_STATE_CONNECTING;
+	}
 
 	/*
 	 * Assume the last time we received a message was now, so that
@@ -661,6 +693,8 @@
 {
 	assert(s);
 
+	irc_log_debug("server %s: state %s -> %s", s->name,
+	    statename(s->state), statename(IRC_SERVER_STATE_DISCONNECTED));
 	s->state = IRC_SERVER_STATE_DISCONNECTED;
 
 	clear_channels(s, 0);
@@ -691,8 +725,10 @@
 		if (difftime(time(NULL), s->last_tp) >= TIMEOUT) {
 			irc_log_warn("server %s: no message in more than %u seconds", s->name, TIMEOUT);
 			fail(s);
-		} else if (irc_conn_flush(&s->conn, pfd) < 0)
+		} else if (irc_conn_flush(&s->conn, pfd) < 0) {
+			irc_log_warn("server %s: %s", s->name, strerror(errno));
 			return fail(s);
+		}
 		break;
 	case IRC_SERVER_STATE_CONNECTING:
 		/*
@@ -722,6 +758,8 @@
 	 * something else.
 	 */
 	if (s->state == IRC_SERVER_STATE_DISCONNECTED) {
+		irc_log_debug("server %s: state %s -> %s", s->name,
+		    statename(s->state), statename(IRC_SERVER_STATE_NONE));
 		handle_disconnect(s, ev);
 		s->state = IRC_SERVER_STATE_NONE;
 		return 1;