changeset 586:f462cc16b517

Irccd: server_error now takes server name
author David Demelier <markand@malikania.fr>
date Tue, 05 Dec 2017 21:09:45 +0100
parents 1ad88e2e3086
children 312af09354e0
files libirccd-js/irccd/js/server_jsapi.cpp libirccd/irccd/command.cpp libirccd/irccd/server.cpp libirccd/irccd/server.hpp libirccd/irccd/server_service.cpp libirccd/irccd/server_service.hpp tests/src/plugin-load-command/main.cpp tests/src/server-connect-command/main.cpp
diffstat 8 files changed, 211 insertions(+), 155 deletions(-) [+]
line wrap: on
line diff
--- a/libirccd-js/irccd/js/server_jsapi.cpp	Tue Dec 05 20:45:21 2017 +0100
+++ b/libirccd-js/irccd/js/server_jsapi.cpp	Tue Dec 05 21:09:45 2017 +0100
@@ -370,7 +370,7 @@
 
     try {
         auto json = duk_json_encode(ctx, 0);
-        auto s = server::from_json(dukx_get_irccd(ctx).service(), nlohmann::json::parse(json));
+        auto s = server_service::from_json(dukx_get_irccd(ctx).service(), nlohmann::json::parse(json));
 
         duk_push_this(ctx);
         duk_push_pointer(ctx, new std::shared_ptr<server>(std::move(s)));
--- a/libirccd/irccd/command.cpp	Tue Dec 05 20:45:21 2017 +0100
+++ b/libirccd/irccd/command.cpp	Tue Dec 05 21:09:45 2017 +0100
@@ -153,12 +153,12 @@
     auto id = json_util::get_string(args, "server");
 
     if (!string_util::is_identifier(id))
-        throw server_error(server_error::invalid_identifier);
+        throw server_error(server_error::invalid_identifier, "");
 
     auto server = daemon.servers().get(id);
 
     if (!server)
-        throw server_error(server_error::not_found);
+        throw server_error(server_error::not_found, id);
 
     return server;
 }
@@ -256,10 +256,10 @@
 
 void server_connect_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
-    auto server = server::from_json(irccd.service(), args);
+    auto server = server_service::from_json(irccd.service(), args);
 
     if (irccd.servers().has(server->name()))
-        throw server_error(server_error::error::already_exists);
+        throw server_error(server_error::error::already_exists, server->name());
 
     irccd.servers().add(std::move(server));
     client.success("server-connect");
@@ -278,14 +278,15 @@
         irccd.servers().clear();
     else {
         if (!it->is_string())
-            throw server_error(server_error::invalid_identifier);
+            throw server_error(server_error::invalid_identifier, "");
 
-        auto s = irccd.servers().get(it->get<std::string>());
+        auto name = it->get<std::string>();
+        auto s = irccd.servers().get(name);
 
         if (!s)
-            throw server_error(server_error::not_found);
+            throw server_error(server_error::not_found, name);
 
-        irccd.servers().remove(it->get<std::string>());
+        irccd.servers().remove(name);
     }
 
     client.success("server-disconnect");
@@ -329,15 +330,16 @@
 
 void server_invite_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
+    auto server = get_server(irccd, args);
     auto target = json_util::get_string(args, "target");
     auto channel = json_util::get_string(args, "channel");
 
     if (target.empty())
-        throw server_error(server_error::invalid_nickname);
+        throw server_error(server_error::invalid_nickname, server->name());
     if (channel.empty())
-        throw server_error(server_error::invalid_channel);
+        throw server_error(server_error::invalid_channel, server->name());
 
-    get_server(irccd, args)->invite(target, channel);
+    server->invite(target, channel);
     client.success("server-invite");
 }
 
@@ -348,13 +350,14 @@
 
 void server_join_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
+    auto server = get_server(irccd, args);
     auto channel = json_util::get_string(args, "channel");
     auto password = json_util::get_string(args, "password");
 
     if (channel.empty())
-        throw server_error(server_error::invalid_channel);
+        throw server_error(server_error::invalid_channel, server->name());
 
-    get_server(irccd, args)->join(channel, password);
+    server->join(channel, password);
     client.success("server-join");
 }
 
@@ -365,16 +368,17 @@
 
 void server_kick_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
+    auto server = get_server(irccd, args);
     auto target = json_util::get_string(args, "target");
     auto channel = json_util::get_string(args, "channel");
     auto reason = json_util::get_string(args, "reason");
 
     if (target.empty())
-        throw server_error(server_error::invalid_nickname);
+        throw server_error(server_error::invalid_nickname, server->name());
     if (channel.empty())
-        throw server_error(server_error::invalid_channel);
+        throw server_error(server_error::invalid_channel, server->name());
 
-    get_server(irccd, args)->kick(target, channel, reason);
+    server->kick(target, channel, reason);
     client.success("server-kick");
 }
 
@@ -404,13 +408,14 @@
 
 void server_me_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
+    auto server = get_server(irccd, args);
     auto channel = json_util::get_string(args, "target");
     auto message = json_util::get_string(args, "message");
 
     if (channel.empty())
-        throw server_error(server_error::invalid_channel);
+        throw server_error(server_error::invalid_channel, server->name());
 
-    get_server(irccd, args)->me(channel, message);
+    server->me(channel, message);
     client.success("server-me");
 }
 
@@ -421,13 +426,14 @@
 
 void server_message_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
+    auto server = get_server(irccd, args);
     auto channel = json_util::get_string(args, "target");
     auto message = json_util::get_string(args, "message");
 
     if (channel.empty())
-        throw server_error(server_error::invalid_channel);
+        throw server_error(server_error::invalid_channel, server->name());
 
-    get_server(irccd, args)->message(channel, message);
+    server->message(channel, message);
     client.success("server-message");
 }
 
@@ -438,19 +444,20 @@
 
 void server_mode_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
+    auto server = get_server(irccd, args);
     auto channel = json_util::get_string(args, "channel");
     auto mode = json_util::get_string(args, "mode");
 
     if (channel.empty())
-        throw server_error(server_error::invalid_channel);
+        throw server_error(server_error::invalid_channel, server->name());
     if (mode.empty())
-        throw server_error(server_error::invalid_mode);
+        throw server_error(server_error::invalid_mode, server->name());
 
     auto limit = json_util::get_string(args, "limit");
     auto user = json_util::get_string(args, "user");
     auto mask = json_util::get_string(args, "mask");
 
-    get_server(irccd, args)->mode(channel, mode, limit, user, mask);
+    server->mode(channel, mode, limit, user, mask);
     client.success("server-mode");
 }
 
@@ -461,12 +468,13 @@
 
 void server_nick_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
+    auto server = get_server(irccd, args);
     auto nick = json_util::get_string(args, "nickname");
 
     if (nick.empty())
-        throw server_error(server_error::invalid_nickname);
+        throw server_error(server_error::invalid_nickname, server->name());
 
-    get_server(irccd, args)->set_nickname(nick);
+    server->set_nickname(nick);
     client.success("server-nick");
 }
 
@@ -477,13 +485,14 @@
 
 void server_notice_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
+    auto server = get_server(irccd, args);
     auto channel = json_util::get_string(args, "target");
     auto message = json_util::get_string(args, "message");
 
     if (channel.empty())
-        throw server_error(server_error::invalid_channel);
+        throw server_error(server_error::invalid_channel, server->name());
 
-    get_server(irccd, args)->notice(channel, message);
+    server->notice(channel, message);
     client.success("server-notice");
 }
 
@@ -494,13 +503,14 @@
 
 void server_part_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
+    auto server = get_server(irccd, args);
     auto channel = json_util::get_string(args, "channel");
     auto reason = json_util::get_string(args, "reason");
 
     if (channel.empty())
-        throw server_error(server_error::invalid_channel);
+        throw server_error(server_error::invalid_channel, server->name());
 
-    get_server(irccd, args)->part(channel, reason);
+    server->part(channel, reason);
     client.success("server-part");
 }
 
@@ -518,12 +528,13 @@
             server->reconnect();
     } else {
         if (!server->is_string() || !string_util::is_identifier(server->get<std::string>()))
-            throw server_error(server_error::invalid_identifier);
+            throw server_error(server_error::invalid_identifier, "");
 
-        auto s = irccd.servers().get(server->get<std::string>());
+        auto name = server->get<std::string>();
+        auto s = irccd.servers().get(name);
 
         if (!s)
-            throw server_error(server_error::not_found);
+            throw server_error(server_error::not_found, name);
 
         s->reconnect();
     }
@@ -538,13 +549,14 @@
 
 void server_topic_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
+    auto server = get_server(irccd, args);
     auto channel = json_util::get_string(args, "channel");
     auto topic = json_util::get_string(args, "topic");
 
     if (channel.empty())
-        throw server_error(server_error::invalid_channel);
+        throw server_error(server_error::invalid_channel, server->name());
 
-    get_server(irccd, args)->topic(channel, topic);
+    server->topic(channel, topic);
     client.success("server-topic");
 }
 
--- a/libirccd/irccd/server.cpp	Tue Dec 05 20:45:21 2017 +0100
+++ b/libirccd/irccd/server.cpp	Tue Dec 05 21:09:45 2017 +0100
@@ -104,48 +104,6 @@
     return modes;
 }
 
-std::string from_json_get_id(const nlohmann::json& json)
-{
-    auto id = json_util::get_string(json, "name");
-
-    if (!string_util::is_identifier(id))
-        throw server_error(server_error::invalid_identifier);
-
-    return id;
-}
-
-std::string from_json_get_host(const nlohmann::json& json)
-{
-    auto host = json_util::get_string(json, "host");
-
-    if (host.empty())
-        throw server_error(server_error::invalid_hostname);
-
-    return host;
-}
-
-template <typename T>
-T from_json_get_uint(const nlohmann::json& json,
-                     const std::string& key,
-                     server_error::error error,
-                     T fallback)
-
-{
-    auto v = json.find(key);
-
-    if (v == json.end())
-        return fallback;
-    if (!v->is_number())
-        throw server_error(error);
-
-    auto n = v->get<unsigned>();
-
-    if (n > std::numeric_limits<T>::max())
-        throw server_error(error);
-
-    return static_cast<T>(n);
-}
-
 } // !namespace
 
 void server::remove_joined_channel(const std::string& channel)
@@ -153,40 +111,6 @@
     jchannels_.erase(std::remove(jchannels_.begin(), jchannels_.end(), channel), jchannels_.end());
 }
 
-std::shared_ptr<server> server::from_json(boost::asio::io_service& service, const nlohmann::json& object)
-{
-    // TODO: move this function in server_service.
-    auto sv = std::make_shared<server>(service, from_json_get_id(object));
-
-    sv->set_host(from_json_get_host(object));
-    sv->set_port(from_json_get_uint(object, "port",
-        server_error::invalid_port, sv->port()));
-    sv->set_password(json_util::get_string(object, "password"));
-    sv->set_nickname(json_util::get_string(object, "nickname", sv->nickname()));
-    sv->set_realname(json_util::get_string(object, "realname", sv->realname()));
-    sv->set_username(json_util::get_string(object, "username", sv->username()));
-    sv->set_ctcp_version(json_util::get_string(object, "ctcpVersion", sv->ctcp_version()));
-    sv->set_command_char(json_util::get_string(object, "commandChar", sv->command_char()));
-
-    if (json_util::get_bool(object, "ipv6"))
-        sv->set_flags(sv->flags() | server::ipv6);
-    if (json_util::get_bool(object, "sslVerify"))
-        sv->set_flags(sv->flags() | server::ssl_verify);
-    if (json_util::get_bool(object, "autoRejoin"))
-        sv->set_flags(sv->flags() | server::auto_rejoin);
-    if (json_util::get_bool(object, "joinInvite"))
-        sv->set_flags(sv->flags() | server::join_invite);
-
-    if (json_util::get_bool(object, "ssl"))
-#if defined(HAVE_SSL)
-        sv->set_flags(sv->flags() | server::ssl);
-#else
-        throw server_error(server_error::ssl_disabled);
-#endif
-
-    return sv;
-}
-
 channel server::split_channel(const std::string& value)
 {
     auto pos = value.find(':');
@@ -749,6 +673,12 @@
     send(string_util::sprintf("WHOIS %s %s", target, target));
 }
 
+server_error::server_error(error code, std::string name) noexcept
+    : system_error(make_error_code(code))
+    , name_(std::move(name))
+{
+}
+
 const boost::system::error_category& server_category()
 {
     static const class category : public boost::system::error_category {
--- a/libirccd/irccd/server.hpp	Tue Dec 05 20:45:21 2017 +0100
+++ b/libirccd/irccd/server.hpp	Tue Dec 05 21:09:45 2017 +0100
@@ -453,18 +453,6 @@
 
 public:
     /**
-     * Convert a JSON object as a server.
-     *
-     * Used in JavaScript API and transport commands.
-     *
-     * \param service the io service
-     * \param object the object
-     * \return the server
-     * \throw std::exception on failures
-     */
-    static std::shared_ptr<server> from_json(boost::asio::io_service& service, const nlohmann::json& object);
-
-    /**
      * Split a channel from the form channel:password into a server_channel
      * object.
      *
@@ -953,10 +941,27 @@
         ssl_disabled,
     };
 
+private:
+    std::string name_;
+
+public:
     /**
-     * Inherited constructors.
+     * Constructor.
+     *
+     * \param code the error code
+     * \param name the server name
      */
-    using system_error::system_error;
+    server_error(error code, std::string name) noexcept;
+
+    /**
+     * Get the server that triggered the error.
+     *
+     * \return the name
+     */
+    inline const std::string& name() const noexcept
+    {
+        return name_;
+    }
 };
 
 /**
--- a/libirccd/irccd/server_service.cpp	Tue Dec 05 20:45:21 2017 +0100
+++ b/libirccd/irccd/server_service.cpp	Tue Dec 05 21:09:45 2017 +0100
@@ -16,6 +16,8 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <irccd/json_util.hpp>
+
 #include "irccd.hpp"
 #include "logger.hpp"
 #include "plugin_service.hpp"
@@ -56,23 +58,77 @@
 }
 
 template <typename T>
-T to_uint(const std::string& value, server_error::error errc)
+T to_int(const std::string& value, const std::string& name, server_error::error errc)
+{
+    try {
+        return string_util::to_int<T>(value);
+    } catch (...) {
+        throw server_error(errc, name);
+    }
+}
+
+template <typename T>
+T to_uint(const std::string& value, const std::string& name, server_error::error errc)
 {
     try {
         return string_util::to_uint<T>(value);
     } catch (...) {
-        throw server_error(errc);
+        throw server_error(errc, name);
     }
 }
 
 template <typename T>
-T to_int(const std::string& value, server_error::error errc)
+T to_uint(const nlohmann::json& value, const std::string& name, server_error::error errc)
+{
+    if (!value.is_number())
+        throw server_error(errc, name);
+
+    auto n = value.get<unsigned>();
+
+    if (n > std::numeric_limits<T>::max())
+        throw server_error(errc, name);
+
+    return static_cast<T>(n);
+}
+
+std::string to_id(const ini::section& sc)
+{
+    auto id = sc.get("name");
+
+    if (!string_util::is_identifier(id.value()))
+        throw server_error(server_error::invalid_identifier, "");
+
+    return id.value();
+}
+
+std::string to_id(const nlohmann::json& object)
 {
-    try {
-        return string_util::to_int<T>(value);
-    } catch (...) {
-        throw server_error(errc);
-    }
+    auto id = json_util::get_string(object, "name");
+
+    if (!string_util::is_identifier(id))
+        throw server_error(server_error::invalid_identifier, "");
+
+    return id;
+}
+
+std::string to_host(const ini::section& sc, const std::string& name)
+{
+    auto value = sc.get("host");
+
+    if (value.empty())
+        throw server_error(server_error::invalid_hostname, name);
+
+    return name;
+}
+
+std::string to_host(const nlohmann::json& object, const std::string& name)
+{
+    auto value = json_util::get_string(object, "host");
+
+    if (value.empty())
+        throw server_error(server_error::invalid_hostname, name);
+
+    return value;
 }
 
 void load_server_identity(std::shared_ptr<server>& server,
@@ -109,23 +165,14 @@
 {
     assert(sc.key() == "server");
 
+    auto sv = std::make_shared<server>(service, to_id(sc));
+
+    // Mandatory fields.
+    sv->set_host(to_host(sc, sv->name()));
+
+    // Optional fields.
     ini::section::const_iterator it;
 
-    // Name.
-    auto name = sc.get("name").value();
-
-    if (!string_util::is_identifier(name))
-        throw server_error(server_error::invalid_identifier);
-
-    auto sv = std::make_shared<server>(service, name);
-
-    // Host
-    if ((it = sc.find("host")) == sc.end())
-        throw server_error(server_error::invalid_hostname);
-
-    sv->set_host(it->value());
-
-    // Optional password
     if ((it = sc.find("password")) != sc.end())
         sv->set_password(it->value());
 
@@ -173,13 +220,20 @@
 
     // Reconnect and ping timeout
     if ((it = sc.find("port")) != sc.end())
-        sv->set_port(to_uint<std::uint16_t>(it->value(), server_error::invalid_port));
+        sv->set_port(to_uint<std::uint16_t>(it->value(),
+            sv->name(), server_error::invalid_port));
+
     if ((it = sc.find("reconnect-tries")) != sc.end())
-        sv->set_reconnect_tries(to_int<std::int8_t>(it->value(), server_error::invalid_reconnect_tries));
+        sv->set_reconnect_tries(to_int<std::int8_t>(it->value(),
+            sv->name(), server_error::invalid_reconnect_tries));
+
     if ((it = sc.find("reconnect-timeout")) != sc.end())
-        sv->set_reconnect_delay(to_uint<std::uint16_t>(it->value(), server_error::invalid_reconnect_timeout));
+        sv->set_reconnect_delay(to_uint<std::uint16_t>(it->value(),
+            sv->name(), server_error::invalid_reconnect_timeout));
+
     if ((it = sc.find("ping-timeout")) != sc.end())
-        sv->set_ping_timeout(to_uint<std::uint16_t>(it->value(), server_error::invalid_ping_timeout));
+        sv->set_ping_timeout(to_uint<std::uint16_t>(it->value(),
+            sv->name(), server_error::invalid_ping_timeout));
 
     return sv;
 }
@@ -526,6 +580,43 @@
     );
 }
 
+std::shared_ptr<server> server_service::from_json(boost::asio::io_service& service, const nlohmann::json& object)
+{
+    // TODO: move this function in server_service.
+    auto sv = std::make_shared<server>(service, to_id(object));
+
+    // Mandatory fields.
+    sv->set_host(to_host(object, sv->name()));
+
+    // Optional fields.
+    if (object.count("port"))
+        sv->set_port(to_uint<std::uint16_t>(object["port"], sv->name(), server_error::invalid_port));
+    sv->set_password(json_util::get_string(object, "password"));
+    sv->set_nickname(json_util::get_string(object, "nickname", sv->nickname()));
+    sv->set_realname(json_util::get_string(object, "realname", sv->realname()));
+    sv->set_username(json_util::get_string(object, "username", sv->username()));
+    sv->set_ctcp_version(json_util::get_string(object, "ctcpVersion", sv->ctcp_version()));
+    sv->set_command_char(json_util::get_string(object, "commandChar", sv->command_char()));
+
+    if (json_util::get_bool(object, "ipv6"))
+        sv->set_flags(sv->flags() | server::ipv6);
+    if (json_util::get_bool(object, "sslVerify"))
+        sv->set_flags(sv->flags() | server::ssl_verify);
+    if (json_util::get_bool(object, "autoRejoin"))
+        sv->set_flags(sv->flags() | server::auto_rejoin);
+    if (json_util::get_bool(object, "joinInvite"))
+        sv->set_flags(sv->flags() | server::join_invite);
+
+    if (json_util::get_bool(object, "ssl"))
+#if defined(HAVE_SSL)
+        sv->set_flags(sv->flags() | server::ssl);
+#else
+        throw server_error(server_error::ssl_disabled);
+#endif
+
+    return sv;
+}
+
 server_service::server_service(irccd &irccd)
     : irccd_(irccd)
 {
--- a/libirccd/irccd/server_service.hpp	Tue Dec 05 20:45:21 2017 +0100
+++ b/libirccd/irccd/server_service.hpp	Tue Dec 05 21:09:45 2017 +0100
@@ -31,6 +31,7 @@
 
 namespace irccd {
 
+class config;
 class irccd;
 
 /**
@@ -59,6 +60,18 @@
 
 public:
     /**
+     * Convert a JSON object as a server.
+     *
+     * Used in JavaScript API and transport commands.
+     *
+     * \param service the io service
+     * \param object the object
+     * \return the server
+     * \throw std::exception on failures
+     */
+    static std::shared_ptr<server> from_json(boost::asio::io_service& service, const nlohmann::json& object);
+
+    /**
      * Create the server service.
      */
     server_service(irccd& instance);
--- a/tests/src/plugin-load-command/main.cpp	Tue Dec 05 20:45:21 2017 +0100
+++ b/tests/src/plugin-load-command/main.cpp	Tue Dec 05 21:09:45 2017 +0100
@@ -30,6 +30,11 @@
 
 class custom_loader : public plugin_loader {
 public:
+    custom_loader()
+        : plugin_loader({}, {".none"})
+    {
+    }
+
     std::shared_ptr<plugin> open(const std::string&,
                                  const std::string&) noexcept override
     {
--- a/tests/src/server-connect-command/main.cpp	Tue Dec 05 20:45:21 2017 +0100
+++ b/tests/src/server-connect-command/main.cpp	Tue Dec 05 21:09:45 2017 +0100
@@ -223,7 +223,7 @@
         return result;
     });
 
-    BOOST_ASSERT(result == server_error::invalid_port_number);
+    BOOST_ASSERT(result == server_error::invalid_port);
 }
 
 BOOST_AUTO_TEST_CASE(invalid_port_2)
@@ -244,7 +244,7 @@
         return result;
     });
 
-    BOOST_ASSERT(result == server_error::invalid_port_number);
+    BOOST_ASSERT(result == server_error::invalid_port);
 }
 
 BOOST_AUTO_TEST_CASE(invalid_port_3)
@@ -265,7 +265,7 @@
         return result;
     });
 
-    BOOST_ASSERT(result == server_error::invalid_port_number);
+    BOOST_ASSERT(result == server_error::invalid_port);
 }
 
 #if !defined(HAVE_SSL)