#include "src/sdk.h" // #include #include #include #include #include #include #include #include #include "src/http_server.h" namespace { namespace net = boost::asio; using namespace std::literals; namespace sys = boost::system; namespace json = boost::json; namespace http = boost::beast::http; using namespace std; using net::ip::tcp; // Запрос, тело которого представлено в виде строки using StringRequest = http::request; // Ответ, тело которого представлено в виде строки using StringResponse = http::response; struct content_type { content_type() = delete; constexpr static std::string_view k_TextHTML = "text/html"sv; constexpr static std::string_view k_JSON = "application/json"sv; // При необходимости внутрь content_type можно добавить и другие типы контента }; StringResponse HandleRequest(StringRequest&& req) { constexpr static string_view k_MapsPattern = "/api/v1/maps"sv; const auto route = req.target(); if (equal(k_MapsPattern.begin(), k_MapsPattern.end(), route.begin(), route.end())) { ifstream stream("./config.json"s); string config; string buf; while (std::getline(stream, buf)) { config += buf; } string_view config_ref {config.begin(), config.end()}; auto parsed_config = json::parse(config_ref); StringResponse res(http::status::ok, 1); res.set(http::field::content_type, content_type::k_JSON); res.body() = json::serialize(parsed_config.as_object().at("maps"sv).as_array()); res.content_length(res.body().size()); res.keep_alive(true); return res; } else if (equal(k_MapsPattern.begin(), k_MapsPattern.end(), route.begin(), route.begin() + k_MapsPattern.size())) { } else { StringResponse res(http::status::bad_request, 1); res.set(http::field::content_type, content_type::k_JSON); string body = "{\n" " \"code\": \"badRequest\",\n" " \"message\": \"Bad request\"\n" "} "s; res.body() = body; res.content_length(body.size()); res.keep_alive(true); return res; } } // Запускает функцию fn на n потоках, включая текущий template void RunWorkers(unsigned n, const Fn& fn) { n = std::max(1u, n); std::vector workers; workers.reserve(n - 1); // Запускаем n-1 рабочих потоков, выполняющих функцию fn while (--n) { workers.emplace_back(fn); } fn(); } } // namespace int main() { const unsigned num_threads = std::thread::hardware_concurrency(); net::io_context ioc(num_threads); tcp::acceptor acceptor(net::make_strand(ioc)); // Подписываемся на сигналы и при их получении завершаем работу сервера net::signal_set signals(ioc, SIGINT, SIGTERM); signals.async_wait([&ioc](const sys::error_code& ec, [[maybe_unused]] int signal_number) { if (!ec) { cout << "Signal "sv << signal_number << " received"sv << endl; ioc.stop(); } }); const auto address = net::ip::make_address("0.0.0.0"); constexpr net::ip::port_type port = 8080; http_server::ServeHttp(ioc, {address, port}, [](auto&& req, auto&& sender) { sender(HandleRequest(std::forward(req))); }); net::steady_timer t {ioc, 30s}; t.async_wait([](sys::error_code ec) { cout << "Timer expired"sv << endl; }); std::cout << "Server has started..."sv << std::endl; RunWorkers(num_threads, [&ioc] { ioc.run(); }); }