changeset 106:8e7ddb14965e

Irccd: make ServerEvent a functor, #484
author David Demelier <markand@malikania.fr>
date Wed, 27 Apr 2016 07:36:42 +0200
parents 378fdc2c7b56
children 57a47f76c5e4
files lib/irccd/CMakeSources.cmake lib/irccd/irccd.cpp lib/irccd/irccd.hpp
diffstat 3 files changed, 143 insertions(+), 181 deletions(-) [+]
line wrap: on
line diff
--- a/lib/irccd/CMakeSources.cmake	Wed Apr 27 12:38:18 2016 +0200
+++ b/lib/irccd/CMakeSources.cmake	Wed Apr 27 07:36:42 2016 +0200
@@ -56,6 +56,7 @@
 	${CMAKE_CURRENT_LIST_DIR}/plugin.hpp
 	${CMAKE_CURRENT_LIST_DIR}/rule.hpp
 	${CMAKE_CURRENT_LIST_DIR}/server.hpp
+	${CMAKE_CURRENT_LIST_DIR}/server-event.hpp
 	${CMAKE_CURRENT_LIST_DIR}/server-private.hpp
 	${CMAKE_CURRENT_LIST_DIR}/server-state.hpp
 	${CMAKE_CURRENT_LIST_DIR}/server-state-connected.hpp
@@ -124,6 +125,7 @@
 	${CMAKE_CURRENT_LIST_DIR}/plugin.cpp
 	${CMAKE_CURRENT_LIST_DIR}/rule.cpp
 	${CMAKE_CURRENT_LIST_DIR}/server.cpp
+	${CMAKE_CURRENT_LIST_DIR}/server-event.cpp
 	${CMAKE_CURRENT_LIST_DIR}/server-state-connected.cpp
 	${CMAKE_CURRENT_LIST_DIR}/server-state-connecting.cpp
 	${CMAKE_CURRENT_LIST_DIR}/server-state-disconnected.cpp
--- a/lib/irccd/irccd.cpp	Wed Apr 27 12:38:18 2016 +0200
+++ b/lib/irccd/irccd.cpp	Wed Apr 27 07:36:42 2016 +0200
@@ -23,6 +23,7 @@
 #include "irccd.hpp"
 #include "logger.hpp"
 #include "path.hpp"
+#include "server-event.hpp"
 #include "util.hpp"
 
 using namespace std;
@@ -44,25 +45,25 @@
 	log::debug() << "  mode: " << mode << "\n";
 	log::debug() << "  argument: " << arg << std::endl;
 
-	json::Value json = json::object({
+	broadcast(json::object({
 		{ "event",	"onChannelMode"		},
 		{ "server",	server->info().name	},
 		{ "origin",	origin			},
 		{ "channel",	channel			},
 		{ "mode",	mode			},
 		{ "argument",	arg			}
-	});
+	}).toJson(0));
 
-	postServerEvent({server->info().name, origin, channel, json.toJson(0)
 #if defined(WITH_JS)
-		, [=] (Plugin &) -> std::string {
+	post(ServerEvent(server->info().name, origin, channel,
+		[=] (Plugin &) -> std::string {
 			return "onChannelMode";
-		}
-		, [=] (Plugin &plugin) {
+		},
+		[=] (Plugin &plugin) {
 			plugin.onChannelMode(std::move(server), std::move(origin), std::move(channel), std::move(mode), std::move(arg));
 		}
+	));
 #endif
-	});
 }
 
 void Irccd::handleServerChannelNotice(std::weak_ptr<Server> ptr, std::string origin, std::string channel, std::string message)
@@ -77,24 +78,24 @@
 	log::debug() << "  channel: " << channel << "\n";
 	log::debug() << "  message: " << message << std::endl;
 
-	json::Value json = json::object({
+	broadcast(json::object({
 		{ "event",	"onChannelNotice"	},
 		{ "server",	server->info().name	},
 		{ "origin",	origin			},
 		{ "channel",	channel			},
 		{ "message",	message			}
-	});
+	}).toJson(0));
 
-	postServerEvent({server->info().name, origin, channel, json.toJson(0)
 #if defined(WITH_JS)
-		, [=] (Plugin &) -> std::string {
+	post(ServerEvent(server->info().name, origin, channel,
+		[=] (Plugin &) -> std::string {
 			return "onChannelNotice";
-		}
-		, [=] (Plugin &plugin) {
+		},
+		[=] (Plugin &plugin) {
 			plugin.onChannelNotice(std::move(server), std::move(origin), std::move(channel), std::move(message));
 		}
+	));
 #endif
-	});
 }
 
 void Irccd::handleServerConnect(std::weak_ptr<Server> ptr)
@@ -106,21 +107,21 @@
 
 	log::debug() << "server " << server->info().name << ": event onConnect" << std::endl;
 
-	json::Value json = json::object({
+	broadcast(json::object({
 		{ "event",	"onConnect"		},
 		{ "server",	server->info().name	}
-	});
+	}).toJson(0));
 
-	postServerEvent({server->info().name, /* origin */ "", /* channel */ "", json.toJson(0)
 #if defined(WITH_JS)
-		, [=] (Plugin &) -> std::string {
+	post(ServerEvent(server->info().name, /* origin */ "", /* channel */ "",
+		[=] (Plugin &) -> std::string {
 			return "onConnect";
-		}
-		, [=] (Plugin &plugin) {
+		},
+		[=] (Plugin &plugin) {
 			plugin.onConnect(std::move(server));
 		}
+	));
 #endif
-	});
 }
 
 void Irccd::handleServerInvite(std::weak_ptr<Server> ptr, std::string origin, std::string channel, std::string target)
@@ -135,23 +136,23 @@
 	log::debug() << "  channel: " << channel << "\n";
 	log::debug() << "  target: " << target << std::endl;
 
-	json::Value json = json::object({
+	broadcast(json::object({
 		{ "event",	"onInvite"		},
 		{ "server",	server->info().name	},
 		{ "origin",	origin			},
 		{ "channel",	channel			}
-	});
+	}).toJson(0));
 
-	postServerEvent({server->info().name, origin, channel, json.toJson(0)
 #if defined(WITH_JS)
-		, [=] (Plugin &) -> std::string {
+	post(ServerEvent(server->info().name, origin, channel,
+		[=] (Plugin &) -> std::string {
 			return "onInvite";
-		}
-		, [=] (Plugin &plugin) {
+		},
+		[=] (Plugin &plugin) {
 			plugin.onInvite(std::move(server), std::move(origin), std::move(channel));
 		}
+	));
 #endif
-	});
 }
 
 void Irccd::handleServerJoin(std::weak_ptr<Server> ptr, std::string origin, std::string channel)
@@ -165,23 +166,23 @@
 	log::debug() << "  origin: " << origin << "\n";
 	log::debug() << "  channel: " << channel << std::endl;
 
-	json::Value json = json::object({
+	broadcast(json::object({
 		{ "event",	"onJoin"		},
 		{ "server",	server->info().name	},
 		{ "origin",	origin			},
 		{ "channel",	channel			}
-	});
+	}).toJson(0));
 
-	postServerEvent({server->info().name, origin, channel, json.toJson(0)
 #if defined(WITH_JS)
-		, [=] (Plugin &) -> std::string {
+	post(ServerEvent(server->info().name, origin, channel,
+		[=] (Plugin &) -> std::string {
 			return "onJoin";
-		}
-		, [=] (Plugin &plugin) {
+		},
+		[=] (Plugin &plugin) {
 			plugin.onJoin(std::move(server), std::move(origin), std::move(channel));
 		}
+	));
 #endif
-	});
 }
 
 void Irccd::handleServerKick(std::weak_ptr<Server> ptr, std::string origin, std::string channel, std::string target, std::string reason)
@@ -197,25 +198,25 @@
 	log::debug() << "  target: " << target << "\n";
 	log::debug() << "  reason: " << reason << std::endl;
 
-	json::Value json = json::object({
+	broadcast(json::object({
 		{ "event",	"onKick"		},
 		{ "server",	server->info().name	},
 		{ "origin",	origin			},
 		{ "channel",	channel			},
 		{ "target",	target			},
 		{ "reason",	reason			}
-	});
+	}).toJson(0));
 
-	postServerEvent({server->info().name, origin, channel, json.toJson(0)
 #if defined(WITH_JS)
-		, [=] (Plugin &) -> std::string {
+	post(ServerEvent(server->info().name, origin, channel,
+		[=] (Plugin &) -> std::string {
 			return "onKick";
-		}
-		, [=] (Plugin &plugin) {
+		},
+		[=] (Plugin &plugin) {
 			plugin.onKick(std::move(server), std::move(origin), std::move(channel), std::move(target), std::move(reason));
 		}
+	));
 #endif
-	});
 }
 
 void Irccd::handleServerMessage(std::weak_ptr<Server> ptr, std::string origin, std::string channel, std::string message)
@@ -230,20 +231,20 @@
 	log::debug() << "  channel: " << channel << "\n";
 	log::debug() << "  message: " << message << std::endl;
 
-	json::Value json = json::object({
+	broadcast(json::object({
 		{ "event",	"onMessage"		},
 		{ "server",	server->info().name	},
 		{ "origin",	origin			},
 		{ "channel",	channel			},
 		{ "message",	message			}
-	});
+	}).toJson(0));
 
-	postServerEvent({server->info().name, origin, channel, json.toJson(0)
 #if defined(WITH_JS)
-		, [=] (Plugin &plugin) -> std::string {
+	post(ServerEvent(server->info().name, origin, channel,
+		[=] (Plugin &plugin) -> std::string {
 			return util::parseMessage(message, server->settings().command, plugin.info().name).second == util::MessageType::Command ? "onCommand" : "onMessage";
-		}
-		, [=] (Plugin &plugin) {
+		},
+		[=] (Plugin &plugin) {
 			util::MessagePair pack = util::parseMessage(message, server->settings().command, plugin.info().name);
 
 			if (pack.second == util::MessageType::Command)
@@ -251,8 +252,8 @@
 			else
 				plugin.onMessage(std::move(server), std::move(origin), std::move(channel), std::move(pack.first));
 		}
+	));
 #endif
-	});
 }
 
 void Irccd::handleServerMe(std::weak_ptr<Server> ptr, std::string origin, std::string target, std::string message)
@@ -267,24 +268,24 @@
 	log::debug() << "  target: " << target << "\n";
 	log::debug() << "  message: " << message << std::endl;
 
-	json::Value json = json::object({
+	broadcast(json::object({
 		{ "event",	"onMe"			},
 		{ "server",	server->info().name	},
 		{ "origin",	origin			},
 		{ "target",	target			},
 		{ "message",	message			}
-	});
+	}).toJson(0));
 
-	postServerEvent({server->info().name, origin, target, json.toJson(0)
 #if defined(WITH_JS)
-		, [=] (Plugin &) -> std::string {
+	post(ServerEvent(server->info().name, origin, target,
+		[=] (Plugin &) -> std::string {
 			return "onMe";
-		}
-		, [=] (Plugin &plugin) {
+		},
+		[=] (Plugin &plugin) {
 			plugin.onMe(std::move(server), std::move(origin), std::move(target), std::move(message));
 		}
+	));
 #endif
-	});
 }
 
 void Irccd::handleServerMode(std::weak_ptr<Server> ptr, std::string origin, std::string mode)
@@ -298,23 +299,23 @@
 	log::debug() << "  origin: " << origin << "\n";
 	log::debug() << "  mode: " << mode << std::endl;
 
-	json::Value json = json::object({
+	broadcast(json::object({
 		{ "event",	"onMode"		},
 		{ "server",	server->info().name	},
 		{ "origin",	origin			},
 		{ "mode",	mode			}
-	});
+	}).toJson(0));
 
-	postServerEvent({server->info().name, origin, /* channel */ "", json.toJson(0)
 #if defined(WITH_JS)
-		, [=] (Plugin &) -> std::string {
+	post(ServerEvent(server->info().name, origin, /* channel */ "",
+		[=] (Plugin &) -> std::string {
 			return "onMode";
-		}
-		, [=] (Plugin &plugin) {
+		},
+		[=] (Plugin &plugin) {
 			plugin.onMode(std::move(server), std::move(origin), std::move(mode));
 		}
+	));
 #endif
-	});
 }
 
 void Irccd::handleServerNames(std::weak_ptr<Server> ptr, std::string channel, std::set<std::string> nicknames)
@@ -329,23 +330,24 @@
 	log::debug() << "  names: " << util::join(nicknames.begin(), nicknames.end(), ", ") << std::endl;
 
 	json::Value names(std::vector<json::Value>(nicknames.begin(), nicknames.end()));
-	json::Value json = json::object({
+
+	broadcast(json::object({
 		{ "event",	"onNames"		},
 		{ "server",	server->info().name	},
 		{ "channel",	channel			},
 		{ "names",	std::move(names)	}
-	});
+	}).toJson(0));
 
-	postServerEvent({server->info().name, /* origin */ "", channel, json.toJson(0)
 #if defined(WITH_JS)
-		, [=] (Plugin &) -> std::string {
+	post(ServerEvent(server->info().name, /* origin */ "", channel,
+		[=] (Plugin &) -> std::string {
 			return "onNames";
-		}
-		, [=] (Plugin &plugin) {
+		},
+		[=] (Plugin &plugin) {
 			plugin.onNames(std::move(server), std::move(channel), std::vector<std::string>(nicknames.begin(), nicknames.end()));
 		}
+	));
 #endif
-	});
 }
 
 void Irccd::handleServerNick(std::weak_ptr<Server> ptr, std::string origin, std::string nickname)
@@ -359,23 +361,23 @@
 	log::debug() << "  origin: " << origin << "\n";
 	log::debug() << "  nickname: " << nickname << std::endl;
 
-	json::Value json = json::object({
+	broadcast(json::object({
 		{ "event",	"onNick"		},
 		{ "server",	server->info().name	},
 		{ "origin",	origin			},
 		{ "nickname",	nickname		}
-	});
+	}).toJson(0));
 
-	postServerEvent({server->info().name, origin, /* channel */ "", json.toJson(0)
 #if defined(WITH_JS)
-		, [=] (Plugin &) -> std::string {
+	post(ServerEvent(server->info().name, origin, /* channel */ "",
+		[=] (Plugin &) -> std::string {
 			return "onNick";
-		}
-		, [=] (Plugin &plugin) {
+		},
+		[=] (Plugin &plugin) {
 			plugin.onNick(std::move(server), std::move(origin), std::move(nickname));
 		}
+	));
 #endif
-	});
 }
 
 void Irccd::handleServerNotice(std::weak_ptr<Server> ptr, std::string origin, std::string message)
@@ -389,23 +391,23 @@
 	log::debug() << "  origin: " << origin << "\n";
 	log::debug() << "  message: " << message << std::endl;
 
-	json::Value json = json::object({
+	broadcast(json::object({
 		{ "event",	"onNotice"		},
 		{ "server",	server->info().name	},
 		{ "origin",	origin			},
 		{ "message",	message			}
-	});
+	}).toJson(0));
 
-	postServerEvent({server->info().name, origin, /* channel */ "", json.toJson(0)
 #if defined(WITH_JS)
-		, [=] (Plugin &) -> std::string {
+	post(ServerEvent(server->info().name, origin, /* channel */ "",
+		[=] (Plugin &) -> std::string {
 			return "onNotice";
-		}
-		, [=] (Plugin &plugin) {
+		},
+		[=] (Plugin &plugin) {
 			plugin.onNotice(std::move(server), std::move(origin), std::move(message));
 		}
+	));
 #endif
-	});
 }
 
 void Irccd::handleServerPart(std::weak_ptr<Server> ptr, std::string origin, std::string channel, std::string reason)
@@ -420,24 +422,24 @@
 	log::debug() << "  channel: " << channel << "\n";
 	log::debug() << "  reason: " << reason << std::endl;
 
-	json::Value json = json::object({
+	broadcast(json::object({
 		{ "event",	"onPart"		},
 		{ "server",	server->info().name	},
 		{ "origin",	origin			},
 		{ "channel",	channel			},
 		{ "reason",	reason			}
-	});
+	}).toJson(0));
 
-	postServerEvent({server->info().name, origin, channel, json.toJson(0)
 #if defined(WITH_JS)
-		, [=] (Plugin &) -> std::string {
+	post(ServerEvent(server->info().name, origin, channel,
+		[=] (Plugin &) -> std::string {
 			return "onPart";
-		}
-		, [=] (Plugin &plugin) {
+		},
+		[=] (Plugin &plugin) {
 			plugin.onPart(std::move(server), std::move(origin), std::move(channel), std::move(reason));
 		}
+	));
 #endif
-	});
 }
 
 void Irccd::handleServerQuery(std::weak_ptr<Server> ptr, std::string origin, std::string message)
@@ -451,19 +453,19 @@
 	log::debug() << "  origin: " << origin << "\n";
 	log::debug() << "  message: " << message << std::endl;
 
-	json::Value json = json::object({
+	broadcast(json::object({
 		{ "event",	"onQuery"		},
 		{ "server",	server->info().name	},
 		{ "origin",	origin			},
 		{ "message",	message			}
-	});
+	}).toJson(0));
 
-	postServerEvent({server->info().name, origin, /* channel */ "", json.toJson(0)
 #if defined(WITH_JS)
-		, [=] (Plugin &plugin) -> std::string {
+	post(ServerEvent(server->info().name, origin, /* channel */ "",
+		[=] (Plugin &plugin) -> std::string {
 			return util::parseMessage(message, server->settings().command, plugin.info().name).second == util::MessageType::Command ? "onQueryCommand" : "onQuery";
-		}
-		, [=] (Plugin &plugin) {
+		},
+		[=] (Plugin &plugin) {
 			util::MessagePair pack = util::parseMessage(message, server->settings().command, plugin.info().name);
 
 			if (pack.second == util::MessageType::Command)
@@ -471,8 +473,8 @@
 			else
 				plugin.onQuery(std::move(server), std::move(origin), std::move(pack.first));
 		}
+	));
 #endif
-	});
 }
 
 void Irccd::handleServerTopic(std::weak_ptr<Server> ptr, std::string origin, std::string channel, std::string topic)
@@ -487,24 +489,24 @@
 	log::debug() << "  channel: " << channel << "\n";
 	log::debug() << "  topic: " << topic << std::endl;
 
-	json::Value json = json::object({
+	broadcast(json::object({
 		{ "event",	"onTopic"		},
 		{ "server",	server->info().name	},
 		{ "origin",	origin			},
 		{ "channel",	channel			},
 		{ "topic",	topic			}
-	});
+	}).toJson(0));
 
-	postServerEvent({server->info().name, origin, channel, json.toJson(0)
 #if defined(WITH_JS)
-		, [=] (Plugin &) -> std::string {
+	post(ServerEvent(server->info().name, origin, channel,
+		[=] (Plugin &) -> std::string {
 			return "onTopic";
-		}
-		, [=] (Plugin &plugin) {
+		},
+		[=] (Plugin &plugin) {
 			plugin.onTopic(std::move(server), std::move(origin), std::move(channel), std::move(topic));
 		}
+	));
 #endif
-	});
 }
 
 void Irccd::handleServerWhois(std::weak_ptr<Server> ptr, ServerWhois whois)
@@ -521,31 +523,31 @@
 	log::debug() << "  realname: " << whois.realname << "\n";
 	log::debug() << "  channels: " << util::join(whois.channels.begin(), whois.channels.end()) << std::endl;
 
-	json::Value object = json::object({
+	broadcast(json::object({
 		{ "server",	server->info().name	},
 		{ "nickname",	whois.nick		},
 		{ "username",	whois.user		},
 		{ "host",	whois.host		},
 		{ "realname",	whois.realname		}
-	});
+	}).toJson(0));
 
-	postServerEvent({server->info().name, /* origin */ "", /* channel */ "", object.toJson(-1)
 #if defined(WITH_JS)
-		, [=] (Plugin &) -> std::string {
+	post(ServerEvent(server->info().name, /* origin */ "", /* channel */ "",
+		[=] (Plugin &) -> std::string {
 			return "onWhois";
-		}
-		, [=] (Plugin &plugin) {
+		},
+		[=] (Plugin &plugin) {
 			plugin.onWhois(std::move(server), std::move(whois));
 		}
+	));
 #endif
-	});
 }
 
 void Irccd::handleTransportCommand(std::weak_ptr<TransportClient> ptr, const json::Value &object)
 {
 	assert(object.isObject());
 
-	post([=] () {
+	post([=] (Irccd &) {
 		/* 0. Be sure the object still exists */
 		auto tc = ptr.lock();
 
@@ -595,7 +597,7 @@
 
 void Irccd::handleTransportDie(std::weak_ptr<TransportClient> ptr)
 {
-	post([=] () {
+	post([=] (Irccd &) {
 		log::info() << "transport: client disconnected" << std::endl;
 
 		auto tc = ptr.lock();
@@ -680,40 +682,6 @@
 	processServers(setinput, setoutput);
 }
 
-void Irccd::postServerEvent(ServerEvent event) noexcept
-{
-#if defined(WITH_JS)
-	post([=] () {
-		for (auto &pair : m_plugins) {
-			auto name = event.name(*pair.second);
-			auto allowed = Rule::solve(m_rules, event.server, event.target, event.origin, pair.first, name);
-
-			if (!allowed) {
-				log::debug() << "rule: event skipped on match" << std::endl;
-				continue;
-			} else {
-				log::debug() << "rule: event allowed" << std::endl;
-			}
-
-			try {
-				event.exec(*pair.second);
-			} catch (const duk::ErrorInfo &info) {
-				log::warning() << "plugin " << pair.second->info().name << ": error: " << info.what() << std::endl;
-
-				if (!info.fileName.empty())
-					log::warning() << "    " << info.fileName << ":" << info.lineNumber << std::endl;
-				if (!info.stack.empty())
-					log::warning() << "    " << info.stack << std::endl;
-			}
-		}
-	});
-#endif
-
-	/* Asynchronous send */
-	for (auto &pair : m_lookupTransportClients)
-		pair.second->send(event.json);
-}
-
 Irccd::Irccd()
 {
 	/* Bind a socket to any port */
@@ -727,7 +695,7 @@
 	m_socketClient.set(net::option::SockBlockMode{false});
 }
 
-void Irccd::post(Event ev) noexcept
+void Irccd::post(std::function<void (Irccd &)> ev) noexcept
 {
 	std::lock_guard<mutex> lock(m_mutex);
 
@@ -763,7 +731,7 @@
 	server->onTopic.connect(std::bind(&Irccd::handleServerTopic, this, ptr, _1, _2, _3));
 	server->onWhois.connect(std::bind(&Irccd::handleServerWhois, this, ptr, _1));
 	server->onDie.connect([this, ptr] () {
-		post([=] () {
+		post([=] (Irccd &) {
 			auto server = ptr.lock();
 
 			if (server) {
@@ -819,6 +787,14 @@
 	m_lookupTransportServers.emplace(ts->handle(), ts);
 }
 
+void Irccd::broadcast(std::string data)
+{
+	/* Asynchronous send */
+	for (auto &pair : m_lookupTransportClients) {
+		pair.second->send(data);
+	}
+}
+
 #if defined(WITH_JS)
 
 std::shared_ptr<Plugin> Irccd::getPlugin(const std::string &name) const noexcept
@@ -925,7 +901,7 @@
 
 void Irccd::handleTimerSignal(std::weak_ptr<Plugin> ptr, std::shared_ptr<Timer> timer)
 {
-	post([this, ptr, timer] () {
+	post([this, ptr, timer] (Irccd &) {
 		auto plugin = ptr.lock();
 
 		if (!plugin)
@@ -947,7 +923,7 @@
 
 void Irccd::handleTimerEnd(std::weak_ptr<Plugin> ptr, std::shared_ptr<Timer> timer)
 {
-	post([this, ptr, timer] () {
+	post([this, ptr, timer] (Irccd &) {
 		auto plugin = ptr.lock();
 
 		if (plugin) {
@@ -1045,7 +1021,7 @@
 		log::debug() << "irccd: dispatching " << copy.size() << " event" << (copy.size() > 1 ? "s" : "") << endl;
 
 	for (auto &ev : copy)
-		ev();
+		ev(*this);
 }
 
 void Irccd::stop()
--- a/lib/irccd/irccd.hpp	Wed Apr 27 12:38:18 2016 +0200
+++ b/lib/irccd/irccd.hpp	Wed Apr 27 07:36:42 2016 +0200
@@ -47,13 +47,14 @@
 
 namespace irccd {
 
+class Irccd;
 class Plugin;
 class TransportCommand;
 
 /**
  * Event to execute after the poll.
  */
-using Event = std::function<void ()>;
+using Event = std::function<void (Irccd &)>;
 
 /**
  * List of events.
@@ -71,24 +72,6 @@
 using Rules = std::vector<Rule>;
 
 /**
- * \class ServerEvent
- * \brief Structure that owns several informations about an IRC event
- *
- * This structure is used to dispatch the IRC event to the plugins and the transports.
- */
-class ServerEvent {
-public:
-	std::string server;					//!< the server
-	std::string origin;					//!< the originator
-	std::string target;					//!< the target
-	std::string json;					//!< the JSON message
-#if defined(WITH_JS)
-	std::function<std::string (Plugin &)> name;		//!< the function to event name
-	std::function<void (Plugin &)> exec;			//!< the plugin function to call
-#endif
-};
-
-/**
  * Map of servers.
  */
 using Servers = std::unordered_map<std::string, std::shared_ptr<Server>>;
@@ -112,6 +95,8 @@
 
 #endif
 
+class ServerEvent;
+
 /**
  * \class Irccd
  * \brief Irccd main instance
@@ -241,15 +226,7 @@
 	 * \param ev the event
 	 * \note Thread-safe
 	 */
-	void post(Event ev) noexcept;
-
-	/**
-	 * This function wraps post() to iterate over all plugins to call the function and to send to all
-	 * connected transport the event.
-	 *
-	 * \param ev the event
-	 */
-	void postServerEvent(ServerEvent ev) noexcept;
+	void post(std::function<void (Irccd &)> ev) noexcept;
 
 	/*
 	 * Identity management
@@ -367,6 +344,13 @@
 	 */
 	void addTransport(std::shared_ptr<TransportServer> ts);
 
+	/**
+	 * Send data to all clients.
+	 *
+	 * \param data the data
+	 */
+	void broadcast(std::string data);
+
 	/*
 	 * Plugin management
 	 * ----------------------------------------------------------