changeset 180:23ee2b6091e8

Server: add custom error code
author David Demelier <markand@malikania.fr>
date Tue, 21 Aug 2018 10:55:13 +0200
parents ffe8ac5c35c0
children fbfc2555bda5
files libcommon/CMakeLists.txt libcommon/malikania/error/auth_error.cpp libcommon/malikania/error/auth_error.hpp libcommon/malikania/error/error.hpp libserver/malikania/server/client.cpp libserver/malikania/server/client.hpp libserver/malikania/server/net/auth_handler.cpp
diffstat 7 files changed, 236 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/libcommon/CMakeLists.txt	Mon Oct 08 09:51:12 2018 +0200
+++ b/libcommon/CMakeLists.txt	Tue Aug 21 10:55:13 2018 +0200
@@ -23,6 +23,8 @@
 
 set(
     HEADERS
+    ${libmlk-common_SOURCE_DIR}/malikania/error/error.hpp
+    ${libmlk-common_SOURCE_DIR}/malikania/error/auth_error.hpp
     ${libmlk-common_SOURCE_DIR}/malikania/game.hpp
     ${libmlk-common_SOURCE_DIR}/malikania/loader.hpp
     ${libmlk-common_SOURCE_DIR}/malikania/locator.hpp
@@ -34,6 +36,7 @@
 
 set(
     SOURCES
+    ${libmlk-common_SOURCE_DIR}/malikania/error/auth_error.cpp
     ${libmlk-common_SOURCE_DIR}/malikania/loader.cpp
     ${libmlk-common_SOURCE_DIR}/malikania/locator.cpp
     ${libmlk-common_SOURCE_DIR}/malikania/unicode.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcommon/malikania/error/auth_error.cpp	Tue Aug 21 10:55:13 2018 +0200
@@ -0,0 +1,40 @@
+/*
+ * auth_error.hpp -- auth command error
+ *
+ * Copyright (c) 2013-2018 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 "auth_error.hpp"
+
+namespace mlk {
+
+auto auth_error::error_category() -> std::string
+{
+	return "auth";
+}
+
+auto auth_error::error_message(error code) -> std::string
+{
+	switch (code) {
+	case invalid_credentials:
+		return "invalid credentials";
+	case already_connected:
+		return "already connected";
+	default:
+		return "no error";
+	}
+}
+
+} // !mlk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcommon/malikania/error/auth_error.hpp	Tue Aug 21 10:55:13 2018 +0200
@@ -0,0 +1,73 @@
+/*
+ * auth_error.hpp -- auth command error
+ *
+ * Copyright (c) 2013-2018 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 MALIKANIA_AUTH_ERROR_HPP
+#define MALIKANIA_AUTH_ERROR_HPP
+
+/**
+ * \file auth_error.hpp
+ * \brief Auth command error.
+ */
+
+#include "error.hpp"
+
+namespace mlk {
+
+/**
+ * \brief Auth command error.
+ */
+struct auth_error {
+	/**
+	 * \brief Error description
+	 */
+	enum error {
+		/**
+		 * \brief No error.
+		 */
+		no_error = 0,
+
+		/**
+		 * \brief Invalid password or login.
+		 */
+		invalid_credentials,
+
+		/**
+		 * \brief User is already connected.
+		 */
+		already_connected
+	};
+
+	static auto error_category() -> std::string;
+
+	/**
+	 * Convert the code to a human message.
+	 *
+	 * \param code the code
+	 */
+	static auto error_message(error code) -> std::string;
+};
+
+} // !mlk
+
+MALIKANIA_ERROR_CODE(
+	mlk::auth_error::error,
+	mlk::auth_error::error_category,
+	mlk::auth_error::error_message
+)
+
+#endif // !MALIKANIA_AUTH_ERROR_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcommon/malikania/error/error.hpp	Tue Aug 21 10:55:13 2018 +0200
@@ -0,0 +1,99 @@
+/*
+ * error.hpp -- error code creation
+ *
+ * Copyright (c) 2013-2018 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 MALIKANIA_ERROR_HPP
+#define MALIKANIA_ERROR_HPP
+
+/**
+ * \file error.hpp
+ * \brief Error code creation.
+ */
+
+#include <string>
+#include <system_error>
+#include <type_traits>
+
+/**
+ * Generate a custom std::error_code with the given type. The macro must be
+ * called outside mlk namespace.
+ *
+ * See the following example.
+ *
+ * ```cpp
+ * namespace mlk {
+ *
+ * class foo {
+ * public:
+ *     enum class error {
+ *         no_error = 0,
+ *         error_kind_foo,
+ *         error_kind_bar
+ *     };
+ *
+ *     static auto error_category() -> std::string
+ *     {
+ *         return "sometext";
+ *     }
+ *
+ *     static auto error_message(error code) -> std::string
+ *     {
+ *         // convert code to a string.
+ *     }
+ * };
+ *
+ * } // !mlk
+ *
+ * MALIKANIA_ERROR_CODE(
+ *     my_error::error,
+ *     my_error::error_category,
+ *     my_error::error_message
+ * )
+ * ```
+ */
+#define MALIKANIA_ERROR_CODE(Enum, Category, Message)                       \
+namespace std {                                                             \
+                                                                            \
+template <>                                                                 \
+struct is_error_code_enum<Enum> : public std::true_type {                   \
+};                                                                          \
+                                                                            \
+}                                                                           \
+                                                                            \
+namespace mlk {                                                             \
+                                                                            \
+inline auto make_error_code(Enum code) noexcept -> std::error_code          \
+{                                                                           \
+        static const class : public std::error_category {                   \
+        public:                                                             \
+            auto name() const noexcept -> const char* override              \
+            {                                                               \
+                    return Category().c_str();                              \
+            }                                                               \
+                                                                            \
+            auto message(int e) const -> std::string override               \
+            {                                                               \
+                    return Message(static_cast<Enum>(e));                   \
+            }                                                               \
+        } category;                                                         \
+                                                                            \
+        return { static_cast<int>(code), category };                        \
+}                                                                           \
+                                                                            \
+}
+
+#endif // !MALIKANIA_ERROR_HPP
--- a/libserver/malikania/server/client.cpp	Mon Oct 08 09:51:12 2018 +0200
+++ b/libserver/malikania/server/client.cpp	Tue Aug 21 10:55:13 2018 +0200
@@ -167,25 +167,18 @@
     send(std::move(message));
 }
 
-void client::error(std::string cmd, nlohmann::json args)
+void client::error(std::string cmd, std::error_code code)
 {
-    assert(args.is_object() || args.is_string());
-
-    if (args.is_string()) {
-        args = nlohmann::json::object({
-            { "error", args.get<std::string>() }
-        });
-    }
-
-    args["command"] = std::move(cmd);
-    args["status"] = false;
-
-    send(std::move(args));
+    send({
+        { "command",    std::move(cmd)  },
+        { "status",     code.value()    },
+        { "error",      code.message()  }
+    });
 }
 
-void client::fatal(std::string cmd, nlohmann::json args)
+void client::fatal(std::string cmd, std::error_code code)
 {
-    error(std::move(cmd), std::move(args));
+    error(std::move(cmd), std::move(code));
     state_ = state::closing;
 }
 
--- a/libserver/malikania/server/client.hpp	Mon Oct 08 09:51:12 2018 +0200
+++ b/libserver/malikania/server/client.hpp	Tue Aug 21 10:55:13 2018 +0200
@@ -30,6 +30,7 @@
 #include <optional>
 #include <sstream>
 #include <string>
+#include <system_error>
 
 #include <boost/asio.hpp>
 #include <boost/asio/ssl.hpp>
@@ -158,24 +159,24 @@
     /**
      * Send a error command result.
      *
-     * \pre !cmd.empty() && !reason.empty()
-     * \pre args.is_object() || args.is_string()
+     * \pre !cmd.empty()
+     * \pre code
      * \param cmd the command name
-     * \param args the extra data (can be a string)
+     * \param code the error code
      */
-    void error(std::string cmd, nlohmann::json args);
+    void error(std::string cmd, std::error_code code);
 
     /**
      * Send a fatal error result.
      *
      * The client state is changed to closing.
      *
-     * \pre !cmd.empty() && !reason.empty()
-     * \pre args.is_object() || args.is_string()
+     * \pre !cmd.empty()
+     * \pre code
      * \param cmd the command name
-     * \param args the extra data (can be a string)
+     * \param code the error code
      */
-    void fatal(std::string cmd, nlohmann::json args);
+    void fatal(std::string cmd, std::error_code code);
 };
 
 } // !mlk::server
--- a/libserver/malikania/server/net/auth_handler.cpp	Mon Oct 08 09:51:12 2018 +0200
+++ b/libserver/malikania/server/net/auth_handler.cpp	Tue Aug 21 10:55:13 2018 +0200
@@ -18,6 +18,8 @@
 
 #include <util.hpp>
 
+#include <malikania/error/auth_error.hpp>
+
 #include "db/account.hpp"
 
 #include "auth_handler.hpp"
@@ -51,9 +53,9 @@
     );
 
     if (!ac)
-        clt.error("auth", "invalid credentials");
+        clt.fatal("auth", auth_error::invalid_credentials);
     else if (is_connected(server, *ac))
-        clt.error("auth", "already connected");
+        clt.fatal("auth", auth_error::already_connected);
     else {
         clt.set_account(std::move(*ac));
         clt.set_state(client::state::ready);