1#include "game_logic_manager.h"
7#include <boost/asio.hpp>
8#include <boost/process.hpp>
11namespace cavoke::server::model {
13GameLogicManager::GameLogicManager(std::shared_ptr<GamesStorage> games_storage)
14 : m_games_storage(std::move(games_storage)) {
17std::string GameLogicManager::invoke_logic_local(
const Game &game,
18 const std::string &input) {
19 namespace bp = boost::process;
20 boost::asio::io_service ios;
22 auto input_buffer = boost::asio::buffer(input);
23 bp::async_pipe input_pipe(ios);
24 std::vector<char> output_buffer(MAX_GAME_RESPONSE_B);
27 system_complete(game.logic_file), bp::start_dir(game.directory),
28 bp::std_in<input_pipe, bp::std_out> boost::asio::buffer(output_buffer),
31 boost::asio::async_write(
32 input_pipe, input_buffer,
33 [&input_pipe](
const boost::system::error_code &ec, std::size_t n) {
34 input_pipe.async_close();
39 if (!c.wait_for(std::chrono::milliseconds{LOGIC_TIMEOUT_MS})) {
40 LOG_ERROR << game.logic_file.string() <<
" logic executable timeout ("
41 << LOGIC_TIMEOUT_MS <<
" ms) exceeded";
45 return std::string(output_buffer.begin(), output_buffer.end());
49 const std::string &game_id,
51 const std::vector<int> &occupied_positions) {
52 std::optional<Game> game_info = m_games_storage->get_game_by_id(game_id);
53 if (!game_info.has_value()) {
54 throw validation_error(
"no game with id '" + game_id +
"'");
59 if (game_info->config.app_type ==
"LOCAL") {
60 std::ostringstream request;
61 request <<
"VALIDATE ";
62 json request_data = InitSettings{settings, occupied_positions};
63 request << request_data;
64 response = invoke_logic_local(game_info.value(), request.str());
65 }
else if (game_info->config.app_type ==
"EXTERNAL") {
66 response = invoke_logic_external(
67 game_info.value(),
"validate",
68 json(InitSettings{settings, occupied_positions}).dump());
71 json response_json = json::parse(response);
77GameStateStorage::GameState GameLogicManager::init_state(
78 const std::string &game_id,
80 const std::vector<int> &occupied_positions) {
81 std::optional<Game> game_info = m_games_storage->get_game_by_id(game_id);
82 if (!game_info.has_value()) {
88 if (game_info->config.app_type ==
"LOCAL") {
89 std::ostringstream request;
91 json request_data = InitSettings{settings, occupied_positions};
92 request << request_data;
93 response = invoke_logic_local(game_info.value(), request.str());
94 }
else if (game_info->config.app_type ==
"EXTERNAL") {
95 response = invoke_logic_external(
96 game_info.value(),
"init_state",
97 json(InitSettings{settings, occupied_positions}).dump());
100 json response_json = json::parse(response);
101 auto result = response_json.get<GameStateStorage::GameState>();
106GameStateStorage::GameState GameLogicManager::send_move(
107 const std::string &game_id,
108 const cavoke::GameMove &move) {
109 std::optional<Game> game_info = m_games_storage->get_game_by_id(game_id);
110 if (!game_info.has_value()) {
114 std::string response;
116 if (game_info->config.app_type ==
"LOCAL") {
117 std::ostringstream request;
119 json request_data = move;
120 request << request_data;
121 response = invoke_logic_local(game_info.value(), request.str());
122 }
else if (game_info->config.app_type ==
"EXTERNAL") {
123 response = invoke_logic_external(game_info.value(),
"apply_move",
127 json response_json = json::parse(response);
128 auto result = response_json.get<GameStateStorage::GameState>();
133std::string GameLogicManager::invoke_logic_external(
const Game &game,
134 const std::string &method,
135 const std::string &input) {
136 auto client = drogon::HttpClient::newHttpClient(game.config.url,
137 drogon::app().getLoop());
138 auto request = drogon::HttpRequest::newHttpRequest();
139 request->setPath(
"/" + method);
140 request->setMethod(drogon::Post);
141 request->setBody(input);
142 auto result = client->sendRequest(request, 30.0);
144 if (result.first != drogon::ReqResult::Ok) {
145 LOG_ERROR <<
"Failed to connect with game logic on address "
146 << game.config.url <<
" " << request->getPath() <<
": "
147 << to_string(result.first);
151 return std::string(result.second->getBody());
154validation_error::validation_error(std::string message)
155 : cavoke_base_exception(std::move(message),
157 "cavoke/validation") {