From 09bd8bb2c684d313cfd92f3207e88cd381d63bb5 Mon Sep 17 00:00:00 2001 From: Alex Kovrigin Date: Tue, 15 Feb 2022 02:54:40 +0300 Subject: [PATCH 01/20] [general] cmake stuff --- CMakeLists.txt | 12 ++++++++++++ client/CMakeLists.txt | 16 +++++++--------- 2 files changed, 19 insertions(+), 9 deletions(-) create mode 100644 CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..cc5cf7c5 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.10) +project(cavoke) + +option(BUILD_SERVER "Enable building server" ON) +option(BUILD_CLIENT "Enable building client" ON) + +if(BUILD_SERVER) + add_subdirectory(server) +endif() +if(BUILD_CLIENT) + add_subdirectory(client) +endif() diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 301f46d6..542464c7 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -1,13 +1,11 @@ cmake_minimum_required(VERSION 3.10) -project(client) +project(cavoke_client) + +option(QT_MAJOR_VERSION "Qt Major Version (e.g. Qt5/Qt6)" 6) set(CMAKE_CXX_STANDARD 17) set(CMAKE_INCLUDE_CURRENT_DIR ON) -if (NOT QT_MAJOR_VERSION) - set(QT_MAJOR_VERSION 6) -endif() - find_package(Qt${QT_MAJOR_VERSION}Widgets REQUIRED) find_package(Qt${QT_MAJOR_VERSION}Quick REQUIRED) @@ -20,7 +18,7 @@ include_directories(${CMAKE_BINARY_DIR}) # https://api.kde.org/frameworks-api/frameworks-apidocs/frameworks/karchive/html/index.html find_package(KF5Archive REQUIRED) -add_executable(client +add_executable(cavoke_client main.cpp cavokeclientcontroller.cpp cavokeclientmodel.cpp @@ -29,6 +27,6 @@ add_executable(client tictactoelogic.cpp cache_manager.cpp) -target_link_libraries(client Qt${QT_MAJOR_VERSION}::Widgets) -target_link_libraries(client Qt${QT_MAJOR_VERSION}::Quick) -target_link_libraries(client KF5::Archive) +target_link_libraries(cavoke_client Qt${QT_MAJOR_VERSION}::Widgets) +target_link_libraries(cavoke_client Qt${QT_MAJOR_VERSION}::Quick) +target_link_libraries(cavoke_client KF5::Archive) From 98ca994554cec605c6d6ffd6d31e8cbe5d291082 Mon Sep 17 00:00:00 2001 From: Alex Kovrigin Date: Tue, 15 Feb 2022 02:56:02 +0300 Subject: [PATCH 02/20] [server] WIP games storage config + options parsing for server --- server/CMakeLists.txt | 13 ++++++-- server/main.cpp | 50 ++++++++++++++++++++++++----- server/model/GamesStorageConfig.cpp | 36 +++++++++++++++++++++ server/model/GamesStorageConfig.h | 14 ++++++++ server/model/game.cpp | 43 ++++++++++++++----------- server/model/game.h | 15 +++++---- server/model/games_storage.cpp | 8 ++--- server/model/games_storage.h | 5 +-- 8 files changed, 142 insertions(+), 42 deletions(-) create mode 100644 server/model/GamesStorageConfig.cpp create mode 100644 server/model/GamesStorageConfig.h diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index 72268401..cbda9823 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -5,10 +5,19 @@ set(CMAKE_CXX_STANDARD 17) find_package(Drogon REQUIRED) -find_package(Boost 1.71 REQUIRED filesystem) +find_package(Boost 1.71 REQUIRED filesystem program_options) include_directories(${Boost_INCLUDE_DIRS}) link_directories(${Boost_LIBRARY_DIRS}) -add_executable(cavoke_server model/games_storage.cpp model/game.cpp controllers/games_controller.cpp main.cpp controllers/health_controller.cpp controllers/health_controller.h) +add_executable(cavoke_server + model/games_storage.cpp + model/game.cpp + controllers/games_controller.cpp + main.cpp + controllers/health_controller.cpp + controllers/health_controller.h + model/GamesStorageConfig.cpp + model/GamesStorageConfig.h + ) target_link_libraries(cavoke_server Drogon::Drogon) target_link_libraries(cavoke_server ${Boost_LIBRARIES} ${CMAKE_DL_LIBS}) diff --git a/server/main.cpp b/server/main.cpp index 0414850f..4450d0a6 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -1,31 +1,65 @@ #include "controllers/games_controller.h" #include "model/games_storage.h" + +#include #include namespace cavoke::server { -void run() { +void run(const std::string &host, uint16_t port, const std::string &config_file) { // TODO: logging // init models std::cout << "Initialize models..." << std::endl; auto games_storage = std::make_shared( - model::GamesStorage::GamesStorageConfig{"../../local_server/games"}); + model::GamesStorageConfig::load(config_file)); // init controllers std::cout << "Initialize controllers..." << std::endl; auto games_controller = std::make_shared(games_storage); + auto& app = drogon::app(); + // register controllers - drogon::app().registerController(games_controller); + app.registerController(games_controller); - // RUN! - std::cout << "Run server on 127.0.0.1:8080" << std::endl; - drogon::app().addListener("127.0.0.1", 8080).run(); + // start server + std::cout << "Listening at " << host << ":" << port << std::endl; + app.addListener(host, port).run(); } } // namespace cavoke::server -int main() { - cavoke::server::run(); + +namespace po = boost::program_options; + +int main(int argc, char* argv[]) { + po::options_description desc("Allowed options"); + desc.add_options() + ("help,h,?", "Print help") + ("config-file,c", po::value(), "File with game storage configuration") + ("host,ip,a", po::value()->default_value("0.0.0.0"), "Host on which server is located") + ("port,p", po::value()->default_value(8080), "TCP/IP port number for connection") + ; + + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + + if (vm.count("help")) { + std::cout << desc << "\n"; + return 0; + } + + std::string config_file; + if (vm.count("config-file")) { + config_file = vm["config-file"].as(); + } else { +// config_file = std::getenv("CAVOKE_SERVER_CONFIG"); // TODO: think and discuss + } + + std::string host = vm.at("host").as(); + uint16_t port = vm.at("port").as(); + + cavoke::server::run(host, port, config_file); return 0; } diff --git a/server/model/GamesStorageConfig.cpp b/server/model/GamesStorageConfig.cpp new file mode 100644 index 00000000..09aa1555 --- /dev/null +++ b/server/model/GamesStorageConfig.cpp @@ -0,0 +1,36 @@ +#include "GamesStorageConfig.h" +#include +#include +#include + +namespace cavoke::server::model { + +GamesStorageConfig +GamesStorageConfig::load(const std::string &config_file) { + if (config_file.empty()) { + // FIXME: rewrite this mess... + std::cerr << "No games storage config specified. Using a default one. Please use `-c` option.\n"; + return GamesStorageConfig{ + "../../local_server/games", + "logic", + "client.zip", + "config.json" + }; + } + if (!boost::filesystem::exists(config_file) || + !boost::filesystem::is_regular_file(config_file)) { // FIXME + throw std::invalid_argument("No such game storage configuration file: " + config_file); + } + + // FIXME: trash code; let's use https://github.com/nlohmann/json#arbitrary-types-conversions or something similar + Json::Value obj; + std::ifstream file(config_file); + Json::Reader reader; + assert(reader.parse(file, obj, false)); + file.close(); + + GamesStorageConfig res{obj["games_directory"].as(), obj["logic_name"].as(), obj["zip_name"].as(), obj["config_name"].as()}; + return res; +} + +} \ No newline at end of file diff --git a/server/model/GamesStorageConfig.h b/server/model/GamesStorageConfig.h new file mode 100644 index 00000000..96c12ed5 --- /dev/null +++ b/server/model/GamesStorageConfig.h @@ -0,0 +1,14 @@ +#ifndef CAVOKE_GAMESSTORAGECONFIG_H +#define CAVOKE_GAMESSTORAGECONFIG_H + +#include +namespace cavoke::server::model { +struct GamesStorageConfig { + const boost::filesystem::path games_directory; + const std::string logic_name; + const std::string zip_name; + const std::string json_name; + static GamesStorageConfig load(const std::string &config_file); +}; +} +#endif // CAVOKE_GAMESSTORAGECONFIG_H diff --git a/server/model/game.cpp b/server/model/game.cpp index aa750b65..57e2ad1d 100644 --- a/server/model/game.cpp +++ b/server/model/game.cpp @@ -8,13 +8,13 @@ namespace cavoke::server::model { -const std::string Game::CONFIG_FILE = "config.json"; -const std::string Game::CLIENT_FILE = "client.zip"; -const std::string Game::LOGIC_FILE = "logic"; - -Game::Game(boost::filesystem::path directory_) - : directory(std::move(directory_)), logic_file(directory / LOGIC_FILE), - client_file(directory / CLIENT_FILE) { +Game::Game(boost::filesystem::path directory, + const GamesStorageConfig &game_storage_config) + : directory(std::move(directory)), logic_file(directory / LOGIC_FILE), + client_file(directory / CLIENT_FILE), + CLIENT_FILE(game_storage_config.zip_name), + LOGIC_FILE(game_storage_config.logic_name), + CONFIG_FILE(game_storage_config.json_name) { Json::Value json_config; read_config_file(directory / CONFIG_FILE, json_config); config.id = json_config["id"].asString(); @@ -23,29 +23,36 @@ Game::Game(boost::filesystem::path directory_) config.players_num = json_config["players_num"].asInt(); } -bool Game::is_game_directory(const boost::filesystem::path &directory) { +bool Game::is_game_directory(const boost::filesystem::path &path, + const GamesStorageConfig &games_storage_config) { Json::Value tmp; - return boost::filesystem::exists(directory) && - boost::filesystem::is_directory(directory) && - boost::filesystem::exists(directory / CLIENT_FILE) && - boost::filesystem::is_regular_file(directory / CLIENT_FILE) && - boost::filesystem::exists(directory / CONFIG_FILE) && - boost::filesystem::is_regular_file(directory / CONFIG_FILE) && - boost::filesystem::exists(directory / LOGIC_FILE) && - boost::filesystem::is_regular_file(directory / LOGIC_FILE) && - read_config_file(directory / CONFIG_FILE, tmp); + // TODO: rewrite + const auto& CLIENT_FILE = games_storage_config.zip_name, + CONFIG_FILE = games_storage_config.json_name, + LOGIC_FILE = games_storage_config.logic_name; + // TODO: extract function exists & directory + exists & regular file + return boost::filesystem::exists(path) && + boost::filesystem::is_directory(path) && + boost::filesystem::exists(path / CLIENT_FILE) && + boost::filesystem::is_regular_file(path / CLIENT_FILE) && + boost::filesystem::exists(path / CONFIG_FILE) && + boost::filesystem::is_regular_file(path / CONFIG_FILE) && + boost::filesystem::exists(path / LOGIC_FILE) && + boost::filesystem::is_regular_file(path / LOGIC_FILE) && + read_config_file(path / CONFIG_FILE, tmp); } bool Game::read_config_file(const boost::filesystem::path &path, Json::Value &json_obj) { std::ifstream file(path); - Json::Reader reader; + Json::Reader reader; // deprecated bool success = reader.parse(file, json_obj, false); file.close(); return success; } Json::Value Game::GameConfig::to_json() const { + // TODO: please let's use https://github.com/nlohmann/json#arbitrary-types-conversions Json::Value result; result["id"] = id; result["display_name"] = display_name; diff --git a/server/model/game.h b/server/model/game.h index f22f7033..8c523111 100644 --- a/server/model/game.h +++ b/server/model/game.h @@ -3,13 +3,14 @@ #include #include #include +#include "GamesStorageConfig.h" namespace cavoke::server::model { class Game { - static const std::string CONFIG_FILE; - static const std::string CLIENT_FILE; - static const std::string LOGIC_FILE; + const std::string CONFIG_FILE; + const std::string CLIENT_FILE; + const std::string LOGIC_FILE; boost::filesystem::path directory; @@ -26,14 +27,16 @@ class Game { Json::Value &json_obj); public: - explicit Game(boost::filesystem::path directory); - Game() = default; + explicit Game(boost::filesystem::path directory, + const GamesStorageConfig &game_storage_config); + Game() = default; // TODO: rethink json boost::filesystem::path client_file; GameConfig config; boost::filesystem::path logic_file; - static bool is_game_directory(const boost::filesystem::path &path); + static bool is_game_directory(const boost::filesystem::path &path, + const GamesStorageConfig &games_storage_config); }; } // namespace cavoke::server::model diff --git a/server/model/games_storage.cpp b/server/model/games_storage.cpp index 83bb434a..ff71f435 100644 --- a/server/model/games_storage.cpp +++ b/server/model/games_storage.cpp @@ -7,8 +7,8 @@ namespace cavoke::server::model { -GamesStorage::GamesStorage(GamesStorage::GamesStorageConfig config_) - : m_config(std::move(config_)) { +GamesStorage::GamesStorage(GamesStorageConfig config) + : m_config(std::move(config)) { if (!boost::filesystem::exists(m_config.games_directory)) { bool success = @@ -42,12 +42,12 @@ void GamesStorage::update() { for (auto &entry : boost::make_iterator_range( boost::filesystem::directory_iterator(m_config.games_directory), {})) { - if (!Game::is_game_directory(entry)) { + if (!Game::is_game_directory(entry, m_config)) { // TODO: logging std::cerr << entry << " entity from games directory is not a valid game" << std::endl; } else { - Game game(entry); + Game game(entry, m_config); m_games.emplace(game.config.id, game); } } diff --git a/server/model/games_storage.h b/server/model/games_storage.h index bf663d19..980a851d 100644 --- a/server/model/games_storage.h +++ b/server/model/games_storage.h @@ -2,6 +2,7 @@ #define CAVOKE_GAMES_STORAGE_H #include "game.h" +#include "GamesStorageConfig.h" #include #include #include @@ -10,10 +11,6 @@ namespace cavoke::server::model { class GamesStorage { // TODO: thread-safety public: - struct GamesStorageConfig { - boost::filesystem::path games_directory; - }; - explicit GamesStorage(GamesStorageConfig config); void update(); From b3744043e89c0a041bd0f22790c48ea1714fe419 Mon Sep 17 00:00:00 2001 From: Alex Kovrigin Date: Tue, 15 Feb 2022 03:05:40 +0300 Subject: [PATCH 03/20] [server] minor fixes for ci --- server/controllers/health_controller.cpp | 2 +- server/model/GamesStorageConfig.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server/controllers/health_controller.cpp b/server/controllers/health_controller.cpp index b8dfbc4a..4c65e546 100644 --- a/server/controllers/health_controller.cpp +++ b/server/controllers/health_controller.cpp @@ -3,7 +3,7 @@ void cavoke::server::controllers::HealthController::health( const drogon::HttpRequestPtr &req, std::function &&callback) { auto resp = drogon::HttpResponse::newHttpResponse(); - resp->setContentTypeString("text/plain"); + resp->setContentTypeCode(drogon::CT_TEXT_PLAIN); resp->setBody("OK"); callback(resp); } diff --git a/server/model/GamesStorageConfig.cpp b/server/model/GamesStorageConfig.cpp index 09aa1555..a39305de 100644 --- a/server/model/GamesStorageConfig.cpp +++ b/server/model/GamesStorageConfig.cpp @@ -29,7 +29,7 @@ GamesStorageConfig::load(const std::string &config_file) { assert(reader.parse(file, obj, false)); file.close(); - GamesStorageConfig res{obj["games_directory"].as(), obj["logic_name"].as(), obj["zip_name"].as(), obj["config_name"].as()}; + GamesStorageConfig res{obj["games_directory"].asString(), obj["logic_name"].asString(), obj["zip_name"].asString(), obj["config_name"].asString()}; return res; } From d25d9ff3e5e83ad286d4801090df92b3b4916bde Mon Sep 17 00:00:00 2001 From: Alex Kovrigin Date: Tue, 15 Feb 2022 03:13:54 +0300 Subject: [PATCH 04/20] [ci] first basic server ci resolves #13 --- .circleci/config.yml | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1c5cff67..589acbbe 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,7 +1,7 @@ version: 2.1 jobs: - suse-qt5-notests: + client-suse-qt5-notests: docker: - image: kdeorg/ci-suse-qt515 steps: @@ -11,11 +11,11 @@ jobs: - checkout - run: name: Cmake - command: cmake client -DQT_MAJOR_VERSION=5 + command: cmake . -DBUILD_SERVER=OFF -DQT_MAJOR_VERSION=5 - run: name: Make - command: make all - suse-qt6-notests: + command: make cavoke_client + client-suse-qt6-notests: docker: - image: kdeorg/ci-suse-qt62 steps: @@ -25,13 +25,28 @@ jobs: command: chmod +x .circleci/suse-qt6-install-karchive.sh && .circleci/suse-qt6-install-karchive.sh - run: name: Cmake - command: cmake client -DQT_MAJOR_VERSION=6 # QT_MAJOR_VERSION=6 by default, so not necessary + command: cmake . -DBUILD_SERVER=OFF -DQT_MAJOR_VERSION=6 # QT_MAJOR_VERSION=6 by default, so not necessary - run: name: Make - command: make all + command: make cavoke_client + server-docker-notests: + docker: + - image: drogonframework/drogon + steps: + - run: + name: Install Boost + command: apt update -y && apt install libboost-all-dev -y + - checkout + - run: + name: Cmake + run: cmake . -DBUILD_CLIENT=OFF + - run: + name: Make + run: make cavoke_server workflows: client-workflow: jobs: - - suse-qt5-notests - - suse-qt6-notests + - client-suse-qt5-notests + - client-suse-qt6-notests + - server-docker-notests From 1e7d4a24c7a0a897c4df161b524e2830b00f6396 Mon Sep 17 00:00:00 2001 From: Alex Kovrigin Date: Tue, 15 Feb 2022 03:14:37 +0300 Subject: [PATCH 05/20] Updated config.yml --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 589acbbe..f3c0018e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -39,10 +39,10 @@ jobs: - checkout - run: name: Cmake - run: cmake . -DBUILD_CLIENT=OFF + command: cmake . -DBUILD_CLIENT=OFF - run: name: Make - run: make cavoke_server + command: make cavoke_server workflows: client-workflow: From 17c097ef9fe286d7ac055671aa62c5a0303d303b Mon Sep 17 00:00:00 2001 From: Petr Tsvetkov Date: Tue, 15 Feb 2022 09:30:03 +0300 Subject: [PATCH 06/20] Fix std::move(directory) bug --- server/model/game.cpp | 6 +++--- server/model/game.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/server/model/game.cpp b/server/model/game.cpp index 57e2ad1d..4a2e4d86 100644 --- a/server/model/game.cpp +++ b/server/model/game.cpp @@ -8,9 +8,9 @@ namespace cavoke::server::model { -Game::Game(boost::filesystem::path directory, +Game::Game(const boost::filesystem::path &directory, const GamesStorageConfig &game_storage_config) - : directory(std::move(directory)), logic_file(directory / LOGIC_FILE), + : directory(directory), logic_file(directory / LOGIC_FILE), client_file(directory / CLIENT_FILE), CLIENT_FILE(game_storage_config.zip_name), LOGIC_FILE(game_storage_config.logic_name), @@ -27,7 +27,7 @@ bool Game::is_game_directory(const boost::filesystem::path &path, const GamesStorageConfig &games_storage_config) { Json::Value tmp; // TODO: rewrite - const auto& CLIENT_FILE = games_storage_config.zip_name, + const auto &CLIENT_FILE = games_storage_config.zip_name, CONFIG_FILE = games_storage_config.json_name, LOGIC_FILE = games_storage_config.logic_name; // TODO: extract function exists & directory + exists & regular file diff --git a/server/model/game.h b/server/model/game.h index 8c523111..6399bf72 100644 --- a/server/model/game.h +++ b/server/model/game.h @@ -27,7 +27,7 @@ class Game { Json::Value &json_obj); public: - explicit Game(boost::filesystem::path directory, + explicit Game(const boost::filesystem::path& directory, const GamesStorageConfig &game_storage_config); Game() = default; // TODO: rethink json From ff685d15d4cd57f64e6ed155a4d03ae602a00758 Mon Sep 17 00:00:00 2001 From: Alex Kovrigin Date: Tue, 15 Feb 2022 16:59:28 +0300 Subject: [PATCH 07/20] [ci] make basic healthcheck for server --- .circleci/config.yml | 7 ++++-- .circleci/server-test-health.py | 43 +++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 .circleci/server-test-health.py diff --git a/.circleci/config.yml b/.circleci/config.yml index f3c0018e..0b89cb6d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -29,7 +29,7 @@ jobs: - run: name: Make command: make cavoke_client - server-docker-notests: + server-docker-healthcheck: docker: - image: drogonframework/drogon steps: @@ -43,10 +43,13 @@ jobs: - run: name: Make command: make cavoke_server + - run: + name: Simple healthcheck + command: chmod +x .circleci/server-test-health.py && .circleci/server-test-health.py ./server/cavoke_server workflows: client-workflow: jobs: - client-suse-qt5-notests - client-suse-qt6-notests - - server-docker-notests + - server-docker-healthcheck diff --git a/.circleci/server-test-health.py b/.circleci/server-test-health.py new file mode 100644 index 00000000..00dd3273 --- /dev/null +++ b/.circleci/server-test-health.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +import atexit +import time + +import requests +import subprocess +import sys + + +def check_eq(expected, actual): + if expected != actual: + print(f'Check failed: expected {repr(expected)}, got {repr(actual)}') + sys.exit(1) + + +def main(): + _, *server_cmd = sys.argv + assert server_cmd, 'Expected usage: ./server-test-health.py ' + + port = 8080 + print(f'Booting server... at {server_cmd}', flush=True) + + server = subprocess.Popen(args=[*server_cmd, '-p', str(port)]) + def kill_server(): + try: + server.wait(timeout=0.1) + except subprocess.TimeoutExpired: + print('Server terminating...', flush=True) + server.kill() + atexit.register(kill_server) + time.sleep(2) # FIXME + print('Checks starting...', flush=True) + + with requests.get(f'http://localhost:{port}/health') as r: + check_eq(200, r.status_code) + check_eq("OK", r.text) + print("Health ok.") + + print('All ok.') + + +if __name__ == '__main__': + main() From 00d09e1cc2c196f84b3595ce4d243cdc7a9bc779 Mon Sep 17 00:00:00 2001 From: Alex Kovrigin Date: Tue, 15 Feb 2022 17:01:20 +0300 Subject: [PATCH 08/20] [ci] make basic healthcheck for server --- .circleci/server-test-health.py | 86 ++++++++++++++++----------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/.circleci/server-test-health.py b/.circleci/server-test-health.py index 00dd3273..254efcd8 100644 --- a/.circleci/server-test-health.py +++ b/.circleci/server-test-health.py @@ -1,43 +1,43 @@ -#!/usr/bin/env python3 -import atexit -import time - -import requests -import subprocess -import sys - - -def check_eq(expected, actual): - if expected != actual: - print(f'Check failed: expected {repr(expected)}, got {repr(actual)}') - sys.exit(1) - - -def main(): - _, *server_cmd = sys.argv - assert server_cmd, 'Expected usage: ./server-test-health.py ' - - port = 8080 - print(f'Booting server... at {server_cmd}', flush=True) - - server = subprocess.Popen(args=[*server_cmd, '-p', str(port)]) - def kill_server(): - try: - server.wait(timeout=0.1) - except subprocess.TimeoutExpired: - print('Server terminating...', flush=True) - server.kill() - atexit.register(kill_server) - time.sleep(2) # FIXME - print('Checks starting...', flush=True) - - with requests.get(f'http://localhost:{port}/health') as r: - check_eq(200, r.status_code) - check_eq("OK", r.text) - print("Health ok.") - - print('All ok.') - - -if __name__ == '__main__': - main() +#!/usr/bin/env python3 +import atexit +import time + +import requests +import subprocess +import sys + + +def check_eq(expected, actual): + if expected != actual: + print(f'Check failed: expected {repr(expected)}, got {repr(actual)}') + sys.exit(1) + + +def main(): + _, *server_cmd = sys.argv + assert server_cmd, 'Expected usage: ./server-test-health.py ' + + port = 8080 + print(f'Booting server... at {server_cmd}', flush=True) + + server = subprocess.Popen(args=[*server_cmd, '-p', str(port)]) + def kill_server(): + try: + server.wait(timeout=0.1) + except subprocess.TimeoutExpired: + print('Server terminating...', flush=True) + server.kill() + atexit.register(kill_server) + time.sleep(2) # FIXME + print('Checks starting...', flush=True) + + with requests.get(f'http://localhost:{port}/health') as r: + check_eq(200, r.status_code) + check_eq("OK", r.text) + print("Health ok.") + + print('All ok.') + + +if __name__ == '__main__': + main() From 548bb4a139c888d18f381f6207ce23e14f003304 Mon Sep 17 00:00:00 2001 From: Alex Kovrigin Date: Sun, 20 Feb 2022 00:50:32 +0300 Subject: [PATCH 09/20] [server] apply clangformat --- .postman/schemas/schema.yaml | 340 ++++++++++++++++------- server/controllers/games_controller.cpp | 57 ++-- server/controllers/games_controller.h | 55 ++-- server/controllers/health_controller.cpp | 8 +- server/controllers/health_controller.h | 16 +- server/main.cpp | 94 ++++--- server/model/GamesStorageConfig.cpp | 53 ++-- server/model/GamesStorageConfig.h | 14 +- server/model/game.cpp | 74 ++--- server/model/game.h | 49 ++-- server/model/games_storage.cpp | 75 ++--- server/model/games_storage.h | 24 +- 12 files changed, 511 insertions(+), 348 deletions(-) diff --git a/.postman/schemas/schema.yaml b/.postman/schemas/schema.yaml index beef7086..c7f098eb 100644 --- a/.postman/schemas/schema.yaml +++ b/.postman/schemas/schema.yaml @@ -1,107 +1,226 @@ openapi: 3.0.0 info: - version: '0.0.2' - title: 'cavoke' + version: '0.0.3' + title: 'cavoke' servers: - - url: 'localhost:8080' + - url: 'localhost:8080' paths: - /health: - get: - summary: 'Simple health check' - operationId: health - responses: - '200': - description: 'OK' - content: - text/plain: - schema: - type: string - example: OK - - /games/list: - get: - summary: 'List available games to play' - operationId: listGames - tags: - - game - responses: - '200': - description: 'List of available games as metadata' - content: - application/json: - schema: - type: array - items: - $ref: "#/components/schemas/GameInfo" - default: - description: Unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /games/{game_id}/get_config: - get: - summary: 'Get GameInfo of specific game' - operationId: configGame - tags: - - game - parameters: - - in: path - name: game_id - schema: - $ref: '#/components/schemas/GameId' - required: true - description: 'String id of the game to get' - responses: - '200': - description: 'Config of an existing game' - content: - application/json: - schema: - $ref: "#/components/schemas/GameInfo" - '404': - description: 'No such game' - default: - description: Unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /games/{game_id}/get_client: - get: - summary: 'Download QML client zip of a game' - operationId: downloadClient - tags: - - game - parameters: - - in: path - name: game_id - schema: + /health: + get: + summary: 'Simple health check' + operationId: health + responses: + '200': + description: 'OK' + content: + text/plain: + schema: + type: string + example: OK + + /games/list: + get: + summary: 'List available games to play' + operationId: listGames + responses: + '200': + description: 'List of available games as metadata' + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/GameInfo" + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /games/{game_id}/get_config: + get: + summary: 'Get GameInfo of specific game' + operationId: configGame + parameters: + - in: path + name: game_id + schema: + $ref: '#/components/schemas/GameId' + required: true + description: 'String id of the game to get' + example: tictactoe + responses: + '200': + description: 'Config of an existing game' + content: + application/json: + schema: + $ref: "#/components/schemas/GameInfo" + '404': + description: 'No such game' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /games/{game_id}/get_client: + get: + summary: 'Download QML client zip of a game' + operationId: downloadClient + parameters: + - in: path + name: game_id + schema: + $ref: '#/components/schemas/GameId' + required: true + description: 'String id of the game to get' + example: 'tictactoe' + responses: + '200': + description: 'Client zip file of an existing game' + content: + application/octet-stream: + schema: + type: string + format: binary + '404': + description: 'No such game' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /sessions/create: + post: + summary: 'Create a game from requested game' + operationId: createSession + parameters: + - in: query + name: game_id + schema: + $ref: '#/components/schemas/GameId' + required: true + description: 'String id of the game to get' + example: tictactoe + - in: query + name: user_id + schema: + $ref: '#/components/schemas/UserId' + required: true + description: 'User id' + example: c84d0d6e-547a-4e3a-92ba-5a6ff6c3d51f + responses: + '200': + description: 'Created successfully' + content: + application/json: + schema: + type: object + properties: + game_id: $ref: '#/components/schemas/GameId' - required: true - description: 'String id of the game to get' - example: 'tictactoe' - responses: - '200': - description: 'Client zip file of an existing game' - content: - application/octet-stream: - schema: - type: string - format: binary - '404': - description: 'No such game' - default: - description: Unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' + session_id: + $ref: '#/components/schemas/SessionId' + '400': + description: 'Bad request' + '404': + description: 'No game with such game id' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /play/{session_id}/send_move: + post: + summary: 'Send a move from QML game' + operationId: sendMove + parameters: + - in: path + name: session_id + schema: + $ref: '#/components/schemas/SessionId' + required: true + example: 83896dd5-6f03-4805-8cf1-03ce6bd6077f + - in: query + name: user_id + schema: + $ref: '#/components/schemas/UserId' + required: true + description: 'User id' + example: c84d0d6e-547a-4e3a-92ba-5a6ff6c3d51f + requestBody: + description: Game move data + content: + application/json: + schema: + $ref: '#/components/schemas/GameMove' + responses: + '200': + description: 'Move accepted' + + '404': + description: 'No such session / no such user' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /play/{session_id}/get_update: + get: + summary: 'Try get an update from QML game' + operationId: getUpdate + tags: + - play + parameters: + - in: path + name: session_id + schema: + type: string + format: uuid + required: true + description: 'UUID of a game session (room to game pair)' + - in: query + name: user_id + schema: + $ref: '#/components/schemas/UserId' + required: true + description: 'User id' + example: c84d0d6e-547a-4e3a-92ba-5a6ff6c3d51f + - in: query + name: offset + schema: + type: integer + format: int32 + example: 32 + description: 'Only get updates after this id (by default 0, so returns all updates throught the game)' + responses: + '200': + description: 'List updates (in an ascending order of ids)' + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/GameUpdate" + '404': + description: 'No such session / no such user' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' components: schemas: GameId: type: string + example: tictactoe GameInfo: type: object required: @@ -128,8 +247,41 @@ components: code: type: integer format: int32 + example: 31 message: type: string + example: 'Something went wrong' + GameMove: + type: object + properties: + move: + type: string + description: 'Any information about the move supplied by QML. May be any string (e.g. JSON)' + required: + - user_id + - move + GameUpdate: + type: object + properties: + user_id: + type: string + format: uuid + example: c84d0d6e-547a-4e3a-92ba-5a6ff6c3d51f + update: + type: string + description: "Any information about the update supplied by app's logic. May be any string (e.g. JSON)" + example: '{"action": "x_move", x: 0, y: 2}' + id: + type: integer + format: int32 + example: 1 + required: + - user_id + - update + SessionId: + type: string + format: uuid + example: 83896dd5-6f03-4805-8cf1-03ce6bd6077f securitySchemes: BasicAuth: type: http diff --git a/server/controllers/games_controller.cpp b/server/controllers/games_controller.cpp index 689dfd09..7c88805f 100644 --- a/server/controllers/games_controller.cpp +++ b/server/controllers/games_controller.cpp @@ -1,54 +1,55 @@ #include "games_controller.h" -#include "../model/game.h" - #include #include +#include "../model/game.h" cavoke::server::controllers::GamesController::GamesController( std::shared_ptr games_storage) - : m_games_storage(std::move(games_storage)) {} + : m_games_storage(std::move(games_storage)) { +} void cavoke::server::controllers::GamesController::games_list( const drogon::HttpRequestPtr &req, std::function &&callback) { - std::vector games = m_games_storage->list_games(); - Json::Value result(Json::arrayValue); - for (const auto &game : games) { - result.append(game.config.to_json()); - } + std::vector games = m_games_storage->list_games(); + Json::Value result(Json::arrayValue); + for (const auto &game : games) { + result.append(game.config.to_json()); + } - auto resp = drogon::HttpResponse::newHttpJsonResponse(result); - callback(resp); + auto resp = drogon::HttpResponse::newHttpJsonResponse(result); + callback(resp); } void cavoke::server::controllers::GamesController::game_config( const drogon::HttpRequestPtr &req, std::function &&callback, const std::string &game_id) { - auto game = m_games_storage->get_game_by_id(game_id); - if (!game.has_value()) { - auto resp = drogon::HttpResponse::newNotFoundResponse(); + auto game = m_games_storage->get_game_by_id(game_id); + if (!game.has_value()) { + auto resp = drogon::HttpResponse::newNotFoundResponse(); + callback(resp); + return; + } + + auto resp = + drogon::HttpResponse::newHttpJsonResponse(game->config.to_json()); callback(resp); - return; - } - - auto resp = drogon::HttpResponse::newHttpJsonResponse(game->config.to_json()); - callback(resp); } void cavoke::server::controllers::GamesController::game_client_file( const drogon::HttpRequestPtr &req, std::function &&callback, const std::string &game_id) { - auto game = m_games_storage->get_game_by_id(game_id); - if (!game.has_value()) { - auto resp = drogon::HttpResponse::newNotFoundResponse(); + auto game = m_games_storage->get_game_by_id(game_id); + if (!game.has_value()) { + auto resp = drogon::HttpResponse::newNotFoundResponse(); + callback(resp); + return; + } + + auto resp = drogon::HttpResponse::newFileResponse( + boost::filesystem::canonical(game->client_file).string(), + game->config.id + ".zip"); callback(resp); - return; - } - - auto resp = drogon::HttpResponse::newFileResponse( - boost::filesystem::canonical(game->client_file).string(), - game->config.id + ".zip"); - callback(resp); } diff --git a/server/controllers/games_controller.h b/server/controllers/games_controller.h index 1d19b9af..468e2613 100644 --- a/server/controllers/games_controller.h +++ b/server/controllers/games_controller.h @@ -1,40 +1,43 @@ #ifndef CAVOKE_SERVER_GAMES_CONTROLLER_H #define CAVOKE_SERVER_GAMES_CONTROLLER_H -#include "../model/games_storage.h" #include +#include "../model/games_storage.h" namespace cavoke::server::controllers { class GamesController : public drogon::HttpController { - std::shared_ptr m_games_storage; + std::shared_ptr m_games_storage; public: - METHOD_LIST_BEGIN - ADD_METHOD_TO(GamesController::games_list, "/games/list", drogon::Get); - ADD_METHOD_TO(GamesController::game_config, "/games/{game_id}/get_config", - drogon::Get); - ADD_METHOD_TO(GamesController::game_client_file, - "/games/{game_id}/get_client", drogon::Get); - METHOD_LIST_END - - explicit GamesController(std::shared_ptr games_storage); + METHOD_LIST_BEGIN + ADD_METHOD_TO(GamesController::games_list, "/games/list", drogon::Get); + ADD_METHOD_TO(GamesController::game_config, + "/games/{game_id}/get_config", + drogon::Get); + ADD_METHOD_TO(GamesController::game_client_file, + "/games/{game_id}/get_client", + drogon::Get); + METHOD_LIST_END + + explicit GamesController( + std::shared_ptr games_storage); protected: - void - games_list(const drogon::HttpRequestPtr &req, - std::function &&callback); - - void - game_config(const drogon::HttpRequestPtr &req, - std::function &&callback, - const std::string& game_id); - - void game_client_file( - const drogon::HttpRequestPtr &req, - std::function &&callback, - const std::string& game_id); + void games_list( + const drogon::HttpRequestPtr &req, + std::function &&callback); + + void game_config( + const drogon::HttpRequestPtr &req, + std::function &&callback, + const std::string &game_id); + + void game_client_file( + const drogon::HttpRequestPtr &req, + std::function &&callback, + const std::string &game_id); }; -} // namespace cavoke::server::controllers -#endif // CAVOKE_SERVER_GAMES_CONTROLLER_H +} // namespace cavoke::server::controllers +#endif // CAVOKE_SERVER_GAMES_CONTROLLER_H diff --git a/server/controllers/health_controller.cpp b/server/controllers/health_controller.cpp index 4c65e546..db2ec555 100644 --- a/server/controllers/health_controller.cpp +++ b/server/controllers/health_controller.cpp @@ -2,8 +2,8 @@ void cavoke::server::controllers::HealthController::health( const drogon::HttpRequestPtr &req, std::function &&callback) { - auto resp = drogon::HttpResponse::newHttpResponse(); - resp->setContentTypeCode(drogon::CT_TEXT_PLAIN); - resp->setBody("OK"); - callback(resp); + auto resp = drogon::HttpResponse::newHttpResponse(); + resp->setContentTypeCode(drogon::CT_TEXT_PLAIN); + resp->setBody("OK"); + callback(resp); } diff --git a/server/controllers/health_controller.h b/server/controllers/health_controller.h index 3f3a629b..5f957e4d 100644 --- a/server/controllers/health_controller.h +++ b/server/controllers/health_controller.h @@ -6,17 +6,17 @@ namespace cavoke::server::controllers { class HealthController : public drogon::HttpController { - public: - METHOD_LIST_BEGIN - ADD_METHOD_TO(HealthController::health, "/health", drogon::Get); - METHOD_LIST_END + METHOD_LIST_BEGIN + ADD_METHOD_TO(HealthController::health, "/health", drogon::Get); + METHOD_LIST_END protected: - void health(const drogon::HttpRequestPtr &req, - std::function &&callback); + void health( + const drogon::HttpRequestPtr &req, + std::function &&callback); }; -} // namespace cavoke::server::controllers +} // namespace cavoke::server::controllers -#endif // CAVOKE_SERVER_HEALTH_CONTROLLER_H +#endif // CAVOKE_SERVER_HEALTH_CONTROLLER_H diff --git a/server/main.cpp b/server/main.cpp index 4450d0a6..e8b0e6b9 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -1,65 +1,67 @@ +#include +#include #include "controllers/games_controller.h" #include "model/games_storage.h" -#include -#include - namespace cavoke::server { -void run(const std::string &host, uint16_t port, const std::string &config_file) { - // TODO: logging +void run(const std::string &host, + uint16_t port, + const std::string &config_file) { + // TODO: logging - // init models - std::cout << "Initialize models..." << std::endl; - auto games_storage = std::make_shared( - model::GamesStorageConfig::load(config_file)); + // init models + std::cout << "Initialize models..." << std::endl; + auto games_storage = std::make_shared( + model::GamesStorageConfig::load(config_file)); - // init controllers - std::cout << "Initialize controllers..." << std::endl; - auto games_controller = - std::make_shared(games_storage); + // init controllers + std::cout << "Initialize controllers..." << std::endl; + auto games_controller = + std::make_shared(games_storage); - auto& app = drogon::app(); + auto &app = drogon::app(); - // register controllers - app.registerController(games_controller); + // register controllers + app.registerController(games_controller); - // start server - std::cout << "Listening at " << host << ":" << port << std::endl; - app.addListener(host, port).run(); + // start server + std::cout << "Listening at " << host << ":" << port << std::endl; + app.addListener(host, port).run(); } -} // namespace cavoke::server - +} // namespace cavoke::server namespace po = boost::program_options; -int main(int argc, char* argv[]) { - po::options_description desc("Allowed options"); - desc.add_options() - ("help,h,?", "Print help") - ("config-file,c", po::value(), "File with game storage configuration") - ("host,ip,a", po::value()->default_value("0.0.0.0"), "Host on which server is located") - ("port,p", po::value()->default_value(8080), "TCP/IP port number for connection") - ; +int main(int argc, char *argv[]) { + po::options_description desc("Allowed options"); + desc.add_options()("help,h,?", "Print help")( + "config-file,c", po::value(), + "File with game storage configuration")( + "host,ip,a", po::value()->default_value("0.0.0.0"), + "Host on which server is located")( + "port,p", po::value()->default_value(8080), + "TCP/IP port number for connection"); - po::variables_map vm; - po::store(po::parse_command_line(argc, argv, desc), vm); - po::notify(vm); + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); - if (vm.count("help")) { - std::cout << desc << "\n"; - return 0; - } + if (vm.count("help")) { + std::cout << desc << "\n"; + return 0; + } - std::string config_file; - if (vm.count("config-file")) { - config_file = vm["config-file"].as(); - } else { -// config_file = std::getenv("CAVOKE_SERVER_CONFIG"); // TODO: think and discuss - } + std::string config_file; + if (vm.count("config-file")) { + config_file = vm["config-file"].as(); + } else { + // config_file = std::getenv("CAVOKE_SERVER_CONFIG"); // TODO: think + // and discuss + } - std::string host = vm.at("host").as(); - uint16_t port = vm.at("port").as(); + std::string host = vm.at("host").as(); + uint16_t port = vm.at("port").as(); - cavoke::server::run(host, port, config_file); - return 0; + cavoke::server::run(host, port, config_file); + return 0; } diff --git a/server/model/GamesStorageConfig.cpp b/server/model/GamesStorageConfig.cpp index a39305de..fa889727 100644 --- a/server/model/GamesStorageConfig.cpp +++ b/server/model/GamesStorageConfig.cpp @@ -1,36 +1,37 @@ #include "GamesStorageConfig.h" -#include #include +#include #include namespace cavoke::server::model { -GamesStorageConfig -GamesStorageConfig::load(const std::string &config_file) { - if (config_file.empty()) { - // FIXME: rewrite this mess... - std::cerr << "No games storage config specified. Using a default one. Please use `-c` option.\n"; - return GamesStorageConfig{ - "../../local_server/games", - "logic", - "client.zip", - "config.json" - }; - } - if (!boost::filesystem::exists(config_file) || - !boost::filesystem::is_regular_file(config_file)) { // FIXME - throw std::invalid_argument("No such game storage configuration file: " + config_file); - } +GamesStorageConfig GamesStorageConfig::load(const std::string &config_file) { + if (config_file.empty()) { + // FIXME: rewrite this mess... + std::cerr << "No games storage config specified. Using a default one. " + "Please use `-c` option.\n"; + return GamesStorageConfig{"../../local_server/games", "logic", + "client.zip", "config.json"}; + } + if (!boost::filesystem::exists(config_file) || + !boost::filesystem::is_regular_file(config_file)) { // FIXME + throw std::invalid_argument( + "No such game storage configuration file: " + config_file); + } - // FIXME: trash code; let's use https://github.com/nlohmann/json#arbitrary-types-conversions or something similar - Json::Value obj; - std::ifstream file(config_file); - Json::Reader reader; - assert(reader.parse(file, obj, false)); - file.close(); + // FIXME: trash code; let's use + // https://github.com/nlohmann/json#arbitrary-types-conversions or something + // similar + Json::Value obj; + std::ifstream file(config_file); + Json::Reader reader; + assert(reader.parse(file, obj, false)); + file.close(); - GamesStorageConfig res{obj["games_directory"].asString(), obj["logic_name"].asString(), obj["zip_name"].asString(), obj["config_name"].asString()}; - return res; + GamesStorageConfig res{ + obj["games_directory"].asString(), obj["logic_name"].asString(), + obj["zip_name"].asString(), obj["config_name"].asString()}; + return res; } -} \ No newline at end of file +} // namespace cavoke::server::model \ No newline at end of file diff --git a/server/model/GamesStorageConfig.h b/server/model/GamesStorageConfig.h index 96c12ed5..66de8b09 100644 --- a/server/model/GamesStorageConfig.h +++ b/server/model/GamesStorageConfig.h @@ -4,11 +4,11 @@ #include namespace cavoke::server::model { struct GamesStorageConfig { - const boost::filesystem::path games_directory; - const std::string logic_name; - const std::string zip_name; - const std::string json_name; - static GamesStorageConfig load(const std::string &config_file); + const boost::filesystem::path games_directory; + const std::string logic_name; + const std::string zip_name; + const std::string json_name; + static GamesStorageConfig load(const std::string &config_file); }; -} -#endif // CAVOKE_GAMESSTORAGECONFIG_H +} // namespace cavoke::server::model +#endif // CAVOKE_GAMESSTORAGECONFIG_H diff --git a/server/model/game.cpp b/server/model/game.cpp index 4a2e4d86..43cdc9bb 100644 --- a/server/model/game.cpp +++ b/server/model/game.cpp @@ -1,65 +1,67 @@ #include "game.h" -#include "games_storage.h" #include #include #include #include #include +#include "games_storage.h" namespace cavoke::server::model { Game::Game(const boost::filesystem::path &directory, const GamesStorageConfig &game_storage_config) - : directory(directory), logic_file(directory / LOGIC_FILE), + : directory(directory), + logic_file(directory / LOGIC_FILE), client_file(directory / CLIENT_FILE), CLIENT_FILE(game_storage_config.zip_name), LOGIC_FILE(game_storage_config.logic_name), CONFIG_FILE(game_storage_config.json_name) { - Json::Value json_config; - read_config_file(directory / CONFIG_FILE, json_config); - config.id = json_config["id"].asString(); - config.display_name = json_config["display_name"].asString(); - config.description = json_config["description"].asString(); - config.players_num = json_config["players_num"].asInt(); + Json::Value json_config; + read_config_file(directory / CONFIG_FILE, json_config); + config.id = json_config["id"].asString(); + config.display_name = json_config["display_name"].asString(); + config.description = json_config["description"].asString(); + config.players_num = json_config["players_num"].asInt(); } bool Game::is_game_directory(const boost::filesystem::path &path, const GamesStorageConfig &games_storage_config) { - Json::Value tmp; - // TODO: rewrite - const auto &CLIENT_FILE = games_storage_config.zip_name, - CONFIG_FILE = games_storage_config.json_name, - LOGIC_FILE = games_storage_config.logic_name; - // TODO: extract function exists & directory + exists & regular file - return boost::filesystem::exists(path) && - boost::filesystem::is_directory(path) && - boost::filesystem::exists(path / CLIENT_FILE) && - boost::filesystem::is_regular_file(path / CLIENT_FILE) && - boost::filesystem::exists(path / CONFIG_FILE) && - boost::filesystem::is_regular_file(path / CONFIG_FILE) && - boost::filesystem::exists(path / LOGIC_FILE) && - boost::filesystem::is_regular_file(path / LOGIC_FILE) && - read_config_file(path / CONFIG_FILE, tmp); + Json::Value tmp; + // TODO: rewrite + const auto &CLIENT_FILE = games_storage_config.zip_name, + CONFIG_FILE = games_storage_config.json_name, + LOGIC_FILE = games_storage_config.logic_name; + // TODO: extract function exists & directory + exists & regular file + return boost::filesystem::exists(path) && + boost::filesystem::is_directory(path) && + boost::filesystem::exists(path / CLIENT_FILE) && + boost::filesystem::is_regular_file(path / CLIENT_FILE) && + boost::filesystem::exists(path / CONFIG_FILE) && + boost::filesystem::is_regular_file(path / CONFIG_FILE) && + boost::filesystem::exists(path / LOGIC_FILE) && + boost::filesystem::is_regular_file(path / LOGIC_FILE) && + read_config_file(path / CONFIG_FILE, tmp); } bool Game::read_config_file(const boost::filesystem::path &path, Json::Value &json_obj) { - std::ifstream file(path); - Json::Reader reader; // deprecated - bool success = reader.parse(file, json_obj, false); - file.close(); - return success; + std::ifstream file(path); + Json::Reader reader; // deprecated + bool success = reader.parse(file, json_obj, false); + file.close(); + return success; } Json::Value Game::GameConfig::to_json() const { - // TODO: please let's use https://github.com/nlohmann/json#arbitrary-types-conversions - Json::Value result; - result["id"] = id; - result["display_name"] = display_name; - result["description"] = description; - result["players_num"] = players_num; + // TODO: please let's use + // https://github.com/nlohmann/json#arbitrary-types-conversions + Json::Value result; + result["id"] = id; + result["display_name"] = display_name; + result["description"] = description; + result["players_num"] = players_num; - return result; + return result; } -} // namespace cavoke::server::model +} // namespace cavoke::server::model diff --git a/server/model/game.h b/server/model/game.h index 6399bf72..7799e355 100644 --- a/server/model/game.h +++ b/server/model/game.h @@ -1,44 +1,45 @@ #ifndef CAVOKE_SERVER_GAME_H #define CAVOKE_SERVER_GAME_H -#include #include +#include #include #include "GamesStorageConfig.h" namespace cavoke::server::model { class Game { - const std::string CONFIG_FILE; - const std::string CLIENT_FILE; - const std::string LOGIC_FILE; + const std::string CONFIG_FILE; + const std::string CLIENT_FILE; + const std::string LOGIC_FILE; - boost::filesystem::path directory; + boost::filesystem::path directory; - struct GameConfig { - std::string id; - std::string display_name; - std::string description; - int players_num; + struct GameConfig { + std::string id; + std::string display_name; + std::string description; + int players_num; - [[nodiscard]] Json::Value to_json() const; - }; + [[nodiscard]] Json::Value to_json() const; + }; - static bool read_config_file(const boost::filesystem::path &path, - Json::Value &json_obj); + static bool read_config_file(const boost::filesystem::path &path, + Json::Value &json_obj); public: - explicit Game(const boost::filesystem::path& directory, - const GamesStorageConfig &game_storage_config); - Game() = default; // TODO: rethink json + explicit Game(const boost::filesystem::path &directory, + const GamesStorageConfig &game_storage_config); + Game() = default; // TODO: rethink json - boost::filesystem::path client_file; - GameConfig config; - boost::filesystem::path logic_file; + boost::filesystem::path client_file; + GameConfig config; + boost::filesystem::path logic_file; - static bool is_game_directory(const boost::filesystem::path &path, - const GamesStorageConfig &games_storage_config); + static bool is_game_directory( + const boost::filesystem::path &path, + const GamesStorageConfig &games_storage_config); }; -} // namespace cavoke::server::model +} // namespace cavoke::server::model -#endif // CAVOKE_SERVER_GAME_H +#endif // CAVOKE_SERVER_GAME_H diff --git a/server/model/games_storage.cpp b/server/model/games_storage.cpp index ff71f435..a9430bc0 100644 --- a/server/model/games_storage.cpp +++ b/server/model/games_storage.cpp @@ -9,55 +9,56 @@ namespace cavoke::server::model { GamesStorage::GamesStorage(GamesStorageConfig config) : m_config(std::move(config)) { - - if (!boost::filesystem::exists(m_config.games_directory)) { - bool success = - boost::filesystem::create_directories(m_config.games_directory); - if (!success) { - throw std::invalid_argument("Cannot create games directory " + - m_config.games_directory.string() + "\n"); + if (!boost::filesystem::exists(m_config.games_directory)) { + bool success = + boost::filesystem::create_directories(m_config.games_directory); + if (!success) { + throw std::invalid_argument("Cannot create games directory " + + m_config.games_directory.string() + + "\n"); + } } - } - if (!boost::filesystem::is_directory(m_config.games_directory)) { - throw std::invalid_argument("Invalid games directory " + - m_config.games_directory.string() + "\n"); - } + if (!boost::filesystem::is_directory(m_config.games_directory)) { + throw std::invalid_argument("Invalid games directory " + + m_config.games_directory.string() + "\n"); + } - update(); + update(); } std::vector GamesStorage::list_games() { - update(); + update(); - std::vector result; - for (auto e : m_games) { - result.emplace_back(e.second); - } - return result; + std::vector result; + for (auto e : m_games) { + result.emplace_back(e.second); + } + return result; } void GamesStorage::update() { - m_games.clear(); - for (auto &entry : boost::make_iterator_range( - boost::filesystem::directory_iterator(m_config.games_directory), - {})) { - if (!Game::is_game_directory(entry, m_config)) { - // TODO: logging - std::cerr << entry << " entity from games directory is not a valid game" - << std::endl; - } else { - Game game(entry, m_config); - m_games.emplace(game.config.id, game); + m_games.clear(); + for (auto &entry : boost::make_iterator_range( + boost::filesystem::directory_iterator(m_config.games_directory), + {})) { + if (!Game::is_game_directory(entry, m_config)) { + // TODO: logging + std::cerr << entry + << " entity from games directory is not a valid game" + << std::endl; + } else { + Game game(entry, m_config); + m_games.emplace(game.config.id, game); + } } - } } -std::optional GamesStorage::get_game_by_id(const std::string& game_id) { - if (m_games.count(game_id) > 0) { - return m_games[game_id]; - } - return {}; +std::optional GamesStorage::get_game_by_id(const std::string &game_id) { + if (m_games.count(game_id) > 0) { + return m_games[game_id]; + } + return {}; } -} // namespace cavoke::server::model +} // namespace cavoke::server::model diff --git a/server/model/games_storage.h b/server/model/games_storage.h index 980a851d..d2c3c552 100644 --- a/server/model/games_storage.h +++ b/server/model/games_storage.h @@ -1,29 +1,29 @@ #ifndef CAVOKE_GAMES_STORAGE_H #define CAVOKE_GAMES_STORAGE_H -#include "game.h" -#include "GamesStorageConfig.h" -#include #include +#include #include +#include "GamesStorageConfig.h" +#include "game.h" namespace cavoke::server::model { class GamesStorage { - // TODO: thread-safety + // TODO: thread-safety public: - explicit GamesStorage(GamesStorageConfig config); + explicit GamesStorage(GamesStorageConfig config); - void update(); + void update(); - std::vector list_games(); + std::vector list_games(); - std::optional get_game_by_id(const std::string& game_id); + std::optional get_game_by_id(const std::string &game_id); private: - GamesStorageConfig m_config; - std::map m_games; + GamesStorageConfig m_config; + std::map m_games; }; -} // namespace cavoke::server::model +} // namespace cavoke::server::model -#endif // CAVOKE_GAMES_STORAGE_H +#endif // CAVOKE_GAMES_STORAGE_H From 0a79de3ef8f8ea9689095eba03678ef9b0b6b2bf Mon Sep 17 00:00:00 2001 From: Alex Kovrigin Date: Sun, 20 Feb 2022 14:38:46 +0300 Subject: [PATCH 10/20] [server] replace jsoncpp with nlohmann-json --- .circleci/config.yml | 4 +- server/CMakeLists.txt | 5 +- server/controllers/games_controller.cpp | 13 ++--- server/controllers/games_controller.h | 2 + server/model/GamesStorageConfig.cpp | 15 +----- server/model/GamesStorageConfig.h | 18 +++++-- server/model/game.cpp | 72 +++++++++---------------- server/model/game.h | 33 +++++++----- server/utils.h | 40 ++++++++++++++ 9 files changed, 115 insertions(+), 87 deletions(-) create mode 100644 server/utils.h diff --git a/.circleci/config.yml b/.circleci/config.yml index 0b89cb6d..1184430b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -34,8 +34,8 @@ jobs: - image: drogonframework/drogon steps: - run: - name: Install Boost - command: apt update -y && apt install libboost-all-dev -y + name: Install Boost & nlohmann-json + command: apt update -y && apt install libboost-all-dev nlohmann-json-dev -y - checkout - run: name: Cmake diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index cbda9823..9a4b6b06 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -9,6 +9,8 @@ find_package(Boost 1.71 REQUIRED filesystem program_options) include_directories(${Boost_INCLUDE_DIRS}) link_directories(${Boost_LIBRARY_DIRS}) +find_package(nlohmann_json 3.2.0 REQUIRED) + add_executable(cavoke_server model/games_storage.cpp model/game.cpp @@ -18,6 +20,7 @@ add_executable(cavoke_server controllers/health_controller.h model/GamesStorageConfig.cpp model/GamesStorageConfig.h - ) + utils.h) target_link_libraries(cavoke_server Drogon::Drogon) target_link_libraries(cavoke_server ${Boost_LIBRARIES} ${CMAKE_DL_LIBS}) +target_link_libraries(cavoke_server nlohmann_json::nlohmann_json) diff --git a/server/controllers/games_controller.cpp b/server/controllers/games_controller.cpp index 7c88805f..75f7ac10 100644 --- a/server/controllers/games_controller.cpp +++ b/server/controllers/games_controller.cpp @@ -1,7 +1,6 @@ #include "games_controller.h" #include #include -#include "../model/game.h" cavoke::server::controllers::GamesController::GamesController( std::shared_ptr games_storage) @@ -12,12 +11,11 @@ void cavoke::server::controllers::GamesController::games_list( const drogon::HttpRequestPtr &req, std::function &&callback) { std::vector games = m_games_storage->list_games(); - Json::Value result(Json::arrayValue); - for (const auto &game : games) { - result.append(game.config.to_json()); - } + std::vector configs(games.size()); + std::transform(games.begin(), games.end(), configs.begin(), + [](const model::Game &g) { return g.config; }); - auto resp = drogon::HttpResponse::newHttpJsonResponse(result); + auto resp = newNlohmannJsonResponse(configs); callback(resp); } @@ -32,8 +30,7 @@ void cavoke::server::controllers::GamesController::game_config( return; } - auto resp = - drogon::HttpResponse::newHttpJsonResponse(game->config.to_json()); + auto resp = newNlohmannJsonResponse(game->config); callback(resp); } diff --git a/server/controllers/games_controller.h b/server/controllers/games_controller.h index 468e2613..cb537624 100644 --- a/server/controllers/games_controller.h +++ b/server/controllers/games_controller.h @@ -6,6 +6,8 @@ namespace cavoke::server::controllers { +using json = nlohmann::json; + class GamesController : public drogon::HttpController { std::shared_ptr m_games_storage; diff --git a/server/model/GamesStorageConfig.cpp b/server/model/GamesStorageConfig.cpp index fa889727..45e70a26 100644 --- a/server/model/GamesStorageConfig.cpp +++ b/server/model/GamesStorageConfig.cpp @@ -1,5 +1,4 @@ #include "GamesStorageConfig.h" -#include #include #include @@ -19,19 +18,9 @@ GamesStorageConfig GamesStorageConfig::load(const std::string &config_file) { "No such game storage configuration file: " + config_file); } - // FIXME: trash code; let's use - // https://github.com/nlohmann/json#arbitrary-types-conversions or something - // similar - Json::Value obj; std::ifstream file(config_file); - Json::Reader reader; - assert(reader.parse(file, obj, false)); - file.close(); - - GamesStorageConfig res{ - obj["games_directory"].asString(), obj["logic_name"].asString(), - obj["zip_name"].asString(), obj["config_name"].asString()}; - return res; + json j = json::parse(file); + return j.get(); } } // namespace cavoke::server::model \ No newline at end of file diff --git a/server/model/GamesStorageConfig.h b/server/model/GamesStorageConfig.h index 66de8b09..ad1983dd 100644 --- a/server/model/GamesStorageConfig.h +++ b/server/model/GamesStorageConfig.h @@ -2,13 +2,23 @@ #define CAVOKE_GAMESSTORAGECONFIG_H #include +#include +#include "../utils.h" // TODO: avoid relative paths namespace cavoke::server::model { +using json = nlohmann::json; + struct GamesStorageConfig { - const boost::filesystem::path games_directory; - const std::string logic_name; - const std::string zip_name; - const std::string json_name; + boost::filesystem::path games_directory; + std::string logic_name; + std::string zip_name; + std::string config_name; + static GamesStorageConfig load(const std::string &config_file); }; +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(GamesStorageConfig, + games_directory, + logic_name, + zip_name, + config_name) } // namespace cavoke::server::model #endif // CAVOKE_GAMESSTORAGECONFIG_H diff --git a/server/model/game.cpp b/server/model/game.cpp index 43cdc9bb..9dd85430 100644 --- a/server/model/game.cpp +++ b/server/model/game.cpp @@ -1,10 +1,6 @@ #include "game.h" #include -#include -#include #include -#include -#include "games_storage.h" namespace cavoke::server::model { @@ -15,53 +11,37 @@ Game::Game(const boost::filesystem::path &directory, client_file(directory / CLIENT_FILE), CLIENT_FILE(game_storage_config.zip_name), LOGIC_FILE(game_storage_config.logic_name), - CONFIG_FILE(game_storage_config.json_name) { - Json::Value json_config; - read_config_file(directory / CONFIG_FILE, json_config); - config.id = json_config["id"].asString(); - config.display_name = json_config["display_name"].asString(); - config.description = json_config["description"].asString(); - config.players_num = json_config["players_num"].asInt(); + CONFIG_FILE(game_storage_config.config_name) { + json j = json::parse(std::ifstream(directory / CONFIG_FILE)); + config = j.get(); } -bool Game::is_game_directory(const boost::filesystem::path &path, - const GamesStorageConfig &games_storage_config) { - Json::Value tmp; - // TODO: rewrite - const auto &CLIENT_FILE = games_storage_config.zip_name, - CONFIG_FILE = games_storage_config.json_name, - LOGIC_FILE = games_storage_config.logic_name; - // TODO: extract function exists & directory + exists & regular file - return boost::filesystem::exists(path) && - boost::filesystem::is_directory(path) && - boost::filesystem::exists(path / CLIENT_FILE) && - boost::filesystem::is_regular_file(path / CLIENT_FILE) && - boost::filesystem::exists(path / CONFIG_FILE) && - boost::filesystem::is_regular_file(path / CONFIG_FILE) && - boost::filesystem::exists(path / LOGIC_FILE) && - boost::filesystem::is_regular_file(path / LOGIC_FILE) && - read_config_file(path / CONFIG_FILE, tmp); +/// Checks whether given path is a directory +bool check_is_directory(const boost::filesystem::path &path) { + return exists(path) && is_directory(path); } - -bool Game::read_config_file(const boost::filesystem::path &path, - Json::Value &json_obj) { - std::ifstream file(path); - Json::Reader reader; // deprecated - bool success = reader.parse(file, json_obj, false); - file.close(); - return success; +/// Checks whether given path exists and is a regular file +bool check_is_regular_file(const boost::filesystem::path &path) { + return exists(path) && is_regular_file(path); +} +/// Checks whether given file is a valid `GameConfig` +bool check_valid_game_config(const boost::filesystem::path &path) { + try { // slow? + json j = json::parse(std::ifstream(path)); + auto conf = j.get(); + conf.validate(); + return true; + } catch (...) { + return false; + } } -Json::Value Game::GameConfig::to_json() const { - // TODO: please let's use - // https://github.com/nlohmann/json#arbitrary-types-conversions - Json::Value result; - result["id"] = id; - result["display_name"] = display_name; - result["description"] = description; - result["players_num"] = players_num; - - return result; +bool Game::is_game_directory(const boost::filesystem::path &path, + const GamesStorageConfig &games_storage_config) { + return check_is_directory(path) && + check_is_regular_file(path / games_storage_config.zip_name) && + check_is_regular_file(path / games_storage_config.logic_name) && + check_valid_game_config(path / games_storage_config.config_name); } } // namespace cavoke::server::model diff --git a/server/model/game.h b/server/model/game.h index 7799e355..e27a4ba7 100644 --- a/server/model/game.h +++ b/server/model/game.h @@ -2,11 +2,30 @@ #define CAVOKE_SERVER_GAME_H #include #include +#include #include #include "GamesStorageConfig.h" namespace cavoke::server::model { +struct GameConfig { + std::string id; + std::string display_name; + std::string description; + int players_num; + + /// Validates config. Throws an exception if invalid + void validate() const { + // TODO: just a sample, `assert` removed in Release + assert(players_num >= 1); + } +}; +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(GameConfig, + id, + display_name, + description, + players_num) + class Game { const std::string CONFIG_FILE; const std::string CLIENT_FILE; @@ -14,22 +33,10 @@ class Game { boost::filesystem::path directory; - struct GameConfig { - std::string id; - std::string display_name; - std::string description; - int players_num; - - [[nodiscard]] Json::Value to_json() const; - }; - - static bool read_config_file(const boost::filesystem::path &path, - Json::Value &json_obj); - public: explicit Game(const boost::filesystem::path &directory, const GamesStorageConfig &game_storage_config); - Game() = default; // TODO: rethink json + Game() = default; boost::filesystem::path client_file; GameConfig config; diff --git a/server/utils.h b/server/utils.h new file mode 100644 index 00000000..fdbe842b --- /dev/null +++ b/server/utils.h @@ -0,0 +1,40 @@ +#ifndef CAVOKE_UTILS_H +#define CAVOKE_UTILS_H + +#include +#include +#include + +namespace nlohmann { +/// nlohmann::json serializer for `boost::filesystem::path` +template <> +struct adl_serializer { + static void to_json(json &j, const boost::filesystem::path &value) { + j = json{value.string()}; + } + + static void from_json(const json &j, boost::filesystem::path &value) { + value = j.get(); + } +}; +} // namespace nlohmann + +namespace cavoke::server::controllers { + +/** + * Creates a drogon response from serializable object. + * + * Preferably pass the object itself, not the json object, + * because `nlohmann::json{configs}` adds extra square brackets to objects + * see https://github.com/cavoke-project/cavoke/issues/22. Avoid curly braces. + */ +inline drogon::HttpResponsePtr newNlohmannJsonResponse( + const nlohmann::json &obj) { + auto res = drogon::HttpResponse::newHttpResponse(); + res->setContentTypeCode(drogon::CT_APPLICATION_JSON); + res->setBody(obj.dump()); + return res; +} +} // namespace cavoke::server::controllers + +#endif // CAVOKE_UTILS_H From e991c8a02e1d28fdef57f15ec186c51caac849f8 Mon Sep 17 00:00:00 2001 From: Alex Kovrigin Date: Sun, 20 Feb 2022 14:47:15 +0300 Subject: [PATCH 11/20] [ci] fix nlohmann install --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1184430b..60b5866e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -35,7 +35,7 @@ jobs: steps: - run: name: Install Boost & nlohmann-json - command: apt update -y && apt install libboost-all-dev nlohmann-json-dev -y + command: apt update -y && apt install libboost-all-dev nlohmann-json3-dev -y - checkout - run: name: Cmake From e2b6a3d2421c88d9648b115a169b76974ea33d1d Mon Sep 17 00:00:00 2001 From: Alex Kovrigin Date: Sun, 20 Feb 2022 14:50:05 +0300 Subject: [PATCH 12/20] [server] try fix ci build --- server/utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/utils.h b/server/utils.h index fdbe842b..e7686916 100644 --- a/server/utils.h +++ b/server/utils.h @@ -10,7 +10,7 @@ namespace nlohmann { template <> struct adl_serializer { static void to_json(json &j, const boost::filesystem::path &value) { - j = json{value.string()}; + j = value.string(); } static void from_json(const json &j, boost::filesystem::path &value) { From 92112c5cd3073e06f88f95cc8ad597995d9ee1a4 Mon Sep 17 00:00:00 2001 From: Alex Kovrigin Date: Sun, 20 Feb 2022 15:15:38 +0300 Subject: [PATCH 13/20] [ci] set nlohmann minimum version --- .circleci/config.yml | 7 +++++-- server/CMakeLists.txt | 3 ++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 60b5866e..1bc52831 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -34,8 +34,11 @@ jobs: - image: drogonframework/drogon steps: - run: - name: Install Boost & nlohmann-json - command: apt update -y && apt install libboost-all-dev nlohmann-json3-dev -y + name: Install Boost + command: apt update -y && apt install libboost-all-dev -y + - run: + name: Install nlohmann/json + command: apt update -y && apt install python3-pip && pip3 install cget && cget install nlohmann/json - checkout - run: name: Cmake diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index 9a4b6b06..404b0c59 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -9,7 +9,8 @@ find_package(Boost 1.71 REQUIRED filesystem program_options) include_directories(${Boost_INCLUDE_DIRS}) link_directories(${Boost_LIBRARY_DIRS}) -find_package(nlohmann_json 3.2.0 REQUIRED) +# https://github.com/nlohmann/json/releases/tag/v3.9.0 for convenience macros +find_package(nlohmann_json 3.9.0 REQUIRED) add_executable(cavoke_server model/games_storage.cpp From 1cc21fe010d7dfdaf16db59e9e386c655205c001 Mon Sep 17 00:00:00 2001 From: Alex Kovrigin Date: Sun, 20 Feb 2022 15:16:58 +0300 Subject: [PATCH 14/20] [ci] set nlohmann minimum version --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1bc52831..ef38ceb5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -38,7 +38,7 @@ jobs: command: apt update -y && apt install libboost-all-dev -y - run: name: Install nlohmann/json - command: apt update -y && apt install python3-pip && pip3 install cget && cget install nlohmann/json + command: apt update -y && apt install python3-pip -y && pip3 install cget && cget install nlohmann/json - checkout - run: name: Cmake From 2989f3676e97f76b7f389bc002a7623d0b0d434d Mon Sep 17 00:00:00 2001 From: Alex Kovrigin Date: Sun, 20 Feb 2022 21:07:59 +0300 Subject: [PATCH 15/20] [ci] try with custom docker image --- .circleci/config.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index ef38ceb5..39d5a2b9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -31,14 +31,8 @@ jobs: command: make cavoke_client server-docker-healthcheck: docker: - - image: drogonframework/drogon + - image: ghcr.io/cavoke-project/cavoke_ci:drogon # TODO: use circleci orbs steps: - - run: - name: Install Boost - command: apt update -y && apt install libboost-all-dev -y - - run: - name: Install nlohmann/json - command: apt update -y && apt install python3-pip -y && pip3 install cget && cget install nlohmann/json - checkout - run: name: Cmake From bfa31d952569490c1a495d6cd414cb90e361a56f Mon Sep 17 00:00:00 2001 From: Alex Kovrigin Date: Sun, 20 Feb 2022 21:15:47 +0300 Subject: [PATCH 16/20] [ci] try with custom docker image --- .circleci/config.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 39d5a2b9..db9dd8da 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -32,6 +32,9 @@ jobs: server-docker-healthcheck: docker: - image: ghcr.io/cavoke-project/cavoke_ci:drogon # TODO: use circleci orbs + auth: + username: $GHCR_USERNAME + password: $GHCR_PASSWORD steps: - checkout - run: From 8a7d84f3388fb6b86e2fe9eb1687c170bea50bc2 Mon Sep 17 00:00:00 2001 From: Alex Kovrigin Date: Mon, 21 Feb 2022 00:00:27 +0300 Subject: [PATCH 17/20] [server] apply clangformat --- server/controllers/state_controller.cpp | 138 ++++++++--------- server/controllers/state_controller.h | 56 +++---- server/main.cpp | 24 +-- server/model/GamesStorageConfig.h | 2 +- server/model/game_logic_manager.cpp | 32 ++-- server/model/game_logic_manager.h | 28 ++-- server/model/game_state_storage.cpp | 73 ++++----- server/model/game_state_storage.h | 30 ++-- server/model/mock_tictactoe/tictactoe.cpp | 171 +++++++++++----------- server/model/mock_tictactoe/tictactoe.h | 2 +- server/model/participation_storage.cpp | 10 +- server/model/participation_storage.h | 13 +- 12 files changed, 293 insertions(+), 286 deletions(-) diff --git a/server/controllers/state_controller.cpp b/server/controllers/state_controller.cpp index 0c571115..1a8bba50 100644 --- a/server/controllers/state_controller.cpp +++ b/server/controllers/state_controller.cpp @@ -1,90 +1,89 @@ #include "state_controller.h" - #include void cavoke::server::controllers::StateController::send_move( const drogon::HttpRequestPtr &req, std::function &&callback, const std::string &session_id) { + std::optional user_id = + req->getOptionalParameter("user_id"); + + if (!user_id.has_value()) { + auto resp = drogon::HttpResponse::newHttpResponse(); + resp->setStatusCode(drogon::HttpStatusCode::k400BadRequest); + callback(resp); + return; + } + + std::optional participant_id = + m_participation_storage->get_participant_id(session_id, + user_id.value()); + + if (!participant_id.has_value()) { + auto resp = drogon::HttpResponse::newHttpResponse(); + resp->setStatusCode(drogon::HttpStatusCode::k403Forbidden); + callback(resp); + return; + } + + std::optional current_state = + m_game_state_storage->get_state(session_id); + + if (!current_state.has_value()) { + // new session + current_state = + m_game_logic_manager->send_update("tictactoe", {-1, "", ""}); + } + + current_state = m_game_logic_manager->send_update( + "tictactoe", {participant_id.value(), std::string(req->getBody()), + current_state->global_state}); + + m_game_state_storage->save_state(session_id, current_state.value()); - std::optional user_id = - req->getOptionalParameter("user_id"); - - if (!user_id.has_value()) { - auto resp = drogon::HttpResponse::newHttpResponse(); - resp->setStatusCode(drogon::HttpStatusCode::k400BadRequest); - callback(resp); - return; - } - - std::optional participant_id = - m_participation_storage->get_participant_id(session_id, user_id.value()); - - if (!participant_id.has_value()) { auto resp = drogon::HttpResponse::newHttpResponse(); - resp->setStatusCode(drogon::HttpStatusCode::k403Forbidden); + resp->setStatusCode(drogon::HttpStatusCode::k200OK); callback(resp); - return; - } - - std::optional current_state = - m_game_state_storage->get_state(session_id); - - if (!current_state.has_value()) { - // new session - current_state = - m_game_logic_manager->send_update("tictactoe", {-1, "", ""}); - } - - current_state = m_game_logic_manager->send_update( - "tictactoe", {participant_id.value(), std::string(req->getBody()), - current_state->global_state}); - - m_game_state_storage->save_state(session_id, current_state.value()); - - auto resp = drogon::HttpResponse::newHttpResponse(); - resp->setStatusCode(drogon::HttpStatusCode::k200OK); - callback(resp); } void cavoke::server::controllers::StateController::get_update( const drogon::HttpRequestPtr &req, std::function &&callback, const std::string &session_id) { + std::optional user_id = + req->getOptionalParameter("user_id"); + + if (!user_id.has_value()) { + auto resp = drogon::HttpResponse::newHttpResponse(); + resp->setStatusCode(drogon::HttpStatusCode::k400BadRequest); + callback(resp); + return; + } + + std::optional participant_id = + m_participation_storage->get_participant_id(session_id, + user_id.value()); + + if (!participant_id.has_value()) { + auto resp = drogon::HttpResponse::newHttpResponse(); + resp->setStatusCode(drogon::HttpStatusCode::k403Forbidden); + callback(resp); + return; + } + + auto state = m_game_state_storage->get_player_state(session_id, + participant_id.value()); + + if (!state.has_value()) { + auto resp = drogon::HttpResponse::newNotFoundResponse(); + callback(resp); + return; + } - std::optional user_id = - req->getOptionalParameter("user_id"); - - if (!user_id.has_value()) { - auto resp = drogon::HttpResponse::newHttpResponse(); - resp->setStatusCode(drogon::HttpStatusCode::k400BadRequest); - callback(resp); - return; - } - - std::optional participant_id = - m_participation_storage->get_participant_id(session_id, user_id.value()); - - if (!participant_id.has_value()) { auto resp = drogon::HttpResponse::newHttpResponse(); - resp->setStatusCode(drogon::HttpStatusCode::k403Forbidden); + resp->setStatusCode(drogon::HttpStatusCode::k200OK); + resp->setBody(state.value()); callback(resp); - return; - } - - auto state = m_game_state_storage->get_player_state(session_id, - participant_id.value()); - - if (!state.has_value()) { - auto resp = drogon::HttpResponse::newNotFoundResponse(); - callback(resp); - return; - } - - auto resp = drogon::HttpResponse::newHttpResponse(); - resp->setStatusCode(drogon::HttpStatusCode::k200OK); - resp->setBody(state.value()); - callback(resp); } cavoke::server::controllers::StateController::StateController( std::shared_ptr mGamesStorage, @@ -94,4 +93,5 @@ cavoke::server::controllers::StateController::StateController( : m_games_storage(std::move(mGamesStorage)), m_game_logic_manager(std::move(mGameLogicManager)), m_game_state_storage(std::move(mGameStateStorage)), - m_participation_storage(std::move(mParticipationStorage)) {} + m_participation_storage(std::move(mParticipationStorage)) { +} diff --git a/server/controllers/state_controller.h b/server/controllers/state_controller.h index d904cc9d..00159914 100644 --- a/server/controllers/state_controller.h +++ b/server/controllers/state_controller.h @@ -1,46 +1,48 @@ #ifndef CAVOKE_STATE_CONTROLLER_H #define CAVOKE_STATE_CONTROLLER_H +#include #include "../model/game_logic_manager.h" #include "../model/games_storage.h" #include "../model/participation_storage.h" -#include namespace cavoke::server::controllers { class StateController : public drogon::HttpController { - std::shared_ptr m_games_storage; - std::shared_ptr m_game_logic_manager; - std::shared_ptr m_game_state_storage; - std::shared_ptr m_participation_storage; + std::shared_ptr m_games_storage; + std::shared_ptr m_game_logic_manager; + std::shared_ptr m_game_state_storage; + std::shared_ptr m_participation_storage; public: - StateController( - std::shared_ptr mGamesStorage, - std::shared_ptr mGameLogicManager, - std::shared_ptr mGameStateStorage, - std::shared_ptr mParticipationStorage); + StateController( + std::shared_ptr mGamesStorage, + std::shared_ptr mGameLogicManager, + std::shared_ptr mGameStateStorage, + std::shared_ptr mParticipationStorage); public: - METHOD_LIST_BEGIN - ADD_METHOD_TO(StateController::send_move, "/play/{session_id}/send_move", - drogon::Post); - ADD_METHOD_TO(StateController::get_update, "/play/{session_id}/get_update", - drogon::Get); - METHOD_LIST_END + METHOD_LIST_BEGIN + ADD_METHOD_TO(StateController::send_move, + "/play/{session_id}/send_move", + drogon::Post); + ADD_METHOD_TO(StateController::get_update, + "/play/{session_id}/get_update", + drogon::Get); + METHOD_LIST_END protected: - void - send_move(const drogon::HttpRequestPtr &req, - std::function &&callback, - const std::string &session_id); - - void - get_update(const drogon::HttpRequestPtr &req, - std::function &&callback, - const std::string &session_id); + void send_move( + const drogon::HttpRequestPtr &req, + std::function &&callback, + const std::string &session_id); + + void get_update( + const drogon::HttpRequestPtr &req, + std::function &&callback, + const std::string &session_id); }; -} // namespace cavoke::server::controllers +} // namespace cavoke::server::controllers -#endif // CAVOKE_STATE_CONTROLLER_H +#endif // CAVOKE_STATE_CONTROLLER_H diff --git a/server/main.cpp b/server/main.cpp index 31b6ad7d..90df2ea4 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -5,7 +5,6 @@ #include "model/game_logic_manager.h" #include "model/games_storage.h" #include "model/participation_storage.h" -#include namespace cavoke::server { void run(const std::string &host, @@ -17,18 +16,19 @@ void run(const std::string &host, std::cout << "Initialize models..." << std::endl; auto games_storage = std::make_shared( model::GamesStorageConfig::load(config_file)); - auto game_logic_manager = - std::make_shared(games_storage); - auto game_state_storage = std::make_shared(); - auto participation_storage = std::make_shared(); + auto game_logic_manager = + std::make_shared(games_storage); + auto game_state_storage = std::make_shared(); + auto participation_storage = + std::make_shared(); - // init controllers - std::cout << "Initialize controllers..." << std::endl; - auto games_controller = - std::make_shared(games_storage); - auto state_controller = std::make_shared( - games_storage, game_logic_manager, game_state_storage, - participation_storage); + // init controllers + std::cout << "Initialize controllers..." << std::endl; + auto games_controller = + std::make_shared(games_storage); + auto state_controller = std::make_shared( + games_storage, game_logic_manager, game_state_storage, + participation_storage); auto &app = drogon::app(); diff --git a/server/model/GamesStorageConfig.h b/server/model/GamesStorageConfig.h index ad1983dd..405076e3 100644 --- a/server/model/GamesStorageConfig.h +++ b/server/model/GamesStorageConfig.h @@ -3,7 +3,7 @@ #include #include -#include "../utils.h" // TODO: avoid relative paths +#include "../utils.h" // TODO: avoid relative paths namespace cavoke::server::model { using json = nlohmann::json; diff --git a/server/model/game_logic_manager.cpp b/server/model/game_logic_manager.cpp index 536d86b0..d17fe985 100644 --- a/server/model/game_logic_manager.cpp +++ b/server/model/game_logic_manager.cpp @@ -1,28 +1,28 @@ #include "game_logic_manager.h" -#include "mock_tictactoe/tictactoe.h" - #include +#include "mock_tictactoe/tictactoe.h" namespace cavoke::server::model { GameLogicManager::GameLogicManager(std::shared_ptr games_storage) - : m_games_storage(std::move(games_storage)) {} + : m_games_storage(std::move(games_storage)) { +} -GameStateStorage::GameState -GameLogicManager::send_update(const std::string &game_id, - const GameLogicManager::GameUpdate &update) { - // TODO: invoke actual logic - GameStateStorage::GameState result = GameStateStorage::parse_state( - tictactoe::apply(update.to_json().toStyledString())); - return result; +GameStateStorage::GameState GameLogicManager::send_update( + const std::string &game_id, + const GameLogicManager::GameUpdate &update) { + // TODO: invoke actual logic + GameStateStorage::GameState result = GameStateStorage::parse_state( + tictactoe::apply(update.to_json().toStyledString())); + return result; } Json::Value GameLogicManager::GameUpdate::to_json() const { - Json::Value result; - result["player_id"] = player_id; - result["update"] = update; - result["global_state"] = global_state; + Json::Value result; + result["player_id"] = player_id; + result["update"] = update; + result["global_state"] = global_state; - return result; + return result; } -} // namespace cavoke::server::model +} // namespace cavoke::server::model diff --git a/server/model/game_logic_manager.h b/server/model/game_logic_manager.h index 672940d2..79aa4b81 100644 --- a/server/model/game_logic_manager.h +++ b/server/model/game_logic_manager.h @@ -1,31 +1,31 @@ #ifndef CAVOKE_SERVER_GAME_LOGIC_MANAGER_H #define CAVOKE_SERVER_GAME_LOGIC_MANAGER_H -#include "game_state_storage.h" -#include "games_storage.h" #include #include +#include "game_state_storage.h" +#include "games_storage.h" namespace cavoke::server::model { class GameLogicManager { - std::shared_ptr m_games_storage; + std::shared_ptr m_games_storage; public: - explicit GameLogicManager(std::shared_ptr games_storage); + explicit GameLogicManager(std::shared_ptr games_storage); - struct GameUpdate { - int player_id; - std::string update; - std::string global_state; + struct GameUpdate { + int player_id; + std::string update; + std::string global_state; - [[nodiscard]] Json::Value to_json() const; - }; + [[nodiscard]] Json::Value to_json() const; + }; - GameStateStorage::GameState send_update(const std::string &game_id, - const GameUpdate &update); + GameStateStorage::GameState send_update(const std::string &game_id, + const GameUpdate &update); }; -} // namespace cavoke::server::model +} // namespace cavoke::server::model -#endif // CAVOKE_SERVER_GAME_LOGIC_MANAGER_H +#endif // CAVOKE_SERVER_GAME_LOGIC_MANAGER_H diff --git a/server/model/game_state_storage.cpp b/server/model/game_state_storage.cpp index d105cb9b..bfa64c94 100644 --- a/server/model/game_state_storage.cpp +++ b/server/model/game_state_storage.cpp @@ -1,5 +1,4 @@ #include "game_state_storage.h" - #include #include @@ -7,46 +6,48 @@ namespace cavoke::server::model { void GameStateStorage::save_state(const std::string &session_id, GameStateStorage::GameState new_state) { - m_states[session_id] = std::move(new_state); + m_states[session_id] = std::move(new_state); } -std::optional -GameStateStorage::get_state(const std::string &session_id) { - if (m_states.count(session_id) == 0) { - return {}; - } - return m_states[session_id]; +std::optional GameStateStorage::get_state( + const std::string &session_id) { + if (m_states.count(session_id) == 0) { + return {}; + } + return m_states[session_id]; } -GameStateStorage::GameState -GameStateStorage::parse_state(const std::string &s) { - GameState state; - Json::Value json_state; - Json::Reader reader; - reader.parse(s, json_state, false); - state.is_terminal = json_state["is_terminal"].asBool(); - state.global_state = json_state["global_state"].asString(); - for (Json::Value::ArrayIndex i = 0; i != json_state["players_state"].size(); - i++) { - state.players_state.push_back(json_state["players_state"][i].asString()); - } - for (Json::Value::ArrayIndex i = 0; i != json_state["winners"].size(); i++) { - state.winners.push_back(json_state["winners"][i].asInt()); - } - return state; +GameStateStorage::GameState GameStateStorage::parse_state( + const std::string &s) { + GameState state; + Json::Value json_state; + Json::Reader reader; + reader.parse(s, json_state, false); + state.is_terminal = json_state["is_terminal"].asBool(); + state.global_state = json_state["global_state"].asString(); + for (Json::Value::ArrayIndex i = 0; i != json_state["players_state"].size(); + i++) { + state.players_state.push_back( + json_state["players_state"][i].asString()); + } + for (Json::Value::ArrayIndex i = 0; i != json_state["winners"].size(); + i++) { + state.winners.push_back(json_state["winners"][i].asInt()); + } + return state; } -std::optional -GameStateStorage::get_player_state(const std::string &session_id, - int player_id) { - auto state = get_state(session_id); - if (!state.has_value()) { - return {}; - } - if (player_id >= state->players_state.size()) { - return {}; - } - return state->players_state[player_id]; +std::optional GameStateStorage::get_player_state( + const std::string &session_id, + int player_id) { + auto state = get_state(session_id); + if (!state.has_value()) { + return {}; + } + if (player_id >= state->players_state.size()) { + return {}; + } + return state->players_state[player_id]; } -} // namespace cavoke::server::model +} // namespace cavoke::server::model diff --git a/server/model/game_state_storage.h b/server/model/game_state_storage.h index 2125a94f..4a14c25b 100644 --- a/server/model/game_state_storage.h +++ b/server/model/game_state_storage.h @@ -8,28 +8,28 @@ namespace cavoke::server::model { -class GameStateStorage { // TODO: thread safety +class GameStateStorage { // TODO: thread safety public: - struct GameState { - bool is_terminal; - std::string global_state; - std::vector players_state; - std::vector winners; - }; + struct GameState { + bool is_terminal; + std::string global_state; + std::vector players_state; + std::vector winners; + }; - static GameState parse_state(const std::string &s); + static GameState parse_state(const std::string &s); - void save_state(const std::string &session_id, GameState new_state); + void save_state(const std::string &session_id, GameState new_state); - std::optional get_state(const std::string &session_id); + std::optional get_state(const std::string &session_id); - std::optional get_player_state(const std::string &session_id, - int player_id); + std::optional get_player_state(const std::string &session_id, + int player_id); private: - std::map m_states; + std::map m_states; }; -} // namespace cavoke::server::model +} // namespace cavoke::server::model -#endif // CAVOKE_SERVER_GAME_STATE_STORAGE_H +#endif // CAVOKE_SERVER_GAME_STATE_STORAGE_H diff --git a/server/model/mock_tictactoe/tictactoe.cpp b/server/model/mock_tictactoe/tictactoe.cpp index 85acb4ba..d46fbca7 100644 --- a/server/model/mock_tictactoe/tictactoe.cpp +++ b/server/model/mock_tictactoe/tictactoe.cpp @@ -1,9 +1,9 @@ #include "tictactoe.h" -#include #include +#include +#include #include #include -#include namespace tictactoe { @@ -11,110 +11,113 @@ std::mt19937 gen; std::uniform_real_distribution<> dis; bool winner(std::string board) { - for (int i = 0; i < 3; ++i) { - if (board[i] != ' ' && board[i] == board[i + 3] && board[i] == board[i + 6]) - return true; - - if (board[i * 3] != ' ' && board[i * 3] == board[i * 3 + 1] && - board[i * 3] == board[i * 3 + 2]) - return true; - } + for (int i = 0; i < 3; ++i) { + if (board[i] != ' ' && board[i] == board[i + 3] && + board[i] == board[i + 6]) + return true; + + if (board[i * 3] != ' ' && board[i * 3] == board[i * 3 + 1] && + board[i * 3] == board[i * 3 + 2]) + return true; + } - if (board[0] != ' ' && board[0] == board[4] && board[0] == board[8]) - return true; + if (board[0] != ' ' && board[0] == board[4] && board[0] == board[8]) + return true; - if (board[2] != ' ' && board[2] == board[4] && board[2] == board[6]) - return true; + if (board[2] != ' ' && board[2] == board[4] && board[2] == board[6]) + return true; - return false; + return false; } bool makeMove(int pos, char player, std::string &board) { - board[pos] = player; - if (winner(board)) { - // gameFinished(player + " wins") - return true; - } - return false; + board[pos] = player; + if (winner(board)) { + // gameFinished(player + " wins") + return true; + } + return false; } void restartGame(std::string &board) { - for (int i = 0; i < 9; ++i) { - board[i] = ' '; - } + for (int i = 0; i < 9; ++i) { + board[i] = ' '; + } } -bool canPlayAtPos(int pos, std::string &board) { return board[pos] == ' '; } +bool canPlayAtPos(int pos, std::string &board) { + return board[pos] == ' '; +} void randomAI(std::string &board) { - std::vector unfilledPosns; + std::vector unfilledPosns; + + for (int i = 0; i < 9; ++i) { + if (canPlayAtPos(i, board)) { + unfilledPosns.emplace_back(i); + } + } - for (int i = 0; i < 9; ++i) { - if (canPlayAtPos(i, board)) { - unfilledPosns.emplace_back(i); + if (unfilledPosns.empty()) { + restartGame(board); + } else { + int choice = unfilledPosns[std::floor(dis(gen) * unfilledPosns.size())]; + makeMove(choice, 'O', board); } - } - - if (unfilledPosns.empty()) { - restartGame(board); - } else { - int choice = unfilledPosns[std::floor(dis(gen) * unfilledPosns.size())]; - makeMove(choice, 'O', board); - } } std::string apply(const std::string &request) { - // TODO: logging - std::cout << "RECEIVED MOVE " << request << std::endl; - Json::Reader reader; - Json::Value json_request; - reader.parse(request, json_request, false); - std::string board = json_request["global_state"].asString(); - std::string update = json_request["update"].asString(); - int player_id = json_request["player_id"].asInt(); - - std::string new_global_state; - std::string new_player_state; - - std::string message = "..."; - - // player_id == -1 -> start new game - if (player_id == -1) { - board = std::string(9, ' '); - } else { - std::stringstream to_split(update); - char action; - to_split >> action; - if (action != 'D') { - int pos; - to_split >> pos; - if (!(pos >= 0 && pos < 9 && canPlayAtPos(pos, board))) { - message= "Invalid action"; - } else { - makeMove(pos, 'X', board); - if (winner(board)) { - message = "X wins"; - restartGame(board); - } else { - randomAI(board); - if (winner(board)) { - message = "O wins"; - restartGame(board); - } + // TODO: logging + std::cout << "RECEIVED MOVE " << request << std::endl; + Json::Reader reader; + Json::Value json_request; + reader.parse(request, json_request, false); + std::string board = json_request["global_state"].asString(); + std::string update = json_request["update"].asString(); + int player_id = json_request["player_id"].asInt(); + + std::string new_global_state; + std::string new_player_state; + + std::string message = "..."; + + // player_id == -1 -> start new game + if (player_id == -1) { + board = std::string(9, ' '); + } else { + std::stringstream to_split(update); + char action; + to_split >> action; + if (action != 'D') { + int pos; + to_split >> pos; + if (!(pos >= 0 && pos < 9 && canPlayAtPos(pos, board))) { + message = "Invalid action"; + } else { + makeMove(pos, 'X', board); + if (winner(board)) { + message = "X wins"; + restartGame(board); + } else { + randomAI(board); + if (winner(board)) { + message = "O wins"; + restartGame(board); + } + } + } } - } } - } - std::string new_state = message + "\n" + board; + std::string new_state = message + "\n" + board; - Json::Value json_result; - json_result["is_terminal"] = false; - json_result["global_state"] = board; - json_result["players_state"].append(board); - json_result["winners"] = Json::arrayValue; + Json::Value json_result; + json_result["is_terminal"] = false; + json_result["global_state"] = board; + json_result["players_state"].append(board); + json_result["winners"] = Json::arrayValue; - return json_result.toStyledString(); + return json_result.toStyledString(); } -} // namespace tictactoe +} // namespace tictactoe diff --git a/server/model/mock_tictactoe/tictactoe.h b/server/model/mock_tictactoe/tictactoe.h index cbc1d194..5445400f 100644 --- a/server/model/mock_tictactoe/tictactoe.h +++ b/server/model/mock_tictactoe/tictactoe.h @@ -9,4 +9,4 @@ std::string apply(const std::string &request); } -#endif // CAVOKE_TICTACTOE_H +#endif // CAVOKE_TICTACTOE_H diff --git a/server/model/participation_storage.cpp b/server/model/participation_storage.cpp index 60548675..b9557d56 100644 --- a/server/model/participation_storage.cpp +++ b/server/model/participation_storage.cpp @@ -1,10 +1,12 @@ #include "participation_storage.h" -cavoke::server::model::ParticipationStorage::ParticipationStorage() {} +cavoke::server::model::ParticipationStorage::ParticipationStorage() { +} std::optional cavoke::server::model::ParticipationStorage::get_participant_id( - const std::string &session_id, const std::string &user_id) { - // TODO - return 0; + const std::string &session_id, + const std::string &user_id) { + // TODO + return 0; } diff --git a/server/model/participation_storage.h b/server/model/participation_storage.h index 02041902..24e9fe38 100644 --- a/server/model/participation_storage.h +++ b/server/model/participation_storage.h @@ -6,16 +6,15 @@ namespace cavoke::server::model { class ParticipationStorage { - // TODO: thread-safety + // TODO: thread-safety public: - ParticipationStorage(); - - std::optional get_participant_id(const std::string& session_id, - const std::string& user_id); + ParticipationStorage(); + std::optional get_participant_id(const std::string &session_id, + const std::string &user_id); }; -} // namespace cavoke::server::model +} // namespace cavoke::server::model -#endif // CAVOKE_SERVER_PARTICIPATION_STORAGE_H +#endif // CAVOKE_SERVER_PARTICIPATION_STORAGE_H From 370ced3e469c8f3c5bfbc0f26dec1e13411f52f5 Mon Sep 17 00:00:00 2001 From: Alex Kovrigin Date: Mon, 21 Feb 2022 00:03:07 +0300 Subject: [PATCH 18/20] [server] various microimprovements and fixes --- server/CMakeLists.txt | 15 +++++++++------ server/main.cpp | 2 +- server/model/game.h | 2 +- server/model/games_storage.h | 2 +- ...StorageConfig.cpp => games_storage_config.cpp} | 2 +- ...amesStorageConfig.h => games_storage_config.h} | 8 ++++---- 6 files changed, 17 insertions(+), 14 deletions(-) rename server/model/{GamesStorageConfig.cpp => games_storage_config.cpp} (93%) rename server/model/{GamesStorageConfig.h => games_storage_config.h} (77%) diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index 78f12d6c..04a41740 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -12,17 +12,20 @@ link_directories(${Boost_LIBRARY_DIRS}) # https://github.com/nlohmann/json/releases/tag/v3.9.0 for convenience macros find_package(nlohmann_json 3.9.0 REQUIRED) +include_directories(.) + add_executable(cavoke_server + main.cpp model/games_storage.cpp model/game.cpp controllers/games_controller.cpp - main.cpp controllers/health_controller.cpp - controllers/health_controller.h - model/GamesStorageConfig.cpp - model/GamesStorageConfig.h - utils.h - model/game_state_storage.cpp model/participation_storage.cpp model/game_logic_manager.cpp model/mock_tictactoe/tictactoe.cpp controllers/state_controller.cpp + model/games_storage_config.cpp + model/game_state_storage.cpp + model/participation_storage.cpp + model/game_logic_manager.cpp + model/mock_tictactoe/tictactoe.cpp + controllers/state_controller.cpp ) target_link_libraries(cavoke_server Drogon::Drogon) target_link_libraries(cavoke_server ${Boost_LIBRARIES} ${CMAKE_DL_LIBS}) diff --git a/server/main.cpp b/server/main.cpp index 90df2ea4..a0eb03d8 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -46,7 +46,7 @@ namespace po = boost::program_options; int main(int argc, char *argv[]) { po::options_description desc("Allowed options"); - desc.add_options()("help,h,?", "Print help")( + desc.add_options()("help,h", "Print help")( "config-file,c", po::value(), "File with game storage configuration")( "host,ip,a", po::value()->default_value("0.0.0.0"), diff --git a/server/model/game.h b/server/model/game.h index e27a4ba7..1809b70c 100644 --- a/server/model/game.h +++ b/server/model/game.h @@ -4,7 +4,7 @@ #include #include #include -#include "GamesStorageConfig.h" +#include "games_storage_config.h" namespace cavoke::server::model { diff --git a/server/model/games_storage.h b/server/model/games_storage.h index d2c3c552..2261318e 100644 --- a/server/model/games_storage.h +++ b/server/model/games_storage.h @@ -4,7 +4,7 @@ #include #include #include -#include "GamesStorageConfig.h" +#include "games_storage_config.h" #include "game.h" namespace cavoke::server::model { diff --git a/server/model/GamesStorageConfig.cpp b/server/model/games_storage_config.cpp similarity index 93% rename from server/model/GamesStorageConfig.cpp rename to server/model/games_storage_config.cpp index 45e70a26..46a48c11 100644 --- a/server/model/GamesStorageConfig.cpp +++ b/server/model/games_storage_config.cpp @@ -1,4 +1,4 @@ -#include "GamesStorageConfig.h" +#include "games_storage_config.h" #include #include diff --git a/server/model/GamesStorageConfig.h b/server/model/games_storage_config.h similarity index 77% rename from server/model/GamesStorageConfig.h rename to server/model/games_storage_config.h index 405076e3..2a2bc1fa 100644 --- a/server/model/GamesStorageConfig.h +++ b/server/model/games_storage_config.h @@ -1,9 +1,9 @@ -#ifndef CAVOKE_GAMESSTORAGECONFIG_H -#define CAVOKE_GAMESSTORAGECONFIG_H +#ifndef CAVOKE_GAMES_STORAGE_CONFIG_H +#define CAVOKE_GAMES_STORAGE_CONFIG_H #include #include -#include "../utils.h" // TODO: avoid relative paths +#include "utils.h" namespace cavoke::server::model { using json = nlohmann::json; @@ -21,4 +21,4 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(GamesStorageConfig, zip_name, config_name) } // namespace cavoke::server::model -#endif // CAVOKE_GAMESSTORAGECONFIG_H +#endif // CAVOKE_GAMES_STORAGE_CONFIG_H From a2f0fc86ea1ac411ea5d5e7b702abf77251f23d6 Mon Sep 17 00:00:00 2001 From: Alex Kovrigin Date: Mon, 21 Feb 2022 00:51:50 +0300 Subject: [PATCH 19/20] [server] set minimum version for drogon --- server/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index 04a41740..9c85e105 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -3,7 +3,7 @@ project(cavoke_server) set(CMAKE_CXX_STANDARD 17) -find_package(Drogon REQUIRED) +find_package(Drogon 1.7.3 REQUIRED) find_package(Boost 1.71 REQUIRED filesystem program_options) include_directories(${Boost_INCLUDE_DIRS}) From 190d5b3cfab90c470d760945fabef8616cbf86b8 Mon Sep 17 00:00:00 2001 From: Alex Kovrigin Date: Mon, 21 Feb 2022 12:06:19 +0300 Subject: [PATCH 20/20] [client] fix cmake `QT_MAJOR_VERSION` previously it was an option which is ON/OFF --- client/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 21583ea7..bd121ae0 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.10) project(cavoke_client) -option(QT_MAJOR_VERSION "Qt Major Version (e.g. Qt5/Qt6)" 6) +set(QT_MAJOR_VERSION 6 CACHE STRING "Qt Major Version (e.g. Qt5/Qt6)") set(CMAKE_CXX_STANDARD 17) set(CMAKE_INCLUDE_CURRENT_DIR ON)