diff --git a/broker/JFJochBrokerHttp.cpp b/broker/JFJochBrokerHttp.cpp index 5861c240..214dad90 100644 --- a/broker/JFJochBrokerHttp.cpp +++ b/broker/JFJochBrokerHttp.cpp @@ -4,57 +4,20 @@ #include "JFJochBrokerHttp.h" -#include #include -#include #include #include +#include -#include "gen/model/Error_message.h" #include "../common/GitInfo.h" -#include "OpenAPIConvert.h" #include "../preview/JFJochTIFF.h" +#include "OpenAPIConvert.h" +#include "gen/model/Error_message.h" using namespace org::openapitools::server::model; namespace { - template - static bool fromStringValue(const std::string& s, T& out) { - std::istringstream is(s); - is >> out; - return !is.fail() && is.eof(); - } - - template <> - static bool fromStringValue(const std::string& s, std::string& out) { - out = s; - return true; - } - - template <> - static bool fromStringValue(const std::string& s, bool& out) { - if (s == "true" || s == "1") { out = true; return true; } - if (s == "false" || s == "0") { out = false; return true; } - return false; - } - - template - std::optional query_optional(const httplib::Request& req, const char* name) { - if (!req.has_param(name)) - return std::nullopt; - T v{}; - if (fromStringValue(req.get_param_value(name), v)) - return v; - return std::nullopt; - } - - inline std::optional query_optional_string(const httplib::Request& req, const char* name) { - if (!req.has_param(name)) - return std::nullopt; - return req.get_param_value(name); - } - - inline std::string mime_from_path(const std::string& path) { + inline std::string mime_from_path(const std::string &path) { if (path.ends_with(".js")) return "text/javascript"; if (path.ends_with(".css")) return "text/css"; if (path.ends_with(".html")) return "text/html"; @@ -68,7 +31,7 @@ namespace { return "application/octet-stream"; } - inline bool read_file_to_string(const std::string& path, std::string& out) { + inline bool read_file_to_string(const std::string &path, std::string &out) { std::ifstream f(path, std::ios::binary); if (!f) return false; @@ -80,8 +43,8 @@ namespace { } JFJochBrokerHttp::JFJochBrokerHttp(const DiffractionExperiment &experiment, - const SpotFindingSettings& spot_finding_settings) - : state_machine(experiment, services, logger, spot_finding_settings) {} + const SpotFindingSettings &spot_finding_settings) + : state_machine(experiment, services, logger, spot_finding_settings) {} void JFJochBrokerHttp::AddDetectorSetup(const DetectorSetup &setup) { state_machine.AddDetectorSetup(setup); @@ -100,9 +63,9 @@ JFJochBrokerHttp &JFJochBrokerHttp::FrontendDirectory(const std::string &directo std::pair JFJochBrokerHttp::handleParsingException(const std::exception &ex) const noexcept { try { throw; - } catch (nlohmann::detail::exception &e) { + } catch (const nlohmann::detail::exception &e) { return {400, e.what()}; - } catch (std::exception &e) { + } catch (const std::exception &e) { return {500, e.what()}; } } @@ -127,7 +90,7 @@ std::pair JFJochBrokerHttp::handleOperationException(const std } } -void JFJochBrokerHttp::attach(httplib::Server& server) { +void JFJochBrokerHttp::attach(httplib::Server &server) { register_routes(server); server.set_error_handler([](const httplib::Request &, httplib::Response &res) { res.status = 404; @@ -135,43 +98,40 @@ void JFJochBrokerHttp::attach(httplib::Server& server) { }); } -void JFJochBrokerHttp::register_routes(httplib::Server& server) { +void JFJochBrokerHttp::register_routes(httplib::Server &server) { auto bind_noarg = [this](auto method) { - return [this, method](const httplib::Request&, httplib::Response& res) { + return [this, method](const httplib::Request &, httplib::Response &res) { try { (this->*method)(res); - } catch (const std::exception& e) { + } catch (const std::exception &e) { auto [c, s] = handleOperationException(e); - res.status = c; - res.set_content(s, "text/plain"); + send_plain(res, c, s); } }; }; auto bind_json = [this](auto method, auto model_tag) { - return [this, method](const httplib::Request& req, httplib::Response& res) { + return [this, method](const httplib::Request &req, httplib::Response &res) { using Model = decltype(model_tag); try { Model v; nlohmann::json::parse(req.body).get_to(v); v.validate(); (this->*method)(v, res); - } catch (const std::exception& e) { + } catch (const std::exception &e) { auto [c, s] = handleParsingException(e); - res.status = c; - res.set_content(s, "text/plain"); + send_plain(res, c, s); } }; }; auto bind_req = [this](auto method) { - return [this, method](const httplib::Request& req, httplib::Response& res) { + return [this, method](const httplib::Request &req, httplib::Response &res) { try { (this->*method)(req, res); - } catch (const std::exception& e) { + } catch (const std::exception &e) { auto [c, s] = handleOperationException(e); - res.status = c; - res.set_content(s, "text/plain"); + send_plain(res, c, s); } }; }; @@ -193,9 +153,22 @@ void JFJochBrokerHttp::register_routes(httplib::Server& server) { server.Put("/config/indexing", bind_json(&JFJochBrokerHttp::config_indexing_put, Indexing_settings{})); server.Get("/config/instrument", bind_noarg(&JFJochBrokerHttp::config_instrument_get)); server.Put("/config/instrument", bind_json(&JFJochBrokerHttp::config_instrument_put, Instrument_metadata{})); - server.Put("/config/internal_generator_image", bind_req(&JFJochBrokerHttp::config_internal_generator_image_put)); - server.Put("/config/internal_generator_image.tiff", bind_req(&JFJochBrokerHttp::config_internal_generator_image_tiff_put)); - server.Get("/config/mask", bind_noarg(&JFJochBrokerHttp::config_mask_get)); + server.Put("/config/internal_generator_image", [this](const httplib::Request &req, httplib::Response &res) { + try { + config_internal_generator_image_put(parse_query_value(req, "id"), req, res); + } catch (const std::exception &e) { + auto [c, s] = handleOperationException(e); + send_plain(res, c, s); + } + }); + server.Put("/config/internal_generator_image.tiff", [this](const httplib::Request &req, httplib::Response &res) { + try { + config_internal_generator_image_tiff_put(parse_query_value(req, "id"), req, res); + } catch (const std::exception &e) { + auto [c, s] = handleOperationException(e); + send_plain(res, c, s); + } + }); server.Get("/config/mask", bind_noarg(&JFJochBrokerHttp::config_mask_get)); server.Get("/config/mask.tiff", bind_noarg(&JFJochBrokerHttp::config_mask_tiff_get)); server.Get("/config/roi", bind_noarg(&JFJochBrokerHttp::config_roi_get)); server.Put("/config/roi", bind_json(&JFJochBrokerHttp::config_roi_put, Roi_definitions{})); @@ -215,118 +188,123 @@ void JFJochBrokerHttp::register_routes(httplib::Server& server) { server.Get("/detector/status", bind_noarg(&JFJochBrokerHttp::detector_status_get)); server.Get("/fpga_status", bind_noarg(&JFJochBrokerHttp::fpga_status_get)); server.Post("/image_buffer/clear", bind_noarg(&JFJochBrokerHttp::image_buffer_clear_post)); - server.Get("/image_buffer/image.cbor", [this](const httplib::Request& req, httplib::Response& res) { + + server.Get("/image_buffer/image.cbor", [this](const httplib::Request &req, httplib::Response &res) { try { - image_buffer_image_cbor_get(query_optional(req, "id"), res); - } catch (const std::exception& e) { + image_buffer_image_cbor_get(parse_query_value(req, "id"), res); + } catch (const std::exception &e) { auto [c, s] = handleOperationException(e); - res.status = c; - res.set_content(s, "text/plain"); + send_plain(res, c, s); } }); - server.Get("/image_buffer/image.jpeg", [this](const httplib::Request& req, httplib::Response& res) { + + server.Get("/image_buffer/image.jpeg", [this](const httplib::Request &req, httplib::Response &res) { try { image_buffer_image_jpeg_get( - query_optional(req, "id"), - query_optional(req, "show_user_mask"), - query_optional(req, "show_roi"), - query_optional(req, "show_spots"), - query_optional(req, "show_beam_center"), - query_optional(req, "saturation"), - query_optional(req, "jpeg_quality"), - query_optional(req, "show_res_ring"), - query_optional_string(req, "color"), - query_optional(req, "show_res_est"), + parse_query_value(req, "id"), + parse_query_value(req, "show_user_mask"), + parse_query_value(req, "show_roi"), + parse_query_value(req, "show_spots"), + parse_query_value(req, "show_beam_center"), + parse_query_value(req, "saturation"), + parse_query_value(req, "jpeg_quality"), + parse_query_value(req, "show_res_ring"), + parse_query_string(req, "color"), + parse_query_value(req, "show_res_est"), res ); - } catch (const std::exception& e) { + } catch (const std::exception &e) { auto [c, s] = handleOperationException(e); - res.status = c; - res.set_content(s, "text/plain"); + send_plain(res, c, s); } }); - server.Get("/image_buffer/image.tiff", [this](const httplib::Request& req, httplib::Response& res) { + + server.Get("/image_buffer/image.tiff", [this](const httplib::Request &req, httplib::Response &res) { try { - image_buffer_image_tiff_get(query_optional(req, "id"), res); - } catch (const std::exception& e) { + image_buffer_image_tiff_get(parse_query_value(req, "id"), res); + } catch (const std::exception &e) { auto [c, s] = handleOperationException(e); - res.status = c; - res.set_content(s, "text/plain"); + send_plain(res, c, s); } }); + server.Get("/image_buffer/start.cbor", bind_noarg(&JFJochBrokerHttp::image_buffer_start_cbor_get)); server.Get("/image_buffer/status", bind_noarg(&JFJochBrokerHttp::image_buffer_status_get)); server.Get("/image_pusher/status", bind_noarg(&JFJochBrokerHttp::image_pusher_status_get)); server.Post("/initialize", bind_noarg(&JFJochBrokerHttp::initialize_post)); server.Post("/pedestal", bind_noarg(&JFJochBrokerHttp::pedestal_post)); - server.Get("/preview/pedestal.tiff", [this](const httplib::Request& req, httplib::Response& res) { + + server.Get("/preview/pedestal.tiff", [this](const httplib::Request &req, httplib::Response &res) { try { - preview_pedestal_tiff_get(query_optional(req, "gain_level"), - query_optional(req, "sc"), res); - } catch (const std::exception& e) { + preview_pedestal_tiff_get(parse_query_value(req, "gain_level"), + parse_query_value(req, "sc"), + res); + } catch (const std::exception &e) { auto [c, s] = handleOperationException(e); - res.status = c; - res.set_content(s, "text/plain"); + send_plain(res, c, s); } }); - server.Get("/preview/plot.bin", [this](const httplib::Request& req, httplib::Response& res) { + + server.Get("/preview/plot.bin", [this](const httplib::Request &req, httplib::Response &res) { try { - preview_plot_bin_get(query_optional_string(req, "type"), - query_optional_string(req, "roi"), + preview_plot_bin_get(parse_query_string(req, "type"), + parse_query_string(req, "roi"), res); - } catch (const std::exception& e) { + } catch (const std::exception &e) { auto [c, s] = handleOperationException(e); - res.status = c; - res.set_content(s, "text/plain"); + send_plain(res, c, s); } }); - server.Get("/preview/plot", [this](const httplib::Request& req, httplib::Response& res) { + + server.Get("/preview/plot", [this](const httplib::Request &req, httplib::Response &res) { try { - preview_plot_get(query_optional_string(req, "type"), - query_optional(req, "binning"), - query_optional(req, "compression"), - query_optional(req, "fill"), - query_optional(req, "experimental_coord"), - query_optional_string(req, "azint_unit"), + preview_plot_get(parse_query_string(req, "type"), + parse_query_value(req, "binning"), + parse_query_value(req, "compression"), + parse_query_value(req, "fill"), + parse_query_value(req, "experimental_coord"), + parse_query_string(req, "azint_unit"), res); - } catch (const std::exception& e) { + } catch (const std::exception &e) { auto [c, s] = handleOperationException(e); - res.status = c; - res.set_content(s, "text/plain"); + send_plain(res, c, s); } }); + server.Get("/result/scan", bind_noarg(&JFJochBrokerHttp::result_scan_get)); server.Post("/start", bind_json(&JFJochBrokerHttp::start_post, Dataset_settings{})); server.Get("/statistics/calibration", bind_noarg(&JFJochBrokerHttp::statistics_calibration_get)); server.Get("/statistics/data_collection", bind_noarg(&JFJochBrokerHttp::statistics_data_collection_get)); - server.Get("/statistics", [this](const httplib::Request& req, httplib::Response& res) { + + server.Get("/statistics", [this](const httplib::Request &req, httplib::Response &res) { try { - statistics_get(query_optional(req, "compression"), res); - } catch (const std::exception& e) { + statistics_get(parse_query_value(req, "compression"), res); + } catch (const std::exception &e) { auto [c, s] = handleOperationException(e); - res.status = c; - res.set_content(s, "text/plain"); + send_plain(res, c, s); } }); + server.Get("/status", bind_noarg(&JFJochBrokerHttp::status_get)); server.Post("/trigger", bind_noarg(&JFJochBrokerHttp::trigger_post)); server.Get("/version", bind_noarg(&JFJochBrokerHttp::version_get)); - server.Post("/wait_till_done", [this](const httplib::Request& req, httplib::Response& res) { + + server.Post("/wait_till_done", [this](const httplib::Request &req, httplib::Response &res) { try { - wait_till_done_post(query_optional(req, "timeout"), res); - } catch (const std::exception& e) { + wait_till_done_post(parse_query_value(req, "timeout"), res); + } catch (const std::exception &e) { auto [c, s] = handleOperationException(e); - res.status = c; - res.set_content(s, "text/plain"); + send_plain(res, c, s); } }); + server.Get("/xfel/event_code", bind_noarg(&JFJochBrokerHttp::xfel_event_code_get)); server.Get("/xfel/pulse_id", bind_noarg(&JFJochBrokerHttp::xfel_pulse_id_get)); - server.Get("/", [this](const httplib::Request& req, httplib::Response& res) { GetStaticFile(req, res); }); - server.Get("/frontend", [this](const httplib::Request& req, httplib::Response& res) { GetStaticFile(req, res); }); - server.Get("/frontend/*", [this](const httplib::Request& req, httplib::Response& res) { GetStaticFile(req, res); }); - server.Get("/frontend/assets/*", [this](const httplib::Request& req, httplib::Response& res) { GetStaticFile(req, res); }); + server.Get("/", [this](const httplib::Request &req, httplib::Response &res) { GetStaticFile(req, res); }); + server.Get("/frontend", [this](const httplib::Request &req, httplib::Response &res) { GetStaticFile(req, res); }); + server.Get("/frontend/*", [this](const httplib::Request &req, httplib::Response &res) { GetStaticFile(req, res); }); + server.Get("/frontend/assets/*", [this](const httplib::Request &req, httplib::Response &res) { GetStaticFile(req, res); }); } void JFJochBrokerHttp::cancel_post(httplib::Response &response) { @@ -355,13 +333,13 @@ void JFJochBrokerHttp::status_get(httplib::Response &response) { ProcessOutput(Convert(state_machine.GetStatus()), response); } -void JFJochBrokerHttp::wait_till_done_post(const std::optional &timeout, - httplib::Response &response) { +void JFJochBrokerHttp::wait_till_done_post(const std::optional &timeout, httplib::Response &response) { BrokerStatus status; if (!timeout) status = state_machine.WaitTillMeasurementDone(std::chrono::minutes(1)); else if ((timeout.value() > 3600) || (timeout.value() < 0)) { response.status = 400; + response.set_content("timeout must be in range 0..3600", "text/plain"); return; } else if (timeout.value() == 0) status = state_machine.GetStatus(); @@ -400,7 +378,7 @@ void JFJochBrokerHttp::config_detector_get(httplib::Response &response) { } void JFJochBrokerHttp::config_detector_put(const Detector_settings &detectorSettings, - httplib::Response &response) { + httplib::Response &response) { state_machine.LoadDetectorSettings(Convert(detectorSettings)); response.status = 200; } @@ -410,7 +388,7 @@ void JFJochBrokerHttp::config_azim_int_get(httplib::Response &response) { } void JFJochBrokerHttp::config_azim_int_put(const Azim_int_settings &radIntSettings, - httplib::Response &response) { + httplib::Response &response) { state_machine.SetRadialIntegrationSettings(Convert(radIntSettings)); response.status = 200; } @@ -437,7 +415,7 @@ void JFJochBrokerHttp::config_spot_finding_put(const Spot_finding_settings &spot void JFJochBrokerHttp::statistics_calibration_get(httplib::Response &response) { nlohmann::json j; - for (const auto &d: Convert(state_machine.GetCalibrationStatistics())) + for (const auto &d : Convert(state_machine.GetCalibrationStatistics())) j.push_back(d); response.set_content(j.dump(), "application/json"); response.status = 200; @@ -445,11 +423,10 @@ void JFJochBrokerHttp::statistics_calibration_get(httplib::Response &response) { void JFJochBrokerHttp::statistics_data_collection_get(httplib::Response &response) { auto stats = state_machine.GetMeasurementStatistics(); - if (stats) { + if (stats) ProcessOutput(Convert(stats.value()), response); - } else { + else response.status = 404; - } } void JFJochBrokerHttp::config_file_writer_get(httplib::Response &response) { @@ -484,7 +461,7 @@ void JFJochBrokerHttp::config_image_format_raw_post(httplib::Response &response) void JFJochBrokerHttp::fpga_status_get(httplib::Response &response) { nlohmann::json j; - for (const auto &d: Convert(state_machine.GetDeviceStatus())) + for (const auto &d : Convert(state_machine.GetDeviceStatus())) j.push_back(d); response.set_content(j.dump(), "application/json"); response.status = 200; @@ -555,6 +532,37 @@ void JFJochBrokerHttp::config_zeromq_metadata_put(const Zeromq_metadata_settings response.status = 200; } +void JFJochBrokerHttp::config_internal_generator_image_put(const std::optional &id, + const httplib::Request &request, + httplib::Response &response) { + int64_t image_number = id.value_or(0); + + if ((image_number < 0) || (image_number > 127)) { + response.status = 400; + response.set_content("id must be in range 0-127", "text/plain"); + return; + } + + state_machine.LoadInternalGeneratorImage(request.body.data(), request.body.size(), image_number); + logger.Info("Internal generator image #{} loaded", image_number); + response.status = 200; +} + +void JFJochBrokerHttp::config_internal_generator_image_tiff_put(const std::optional &id, + const httplib::Request &request, + httplib::Response &response) { + int64_t image_number = id.value_or(0); + + if ((image_number < 0) || (image_number > 127)) { + response.status = 400; + response.set_content("id must be in range 0-127", "text/plain"); + return; + } + + state_machine.LoadInternalGeneratorImageTIFF(request.body, image_number); + response.status = 200; +} + void JFJochBrokerHttp::image_buffer_clear_post(httplib::Response &response) { state_machine.ClearImageBuffer(); response.status = 200; @@ -564,7 +572,7 @@ void JFJochBrokerHttp::image_buffer_image_cbor_get(const std::optional httplib::Response &response) { std::vector tmp_vector; state_machine.GetImageFromBuffer(tmp_vector, imageNumber.value_or(-1)); - std::string s(reinterpret_cast(tmp_vector.data()), tmp_vector.size()); + std::string s(reinterpret_cast(tmp_vector.data()), tmp_vector.size()); if (!s.empty()) response.set_content(s, "application/cbor"); @@ -582,7 +590,7 @@ void JFJochBrokerHttp::image_buffer_image_jpeg_get(const std::optional const std::optional &showResRing, const std::optional &color, const std::optional &showResEst, - httplib::Response &response) { + httplib::Response &response) { int64_t image_id = id.value_or(ImageBuffer::MaxImage); PreviewImageSettings settings{}; @@ -592,9 +600,9 @@ void JFJochBrokerHttp::image_buffer_image_jpeg_get(const std::optional settings.saturation_value = saturation; settings.background_value = 0.0; settings.jpeg_quality = jpegQuality.value_or(100); - if (showResEst.value_or(false)) + if (showResEst.value_or(false)) { settings.show_res_est = true; - else { + } else { settings.show_res_est = false; settings.resolution_ring = showResRing; } @@ -611,9 +619,7 @@ void JFJochBrokerHttp::image_buffer_image_jpeg_get(const std::optional void JFJochBrokerHttp::image_buffer_image_tiff_get(const std::optional &id, httplib::Response &response) { - int64_t image_id = ImageBuffer::MaxImage; - if (id.has_value()) - image_id = id.value(); + int64_t image_id = id.value_or(ImageBuffer::MaxImage); std::string s = state_machine.GetPreviewTIFF(image_id); if (!s.empty()) @@ -753,6 +759,7 @@ void JFJochBrokerHttp::preview_pedestal_tiff_get(const std::optional &g httplib::Response &response) { if (!gainLevel) { response.status = 400; + response.set_content("gain_level is required", "text/plain"); return; } @@ -769,12 +776,14 @@ void JFJochBrokerHttp::preview_plot_bin_get(const std::optional &ty std::vector ret; state_machine.GetPlotRaw(ret, ConvertPlotType(type), roi.value_or("")); - if (ret.empty()) + if (ret.empty()) { response.status = 200; - else - response.set_content(reinterpret_cast(ret.data()), - ret.size() * sizeof(float), - "application/octet-stream"); + return; + } + + response.set_content(reinterpret_cast(ret.data()), + ret.size() * sizeof(float), + "application/octet-stream"); response.status = 200; } @@ -846,68 +855,26 @@ void JFJochBrokerHttp::xfel_pulse_id_get(httplib::Response &response) { response.status = 200; } -void JFJochBrokerHttp::config_zeromq_preview_put(const Zeromq_preview_settings &zeromqPreviewSettings, - httplib::Response &response) { - state_machine.SetPreviewSocketSettings(Convert(zeromqPreviewSettings)); - response.status = 200; -} - -void JFJochBrokerHttp::config_zeromq_metadata_put(const Zeromq_metadata_settings &zeromqMetadataSettings, - httplib::Response &response) { - state_machine.SetMetadataSocketSettings(Convert(zeromqMetadataSettings)); - response.status = 200; -} - -void JFJochBrokerHttp::config_zeromq_preview_get(httplib::Response &response) { - ProcessOutput(Convert(state_machine.GetPreviewSocketSettings()), response); -} - -void JFJochBrokerHttp::config_zeromq_metadata_get(httplib::Response &response) { - ProcessOutput(Convert(state_machine.GetMetadataSocketSettings()), response); -} - -void JFJochBrokerHttp::image_buffer_clear_post(httplib::Response &response) { - state_machine.ClearImageBuffer(); - response.status = 200; -} - -void JFJochBrokerHttp::config_file_writer_get(httplib::Response &response) { - ProcessOutput(Convert(state_machine.GetFileWriterSettings()), response); -} - -void JFJochBrokerHttp::config_file_writer_put(const File_writer_settings &fileWriterSettings, - httplib::Response &response) { - state_machine.LoadFileWriterSettings(Convert(fileWriterSettings)); - response.status = 200; -} - -void JFJochBrokerHttp::image_pusher_status_get(httplib::Response &response) { - ProcessOutput(Convert(state_machine.GetImagePusherStatus()), response); -} - -void JFJochBrokerHttp::image_buffer_status_get(httplib::Response &response) { - ProcessOutput(Convert(state_machine.GetImageBufferStatus()), response); -} - void JFJochBrokerHttp::GetStaticFile(const httplib::Request &request, httplib::Response &response) { if (frontend_directory.empty()) { response.status = 404; return; } - logger.Info("Requesting static resource {} from {}", request.path, frontend_directory); + const std::string path = request.path; + logger.Info("Requesting static resource {} from {}", path, frontend_directory); - if (request.path.find("../") != std::string::npos) { + if (path.find("../") != std::string::npos) { response.status = 403; return; } std::string rel; - if (request.path == "/" || request.path == "/frontend" || request.path == "/frontend/") + if (path == "/" || path == "/frontend" || path == "/frontend/") { rel = "index.html"; - else if (request.path.starts_with("/frontend/")) - rel = request.path.substr(std::string("/frontend/").size()); - else { + } else if (path.starts_with("/frontend/")) { + rel = path.substr(std::string("/frontend/").size()); + } else { response.status = 404; return; } diff --git a/broker/JFJochBrokerHttp.h b/broker/JFJochBrokerHttp.h index 6b39dabf..864a09d8 100644 --- a/broker/JFJochBrokerHttp.h +++ b/broker/JFJochBrokerHttp.h @@ -1,44 +1,36 @@ // SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only // Using OpenAPI licensed with Apache License 2.0 - #pragma once #include #include -#include #include #include #include -#include -#include #include #include "../common/Logger.h" -#include "JFJochStateMachine.h" #include "JFJochServices.h" +#include "JFJochStateMachine.h" #include "OpenAPIConvert.h" #include "gen/model/Azim_int_settings.h" #include "gen/model/Broker_status.h" -#include "gen/model/Calibration_statistics_inner.h" #include "gen/model/Dark_mask_settings.h" #include "gen/model/Dataset_settings.h" -#include "gen/model/Detector_list.h" #include "gen/model/Detector_selection.h" #include "gen/model/Detector_settings.h" #include "gen/model/Detector_status.h" #include "gen/model/Error_message.h" #include "gen/model/File_writer_settings.h" -#include "gen/model/Fpga_status_inner.h" #include "gen/model/Image_buffer_status.h" #include "gen/model/Image_format_settings.h" #include "gen/model/Image_pusher_status.h" #include "gen/model/Indexing_settings.h" #include "gen/model/Instrument_metadata.h" #include "gen/model/Jfjoch_statistics.h" -#include "gen/model/Measurement_statistics.h" #include "gen/model/Plots.h" #include "gen/model/Roi_definitions.h" #include "gen/model/Scan_result.h" @@ -46,7 +38,6 @@ #include "gen/model/Zeromq_metadata_settings.h" #include "gen/model/Zeromq_preview_settings.h" - class JFJochBrokerHttp { Logger logger{"JFJochBroker"}; JFJochServices services{logger}; @@ -54,209 +45,52 @@ class JFJochBrokerHttp { std::string frontend_directory; template - static void send_plain(httplib::Response &res, int code, const T &body) { - res.status = code; - res.set_content(body, "text/plain"); + static bool fromStringValue(const std::string &s, T &out) { + std::istringstream is(s); + is >> out; + return !is.fail() && is.eof(); } - template - static void send_json(httplib::Response &res, int code, const T &body) { - res.status = code; - res.set_content(body, "application/json"); + template<> + static bool fromStringValue(const std::string &s, std::string &out) { + out = s; + return true; + } + + template<> + static bool fromStringValue(const std::string &s, bool &out) { + if (s == "true" || s == "1") { + out = true; + return true; + } + if (s == "false" || s == "0") { + out = false; + return true; + } + return false; } template static std::optional parse_query_value(const httplib::Request &req, const char *name) { - if (!req.has_param(name)) return std::nullopt; + if (!req.has_param(name)) + return std::nullopt; T v{}; - if (fromStringValue(req.get_param_value(name), v)) return v; + if (fromStringValue(req.get_param_value(name), v)) + return v; return std::nullopt; } - template - void with_json_body(const httplib::Request &req, httplib::Response &res, Fn &&fn) { - try { - Model v; - nlohmann::json::parse(req.body).get_to(v); - v.validate(); - std::forward(fn)(v, res); - } catch (const std::exception &e) { - auto [c, s] = handleParsingException(e); - send_plain(res, c, s); - } + static std::optional parse_query_string(const httplib::Request &req, const char *name) { + if (!req.has_param(name)) + return std::nullopt; + return req.get_param_value(name); } - template - void with_no_body(const httplib::Request &, httplib::Response &res, Fn &&fn) { - try { - std::forward(fn)(res); - } catch (const std::exception &e) { - auto [c, s] = handleOperationException(e); - send_plain(res, c, s); - } + static void send_plain(httplib::Response &res, int code, const std::string &body) { + res.status = code; + res.set_content(body, "text/plain"); } - template - void with_request(const httplib::Request &req, httplib::Response &res, Fn &&fn) { - try { - std::forward(fn)(req, res); - } catch (const std::exception &e) { - auto [c, s] = handleOperationException(e); - send_plain(res, c, s); - } - } - - std::pair handleParsingException(const std::exception &ex) const noexcept; - - std::pair handleOperationException(const std::exception &ex) const noexcept; - - void register_routes(httplib::Server &server); - - void cancel_post(httplib::Response &response); - - void deactivate_post(httplib::Response &response); - - void initialize_post(httplib::Response &response); - - void start_post(const org::openapitools::server::model::Dataset_settings &datasetSettings, - httplib::Response &response); - - void status_get(httplib::Response &response); - - void wait_till_done_post(const std::optional &timeout, httplib::Response &response); - - void trigger_post(httplib::Response &response); - - void pedestal_post(httplib::Response &response); - - void config_detector_get(httplib::Response &response); - - void config_detector_put(const org::openapitools::server::model::Detector_settings &detectorSettings, - httplib::Response &response); - - void config_azim_int_get(httplib::Response &response); - - void config_azim_int_put(const org::openapitools::server::model::Azim_int_settings &azimIntSettings, - httplib::Response &response); - - void config_file_writer_get(httplib::Response &response); - - void config_file_writer_put(const org::openapitools::server::model::File_writer_settings &fileWriterSettings, - httplib::Response &response); - - void config_image_format_get(httplib::Response &response); - - void config_image_format_put(const org::openapitools::server::model::Image_format_settings &imageFormatSettings, - httplib::Response &response); - - void config_image_format_conversion_post(httplib::Response &response); - - void config_image_format_raw_post(httplib::Response &response); - - void config_indexing_get(httplib::Response &response); - - void config_indexing_put(const org::openapitools::server::model::Indexing_settings &indexingSettings, - httplib::Response &response); - - void config_instrument_get(httplib::Response &response); - - void config_instrument_put(const org::openapitools::server::model::Instrument_metadata &instrumentMetadata, - httplib::Response &response); - - void config_select_detector_get(httplib::Response &response); - - void config_select_detector_put(const org::openapitools::server::model::Detector_selection &detectorSelection, - httplib::Response &response); - - void config_spot_finding_get(httplib::Response &response); - - void config_spot_finding_put(const org::openapitools::server::model::Spot_finding_settings &spotFindingSettings, - httplib::Response &response); - - void config_dark_mask_get(httplib::Response &response); - - void config_dark_mask_put(const org::openapitools::server::model::Dark_mask_settings &darkMaskSettings, - httplib::Response &response); - - void config_zeromq_metadata_get(httplib::Response &response); - - void config_zeromq_metadata_put( - const org::openapitools::server::model::Zeromq_metadata_settings &zeromqMetadataSettings, - httplib::Response &response); - - void config_zeromq_preview_get(httplib::Response &response); - - void config_zeromq_preview_put( - const org::openapitools::server::model::Zeromq_preview_settings &zeromqPreviewSettings, - httplib::Response &response); - - void config_roi_get(httplib::Response &response); - - void config_roi_put(const org::openapitools::server::model::Roi_definitions &roiDefinitions, - httplib::Response &response); - - void config_mask_get(httplib::Response &response); - - void config_mask_tiff_get(httplib::Response &response); - - void config_user_mask_get(httplib::Response &response); - - void config_user_mask_put(const httplib::Request &request, httplib::Response &response); - - void config_user_mask_tiff_get(httplib::Response &response); - - void config_user_mask_tiff_put(const httplib::Request &request, httplib::Response &response); - - void image_buffer_clear_post(httplib::Response &response); - - void image_buffer_image_cbor_get(const std::optional &id, httplib::Response &response); - - void image_buffer_image_jpeg_get(const std::optional &id, const std::optional &showUserMask, - const std::optional &showRoi, const std::optional &showSpots, - const std::optional &showBeamCenter, const std::optional &saturation, - const std::optional &jpegQuality, const std::optional &showResRing, - const std::optional &color, const std::optional &showResEst, - httplib::Response &response); - - void image_buffer_image_tiff_get(const std::optional &id, httplib::Response &response); - - void image_buffer_start_cbor_get(httplib::Response &response); - - void image_buffer_status_get(httplib::Response &response); - - void image_pusher_status_get(httplib::Response &response); - - void detector_status_get(httplib::Response &response); - - void fpga_status_get(httplib::Response &response); - - void statistics_calibration_get(httplib::Response &response); - - void statistics_data_collection_get(httplib::Response &response); - - void statistics_get(const std::optional &compression, httplib::Response &response); - - void result_scan_get(httplib::Response &response); - - void version_get(httplib::Response &response); - - void preview_pedestal_tiff_get(const std::optional &gainLevel, const std::optional &sc, - httplib::Response &response); - - void preview_plot_bin_get(const std::optional &type, const std::optional &roi, - httplib::Response &response); - - void preview_plot_get(const std::optional &type, const std::optional &binning, - const std::optional &compression, const std::optional &fill, - const std::optional &experimentalCoord, const std::optional &azintUnit, - httplib::Response &response); - - void xfel_event_code_get(httplib::Response &response); - - void xfel_pulse_id_get(httplib::Response &response); - - void GetStaticFile(const httplib::Request &request, httplib::Response &response); - template void ProcessOutput(const T &output, httplib::Response &response, bool compression = false) { std::stringstream s; @@ -264,25 +98,143 @@ class JFJochBrokerHttp { logger.Error(s.str()); response.status = 500; response.set_content(s.str(), "text/plain"); - } else { - nlohmann::json j = output; - if (compression) - response.set_header("Content-Encoding", "deflate"); - response.status = 200; - response.set_content(j.dump(), "application/json"); + return; } + + nlohmann::json j = output; + if (compression) + response.set_header("Content-Encoding", "deflate"); + response.status = 200; + response.set_content(j.dump(), "application/json"); } + std::pair handleParsingException(const std::exception &ex) const noexcept; + std::pair handleOperationException(const std::exception &ex) const noexcept; + + void register_routes(httplib::Server &server); + + void cancel_post(httplib::Response &response); + void deactivate_post(httplib::Response &response); + void initialize_post(httplib::Response &response); + + void start_post(const org::openapitools::server::model::Dataset_settings &datasetSettings, + httplib::Response &response); + void status_get(httplib::Response &response); + void wait_till_done_post(const std::optional &timeout, httplib::Response &response); + void trigger_post(httplib::Response &response); + void pedestal_post(httplib::Response &response); + + void config_detector_get(httplib::Response &response); + void config_detector_put(const org::openapitools::server::model::Detector_settings &detectorSettings, + httplib::Response &response); + + void config_azim_int_get(httplib::Response &response); + void config_azim_int_put(const org::openapitools::server::model::Azim_int_settings &azimIntSettings, + httplib::Response &response); + + void config_select_detector_get(httplib::Response &response); + void config_select_detector_put(const org::openapitools::server::model::Detector_selection &detectorSelection, + httplib::Response &response); + + void config_spot_finding_get(httplib::Response &response); + void config_spot_finding_put(const org::openapitools::server::model::Spot_finding_settings &spotFindingSettings, + httplib::Response &response); + + void statistics_calibration_get(httplib::Response &response); + void statistics_data_collection_get(httplib::Response &response); + + void config_file_writer_get(httplib::Response &response); + void config_file_writer_put(const org::openapitools::server::model::File_writer_settings &fileWriterSettings, + httplib::Response &response); + + void config_image_format_get(httplib::Response &response); + void config_image_format_put(const org::openapitools::server::model::Image_format_settings &imageFormatSettings, + httplib::Response &response); + void config_image_format_conversion_post(httplib::Response &response); + void config_image_format_raw_post(httplib::Response &response); + + void fpga_status_get(httplib::Response &response); + + void statistics_get(const std::optional &compression, httplib::Response &response); + + void config_zeromq_preview_get(httplib::Response &response); + void config_zeromq_preview_put(const org::openapitools::server::model::Zeromq_preview_settings &zeromqPreviewSettings, + httplib::Response &response); + + void config_zeromq_metadata_get(httplib::Response &response); + void config_zeromq_metadata_put(const org::openapitools::server::model::Zeromq_metadata_settings &zeromqMetadataSettings, + httplib::Response &response); + + void config_internal_generator_image_put(const std::optional &id, + const httplib::Request &request, + httplib::Response &response); + + void config_internal_generator_image_tiff_put(const std::optional &id, + const httplib::Request &request, + httplib::Response &response); + + void image_buffer_clear_post(httplib::Response &response); + void image_buffer_image_cbor_get(const std::optional &id, httplib::Response &response); + void image_buffer_image_jpeg_get(const std::optional &id, const std::optional &showUserMask, + const std::optional &showRoi, const std::optional &showSpots, + const std::optional &showBeamCenter, const std::optional &saturation, + const std::optional &jpegQuality, const std::optional &showResRing, + const std::optional &color, const std::optional &showResEst, + httplib::Response &response); + void image_buffer_image_tiff_get(const std::optional &id, httplib::Response &response); + void image_buffer_start_cbor_get(httplib::Response &response); + void image_buffer_status_get(httplib::Response &response); + + void detector_status_get(httplib::Response &response); + void image_pusher_status_get(httplib::Response &response); + + void preview_pedestal_tiff_get(const std::optional &gainLevel, const std::optional &sc, + httplib::Response &response); + void preview_plot_bin_get(const std::optional &type, const std::optional &roi, + httplib::Response &response); + void preview_plot_get(const std::optional &type, const std::optional &binning, + const std::optional &compression, const std::optional &fill, + const std::optional &experimentalCoord, const std::optional &azintUnit, + httplib::Response &response); + + void config_mask_get(httplib::Response &response); + void config_mask_tiff_get(httplib::Response &response); + void config_user_mask_get(httplib::Response &response); + void config_user_mask_put(const httplib::Request &request, httplib::Response &response); + void config_user_mask_tiff_get(httplib::Response &response); + void config_user_mask_tiff_put(const httplib::Request &request, httplib::Response &response); + + void config_roi_get(httplib::Response &response); + void config_roi_put(const org::openapitools::server::model::Roi_definitions &roiDefinitions, + httplib::Response &response); + + void result_scan_get(httplib::Response &response); + void version_get(httplib::Response &response); + + void config_instrument_get(httplib::Response &response); + void config_instrument_put(const org::openapitools::server::model::Instrument_metadata &instrumentMetadata, + httplib::Response &response); + + void config_indexing_get(httplib::Response &response); + void config_indexing_put(const org::openapitools::server::model::Indexing_settings &indexingSettings, + httplib::Response &response); + + void config_dark_mask_get(httplib::Response &response); + void config_dark_mask_put(const org::openapitools::server::model::Dark_mask_settings &darkMaskSettings, + httplib::Response &response); + + void xfel_event_code_get(httplib::Response &response); + void xfel_pulse_id_get(httplib::Response &response); + + void GetStaticFile(const httplib::Request &request, httplib::Response &response); + public: JFJochBrokerHttp(const DiffractionExperiment &experiment, const SpotFindingSettings &spot_finding_settings); void AddDetectorSetup(const DetectorSetup &setup); - JFJochServices &Services(); - JFJochBrokerHttp &FrontendDirectory(const std::string &directory); - void attach(httplib::Server &server); ~JFJochBrokerHttp() = default;