#include "CourtApi.h" #include "Logger.h" #include #include #include #include #include #include #include #include const char* serverDomain = "mirsud.spb.ru"; namespace { boost::asio::ssl::context sslContext(boost::asio::ssl::context::tlsv13_client); using ssl_stream = boost::asio::ssl::stream; } // namespace ssl_stream connect(boost::asio::io_context& asioContext, const std::string& hostname) { sslContext.set_verify_mode(boost::asio::ssl::verify_peer | boost::asio::ssl::verify_fail_if_no_peer_cert); sslContext.set_default_verify_paths(); sslContext.load_verify_file("ISRG_X1.pem"); boost::certify::enable_native_https_server_verification(sslContext); ssl_stream stream(asioContext, sslContext); static boost::asio::ip::tcp::resolver resolver(asioContext); auto const results = resolver.resolve(hostname, "https"); boost::beast::get_lowest_layer(stream).connect(results); boost::certify::set_server_hostname(stream, hostname); boost::certify::sni_hostname(stream, hostname); stream.handshake(boost::asio::ssl::stream_base::client); return stream; } std::pair get(ssl_stream& stream, const std::string& hostname, const std::string& url, std::optional payload = {}) { // Создать HTTP-запрос boost::beast::http::request request; request.method(boost::beast::http::verb::get); request.target(url); request.keep_alive(true); request.set(boost::beast::http::field::host, hostname); if (payload) { request.set(boost::beast::http::field::content_type, "application/json"); request.body() = std::move(*payload); } boost::beast::http::write(stream, request); boost::beast::http::response response; boost::beast::flat_buffer buffer; boost::beast::http::read(stream, buffer, response); return {response.base().result_int(), response.body()}; } nlohmann::json getResults(ssl_stream& stream, const std::string_view& uuid) { int status; std::string result; std::tie(status, result) = get(stream, serverDomain, fmt::format("/cases/api/results/?id={}", uuid)); if (status == 200) { return nlohmann::json::parse(result); } else throw std::runtime_error( fmt::format("failed to retrieve JSON (server returned code {})", status)); } CaseDetails getCaseDetails(boost::asio::io_context& asioContext, const std::string_view& caseNumber) { ssl_stream stream = connect(asioContext, serverDomain); int status; std::string result; std::tie(status, result) = get(stream, serverDomain, fmt::format("/cases/api/detail/?id={}", caseNumber)); if (status == 200) { auto uuid = nlohmann::json::parse(result).at("id").get(); for (int i = 0; i < 5; i++) { auto response = getResults(stream, uuid); if (response.at("finished").get()) { auto& results = response.at("result"); LOG(court, results.dump()); CaseDetails details; details.id = results["id"].get(); details.courtNumber = results["court_number"].get(); details.name = results["name"].get(); details.description = results["description"].get(); details.url = fmt::format("https://{}{}", serverDomain, results["url"].get()); details.districtName = results["district_name"].get(); details.judgeName = results["judge"].get(); for (const auto& participant : results["participants"]) { CaseParticipant p; p.title = participant["title"].get(); p.name = participant["name"].get(); details.participants.push_back(std::move(p)); } for (const auto& obj : results["history"]) { CaseHistoryItem item; item.date = obj.at("date").get(); item.time = obj.at("time").get(); item.status = obj.at("status").get(); item.publishDate = obj.at("publish_date").get(); item.publishTime = obj.at("publish_time").get(); details.history.push_back(std::move(item)); } return details; } else std::this_thread::sleep_for(std::chrono::seconds(1)); } throw std::runtime_error("failed to get results in time"); } else throw std::runtime_error( fmt::format("failed to retrieve JSON (server returned code {})", status)); }