LCOV - code coverage report
Current view: top level - restcmd/src - RestEndpoint.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 0.0 % 62 0
Test Date: 2026-10-11 15:05:20 Functions: 0.0 % 12 0

            Line data    Source code
       1              : /**
       2              :  * @file RestEndpoint.cpp
       3              :  *
       4              :  * This is part of the DUNE DAQ Application Framework, copyright 2020.
       5              :  * Licensing/copyright details are in the COPYING file that you should have
       6              :  * received with this code.
       7              :  */
       8              : #include "restcmd/RestEndpoint.hpp"
       9              : 
      10              : #include "logging/Logging.hpp"
      11              : 
      12              : #include <chrono>
      13              : #include <future>
      14              : #include <sstream>
      15              : #include <string>
      16              : #include <utility>
      17              : 
      18              : using namespace dunedaq::restcmd;
      19              : using namespace Pistache;
      20              : 
      21              : void
      22            0 : RestEndpoint::init(size_t threads)
      23              : {
      24            0 :   auto opts = Http::Endpoint::options()
      25            0 :                 .threads(static_cast<int>(threads))
      26            0 :                 .maxRequestSize(15728640) // 15MB
      27            0 :                 .maxResponseSize(1048576) // 1MB
      28            0 :                 .flags(Pistache::Tcp::Options::ReuseAddr)
      29            0 :                 .flags(Pistache::Tcp::Options::ReusePort);
      30              : 
      31            0 :   http_endpoint_->init(opts);
      32            0 :   createRouting();
      33            0 :   http_client_options_ = Http::Client::options().threads(static_cast<int>(threads));
      34            0 :   http_client_->init(http_client_options_);
      35            0 : }
      36              : 
      37              : void
      38            0 : RestEndpoint::start()
      39              : {
      40            0 :   http_endpoint_->setHandler(router_.handler());
      41            0 :   http_endpoint_->serveThreaded();
      42            0 :   port_ = http_endpoint_->getPort();
      43            0 :   TLOG() << "REST server started on port " << port_;
      44            0 : }
      45              : 
      46              : // void RestEndpoint::serveTask()
      47              : // {
      48              : // }
      49              : 
      50              : void
      51            0 : RestEndpoint::shutdown()
      52              : {
      53            0 :   http_endpoint_->shutdown();
      54              :   // server_thread_.join();
      55            0 :   http_client_->shutdown();
      56            0 : }
      57              : 
      58              : void
      59            0 : RestEndpoint::createRouting()
      60              : {
      61            0 :   using namespace Rest;
      62            0 :   Routes::Post(router_, "/command", Routes::bind(&RestEndpoint::handle_route_command, this));
      63            0 : }
      64              : 
      65              : inline void
      66              : extendHeader(Http::Header::Collection& headers)
      67              : {
      68              :   headers.add<Http::Header::AccessControlAllowOrigin>("*");
      69              :   headers.add<Http::Header::AccessControlAllowMethods>("POST,GET");
      70              :   headers.add<Http::Header::ContentType>(MIME(Text, Plain));
      71              : }
      72              : 
      73              : inline std::string
      74              : getClientAddress(const Pistache::Rest::Request& request)
      75              : {
      76              :   const auto xff = request.headers().tryGetRaw("X-Forwarded-For");
      77              :   if (!xff.isEmpty()) {
      78              :     // TODO: Strip off after first comma (to handle chained proxies). // NOLINT
      79              :     return xff.get().value();
      80              :   }
      81              :   return request.address().host();
      82              : }
      83              : 
      84              : void
      85            0 : RestEndpoint::handle_route_command(const Rest::Request& request, Http::ResponseWriter response)
      86              : {
      87            0 :   dunedaq::cmdlib::cmd::CommandReply meta;
      88            0 :   auto addr = request.address();
      89            0 :   auto headers = request.headers();
      90            0 :   auto ct = headers.get<Http::Header::ContentType>();
      91            0 :   if (ct->mime() != accepted_mime_) {
      92            0 :     auto res = response.send(Http::Code::Not_Acceptable, "Not a JSON command!\n");
      93            0 :   } else {
      94            0 :     auto ansport = headers.getRaw("X-Answer-Port");    // RS: FIXME reply using headers
      95            0 :     auto anshost = headers.tryGetRaw("X-Answer-Host"); // RS: FIXME reply using headers
      96            0 :     meta.data["ans-port"] = ansport.value();
      97            0 :     meta.data["ans-host"] = (!anshost.isEmpty() ? anshost.get().value() : addr.host());
      98            0 :     command_callback_(nlohmann::json::parse(request.body()), meta); // RS: FIXME parse errors
      99            0 :     auto res = response.send(Http::Code::Accepted, "Command received\n");
     100            0 :   }
     101            0 : }
     102              : 
     103              : void
     104            0 : RestEndpoint::handleResponseCommand(const cmdobj_t& cmd, dunedaq::cmdlib::cmd::CommandReply& meta)
     105              : {
     106            0 :   dunedaq::cmdlib::cmd::Command command = cmd.get<dunedaq::cmdlib::cmd::Command>();
     107            0 :   std::ostringstream addrstr;
     108            0 :   addrstr << meta.data["ans-host"].get<std::string>() << ":" << meta.data["ans-port"].get<std::string>() << "/response";
     109            0 :   meta.data["cmdid"] = command.id;
     110            0 :   TLOG() << "Sending POST request to " << addrstr.str();
     111              : 
     112            0 :   nlohmann::json body_json;
     113            0 :   dunedaq::cmdlib::cmd::to_json(body_json, meta);
     114            0 :   auto response = http_client_->post(addrstr.str()).body(body_json.dump()).send();
     115            0 :   response.then([&](Http::Response response) { TLOG() << "Response code = " << response.code(); },
     116            0 :                 [&](std::exception_ptr exc) {
     117              :                   // handle response failure
     118            0 :                   try {
     119            0 :                     std::rethrow_exception(exc);
     120            0 :                   } catch (const std::exception& e) {
     121            0 :                     TLOG() << "Exception thrown by Http::Client::post() call: \"" << e.what()
     122            0 :                            << "\"; errno = " << errno;
     123            0 :                   }
     124            0 :                 });
     125            0 :   http_client_responses_.push_back(std::move(response));
     126            0 : }
        

Generated by: LCOV version 2.0-1