Build Packages / Create release (push) Successful in 24s
Build Packages / build:viewer:macos-arm64:nocuda (push) Successful in 3m29s
Build Packages / build:rugnux:macos-arm64:nocuda (push) Successful in 2m43s
Build Packages / build:rugnux:linux-aarch64:cuda (push) Successful in 8m27s
Build Packages / build:rugnux:linux-x86_64:cuda (push) Successful in 9m53s
Build Packages / build:viewer:linux-x86_64:nocuda (push) Successful in 9m58s
Build Packages / build:viewer:linux-x86_64:cuda (push) Successful in 11m22s
Build Packages / build:jfjoch:rocky8:nocuda (push) Successful in 13m39s
Build Packages / build:viewer:windows-x86_64:nocuda (push) Successful in 18m37s
Build Packages / build:jfjoch:rocky9:nocuda (push) Successful in 16m32s
Build Packages / build:viewer:windows-x86_64:cuda (push) Successful in 24m11s
Build Packages / HDF5 consumer tests (DIALS, XDS) (push) Successful in 25m30s
Build Packages / build:jfjoch:ubuntu2404:nocuda (push) Successful in 19m3s
Build Packages / build:jfjoch:ubuntu2204:nocuda (push) Successful in 20m23s
Build Packages / build:jfjoch:rocky8:cuda-sls9 (push) Successful in 19m41s
Build Packages / Generate python client (push) Successful in 50s
Build Packages / Build documentation (push) Successful in 1m16s
Build Packages / build:jfjoch:rocky9:cuda-sls9 (push) Successful in 21m0s
Build Packages / build:jfjoch:rocky8:cuda (push) Successful in 18m38s
Build Packages / build:rugnux:windows-x86_64:cuda (push) Successful in 14m33s
Build Packages / build:jfjoch:rocky9:cuda (push) Successful in 17m55s
Build Packages / build:jfjoch:ubuntu2204:cuda (push) Successful in 20m50s
Build Packages / build:jfjoch:ubuntu2404:cuda (push) Successful in 18m38s
Build Packages / Unit tests (push) Successful in 1h46m14s
* jfjoch_broker: Optional per-dataset authentication - statistics, images and plots can require a bearer token, which jfjoch_viewer supports. * jfjoch_viewer: Dark mode and a theme-matched colour scheme, a magnifier panel, and simpler contrast and background controls. * Rugnux: Multiple performance improvements on GPU and CPU (CPU-only processing up to 40% faster, faster image decoding on ARM), with unchanged results. * Rugnux: `--model` rigid-body refinement runs on the GPU, and the model-validation check is faster and more reliable. * Rugnux: Improved scaling and merging - error model, outlier rejection, absorption correction and French-Wilson amplitudes now agree more closely with XDS and ctruncate. * Rugnux: Improved integration - radial background on powder and ice rings, crowded rotation data keep their reflections, and CPU-only builds integrate large unit cells as GPU builds do. * Rugnux: More robust detector geometry - measured beam centre, X-ray bandwidth and goniometer rate, and geometry refinement accepted only on significant evidence. * Rugnux: Merged files are written in the standard setting, or in the setting of a reference MTZ, structure-factor mmCIF or model, with its free-R flags. * Rugnux: Richer report - ice and powder rings, further lattices, superstructure candidates and mosaicity, with warnings worded as prompts to check. * Rugnux: Clear error messages when a data set needs more GPU or host memory than is available. Reviewed-on: #83 Co-authored-by: Filip Leonarski <filip.leonarski@psi.ch>
218 lines
11 KiB
C++
218 lines
11 KiB
C++
// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
// Using OpenAPI licensed with Apache License 2.0
|
|
#pragma once
|
|
|
|
#include <httplib.h>
|
|
#include <nlohmann/json.hpp>
|
|
|
|
#include <memory>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <utility>
|
|
|
|
#include "../common/Logger.h"
|
|
#include "JFJochServices.h"
|
|
#include "JFJochStateMachine.h"
|
|
#include "OpenAPIConvert.h"
|
|
|
|
#include "gen/model/Azim_int_settings.h"
|
|
#include "gen/model/Bragg_integration_settings.h"
|
|
#include "gen/model/Broker_status.h"
|
|
#include "gen/model/Dark_mask_settings.h"
|
|
#include "gen/model/Dataset_settings.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/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/Plots.h"
|
|
#include "gen/model/Roi_definitions.h"
|
|
#include "gen/model/Scan_result.h"
|
|
#include "gen/model/Spot_finding_settings.h"
|
|
#include "gen/model/Zeromq_metadata_settings.h"
|
|
#include "gen/model/Zeromq_preview_settings.h"
|
|
|
|
class JFJochBrokerHttp {
|
|
Logger logger{"JFJochBroker"};
|
|
JFJochServices services{logger};
|
|
JFJochStateMachine state_machine;
|
|
std::string frontend_directory;
|
|
|
|
// The API declares 400 as a plain-text exception string and 500 as an error_message object,
|
|
// so an error response has to carry the content type its body actually is - a JSON body
|
|
// labelled text/plain is what the generated clients refuse to deserialize.
|
|
struct HttpError {
|
|
int code;
|
|
std::string body;
|
|
const char *content_type;
|
|
};
|
|
|
|
static void send_error(httplib::Response &res, const HttpError &error) {
|
|
res.status = error.code;
|
|
res.set_content(error.body, error.content_type);
|
|
}
|
|
|
|
static std::string error_message_json(const std::string &msg, const std::string &reason);
|
|
|
|
template<class T>
|
|
void ProcessOutput(const T &output, httplib::Response &response) {
|
|
std::stringstream s;
|
|
if (!output.validate(s)) {
|
|
logger.Error(s.str());
|
|
send_error(response, {500, error_message_json(s.str(), "Other"), "application/json"});
|
|
return;
|
|
}
|
|
|
|
nlohmann::json j = output;
|
|
response.status = 200;
|
|
response.set_content(j.dump(), "application/json");
|
|
}
|
|
|
|
// Writes the 401 and returns false when the current dataset is protected and the request did
|
|
// not present one of its tokens. The response says nothing about the dataset.
|
|
bool Authorized(const httplib::Request &req, httplib::Response &res) const;
|
|
static std::optional<std::string> AuthorizationHeader(const httplib::Request &req);
|
|
|
|
HttpError handleParsingException(const std::exception &ex) const noexcept;
|
|
HttpError 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<int32_t> &timeout, httplib::Response &response);
|
|
void wait_until_running_post(const std::optional<int32_t> &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 httplib::Request &request, 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<int64_t> &id,
|
|
const httplib::Request &request,
|
|
httplib::Response &response);
|
|
|
|
void config_internal_generator_image_tiff_put(const std::optional<int64_t> &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<int64_t> &id, httplib::Response &response);
|
|
void image_buffer_image_jpeg_get(const std::optional<int64_t> &id, const std::optional<bool> &showUserMask,
|
|
const std::optional<bool> &showRoi, const std::optional<bool> &showSpots,
|
|
const std::optional<bool> &showPredictions,
|
|
const std::optional<bool> &showBeamCenter, const std::optional<float> &saturation,
|
|
const std::optional<int64_t> &jpegQuality, const std::optional<float> &showResRing,
|
|
const std::optional<std::string> &color, const std::optional<bool> &showResEst,
|
|
httplib::Response &response);
|
|
void image_buffer_image_tiff_get(const std::optional<int64_t> &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<int32_t> &gainLevel, const std::optional<int32_t> &sc,
|
|
httplib::Response &response);
|
|
void preview_plot_bin_get(const std::optional<std::string> &type, const std::optional<std::string> &roi,
|
|
httplib::Response &response);
|
|
void preview_plot_get(const std::optional<std::string> &type, const std::optional<int32_t> &binning,
|
|
const std::optional<float> &fill,
|
|
const std::optional<bool> &experimentalCoord, const std::optional<std::string> &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_bragg_integration_get(httplib::Response &response);
|
|
void config_bragg_integration_put(const org::openapitools::server::model::Bragg_integration_settings &braggIntegrationSettings,
|
|
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);
|
|
|
|
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;
|
|
};
|