jfjoch_broker: Seem to work, but plots make still trouble
Some checks failed
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Failing after 6m8s
Build Packages / build:rpm (ubuntu2204) (push) Failing after 3m32s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 10m48s
Build Packages / Generate python client (push) Successful in 40s
Build Packages / Build documentation (push) Successful in 26s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 12m33s
Build Packages / Create release (push) Has been skipped
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 13m8s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 16m18s
Build Packages / build:rpm (rocky8) (push) Successful in 16m33s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 17m20s
Build Packages / build:rpm (rocky9) (push) Successful in 17m43s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 9m46s
Build Packages / Unit tests (push) Successful in 56m20s

This commit is contained in:
2026-03-23 22:36:55 +01:00
parent 2d191b08d5
commit 4bd7cd57bb
3 changed files with 76 additions and 113 deletions

View File

@@ -17,7 +17,49 @@
using namespace org::openapitools::server::model;
namespace {
inline std::string mime_from_path(const std::string &path) {
template<class T>
bool fromStringValue(const std::string &s, T &out) {
std::istringstream is(s);
is >> out;
return !is.fail() && is.eof();
}
template<>
bool fromStringValue<std::string>(const std::string &s, std::string &out) {
out = s;
return true;
}
template<>
bool fromStringValue<bool>(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<class T>
std::optional<T> parse_query_value(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;
}
std::optional<std::string> parse_query_string(const httplib::Request &req, const char *name) {
if (!req.has_param(name))
return std::nullopt;
return req.get_param_value(name);
}
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";
@@ -44,7 +86,8 @@ namespace {
JFJochBrokerHttp::JFJochBrokerHttp(const DiffractionExperiment &experiment,
const SpotFindingSettings &spot_finding_settings)
: state_machine(experiment, services, logger, spot_finding_settings) {}
: state_machine(experiment, services, logger, spot_finding_settings) {
}
void JFJochBrokerHttp::AddDetectorSetup(const DetectorSetup &setup) {
state_machine.AddDetectorSetup(setup);
@@ -154,13 +197,13 @@ void JFJochBrokerHttp::register_routes(httplib::Server &server) {
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", [this](const httplib::Request &req, httplib::Response &res) {
try {
config_internal_generator_image_put(parse_query_value<int64_t>(req, "id"), req, res);
} catch (const std::exception &e) {
auto [c, s] = handleOperationException(e);
send_plain(res, c, s);
}
});
try {
config_internal_generator_image_put(parse_query_value<int64_t>(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<int64_t>(req, "id"), req, res);
@@ -168,12 +211,14 @@ void JFJochBrokerHttp::register_routes(httplib::Server &server) {
auto [c, s] = handleOperationException(e);
send_plain(res, c, s);
}
}); server.Get("/config/mask", bind_noarg(&JFJochBrokerHttp::config_mask_get));
});
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{}));
server.Get("/config/select_detector", bind_noarg(&JFJochBrokerHttp::config_select_detector_get));
server.Put("/config/select_detector", bind_json(&JFJochBrokerHttp::config_select_detector_put, Detector_selection{}));
server.Put("/config/select_detector",
bind_json(&JFJochBrokerHttp::config_select_detector_put, Detector_selection{}));
server.Get("/config/spot_finding", bind_noarg(&JFJochBrokerHttp::config_spot_finding_get));
server.Put("/config/spot_finding", bind_json(&JFJochBrokerHttp::config_spot_finding_put, Spot_finding_settings{}));
server.Get("/config/user_mask", bind_noarg(&JFJochBrokerHttp::config_user_mask_get));
@@ -181,9 +226,11 @@ void JFJochBrokerHttp::register_routes(httplib::Server &server) {
server.Get("/config/user_mask.tiff", bind_noarg(&JFJochBrokerHttp::config_user_mask_tiff_get));
server.Put("/config/user_mask.tiff", bind_req(&JFJochBrokerHttp::config_user_mask_tiff_put));
server.Get("/config/zeromq_metadata", bind_noarg(&JFJochBrokerHttp::config_zeromq_metadata_get));
server.Put("/config/zeromq_metadata", bind_json(&JFJochBrokerHttp::config_zeromq_metadata_put, Zeromq_metadata_settings{}));
server.Put("/config/zeromq_metadata",
bind_json(&JFJochBrokerHttp::config_zeromq_metadata_put, Zeromq_metadata_settings{}));
server.Get("/config/zeromq_preview", bind_noarg(&JFJochBrokerHttp::config_zeromq_preview_get));
server.Put("/config/zeromq_preview", bind_json(&JFJochBrokerHttp::config_zeromq_preview_put, Zeromq_preview_settings{}));
server.Put("/config/zeromq_preview",
bind_json(&JFJochBrokerHttp::config_zeromq_preview_put, Zeromq_preview_settings{}));
server.Post("/deactivate", bind_noarg(&JFJochBrokerHttp::deactivate_post));
server.Get("/detector/status", bind_noarg(&JFJochBrokerHttp::detector_status_get));
server.Get("/fpga_status", bind_noarg(&JFJochBrokerHttp::fpga_status_get));
@@ -237,8 +284,8 @@ void JFJochBrokerHttp::register_routes(httplib::Server &server) {
server.Get("/preview/pedestal.tiff", [this](const httplib::Request &req, httplib::Response &res) {
try {
preview_pedestal_tiff_get(parse_query_value<int32_t>(req, "gain_level"),
parse_query_value<int32_t>(req, "sc"),
res);
parse_query_value<int32_t>(req, "sc"),
res);
} catch (const std::exception &e) {
auto [c, s] = handleOperationException(e);
send_plain(res, c, s);
@@ -300,11 +347,6 @@ void JFJochBrokerHttp::register_routes(httplib::Server &server) {
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); });
}
void JFJochBrokerHttp::cancel_post(httplib::Response &response) {
@@ -415,7 +457,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;
@@ -461,7 +503,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;
@@ -788,12 +830,12 @@ void JFJochBrokerHttp::preview_plot_bin_get(const std::optional<std::string> &ty
}
void JFJochBrokerHttp::preview_plot_get(const std::optional<std::string> &type,
const std::optional<int32_t> &binning,
const std::optional<bool> &compression,
const std::optional<float> &fill,
const std::optional<bool> &experimentalCoord,
const std::optional<std::string> &azintUnit,
httplib::Response &response) {
const std::optional<int32_t> &binning,
const std::optional<bool> &compression,
const std::optional<float> &fill,
const std::optional<bool> &experimentalCoord,
const std::optional<std::string> &azintUnit,
httplib::Response &response) {
PlotAzintUnit unit = PlotAzintUnit::Q_recipA;
if (azintUnit.has_value()) {
if (azintUnit == "Q_recipA" || azintUnit == "q_recipa")
@@ -854,44 +896,3 @@ void JFJochBrokerHttp::xfel_pulse_id_get(httplib::Response &response) {
response.set_content(j.dump(), "application/json");
response.status = 200;
}
void JFJochBrokerHttp::GetStaticFile(const httplib::Request &request, httplib::Response &response) {
if (frontend_directory.empty()) {
response.status = 404;
return;
}
const std::string path = request.path;
logger.Info("Requesting static resource {} from {}", path, frontend_directory);
if (path.find("../") != std::string::npos) {
response.status = 403;
return;
}
std::string rel;
if (path == "/" || path == "/frontend" || path == "/frontend/") {
rel = "index.html";
} else if (path.starts_with("/frontend/")) {
rel = path.substr(std::string("/frontend/").size());
} else {
response.status = 404;
return;
}
const std::string full = frontend_directory + "/" + rel;
try {
std::string body;
if (!read_file_to_string(full, body)) {
response.status = 404;
return;
}
response.set_content(std::move(body), mime_from_path(full));
response.status = 200;
} catch (const std::exception &e) {
logger.Error(e.what());
response.status = 404;
}
}

View File

@@ -44,48 +44,6 @@ class JFJochBrokerHttp {
JFJochStateMachine state_machine;
std::string frontend_directory;
template<class T>
static bool fromStringValue(const std::string &s, T &out) {
std::istringstream is(s);
is >> out;
return !is.fail() && is.eof();
}
template<>
static bool fromStringValue<std::string>(const std::string &s, std::string &out) {
out = s;
return true;
}
template<>
static bool fromStringValue<bool>(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<class T>
static std::optional<T> parse_query_value(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;
}
static std::optional<std::string> parse_query_string(const httplib::Request &req, const char *name) {
if (!req.has_param(name))
return std::nullopt;
return req.get_param_value(name);
}
static void send_plain(httplib::Response &res, int code, const std::string &body) {
res.status = code;
res.set_content(body, "text/plain");
@@ -226,8 +184,6 @@ class JFJochBrokerHttp {
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);

View File

@@ -118,6 +118,12 @@ int main(int argc, char **argv) {
httplib::Server server;
httpServer = &server;
server.Get("/", [](const httplib::Request &req, httplib::Response &res) {
res.status = 302; // Found (temporary redirect)
res.set_header("Location", "/frontend");
});
server.set_mount_point("/frontend", settings.getFrontendDirectory());
signal(SIGPIPE, SIG_IGN);
std::vector<int> sigs{SIGQUIT, SIGINT, SIGTERM, SIGHUP};
setUpUnixSignals(sigs);