#include "src/sdk.h" // #include #include #include #include #include #include #include #include #include #include #include #include #include #include "src/http_server.h" #include "src/Logger.h" #include "src/routes.h" #include "src/handlers/GetMapsHandler.h" #include "src/handlers/GetMapByIdHandler.h" #include "src/handlers/GetStaticAssetHandler.h" namespace { namespace net = boost::asio; using namespace std::literals; namespace sys = boost::system; namespace json = boost::json; namespace http = boost::beast::http; namespace keywords = boost::log::keywords; using namespace std; using namespace http_server; using net::ip::tcp; // Запрос, тело которого представлено в виде строки using StringRequest = http::request; // Ответ, тело которого представлено в виде строки using StringResponse = http::response; using FileResponse = http::response; StringResponse HandleRequest(StringRequest&& req) { const auto route = req.target(); if (equal(k_MapsRoute.begin(), k_MapsRoute.end(), route.begin(), route.end())) { return GetMapsHandler(req); } else if (equal(k_MapsRoute.begin(), k_MapsRoute.end(), route.begin(), route.begin() + k_MapsRoute.size())) { return GetMapByIdHandler(req); } 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; } } FileResponse HandleRequestFile(StringRequest&& req) { return GetStaticAssetHandler(req); } // Запускает функцию 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() { boost::log::add_file_log(keywords::file_name = "./public/my_logs.txt", keywords::format = "[%TimeStamp%]: %Message%"); BOOST_LOG_TRIVIAL(info) << "Server started!"sv; 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) { const auto route = req.target(); if (req.target() == "/"sv || find(route.begin(), route.end(), '.') != route.end()) { auto res = HandleRequestFile(std::forward(req)); if (res.result() == http::status::not_found) { StringResponse errres(http::status::bad_request, 1); errres.set(http::field::content_type, content_type::k_JSON); string body = "{\n" " \"code\": \"badRequest\",\n" " \"message\": \"Bad request\"\n" "} "s; errres.body() = body; errres.content_length(body.size()); errres.keep_alive(true); sender(errres); } else { sender(res); } } else 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(); }); }