changeset 127:77f950caab35

Irccd: implement RuleService, #498
author David Demelier <markand@malikania.fr>
date Wed, 11 May 2016 13:27:39 +0200
parents 49572a69c41d
children 2d8343b86e2e
files irccd/main.cpp lib/irccd/CMakeSources.cmake lib/irccd/config.cpp lib/irccd/irccd.cpp lib/irccd/irccd.hpp lib/irccd/rule.cpp lib/irccd/rule.hpp lib/irccd/server-event.cpp lib/irccd/service-rule.cpp lib/irccd/service-rule.hpp lib/irccd/service-transport.cpp tests/js-timer/main.cpp tests/rules/main.cpp
diffstat 13 files changed, 225 insertions(+), 139 deletions(-) [+]
line wrap: on
line diff
--- a/irccd/main.cpp	Wed May 11 13:00:40 2016 +0200
+++ b/irccd/main.cpp	Wed May 11 13:27:39 2016 +0200
@@ -37,6 +37,7 @@
 #include <irccd/logger.hpp>
 #include <irccd/options.hpp>
 #include <irccd/path.hpp>
+#include <irccd/service-rule.hpp>
 #include <irccd/service-server.hpp>
 #include <irccd/service-transport.hpp>
 #include <irccd/system.hpp>
@@ -239,7 +240,7 @@
 
 	// [rule] section.
 	for (const auto &rule : config.loadRules()) {
-		instance->addRule(rule);
+		instance->ruleService().add(rule);
 	}
 
 	// [plugin] section.
--- a/lib/irccd/CMakeSources.cmake	Wed May 11 13:00:40 2016 +0200
+++ b/lib/irccd/CMakeSources.cmake	Wed May 11 13:27:39 2016 +0200
@@ -64,6 +64,7 @@
 	${CMAKE_CURRENT_LIST_DIR}/server-state-disconnected.hpp
 	${CMAKE_CURRENT_LIST_DIR}/service.hpp
 	${CMAKE_CURRENT_LIST_DIR}/service-interrupt.hpp
+	${CMAKE_CURRENT_LIST_DIR}/service-rule.hpp
 	${CMAKE_CURRENT_LIST_DIR}/service-server.hpp
 	${CMAKE_CURRENT_LIST_DIR}/service-transport.hpp
 	${CMAKE_CURRENT_LIST_DIR}/sockets.hpp
@@ -134,6 +135,7 @@
 	${CMAKE_CURRENT_LIST_DIR}/server-state-connecting.cpp
 	${CMAKE_CURRENT_LIST_DIR}/server-state-disconnected.cpp
 	${CMAKE_CURRENT_LIST_DIR}/service-interrupt.cpp
+	${CMAKE_CURRENT_LIST_DIR}/service-rule.cpp
 	${CMAKE_CURRENT_LIST_DIR}/service-server.cpp
 	${CMAKE_CURRENT_LIST_DIR}/service-transport.cpp
 	${CMAKE_CURRENT_LIST_DIR}/sockets.cpp
--- a/lib/irccd/config.cpp	Wed May 11 13:00:40 2016 +0200
+++ b/lib/irccd/config.cpp	Wed May 11 13:27:39 2016 +0200
@@ -23,6 +23,7 @@
 #include "config.hpp"
 #include "fs.hpp"
 #include "irccd.hpp"
+#include "logger.hpp"
 #include "path.hpp"
 #include "rule.hpp"
 #include "server.hpp"
--- a/lib/irccd/irccd.cpp	Wed May 11 13:00:40 2016 +0200
+++ b/lib/irccd/irccd.cpp	Wed May 11 13:27:39 2016 +0200
@@ -26,6 +26,7 @@
 #include "logger.hpp"
 #include "path.hpp"
 #include "service-interrupt.hpp"
+#include "service-rule.hpp"
 #include "service-server.hpp"
 #include "service-transport.hpp"
 #include "util.hpp"
@@ -42,6 +43,7 @@
 	: m_interruptService(std::make_shared<InterruptService>())
 	, m_serverService(std::make_shared<ServerService>(*this))
 	, m_transportService(std::make_shared<TransportService>(*this))
+	, m_ruleService(std::make_shared<RuleService>())
 {
 	m_services.push_back(m_interruptService);
 	m_services.push_back(m_serverService);
--- a/lib/irccd/irccd.hpp	Wed May 11 13:00:40 2016 +0200
+++ b/lib/irccd/irccd.hpp	Wed May 11 13:27:39 2016 +0200
@@ -26,8 +26,6 @@
 
 #include <algorithm>
 #include <atomic>
-#include <cassert>
-#include <condition_variable>
 #include <functional>
 #include <memory>
 #include <mutex>
@@ -40,14 +38,13 @@
 #endif
 
 #include "application.hpp"
-#include "logger.hpp"
-#include "rule.hpp"
 
 namespace irccd {
 
 class InterruptService;
 class Irccd;
 class Plugin;
+class RuleService;
 class ServerService;
 class Service;
 class TransportService;
@@ -68,13 +65,11 @@
 	std::vector<std::shared_ptr<Plugin>> m_plugins;
 #endif
 
-	// Rules.
-	std::vector<Rule> m_rules;
-
 	// Services.
 	std::shared_ptr<InterruptService> m_interruptService;
 	std::shared_ptr<ServerService> m_serverService;
 	std::shared_ptr<TransportService> m_transportService;
+	std::shared_ptr<RuleService> m_ruleService;
 	std::vector<std::shared_ptr<Service>> m_services;
 
 	/*
@@ -133,6 +128,16 @@
 	}
 
 	/**
+	 * Access the rule service.
+	 *
+	 * \return the service
+	 */
+	inline RuleService &ruleService() noexcept
+	{
+		return *m_ruleService;
+	}
+
+	/**
 	 * Add an event to the queue. This will immediately signals the event loop to interrupt itself to dispatch
 	 * the pending events.
 	 *
@@ -227,60 +232,6 @@
 
 #endif // !WITH_JS
 
-	/*
-	 * Rule management
-	 * ----------------------------------------------------------
-	 *
-	 * Functions for adding, creating new rules that are used to filter IRC events before being processed
-	 * by JavaScript plugins.
-	 */
-
-	/**
-	 * Append a rule.
-	 *
-	 * \param rule the rule to append
-	 */
-	inline void addRule(Rule rule)
-	{
-		m_rules.push_back(std::move(rule));
-	}
-
-	/**
-	 * Insert a new rule at the specified position.
-	 *
-	 * \param rule the rule
-	 * \param position the position
-	 */
-	inline void insertRule(Rule rule, unsigned position)
-	{
-		assert(position <= m_rules.size());
-
-		m_rules.insert(m_rules.begin() + position, std::move(rule));
-	}
-
-	/**
-	 * Get the list of rules.
-	 *
-	 * \return the list of rules
-	 */
-	inline const std::vector<Rule> &rules() const noexcept
-	{
-		return m_rules;
-	}
-
-	/**
-	 * Remove a new rule from the specified position.
-	 *
-	 * \pre position must be valid
-	 * \param position the position
-	 */
-	inline void removeRule(unsigned position)
-	{
-		assert(position < m_rules.size());
-
-		m_rules.erase(m_rules.begin() + position);
-	}
-
 	/**
 	 * Loop forever by calling poll() and dispatch() indefinitely.
 	 */
--- a/lib/irccd/rule.cpp	Wed May 11 13:00:40 2016 +0200
+++ b/lib/irccd/rule.cpp	Wed May 11 13:27:39 2016 +0200
@@ -50,40 +50,6 @@
 
 namespace irccd {
 
-bool Rule::solve(const std::vector<Rule> &rules,
-		 const std::string &server,
-		 const std::string &channel,
-		 const std::string &origin,
-		 const std::string &plugin,
-		 const std::string &event) noexcept
-{
-	bool result = true;
-
-	log::debug() << "rule: solving for:\n"
-		     << "  server: " << server << "\n"
-		     << "  channel: " << channel << "\n"
-		     << "  origin: " << origin << "\n"
-		     << "  plugin: " << plugin << "\n"
-		     << "  event: " << event << std::endl;
-
-	int i = 0;
-	for (const Rule &rule : rules) {
-		log::debug() << "  candidate " << i++ << ":\n"
-			     << "    servers: " << util::join(rule.m_servers.begin(), rule.m_servers.end()) << "\n"
-			     << "    channels: " << util::join(rule.m_channels.begin(), rule.m_channels.end()) << "\n"
-			     << "    origins: " << util::join(rule.m_origins.begin(), rule.m_origins.end()) << "\n"
-			     << "    plugins: " << util::join(rule.m_plugins.begin(), rule.m_plugins.end()) << "\n"
-			     << "    events: " << util::join(rule.m_events.begin(), rule.m_events.end()) << "\n"
-			     << "    action: " << ((rule.m_action == RuleAction::Accept) ? "accept" : "drop") << std::endl;
-
-		if (rule.match(server, channel, origin, plugin, event)) {
-			result = rule.action() == RuleAction::Accept;
-		}
-	}
-
-	return result;
-}
-
 bool Rule::matchMap(const RuleSet &map, const std::string &value) const noexcept
 {
 	return value.empty() || map.empty() || map.count(value) == 1;
--- a/lib/irccd/rule.hpp	Wed May 11 13:00:40 2016 +0200
+++ b/lib/irccd/rule.hpp	Wed May 11 13:27:39 2016 +0200
@@ -50,7 +50,7 @@
  * \class Rule
  * \brief Manage rule to activate or deactive events.
  */
-class Rule final {
+class Rule {
 private:
 	RuleSet m_servers;
 	RuleSet m_channels;
@@ -67,24 +67,6 @@
 
 public:
 	/**
-	 * Resolve the action to execute with the specified list of rules.
-	 *
-	 * \param rules the list of rules
-	 * \param server the server name
-	 * \param channel the channel name
-	 * \param origin the origin
-	 * \param plugin the plugin name
-	 * \param event the event name (e.g onKick)
-	 * \return true if the plugin must be called
-	 */
-	static bool solve(const std::vector<Rule> &rules,
-			  const std::string &server,
-			  const std::string &channel,
-			  const std::string &origin,
-			  const std::string &plugin,
-			  const std::string &event) noexcept;
-
-	/**
 	 * Rule constructor.
 	 *
 	 * \param servers the server list
--- a/lib/irccd/server-event.cpp	Wed May 11 13:00:40 2016 +0200
+++ b/lib/irccd/server-event.cpp	Wed May 11 13:27:39 2016 +0200
@@ -17,8 +17,9 @@
  */
 
 #include "irccd.hpp"
+#include "logger.hpp"
 #include "server-event.hpp"
-#include "rule.hpp"
+#include "service-rule.hpp"
 
 namespace irccd {
 
@@ -39,7 +40,7 @@
 {
 	for (auto &plugin : irccd.plugins()) {
 		auto eventname = m_plugin_function_name(*plugin);
-		auto allowed = Rule::solve(irccd.rules(), m_server, m_target, m_origin, plugin->name(), eventname);
+		auto allowed = irccd.ruleService().solve(m_server, m_target, m_origin, plugin->name(), eventname);
 
 		if (!allowed) {
 			log::debug() << "rule: event skipped on match" << std::endl;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/irccd/service-rule.cpp	Wed May 11 13:27:39 2016 +0200
@@ -0,0 +1,79 @@
+/*
+ * service-rule.cpp -- store and solve rules
+ *
+ * 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 <cassert>
+
+#include <format.h>
+
+#include "logger.hpp"
+#include "service-rule.hpp"
+#include "util.hpp"
+
+using namespace fmt::literals;
+
+namespace irccd {
+
+void RuleService::add(Rule rule)
+{
+	m_rules.push_back(std::move(rule));
+}
+
+void RuleService::insert(Rule rule, unsigned position)
+{
+	assert(position <= m_rules.size());
+
+	m_rules.insert(m_rules.begin() + position, std::move(rule));
+}
+
+void RuleService::remove(unsigned position)
+{
+	assert(position < m_rules.size());
+
+	m_rules.erase(m_rules.begin() + position);
+}
+
+bool RuleService::solve(const std::string &server,
+			const std::string &channel,
+			const std::string &origin,
+			const std::string &plugin,
+			const std::string &event) noexcept
+{
+	bool result = true;
+
+	log::debug("rule: solving for server={}, channel={}, origin={}, plugin={}, event={}"_format(server, channel,
+		   origin, plugin, event));
+
+	int i = 0;
+	for (const Rule &rule : m_rules) {
+		log::debug() << "  candidate " << i++ << ":\n"
+			     << "    servers: " << util::join(rule.servers().begin(), rule.servers().end()) << "\n"
+			     << "    channels: " << util::join(rule.channels().begin(), rule.channels().end()) << "\n"
+			     << "    origins: " << util::join(rule.origins().begin(), rule.origins().end()) << "\n"
+			     << "    plugins: " << util::join(rule.plugins().begin(), rule.plugins().end()) << "\n"
+			     << "    events: " << util::join(rule.events().begin(), rule.events().end()) << "\n"
+			     << "    action: " << ((rule.action() == RuleAction::Accept) ? "accept" : "drop") << std::endl;
+
+		if (rule.match(server, channel, origin, plugin, event)) {
+			result = rule.action() == RuleAction::Accept;
+		}
+	}
+
+	return result;
+}
+
+} // !irccd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/irccd/service-rule.hpp	Wed May 11 13:27:39 2016 +0200
@@ -0,0 +1,103 @@
+/*
+ * service-rule.hpp -- store and solve rules
+ *
+ * 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_SERVICE_RULE_HPP
+#define IRCCD_SERVICE_RULE_HPP
+
+/**
+ * \file service-rule.hpp
+ * \brief Store and solve rules.
+ */
+
+#include <vector>
+
+#include "rule.hpp"
+
+namespace irccd {
+
+/**
+ * \brief Store and solve rules.
+ */
+class RuleService {
+private:
+	std::vector<Rule> m_rules;
+
+public:
+	/**
+	 * Get the list of rules.
+	 *
+	 * \return the list of rules
+	 */
+	inline const std::vector<Rule> &rules() const noexcept
+	{
+		return m_rules;
+	}
+
+	/**
+	 * Get the number of rules.
+	 *
+	 * \return the number of rules
+	 */
+	inline unsigned length() const noexcept
+	{
+		return m_rules.size();
+	}
+
+	/**
+	 * Append a rule.
+	 *
+	 * \param rule the rule to append
+	 */
+	void add(Rule rule);
+
+	/**
+	 * Insert a new rule at the specified position.
+	 *
+	 * \param rule the rule
+	 * \param position the position
+	 */
+	void insert(Rule rule, unsigned position);
+
+	/**
+	 * Remove a new rule from the specified position.
+	 *
+	 * \pre position must be valid
+	 * \param position the position
+	 */
+	void remove(unsigned position);
+
+	/**
+	 * Resolve the action to execute with the specified list of rules.
+	 *
+	 * \param server the server name
+	 * \param channel the channel name
+	 * \param origin the origin
+	 * \param plugin the plugin name
+	 * \param event the event name (e.g onKick)
+	 * \return true if the plugin must be called
+	 */
+	bool solve(const std::string &server,
+		   const std::string &channel,
+		   const std::string &origin,
+		   const std::string &plugin,
+		   const std::string &event) noexcept;
+};
+
+} // !irccd
+
+#endif // !IRCCD_SERVICE_RULE_HPP
--- a/lib/irccd/service-transport.cpp	Wed May 11 13:00:40 2016 +0200
+++ b/lib/irccd/service-transport.cpp	Wed May 11 13:27:39 2016 +0200
@@ -17,6 +17,7 @@
  */
 
 #include "irccd.hpp"
+#include "logger.hpp"
 #include "service-transport.hpp"
 #include "transport-client.hpp"
 #include "transport-server.hpp"
@@ -178,4 +179,4 @@
 	}
 }
 
-} // !irccd
\ No newline at end of file
+} // !irccd
--- a/tests/js-timer/main.cpp	Wed May 11 13:00:40 2016 +0200
+++ b/tests/js-timer/main.cpp	Wed May 11 13:27:39 2016 +0200
@@ -20,6 +20,7 @@
 
 #include <irccd/elapsed-timer.hpp>
 #include <irccd/irccd.hpp>
+#include <irccd/logger.hpp>
 #include <irccd/system.hpp>
 
 using namespace irccd;
--- a/tests/rules/main.cpp	Wed May 11 13:00:40 2016 +0200
+++ b/tests/rules/main.cpp	Wed May 11 13:27:39 2016 +0200
@@ -19,6 +19,7 @@
 #include <gtest/gtest.h>
 
 #include <irccd/rule.hpp>
+#include <irccd/service-rule.hpp>
 
 namespace irccd {
 
@@ -64,13 +65,13 @@
  */
 class RulesTest : public testing::Test {
 protected:
-	std::vector<Rule> m_rules;
+	RuleService m_rules;
 
 	RulesTest()
 	{
 		// #1
 		{
-			m_rules.push_back({
+			m_rules.add({
 				RuleSet{		},	// Servers
 				RuleSet{ "#staff"	},	// Channels
 				RuleSet{		},	// Origins
@@ -82,7 +83,7 @@
 
 		// #2
 		{
-			m_rules.push_back({
+			m_rules.add({
 				RuleSet{ "unsafe"	},
 				RuleSet{ "#staff"	},
 				RuleSet{		},
@@ -94,7 +95,7 @@
 
 		// #3-1
 		{
-			m_rules.push_back({
+			m_rules.add({
 				RuleSet{},
 				RuleSet{},
 				RuleSet{},
@@ -106,7 +107,7 @@
 
 		// #3-2
 		{
-			m_rules.push_back({
+			m_rules.add({
 				RuleSet{ "malikania", "localhost"	},
 				RuleSet{ "#games"			},
 				RuleSet{ 				},
@@ -116,11 +117,6 @@
 			});
 		}
 	}
-
-	~RulesTest()
-	{
-		m_rules.clear();
-	}
 };
 
 TEST_F(RulesTest, basicMatch1)
@@ -196,40 +192,40 @@
 TEST_F(RulesTest, basicSolve)
 {
 	/* Allowed */
-	ASSERT_TRUE(Rule::solve(m_rules, "malikania", "#staff", "", "a", "onMessage"));
+	ASSERT_TRUE(m_rules.solve("malikania", "#staff", "", "a", "onMessage"));
 
 	/* Allowed */
-	ASSERT_TRUE(Rule::solve(m_rules, "freenode", "#staff", "", "b", "onTopic"));
+	ASSERT_TRUE(m_rules.solve("freenode", "#staff", "", "b", "onTopic"));
 
 	/* Not allowed */
-	ASSERT_FALSE(Rule::solve(m_rules, "malikania", "#staff", "", "", "onCommand"));
+	ASSERT_FALSE(m_rules.solve("malikania", "#staff", "", "", "onCommand"));
 
 	/* Not allowed */
-	ASSERT_FALSE(Rule::solve(m_rules, "freenode", "#staff", "", "c", "onCommand"));
+	ASSERT_FALSE(m_rules.solve("freenode", "#staff", "", "c", "onCommand"));
 
 	/* Allowed */
-	ASSERT_TRUE(Rule::solve(m_rules, "unsafe", "#staff", "", "c", "onCommand"));
+	ASSERT_TRUE(m_rules.solve("unsafe", "#staff", "", "c", "onCommand"));
 }
 
 TEST_F(RulesTest, gamesSolve)
 {
 	/* Allowed */
-	ASSERT_TRUE(Rule::solve(m_rules, "malikania", "#games", "", "game", "onMessage"));
+	ASSERT_TRUE(m_rules.solve("malikania", "#games", "", "game", "onMessage"));
 
 	/* Allowed */
-	ASSERT_TRUE(Rule::solve(m_rules, "localhost", "#games", "", "game", "onMessage"));
+	ASSERT_TRUE(m_rules.solve("localhost", "#games", "", "game", "onMessage"));
 
 	/* Allowed */
-	ASSERT_TRUE(Rule::solve(m_rules, "malikania", "#games", "", "game", "onCommand"));
+	ASSERT_TRUE(m_rules.solve("malikania", "#games", "", "game", "onCommand"));
 
 	/* Not allowed */
-	ASSERT_FALSE(Rule::solve(m_rules, "malikania", "#games", "", "game", "onQuery"));
+	ASSERT_FALSE(m_rules.solve("malikania", "#games", "", "game", "onQuery"));
 
 	/* Not allowed */
-	ASSERT_FALSE(Rule::solve(m_rules, "freenode", "#no", "", "game", "onMessage"));
+	ASSERT_FALSE(m_rules.solve("freenode", "#no", "", "game", "onMessage"));
 
 	/* Not allowed */
-	ASSERT_FALSE(Rule::solve(m_rules, "malikania", "#test", "", "game", "onMessage"));
+	ASSERT_FALSE(m_rules.solve("malikania", "#test", "", "game", "onMessage"));
 }
 
 } // !irccd