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

Generated by: LCOV version 2.0-1