changeset 171:ae34e5aec876

Server: cleanup
author David Demelier <markand@malikania.fr>
date Sat, 18 Aug 2018 15:05:08 +0200
parents a3af3b793da4
children 0e84c06ff44a
files libcommon/malikania/backend/sdl/sdl_util.cpp libcommon/malikania/backend/sdl/sdl_util.hpp libserver/CMakeLists.txt libserver/malikania/server/server.cpp libserver/malikania/server/server.hpp server/main.cpp
diffstat 6 files changed, 79 insertions(+), 376 deletions(-) [+]
line wrap: on
line diff
--- a/libcommon/malikania/backend/sdl/sdl_util.cpp	Sat Mar 17 14:51:00 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,148 +0,0 @@
-/*
- * sdl_util.cpp -- common SDL2 related code
- *
- * 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 <cerrno>
-#include <cstdint>
-#include <cstring>
-#include <new>
-
-#include "sdl_util.hpp"
-
-namespace mlk {
-
-namespace {
-
-/*
- * RWFromBinary implementation
- * ------------------------------------------------------------------
- *
- * A little bit inspired by official SDL_RWFromMem implementation, largely
- * modified to match our conventions and the C++ code.
- */
-
-class buffer {
-public:
-    std::string m_data;
-    std::uint64_t m_position;
-    std::uint64_t m_length;
-
-    inline buffer(std::string data) noexcept
-        : m_data(std::move(data))
-        , m_position(0ULL)
-        , m_length(m_data.length())
-    {
-    }
-};
-
-Sint64 size(SDL_RWops* ops) noexcept
-{
-    return reinterpret_cast<buffer*>(ops->hidden.unknown.data1)->m_length;
-}
-
-Sint64 seek(SDL_RWops* ops, Sint64 offset, int whence) noexcept
-{
-    buffer *data = reinterpret_cast<buffer*>(ops->hidden.unknown.data1);
-    Sint64 position = data->m_position;
-
-    switch (whence) {
-    case RW_SEEK_SET:
-        position = offset;
-        break;
-    case RW_SEEK_CUR:
-        position = data->m_position + offset;
-        break;
-    case RW_SEEK_END:
-        position = data->m_length + offset;
-        break;
-    default:
-        break;
-    }
-
-    if (position < 0LL) {
-        position = 0LL;
-    } else if (static_cast<std::uint64_t>(position) > data->m_length) {
-        position = data->m_length;
-    }
-
-    return (data->m_position = position);
-}
-
-std::size_t read(SDL_RWops* ops, void* dst, std::size_t size, std::size_t number) noexcept
-{
-    buffer* data = reinterpret_cast<buffer*>(ops->hidden.unknown.data1);
-    std::size_t total = number * size;
-    std::size_t avail = data->m_length - data->m_position;
-
-    if (number <= 0U || size <= 0U || ((total / number) != static_cast<std::size_t>(size))) {
-        return 0;
-    }
-    if (total > avail) {
-        total = avail;
-    }
-
-    SDL_memcpy(dst, &data->m_data[data->m_position], total);
-    data->m_position += total;
-
-    return total / size;
-}
-
-std::size_t write(SDL_RWops*, const void*, std::size_t, std::size_t) noexcept
-{
-    SDL_SetError("write not supported");
-    return -1;
-}
-
-int close(SDL_RWops* ops) noexcept
-{
-    if (ops != nullptr) {
-        delete reinterpret_cast<buffer*>(ops->hidden.unknown.data1);
-        SDL_FreeRW(ops);
-    }
-
-    return 0;
-}
-
-} // !namespace
-
-SDL_RWops* SDLx_RWFromBinary(std::string data) noexcept
-{
-    SDL_RWops* ops = SDL_AllocRW();
-
-    if (ops == nullptr) {
-        return nullptr;
-    }
-
-    ops->hidden.unknown.data1 = new (std::nothrow) buffer(std::move(data));
-
-    if (ops->hidden.unknown.data1 == nullptr) {
-        SDL_SetError("%s", std::strerror(errno));
-        SDL_FreeRW(ops);
-        return nullptr;
-    }
-
-    ops->type = SDL_RWOPS_UNKNOWN;
-    ops->seek = seek;
-    ops->size = size;
-    ops->read = read;
-    ops->write = write;
-    ops->close = close;
-
-    return ops;
-}
-
-} // !mlk
--- a/libcommon/malikania/backend/sdl/sdl_util.hpp	Sat Mar 17 14:51:00 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/*
- * sdl_util.hpp -- common SDL2 related code
- *
- * 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_SDL_UTIL_HPP
-#define MALIKANIA_SDL_UTIL_HPP
-
-/**
- * \file sdl_util.hpp
- * \brief Utilities for SDL backend.
- */
-
-#include <SDL.h>
-
-#include <string>
-
-namespace mlk {
-
-/**
- * Create a SDL_RWops that owns the binary data.
- *
- * This is a safe alternative to SDL_RWFromMem because it owns the memory
- * pointed by data until it is closed. The data is moved so there are no copies.
- *
- * The stream has read-only support and can not write.
- *
- * Seeking past-the-end or past-the-begin readjust the position to the end or
- * begin respectively.
- *
- * \param data the data
- * \return the object or nullptr on errors
- */
-SDL_RWops* SDLx_RWFromBinary(std::string data) noexcept;
-
-} // !mlk
-
-#endif // !MALIKANIA_SDL_UTIL_HPP
--- a/libserver/CMakeLists.txt	Sat Mar 17 14:51:00 2018 +0100
+++ b/libserver/CMakeLists.txt	Sat Aug 18 15:05:08 2018 +0200
@@ -19,6 +19,7 @@
 project(libmlk-server)
 
 find_package(PostgreSQL REQUIRED)
+find_package(Threads REQUIRED)
 
 set(
     HEADERS
@@ -49,10 +50,11 @@
     LIBRARIES
         ${Boost_LIBRARIES}
         ${PostgreSQL_LIBRARIES}
+        Threads::Threads
         OpenSSL::Crypto
         OpenSSL::SSL
         libmlk-common
-        $<$<BOOL:${WIN32}>:mswsock>
+        $<$<STREQUAL:${CMAKE_SYSTEM_NAME},Windows>:mswsock>
     PUBLIC_INCLUDES
         ${Boost_INCLUDE_DIRS}
         ${PostgreSQL_INCLUDE_DIRS}
--- a/libserver/malikania/server/server.cpp	Sat Mar 17 14:51:00 2018 +0100
+++ b/libserver/malikania/server/server.cpp	Sat Aug 18 15:05:08 2018 +0200
@@ -16,82 +16,50 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <iostream>
-
 #include "client.hpp"
 #include "server.hpp"
 #include "util.hpp"
 
 #include "net/auth_handler.hpp"
 
-namespace mlk {
+namespace mlk::server {
 
-namespace server {
+namespace {
 
-/*
- * server::load
- * ------------------------------------------------------------------
- */
+auto endpoint(const settings& params) -> boost::asio::ip::tcp::endpoint
+{
+    // TODO: add more settings there.
+    return boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), params.port);
+}
+
+} // !namespace
 
 void server::load()
 {
     handle("auth", std::make_unique<auth_handler>());
 }
 
-/*
- * server::start
- * ------------------------------------------------------------------
- *
- * Start an asynchronous accept(2) call.
- */
-
 void server::start()
 {
     auto clt = std::make_shared<client>(*this, service_, context_);
 
     acceptor_.async_accept(clt->socket_.lowest_layer(), [this, clt] (auto code) {
-        this->handle_accept(std::move(clt), code);
+        handle_accept(std::move(clt), code);
     });
 }
 
-/*
- * server::endpoint
- * ------------------------------------------------------------------
- *
- * Create an endpoint according to the parameters.
- */
-
-boost::asio::ip::tcp::endpoint server::endpoint(const settings& params) const
-{
-    // TODO: add more settings there.
-    return boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), params.port());
-}
-
-/*
- * server
- * ------------------------------------------------------------------
- *
- * Construct a server object and start listening for clients.
- */
-
-server::server(boost::asio::io_service& service, mlk::server::database& db, const settings& settings)
+server::server(boost::asio::io_service& service, const settings& settings)
     : service_(service)
     , acceptor_(service, endpoint(settings))
     , context_(boost::asio::ssl::context::sslv23)
-    , database_(db)
 {
-    context_.use_certificate_chain_file(settings.certificate());
-    context_.use_private_key_file(settings.key(), boost::asio::ssl::context::pem);
+    context_.use_certificate_chain_file(settings.certificate);
+    context_.use_private_key_file(settings.key, boost::asio::ssl::context::pem);
 
     load();
     start();
 }
 
-/*
- * server::handle
- * ------------------------------------------------------------------
- */
-
 void server::handle(std::string name, std::unique_ptr<handler> handler)
 {
     assert(!name.empty());
@@ -100,62 +68,41 @@
     handlers_.emplace(std::move(name), std::move(handler));
 }
 
-/*
- * server::handle_disconnect
- * ------------------------------------------------------------------
- *
- * Asynchronous function called when a client has been detected as disconnected.
- * The default implementation just removes the client from the server.
- */
-
 void server::handle_disconnect(std::shared_ptr<client> clt)
 {
-    std::cout << "client disconnected" << std::endl;
     clients_.erase(std::move(clt));
 }
 
-/*
- * server::handle_read
- * ------------------------------------------------------------------
- */
-
 void server::handle_read(std::shared_ptr<client> clt, nlohmann::json message)
 {
     assert(message.is_object());
 
-    auto cmd = message.find("command");
+    const auto cmd = message.find("command");
 
     if (cmd == message.end() || !cmd->is_string()) {
-        std::cerr << "client sent invalid message" << std::endl;
+        // TODO: log error.
         return;
     }
 
-    auto it = handlers_.find(*cmd);
+    const auto it = handlers_.find(*cmd);
 
-    // TODO: try-catch
     if (it == handlers_.end()) {
-        std::cerr << "client send an unknown or unhandled command" << std::endl;
-    } else {
+        // TODO: log error.
+        return;
+    }
+
+    try {
         it->second->exec(*this, std::move(clt), std::move(message));
+    } catch (const std::exception&) {
+        // TODO: log error.
     }
 }
 
-/*
- * server::handle_accept
- * ------------------------------------------------------------------
- *
- * Asynchronous function called once an accept(2) called has been finished with
- * or without errors.
- *
- * On success, request a handshake on the client.
- */
-
-void server::handle_accept(std::shared_ptr<client> clt, boost::system::error_code code)
+void server::handle_accept(std::shared_ptr<client> clt, std::error_code code)
 {
     if (code) {
-        std::cerr << "failed to accept: " << code << std::endl;
+        // TODO: log error.
     } else {
-        std::cout << "new client connected" << std::endl;
         clt->handshake();
         clients_.insert(std::move(clt));
     }
@@ -163,6 +110,4 @@
     start();
 }
 
-} // !server
-
-} // !mlk
+} // !mlk::server
--- a/libserver/malikania/server/server.hpp	Sat Mar 17 14:51:00 2018 +0100
+++ b/libserver/malikania/server/server.hpp	Sat Aug 18 15:05:08 2018 +0200
@@ -19,11 +19,17 @@
 #ifndef MALIKANIA_SERVER_SERVER_HPP
 #define MALIKANIA_SERVER_SERVER_HPP
 
+/**
+ * \file server.hpp
+ * \brief Malikania basic server.
+ */
+
 #include <cstdint>
 #include <memory>
 #include <string>
 #include <unordered_map>
 #include <unordered_set>
+#include <system_error>
 
 #include <boost/asio.hpp>
 #include <boost/asio/ssl.hpp>
@@ -42,62 +48,16 @@
 /**
  * \brief Server parameters
  */
-class settings {
-private:
-    std::uint16_t port_;
-    std::string certificate_;
-    std::string key_;
-
-public:
-    /**
-     * Constructor.
-     *
-     * \param port the port
-     * \param certificate the certificate file
-     * \param key the private key file
-     * \pre !certificate.empty()
-     * \pre !key.empty()
-     */
-    inline settings(std::uint16_t port, std::string certificate, std::string key) noexcept
-        : port_(port)
-        , certificate_(std::move(certificate))
-        , key_(std::move(key))
-    {
-        assert(!certificate_.empty());
-        assert(!key_.empty());
-    }
-
-    /**
-     * Get the associated port.
-     *
-     * \return the port
-     */
-    inline std::uint16_t port() const noexcept
-    {
-        return port_;
-    }
-
-    /**
-     * Get the certificate file.
-     *
-     * \return the path to the certificate file
-     */
-    inline const std::string& certificate() const noexcept
-    {
-        return certificate_;
-    }
-
-    /**
-     * Get the key file.
-     *
-     * \return the path to the key file
-     */
-    inline const std::string& key() const noexcept
-    {
-        return key_;
-    }
+struct settings {
+    std::uint16_t port{3320};
+    std::string certificate;
+    std::string key;
 };
 
+/**
+ * \file server.hpp
+ * \brief Malikania basic server.
+ */
 class server {
 private:
     boost::asio::io_service& service_;
@@ -107,28 +67,17 @@
     std::unordered_set<std::shared_ptr<client>> clients_;
     std::unordered_map<std::string, std::unique_ptr<handler>> handlers_;
 
-    mlk::server::database& database_;
-
     void load();
     void start();
 
-    boost::asio::ip::tcp::endpoint endpoint(const settings& params) const;
-
-protected:
-    void handle_auth(std::shared_ptr<client>, nlohmann::json);
-
 public:
-    server(boost::asio::io_service& service, mlk::server::database& db, const settings& settings);
-
-    inline mlk::server::database& database() noexcept
-    {
-        return database_;
-    }
-
-    inline const mlk::server::database& database() const noexcept
-    {
-        return database_;
-    }
+    /**
+     * Construct a server object.
+     *
+     * \param ctx the IO context
+     * \param settings the settings
+     */
+    server(boost::asio::io_service& service, const settings& settings);
 
     /**
      * Add network handler.
@@ -141,7 +90,12 @@
      */
     void handle(std::string name, std::unique_ptr<handler> handler);
 
-    virtual void handle_disconnect(std::shared_ptr<client>);
+    /**
+     * Handle client disconnection.
+     *
+     * \param client the client
+     */
+    virtual void handle_disconnect(std::shared_ptr<client> client);
 
     /**
      * Asynchronous function called once a message has been completely and
@@ -149,10 +103,19 @@
      *
      * The default implementation searches for a handler defined for this
      * message.
+     *
+     * \param client the client
+     * \param message the message received
      */
     virtual void handle_read(std::shared_ptr<client>, nlohmann::json message);
 
-    virtual void handle_accept(std::shared_ptr<client>, boost::system::error_code);
+    /**
+     * Handle accept of a new client.
+     *
+     * \param client the newly received client
+     * \param code the error code if any
+     */
+    virtual void handle_accept(std::shared_ptr<client> client, std::error_code code);
 };
 
 } // !server
--- a/server/main.cpp	Sat Mar 17 14:51:00 2018 +0100
+++ b/server/main.cpp	Sat Aug 18 15:05:08 2018 +0200
@@ -21,32 +21,24 @@
 #include <malikania/server/db/database.hpp>
 #include <malikania/server/db/account.hpp>
 
-using namespace mlk::server;
-using namespace mlk::server::db;
+#include <malikania/server/server.hpp>
+
+using namespace mlk;
 
 int main()
 {
+    boost::asio::io_context ctx;
+
     try {
-        db::open("", "", "markand", "malikaniadb", "");
-        db::exec("DROP TABLE spell");
-        db::exec("DROP TABLE character");
-        db::exec("DROP TABLE account");
-        db::init();
-
-        account a("markand", "plopation");
+        server::settings settings;
 
-        a.set_email("markand@malikania.fr");
-        a.set_firstname("David");
-        a.set_lastname("Demelier");
-
-        character ch("luna", "fairy");
-        spell s("heal");
-
-        ch.add(std::move(s));
-        puts("ABOUT TO ADD");
-        a.add(std::move(ch));
-        puts("ABOUT TO PUBLISH");
-        a.publish();
+        settings.key = "";
+        settings.certificate = "";
+        settings.port = 3320;
+        
+        server::server sv(ctx, settings);
+        
+        ctx.run();
     } catch (const std::exception& ex) {
         std::cerr << "abort: " << ex.what() << std::endl;
     }