DUNE-DAQ
DUNE Trigger and Data Acquisition software
Loading...
Searching...
No Matches
RestEndpoint.cpp
Go to the documentation of this file.
1
9
10#include "logging/Logging.hpp"
11
12#include <chrono>
13#include <future>
14#include <sstream>
15#include <string>
16#include <utility>
17
18using namespace dunedaq::restcmd;
19using namespace Pistache;
20
21void
22RestEndpoint::init(size_t threads)
23{
24 auto opts = Http::Endpoint::options()
25 .threads(static_cast<int>(threads))
26 .maxRequestSize(15728640) // 15MB
27 .maxResponseSize(1048576) // 1MB
28 .flags(Pistache::Tcp::Options::ReuseAddr)
29 .flags(Pistache::Tcp::Options::ReusePort);
30
31 http_endpoint_->init(opts);
33 http_client_options_ = Http::Client::options().threads(static_cast<int>(threads));
35}
36
37void
39{
40 http_endpoint_->setHandler(router_.handler());
41 http_endpoint_->serveThreaded();
42 port_ = http_endpoint_->getPort();
43 TLOG() << "REST server started on port " << port_;
44}
45
46// void RestEndpoint::serveTask()
47// {
48// }
49
50void
52{
53 http_endpoint_->shutdown();
54 // server_thread_.join();
55 http_client_->shutdown();
56}
57
58void
60{
61 using namespace Rest;
62 Routes::Post(router_, "/command", Routes::bind(&RestEndpoint::handle_route_command, this));
63}
64
65inline void
66extendHeader(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
73inline std::string
74getClientAddress(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
84void
85RestEndpoint::handle_route_command(const Rest::Request& request, Http::ResponseWriter response)
86{
88 auto addr = request.address();
89 auto headers = request.headers();
90 auto ct = headers.get<Http::Header::ContentType>();
91 if (ct->mime() != accepted_mime_) {
92 auto res = response.send(Http::Code::Not_Acceptable, "Not a JSON command!\n");
93 } else {
94 auto ansport = headers.getRaw("X-Answer-Port"); // RS: FIXME reply using headers
95 auto anshost = headers.tryGetRaw("X-Answer-Host"); // RS: FIXME reply using headers
96 meta.data["ans-port"] = ansport.value();
97 meta.data["ans-host"] = (!anshost.isEmpty() ? anshost.get().value() : addr.host());
98 command_callback_(nlohmann::json::parse(request.body()), meta); // RS: FIXME parse errors
99 auto res = response.send(Http::Code::Accepted, "Command received\n");
100 }
101}
102
103void
105{
107 std::ostringstream addrstr;
108 addrstr << meta.data["ans-host"].get<std::string>() << ":" << meta.data["ans-port"].get<std::string>() << "/response";
109 meta.data["cmdid"] = command.id;
110 TLOG() << "Sending POST request to " << addrstr.str();
111
112 nlohmann::json body_json;
113 dunedaq::cmdlib::cmd::to_json(body_json, meta);
114 auto response = http_client_->post(addrstr.str()).body(body_json.dump()).send();
115 response.then([&](Http::Response response) { TLOG() << "Response code = " << response.code(); },
116 [&](std::exception_ptr exc) {
117 // handle response failure
118 try {
119 std::rethrow_exception(exc);
120 } catch (const std::exception& e) {
121 TLOG() << "Exception thrown by Http::Client::post() call: \"" << e.what()
122 << "\"; errno = " << errno;
123 }
124 });
125 http_client_responses_.push_back(std::move(response));
126}
std::string getClientAddress(const Pistache::Rest::Request &request)
void extendHeader(Http::Header::Collection &headers)
Pistache::Rest::Router router_
std::shared_ptr< Pistache::Http::Client > http_client_
void handle_route_command(const Pistache::Rest::Request &, Pistache::Http::ResponseWriter response)
std::shared_ptr< Pistache::Http::Endpoint > http_endpoint_
Pistache::Http::Client::Options http_client_options_
Pistache::Http::Mime::MediaType accepted_mime_
std::function< void(const cmdobj_t &, cmdlib::cmd::CommandReply)> command_callback_
void handleResponseCommand(const cmdobj_t &cmd, cmdlib::cmd::CommandReply &meta)
std::vector< Pistache::Async::Promise< Pistache::Http::Response > > http_client_responses_
#define TLOG(...)
Definition macro.hpp:21
void to_json(data_t &j, const Command &obj)
Definition Nljs.hpp:20
nlohmann::json cmdobj_t