Merge branch 'dev240129_http_writer' into 'main'

jfjoch_writer improvement

See merge request jungfraujoch/nextgendcu!23
This commit is contained in:
2024-01-30 20:34:30 +01:00
22 changed files with 369 additions and 590 deletions
+2 -2
View File
@@ -44,7 +44,7 @@ ADD_SUBDIRECTORY(broker/pistache)
IF (JFJOCH_WRITER_ONLY)
MESSAGE(STATUS "Compiling HDF5 writer only")
SET(jfjoch_executables jfjoch_writer jfjoch_writer_http)
SET(jfjoch_executables jfjoch_writer)
ELSE()
ADD_SUBDIRECTORY(broker)
ADD_SUBDIRECTORY(fpga)
@@ -55,7 +55,7 @@ ELSE()
ADD_SUBDIRECTORY(tests)
ADD_SUBDIRECTORY(tools)
# ADD_SUBDIRECTORY(export_images)
SET(jfjoch_executables jfjoch_broker jfjoch_writer jfjoch_writer_http CatchTest CompressionBenchmark HDF5DatasetWriteTest jfjoch_udp_simulator sls_detector_put sls_detector_get)
SET(jfjoch_executables jfjoch_broker jfjoch_writer CatchTest CompressionBenchmark HDF5DatasetWriteTest jfjoch_udp_simulator sls_detector_put sls_detector_get)
ENDIF()
ADD_CUSTOM_COMMAND(OUTPUT frontend_ui/build/index.html
@@ -795,6 +795,8 @@ std::unique_lock<std::mutex> ul(m);
end_message = EndMessage{};
while (ProcessEndMessageElement(map_value));
break;
case Type::NONE:
break;
}
cborErr(cbor_value_leave_container(&value, &map_value));
+2 -2
View File
@@ -15,11 +15,11 @@
class CBORStream2Deserializer {
public:
enum class Type {START, END, IMAGE};
enum class Type {START, END, IMAGE, NONE};
private:
mutable std::mutex m;
Type msg_type;
Type msg_type = Type::NONE;
DataMessage data_message;
+4 -1
View File
@@ -33,13 +33,16 @@ TEST_CASE("StreamWriterTest_ZMQ","[JFJochWriter]") {
auto pusher_addr = pusher.GetAddress();
REQUIRE(pusher_addr.size() == 1);
REQUIRE_NOTHROW(writer = std::make_unique<StreamWriter>(context, logger, pusher_addr[0]));
CHECK (writer->GetStatistics().state == StreamWriterState::Idle);
REQUIRE_NOTHROW(fpga_receiver_service.Start(x, nullptr));
REQUIRE_NOTHROW(writer->Run());
REQUIRE_NOTHROW(receiver_output = fpga_receiver_service.Stop());
CHECK(receiver_output.status.images_sent == 5);
CHECK(writer->GetStatistics().state == StreamWriterState::Idle);
CHECK(writer->GetStatistics().processed_images == 5);
CHECK(writer->GetStatistics().file_prefix == x.GetFilePrefix());
// HDF5 file can be opened
std::unique_ptr<HDF5ReadOnlyFile> file;
+2 -6
View File
@@ -22,10 +22,6 @@ ADD_LIBRARY(WriterAPI STATIC ${MODEL_SOURCES} gen/api/DefaultApi.cpp gen/api/Def
TARGET_LINK_LIBRARIES(WriterAPI JFJochWriter pistache_static)
TARGET_INCLUDE_DIRECTORIES(WriterAPI PUBLIC gen/model gen/api)
ADD_EXECUTABLE(jfjoch_writer jfjoch_writer.cpp)
TARGET_LINK_LIBRARIES(jfjoch_writer JFJochWriter)
ADD_EXECUTABLE(jfjoch_writer jfjoch_writer.cpp JFJochWriterHttp.h JFJochWriterHttp.cpp)
TARGET_LINK_LIBRARIES(jfjoch_writer JFJochWriter WriterAPI)
INSTALL(TARGETS jfjoch_writer RUNTIME)
ADD_EXECUTABLE(jfjoch_writer_http jfjoch_writer_http.cpp JFJochWriterHttp.h JFJochWriterHttp.cpp)
TARGET_LINK_LIBRARIES(jfjoch_writer_http JFJochWriter WriterAPI)
INSTALL(TARGETS jfjoch_writer_http RUNTIME)
+21 -38
View File
@@ -2,52 +2,35 @@
#include "JFJochWriterHttp.h"
void JFJochWriterHttp::start_post(Pistache::Http::ResponseWriter &response) {
if (writer_future.valid())
response.send(Pistache::Http::Code::Internal_Server_Error);
writer_future = writer.RunFuture();
response.send(Pistache::Http::Code::Ok);
}
void JFJochWriterHttp::status_get(Pistache::Http::ResponseWriter &response) {
auto stat = writer.GetStatistics();
org::openapitools::server::model::Writer_statistics resp_struct;
resp_struct.setNimages(stat.processed_images);
resp_struct.setPerformanceMBs(stat.performance_MBs);
resp_struct.setPerformanceHz(stat.performance_Hz);
resp_struct.setFilePrefix(stat.file_prefix);
switch (stat.state) {
case StreamWriterState::Idle:
resp_struct.setState("idle");
break;
case StreamWriterState::Started:
resp_struct.setState("started");
break;
case StreamWriterState::Receiving:
resp_struct.setState("receiving");
break;
}
void JFJochWriterHttp::wait_till_done_get(Pistache::Http::ResponseWriter &response) {
wait_till_done(std::chrono::seconds(5), response);
}
void JFJochWriterHttp::check_if_done_get(Pistache::Http::ResponseWriter &response) {
wait_till_done(std::chrono::seconds(0), response);
nlohmann::json j = resp_struct;
response.send(Pistache::Http::Code::Ok, j.dump(), MIME(Application, Json));
}
void JFJochWriterHttp::cancel_post(Pistache::Http::ResponseWriter &response) {
writer.Cancel();
response.send(Pistache::Http::Code::Ok);
}
JFJochWriterHttp::JFJochWriterHttp(StreamWriter &in_writer, std::shared_ptr<Pistache::Rest::Router> &rtr)
: DefaultApi(rtr), writer(in_writer){
init();
}
void JFJochWriterHttp::wait_till_done(const std::chrono::seconds &timeout, Pistache::Http::ResponseWriter &response) {
if (!writer_future.valid()) {
response.send(Pistache::Http::Code::Not_Found);
} else {
auto wait_resp = writer_future.wait_for(timeout);
if (wait_resp == std::future_status::timeout) {
response.send(Pistache::Http::Code::Gateway_Timeout);
} else {
try {
auto val = writer_future.get();
org::openapitools::server::model::Writer_statistics resp_struct;
resp_struct.setNimages(val.image_puller_stats.processed_images);
resp_struct.setPerformanceMBs(val.image_puller_stats.performance_MBs);
resp_struct.setPerformanceHz(val.image_puller_stats.performance_Hz);
nlohmann::json j = resp_struct;
response.send(Pistache::Http::Code::Ok, j.dump(), MIME(Application, Json));
} catch (const std::exception &e) {
org::openapitools::server::model::_wait_till_done_get_500_response resp_struct;
resp_struct.setMsg(e.what());
nlohmann::json j = resp_struct;
response.send(Pistache::Http::Code::Internal_Server_Error, j.dump(), MIME(Application, Json));
}
}
}
}
+1 -6
View File
@@ -13,12 +13,7 @@
class JFJochWriterHttp : public org::openapitools::server::api::DefaultApi {
StreamWriter& writer;
std::future<StreamWriterStatistics> writer_future;
void wait_till_done(const std::chrono::seconds& timeout, Pistache::Http::ResponseWriter &response);
void start_post(Pistache::Http::ResponseWriter &response) override;
void wait_till_done_get(Pistache::Http::ResponseWriter &response) override;
void check_if_done_get(Pistache::Http::ResponseWriter &response) override;
void status_get(Pistache::Http::ResponseWriter &response) override;
void cancel_post(Pistache::Http::ResponseWriter &response) override;
public:
JFJochWriterHttp(StreamWriter& writer, std::shared_ptr<Pistache::Rest::Router> &rtr);
+32
View File
@@ -0,0 +1,32 @@
# NXmx compliant writer
## Acknowledgements
* Zdenek Matej (MAX IV)
* Felix Engelmann (MAX IV)
for testing and multiple improvement suggestions.
## Running directory
Writer needs to be running in base directory for writing files - `file_prefix` will be always relative in regard to writer running directory.
Writer detects and protects for basic security issues, like `file_prefix` starting with a slash, or starting with `../`, or containing `/../`.
## Usage
Writer needs to be started as a background service, with the following command:
```
jfjoch_writer_service <address to connect via ZeroMQ to DCU> <port for HTTP> {<address to bind via ZeroMQ to republish>}
```
for example:
```
jfjoch_writer_service tcp://dcu-address:5400 5232 tcp://0.0.0.0:3456
```
## HTTP interface
Writer has dedicated status interface via HTTP. It allows for two operations:
* ***check state of the writer*** to check if the writer is properly synchronized with DCU (e.g., that `file_prefix` agrees with what was set on the DCU) and monitor progress.
* ***cancel writing*** this will close all the HDF5 files being written and restart writer - the option should be used only if DCU process was terminated or disconnected, it SHOULD NOT be used as standard cancellation procedure (when DCU received cancel command it should properly finish writing as well)
## Republish
Republish creates a PULL socket on the writer, where all the messages are republished for further use by data analysis pipeline.
Republish is non-blocking, so if there is no receiver on other end or the sending queue is full - images won't be republished.
In case of START/END messages republishing will attempt sending for 100 ms, but if send times out it won't be retried.
Republish address is optional, if omitted this functionality is not enabled.
## NXmx extensions
There are custom extension to NXmx format. These will be documented in the future.
+77 -52
View File
@@ -7,61 +7,75 @@
#include "MakeDirectory.h"
StreamWriter::StreamWriter(ZMQContext &context, Logger &in_logger, const std::string &zmq_addr, const std::string& repub_address)
: image_puller(context, repub_address), logger(in_logger), running(false) {
: image_puller(context, repub_address), logger(in_logger) {
image_puller.Connect(zmq_addr);
logger.Info("Connected via ZMQ to {}", zmq_addr);
}
void StreamWriter::StartDataCollection() {
image_puller.WaitForImage();
while (image_puller.GetFrameType() != CBORStream2Deserializer::Type::START) {
logger.Error("Expected START image");
image_puller.WaitForImage();
}
start_message = image_puller.GetStartMessage();
logger.Info("Starting writing for dataset {} of {} images", start_message.file_prefix,
start_message.number_of_images);
MakeDirectory(start_message.file_prefix);
}
void StreamWriter::CollectImages(std::vector<HDF5DataFileStatistics> &v) {
bool run = true;
while (run && (image_puller.GetFrameType() != CBORStream2Deserializer::Type::START))
run = image_puller.WaitForImage();
if (!run)
return;
StartMessage start_message = image_puller.GetStartMessage();
logger.Info("Starting writing for dataset {} of {} images", start_message.file_prefix, start_message.number_of_images);
state = StreamWriterState::Started;
processed_images = 0;
processed_image_size = 0;
file_prefix = start_message.file_prefix;
CheckPath(start_message.file_prefix);
MakeDirectory(start_message.file_prefix);
HDF5Writer writer(start_message);
image_puller.WaitForImage();
while (image_puller.GetFrameType() == CBORStream2Deserializer::Type::IMAGE) {
bool first_image = true;
run = image_puller.WaitForImage();
while (run && (image_puller.GetFrameType() == CBORStream2Deserializer::Type::IMAGE)) {
if (first_image) {
state = StreamWriterState::Receiving;
start_time = std::chrono::system_clock::now();
first_image = false;
}
auto image_array = image_puller.GetDataMessage();
writer.Write(image_array);
image_puller.WaitForImage();
processed_images++;
processed_image_size += image_array.image.size;
run = image_puller.WaitForImage();
}
if (image_puller.GetFrameType() == CBORStream2Deserializer::Type::END) {
EndMessage end_message = image_puller.GetEndMessage();
end_time = std::chrono::system_clock::now();
if (end_message.write_master_file)
HDF5Metadata::NXmx(start_message, end_message);
state = StreamWriterState::Idle;
}
writer.GetStatistics(v);
}
void StreamWriter::EndDataCollection() {
while (image_puller.GetFrameType() != CBORStream2Deserializer::Type::END) {
logger.Error("Expected END image");
image_puller.WaitForImage();
}
EndMessage end_message = image_puller.GetEndMessage();
if (end_message.write_master_file)
HDF5Metadata::NXmx(start_message, end_message);
}
void StreamWriter::Cancel() {
logger.Info("Cancel requested");
image_puller.Abort();
}
StreamWriterStatistics StreamWriter::Run() {
{
std::unique_lock<std::mutex> ul(m);
if (running)
throw JFJochException(JFJochExceptionCategory::WrongDAQState, "Writer is busy");
running = true;
}
void StreamWriter::CheckPath(const std::string &s) {
if (s.front() == '/')
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Path cannot start with slash");
if (s.substr(0,3) == "../")
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Path cannot start with ../");
if (s.find("/../") != std::string::npos)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Path cannot contain /../");
}
StreamWriterStatistics ret;
start_message = StartMessage();
StartDataCollection();
StreamWriterOutput StreamWriter::Run() {
StreamWriterOutput ret;
try {
CollectImages(ret.data_file_stats);
} catch (JFJochException &e) {
@@ -69,23 +83,34 @@ StreamWriterStatistics StreamWriter::Run() {
// End data collection will consume all images till the end
logger.ErrorException(e);
}
EndDataCollection();
ret.image_puller_stats = image_puller.GetStatistics();
ret.image_puller_stats = GetStatistics();
logger.Info("Write task done. Images = {} Throughput = {:.0f} MB/s Frame rate = {:.0f} Hz",
ret.image_puller_stats.processed_images, ret.image_puller_stats.performance_MBs, ret.image_puller_stats.performance_Hz);
{
std::unique_lock<std::mutex> ul(m);
running = false;
}
return ret;
}
std::future<StreamWriterStatistics> StreamWriter::RunFuture() {
std::unique_lock<std::mutex> ul(m);
if (running)
throw JFJochException(JFJochExceptionCategory::WrongDAQState, "Writer is busy");
return std::async(std::launch::async, &StreamWriter::Run, this);
}
StreamWriterStatistics StreamWriter::GetStatistics() const {
float perf_MBs = 0.0f, perf_Hz = 0.0f;
if ((state != StreamWriterState::Started) && (processed_images > 0)) {
int64_t time_us;
if (state == StreamWriterState::Idle)
time_us = std::chrono::duration_cast<std::chrono::microseconds>(end_time - start_time).count();
else
time_us = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now() - start_time).count();
// MByte/s ==> Byte/us
perf_MBs = static_cast<float>(processed_image_size) / static_cast<float>(time_us);
perf_Hz = static_cast<float>(processed_images) * 1e6f / static_cast<float>(time_us);
}
return {
.processed_images = processed_images,
.performance_MBs = perf_MBs,
.performance_Hz = perf_Hz,
.file_prefix = file_prefix,
.state = state
};
}
+22 -9
View File
@@ -8,27 +8,40 @@
#include "ZMQImagePuller.h"
#include "HDF5DataFile.h"
enum class StreamWriterState {Idle, Started, Receiving};
struct StreamWriterStatistics {
ZMQImagePullerStatistics image_puller_stats;
uint64_t processed_images;
float performance_MBs;
float performance_Hz;
std::string file_prefix;
StreamWriterState state;
};
struct StreamWriterOutput {
StreamWriterStatistics image_puller_stats;
std::vector<HDF5DataFileStatistics> data_file_stats;
};
class StreamWriter {
bool running;
std::mutex m;
StreamWriterState state = StreamWriterState::Idle;
std::atomic<uint64_t> processed_images;
std::atomic<uint64_t> processed_image_size;
std::chrono::time_point<std::chrono::system_clock> start_time;
std::chrono::time_point<std::chrono::system_clock> end_time;
std::string file_prefix;
ZMQImagePuller image_puller;
Logger &logger;
StartMessage start_message;
void StartDataCollection();
void CheckPath(const std::string& s);
void CollectImages(std::vector<HDF5DataFileStatistics> &v);
void EndDataCollection();
public:
StreamWriter(ZMQContext& context, Logger &logger, const std::string& zmq_addr, const std::string& repub_address = "");
StreamWriterStatistics Run();
std::future<StreamWriterStatistics> RunFuture();
StreamWriterOutput Run();
void Cancel();
StreamWriterStatistics GetStatistics() const;
};
+15 -35
View File
@@ -12,6 +12,7 @@ ZMQImagePuller::ZMQImagePuller(ZMQContext &context, const std::string &repub_add
if (!repub_address.empty()) {
repub_socket = std::make_unique<ZMQSocket>(context, ZMQSocketType::Pull);
repub_socket->SendWaterMark(100);
repub_socket->SendTimeout(std::chrono::milliseconds(100));
repub_socket->Bind(repub_address);
}
}
@@ -34,37 +35,33 @@ void ZMQImagePuller::Abort() {
abort = 1;
}
void ZMQImagePuller::WaitForImage() {
bool ZMQImagePuller::WaitForImage() {
int64_t msg_size = -1;
while ((msg_size < 0) && (!abort))
msg_size = socket.Receive(zmq_recv_buffer, true, true);
if (msg_size > 0) {
// Republishing is always non-blocking
if (repub_socket)
repub_socket->Send(zmq_recv_buffer.data(), zmq_recv_buffer.size(), false);
deserializer.Process(zmq_recv_buffer);
if (deserializer.GetType() == CBORStream2Deserializer::Type::START) {
start_message = std::make_unique<StartMessage>(deserializer.GetStartMessage());
end_message.reset();
processed_images = 0;
processed_size = 0;
first_image = true;
} else if (deserializer.GetType() == CBORStream2Deserializer::Type::END) {
} else if (deserializer.GetType() == CBORStream2Deserializer::Type::END)
end_message = std::make_unique<EndMessage>(deserializer.GetEndMessage());
end_time = std::chrono::system_clock::now();
} else if (deserializer.GetType() == CBORStream2Deserializer::Type::IMAGE) {
if (first_image) {
start_time = std::chrono::system_clock::now();
first_image = false;
}
processed_images++;
else if (deserializer.GetType() == CBORStream2Deserializer::Type::IMAGE)
deserialized_image_message = std::make_unique<DataMessage>(deserializer.GetDataMessage());
processed_size += deserialized_image_message->image.size;
if (repub_socket) {
// Republishing is non-blocking for images
// and blocking (with 100ms timeout) for START/END
repub_socket->Send(zmq_recv_buffer.data(), zmq_recv_buffer.size(),
deserializer.GetType() != CBORStream2Deserializer::Type::IMAGE);
}
}
return true;
} else
return false; // This is all kinds of error
}
const DataMessage &ZMQImagePuller::GetDataMessage() const {
@@ -76,28 +73,11 @@ const DataMessage &ZMQImagePuller::GetDataMessage() const {
CBORStream2Deserializer::Type ZMQImagePuller::GetFrameType() const {
if (abort)
return CBORStream2Deserializer::Type::END;
return CBORStream2Deserializer::Type::NONE;
else
return deserializer.GetType();
}
ZMQImagePullerStatistics ZMQImagePuller::GetStatistics() {
float perf_MBs = 0.0f, perf_Hz = 0.0f;
if (processed_images > 0) {
auto time_us = std::chrono::duration_cast<std::chrono::microseconds>(end_time - start_time);
// MByte/s ==> Byte/us
perf_MBs = static_cast<float>(processed_size) / static_cast<float>(time_us.count());
perf_Hz = static_cast<float>(processed_images) * 1e6f / static_cast<float>(time_us.count());
}
return {
.processed_images = processed_images,
.performance_MBs = perf_MBs,
.performance_Hz = perf_Hz
};
}
StartMessage ZMQImagePuller::GetStartMessage() const {
if (start_message)
return *start_message;
+3 -14
View File
@@ -10,25 +10,15 @@
#include "../common/SpotToSave.h"
#include "../frame_serialize/CBORStream2Deserializer.h"
struct ZMQImagePullerStatistics {
uint64_t processed_images;
float performance_MBs;
float performance_Hz;
};
class ZMQImagePuller {
std::vector<uint8_t> zmq_recv_buffer;
CBORStream2Deserializer deserializer;
constexpr const static uint32_t ReceiverWaterMark = 100;
constexpr const static uint32_t ReceiverWaterMark = 500;
// ZeroMQ receive timeout allows to check for abort value from time to time
constexpr const static auto ReceiveTimeout = std::chrono::milliseconds(100);
size_t processed_size = 0;
size_t processed_images = 0;
bool first_image = false;
std::chrono::time_point<std::chrono::system_clock> start_time;
std::chrono::time_point<std::chrono::system_clock> end_time;
ZMQSocket socket;
std::string addr;
volatile int abort = 0;
@@ -44,10 +34,9 @@ public:
void Disconnect();
void Abort();
void WaitForImage();
[[nodiscard]] bool WaitForImage();
const DataMessage &GetDataMessage() const;
[[nodiscard]] CBORStream2Deserializer::Type GetFrameType() const;
[[nodiscard]] ZMQImagePullerStatistics GetStatistics();
[[nodiscard]] StartMessage GetStartMessage() const;
[[nodiscard]] EndMessage GetEndMessage() const;
};
+3 -45
View File
@@ -34,9 +34,7 @@ void DefaultApi::setupRoutes() {
using namespace Pistache::Rest;
Routes::Post(*router, base + "/cancel", Routes::bind(&DefaultApi::cancel_post_handler, this));
Routes::Get(*router, base + "/check_if_done", Routes::bind(&DefaultApi::check_if_done_get_handler, this));
Routes::Post(*router, base + "/start", Routes::bind(&DefaultApi::start_post_handler, this));
Routes::Get(*router, base + "/wait_till_done", Routes::bind(&DefaultApi::wait_till_done_get_handler, this));
Routes::Get(*router, base + "/status", Routes::bind(&DefaultApi::status_get_handler, this));
// Default handler, called when a route is not found
router->addCustomHandler(Routes::bind(&DefaultApi::default_api_default_handler, this));
@@ -80,52 +78,12 @@ void DefaultApi::cancel_post_handler(const Pistache::Rest::Request &, Pistache::
}
}
void DefaultApi::check_if_done_get_handler(const Pistache::Rest::Request &, Pistache::Http::ResponseWriter response) {
void DefaultApi::status_get_handler(const Pistache::Rest::Request &, Pistache::Http::ResponseWriter response) {
try {
try {
this->check_if_done_get(response);
} catch (Pistache::Http::HttpError &e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;
} catch (std::exception &e) {
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
} catch (std::exception &e) {
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
void DefaultApi::start_post_handler(const Pistache::Rest::Request &, Pistache::Http::ResponseWriter response) {
try {
try {
this->start_post(response);
} catch (Pistache::Http::HttpError &e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;
} catch (std::exception &e) {
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
} catch (std::exception &e) {
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
void DefaultApi::wait_till_done_get_handler(const Pistache::Rest::Request &, Pistache::Http::ResponseWriter response) {
try {
try {
this->wait_till_done_get(response);
this->status_get(response);
} catch (Pistache::Http::HttpError &e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;
+3 -20
View File
@@ -27,7 +27,6 @@
#include <utility>
#include "Writer_statistics.h"
#include "_wait_till_done_get_500_response.h"
namespace org::openapitools::server::api
{
@@ -44,9 +43,7 @@ private:
void setupRoutes();
void cancel_post_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void check_if_done_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void start_post_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void wait_till_done_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void status_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void default_api_default_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
const std::shared_ptr<Pistache::Rest::Router> router;
@@ -73,26 +70,12 @@ private:
/// </remarks>
virtual void cancel_post(Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
///
/// </summary>
/// <remarks>
/// Check if detector is done (similar to wait_till_done, but no timeout)
/// </remarks>
virtual void check_if_done_get(Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Start writer
/// Get writer status
/// </summary>
/// <remarks>
///
/// </remarks>
virtual void start_post(Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Will timeout after 5 seconds If multiple parallel calls are made - only one will result in success
/// </summary>
/// <remarks>
/// Wait for writing done
/// </remarks>
virtual void wait_till_done_get(Pistache::Http::ResponseWriter &response) = 0;
virtual void status_get(Pistache::Http::ResponseWriter &response) = 0;
};
+63 -5
View File
@@ -21,12 +21,16 @@ namespace org::openapitools::server::model
Writer_statistics::Writer_statistics()
{
m_Nimages = 0;
m_Nimages = 0L;
m_NimagesIsSet = false;
m_Performance_MBs = 0.0f;
m_Performance_MBsIsSet = false;
m_Performance_Hz = 0.0f;
m_Performance_HzIsSet = false;
m_File_prefix = "";
m_File_prefixIsSet = false;
m_State = "";
m_StateIsSet = false;
}
@@ -49,7 +53,7 @@ bool Writer_statistics::validate(std::stringstream& msg, const std::string& path
bool success = true;
const std::string _pathPrefix = pathPrefix.empty() ? "Writer_statistics" : pathPrefix;
return success;
}
@@ -65,7 +69,13 @@ bool Writer_statistics::operator==(const Writer_statistics& rhs) const
((!performanceMBsIsSet() && !rhs.performanceMBsIsSet()) || (performanceMBsIsSet() && rhs.performanceMBsIsSet() && getPerformanceMBs() == rhs.getPerformanceMBs())) &&
((!performanceHzIsSet() && !rhs.performanceHzIsSet()) || (performanceHzIsSet() && rhs.performanceHzIsSet() && getPerformanceHz() == rhs.getPerformanceHz()))
((!performanceHzIsSet() && !rhs.performanceHzIsSet()) || (performanceHzIsSet() && rhs.performanceHzIsSet() && getPerformanceHz() == rhs.getPerformanceHz())) &&
((!filePrefixIsSet() && !rhs.filePrefixIsSet()) || (filePrefixIsSet() && rhs.filePrefixIsSet() && getFilePrefix() == rhs.getFilePrefix())) &&
((!stateIsSet() && !rhs.stateIsSet()) || (stateIsSet() && rhs.stateIsSet() && getState() == rhs.getState()))
;
}
@@ -84,6 +94,10 @@ void to_json(nlohmann::json& j, const Writer_statistics& o)
j["performance_MBs"] = o.m_Performance_MBs;
if(o.performanceHzIsSet())
j["performance_Hz"] = o.m_Performance_Hz;
if(o.filePrefixIsSet())
j["file_prefix"] = o.m_File_prefix;
if(o.stateIsSet())
j["state"] = o.m_State;
}
@@ -104,14 +118,24 @@ void from_json(const nlohmann::json& j, Writer_statistics& o)
j.at("performance_Hz").get_to(o.m_Performance_Hz);
o.m_Performance_HzIsSet = true;
}
if(j.find("file_prefix") != j.end())
{
j.at("file_prefix").get_to(o.m_File_prefix);
o.m_File_prefixIsSet = true;
}
if(j.find("state") != j.end())
{
j.at("state").get_to(o.m_State);
o.m_StateIsSet = true;
}
}
int32_t Writer_statistics::getNimages() const
int64_t Writer_statistics::getNimages() const
{
return m_Nimages;
}
void Writer_statistics::setNimages(int32_t const value)
void Writer_statistics::setNimages(int64_t const value)
{
m_Nimages = value;
m_NimagesIsSet = true;
@@ -158,6 +182,40 @@ void Writer_statistics::unsetPerformance_Hz()
{
m_Performance_HzIsSet = false;
}
std::string Writer_statistics::getFilePrefix() const
{
return m_File_prefix;
}
void Writer_statistics::setFilePrefix(std::string const& value)
{
m_File_prefix = value;
m_File_prefixIsSet = true;
}
bool Writer_statistics::filePrefixIsSet() const
{
return m_File_prefixIsSet;
}
void Writer_statistics::unsetFile_prefix()
{
m_File_prefixIsSet = false;
}
std::string Writer_statistics::getState() const
{
return m_State;
}
void Writer_statistics::setState(std::string const& value)
{
m_State = value;
m_StateIsSet = true;
}
bool Writer_statistics::stateIsSet() const
{
return m_StateIsSet;
}
void Writer_statistics::unsetState()
{
m_StateIsSet = false;
}
} // namespace org::openapitools::server::model
+22 -3
View File
@@ -19,6 +19,7 @@
#define Writer_statistics_H_
#include <string>
#include <nlohmann/json.hpp>
namespace org::openapitools::server::model
@@ -60,8 +61,8 @@ public:
/// <summary>
/// Number of images written
/// </summary>
int32_t getNimages() const;
void setNimages(int32_t const value);
int64_t getNimages() const;
void setNimages(int64_t const value);
bool nimagesIsSet() const;
void unsetNimages();
/// <summary>
@@ -78,16 +79,34 @@ public:
void setPerformanceHz(float const value);
bool performanceHzIsSet() const;
void unsetPerformance_Hz();
/// <summary>
/// File prefix for the last written dataset
/// </summary>
std::string getFilePrefix() const;
void setFilePrefix(std::string const& value);
bool filePrefixIsSet() const;
void unsetFile_prefix();
/// <summary>
///
/// </summary>
std::string getState() const;
void setState(std::string const& value);
bool stateIsSet() const;
void unsetState();
friend void to_json(nlohmann::json& j, const Writer_statistics& o);
friend void from_json(const nlohmann::json& j, Writer_statistics& o);
protected:
int32_t m_Nimages;
int64_t m_Nimages;
bool m_NimagesIsSet;
float m_Performance_MBs;
bool m_Performance_MBsIsSet;
float m_Performance_Hz;
bool m_Performance_HzIsSet;
std::string m_File_prefix;
bool m_File_prefixIsSet;
std::string m_State;
bool m_StateIsSet;
};
@@ -1,91 +0,0 @@
/**
* Jungfraujoch writer
* Jungfraujoch Writer Web API
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
#include "_wait_till_done_get_500_response.h"
#include "Helpers.h"
#include <sstream>
namespace org::openapitools::server::model
{
_wait_till_done_get_500_response::_wait_till_done_get_500_response()
{
m_Msg = "";
}
void _wait_till_done_get_500_response::validate() const
{
std::stringstream msg;
if (!validate(msg))
{
throw org::openapitools::server::helpers::ValidationException(msg.str());
}
}
bool _wait_till_done_get_500_response::validate(std::stringstream& msg) const
{
return validate(msg, "");
}
bool _wait_till_done_get_500_response::validate(std::stringstream& msg, const std::string& pathPrefix) const
{
bool success = true;
const std::string _pathPrefix = pathPrefix.empty() ? "_wait_till_done_get_500_response" : pathPrefix;
return success;
}
bool _wait_till_done_get_500_response::operator==(const _wait_till_done_get_500_response& rhs) const
{
return
(getMsg() == rhs.getMsg())
;
}
bool _wait_till_done_get_500_response::operator!=(const _wait_till_done_get_500_response& rhs) const
{
return !(*this == rhs);
}
void to_json(nlohmann::json& j, const _wait_till_done_get_500_response& o)
{
j = nlohmann::json();
j["msg"] = o.m_Msg;
}
void from_json(const nlohmann::json& j, _wait_till_done_get_500_response& o)
{
j.at("msg").get_to(o.m_Msg);
}
std::string _wait_till_done_get_500_response::getMsg() const
{
return m_Msg;
}
void _wait_till_done_get_500_response::setMsg(std::string const& value)
{
m_Msg = value;
}
} // namespace org::openapitools::server::model
@@ -1,77 +0,0 @@
/**
* Jungfraujoch writer
* Jungfraujoch Writer Web API
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
/*
* _wait_till_done_get_500_response.h
*
*
*/
#ifndef _wait_till_done_get_500_response_H_
#define _wait_till_done_get_500_response_H_
#include <string>
#include <nlohmann/json.hpp>
namespace org::openapitools::server::model
{
/// <summary>
///
/// </summary>
class _wait_till_done_get_500_response
{
public:
_wait_till_done_get_500_response();
virtual ~_wait_till_done_get_500_response() = default;
/// <summary>
/// Validate the current data in the model. Throws a ValidationException on failure.
/// </summary>
void validate() const;
/// <summary>
/// Validate the current data in the model. Returns false on error and writes an error
/// message into the given stringstream.
/// </summary>
bool validate(std::stringstream& msg) const;
/// <summary>
/// Helper overload for validate. Used when one model stores another model and calls it's validate.
/// Not meant to be called outside that case.
/// </summary>
bool validate(std::stringstream& msg, const std::string& pathPrefix) const;
bool operator==(const _wait_till_done_get_500_response& rhs) const;
bool operator!=(const _wait_till_done_get_500_response& rhs) const;
/////////////////////////////////////////////
/// _wait_till_done_get_500_response members
/// <summary>
/// Error message
/// </summary>
std::string getMsg() const;
void setMsg(std::string const& value);
friend void to_json(nlohmann::json& j, const _wait_till_done_get_500_response& o);
friend void from_json(const nlohmann::json& j, _wait_till_done_get_500_response& o);
protected:
std::string m_Msg;
};
} // namespace org::openapitools::server::model
#endif /* _wait_till_done_get_500_response_H_ */
+69 -9
View File
@@ -1,23 +1,83 @@
// Copyright (2019-2023) Paul Scherrer Institute
#include <csignal>
#include "../common/Logger.h"
#include "JFJochWriterHttp.h"
#include "StreamWriter.h"
volatile bool quitok = false;
static Pistache::Http::Endpoint *httpEndpoint;
static StreamWriter *writer;
volatile static bool quitok = false;
static void sigHandler (int sig){
switch(sig){
case SIGINT:
case SIGQUIT:
case SIGTERM:
case SIGHUP:
default:
httpEndpoint->shutdown();
quitok = true;
writer->Cancel();
break;
}
}
static void setUpUnixSignals(std::vector<int> quitSignals) {
sigset_t blocking_mask;
sigemptyset(&blocking_mask);
for (auto sig : quitSignals)
sigaddset(&blocking_mask, sig);
struct sigaction sa;
sa.sa_handler = sigHandler;
sa.sa_mask = blocking_mask;
sa.sa_flags = 0;
for (auto sig : quitSignals)
sigaction(sig, &sa, nullptr);
}
int main(int argc, char **argv) {
RegisterHDF5Filter();
Logger logger("jfjoch_writer");
static Logger logger("jfjoch_writer_http");
if (argc < 2) {
logger.Error("Usage ./jfjoch_writer <target ZMQ addr>");
if ((argc != 3) && (argc != 4)) {
logger.Error("Usage ./jfjoch_writer_http <target ZMQ addr> <TCP port> {<repub ZMQ addr to bind>}");
exit(EXIT_FAILURE);
}
ZMQContext context;
StreamWriter writer(context, logger, argv[1]);
uint16_t http_port = atoi(argv[2]);
std::string repub_address;
if (argc == 4)
repub_address = argv[3];
while (!quitok)
writer.Run();
}
ZMQContext context;
Pistache::Address addr(Pistache::Ipv4::any(), Pistache::Port(http_port));
writer = new StreamWriter(context, logger, argv[1], repub_address);
httpEndpoint = new Pistache::Http::Endpoint(addr);
auto router = std::make_shared<Pistache::Rest::Router>();
auto opts = Pistache::Http::Endpoint::options().threads(8);
opts.flags(Pistache::Tcp::Options::ReuseAddr);
httpEndpoint->init(opts);
std::vector<int> sigs{SIGQUIT, SIGINT, SIGTERM, SIGHUP};
setUpUnixSignals(sigs);
std::thread writer_thread([] {
while (!quitok)
writer->Run();
});
JFJochWriterHttp writer_http(*writer, router);
httpEndpoint->setHandler(router->handler());
httpEndpoint->serve();
writer_thread.join();
logger.Info("Clean stop");
exit(EXIT_SUCCESS);
}
-75
View File
@@ -1,75 +0,0 @@
// Copyright (2019-2023) Paul Scherrer Institute
#include <csignal>
#include "../common/Logger.h"
#include "JFJochWriterHttp.h"
#include "StreamWriter.h"
static Pistache::Http::Endpoint *httpEndpoint;
static void sigHandler [[noreturn]] (int sig){
switch(sig){
case SIGINT:
case SIGQUIT:
case SIGTERM:
case SIGHUP:
default:
httpEndpoint->shutdown();
break;
}
exit(0);
}
static void setUpUnixSignals(std::vector<int> quitSignals) {
sigset_t blocking_mask;
sigemptyset(&blocking_mask);
for (auto sig : quitSignals)
sigaddset(&blocking_mask, sig);
struct sigaction sa;
sa.sa_handler = sigHandler;
sa.sa_mask = blocking_mask;
sa.sa_flags = 0;
for (auto sig : quitSignals)
sigaction(sig, &sa, nullptr);
}
int main(int argc, char **argv) {
RegisterHDF5Filter();
Logger logger("jfjoch_writer_http");
if ((argc != 3) && (argc != 4)) {
logger.Error("Usage ./jfjoch_writer_http <target ZMQ addr> <TCP port> {<repub ZMQ addr to bind>}");
exit(EXIT_FAILURE);
}
uint16_t http_port = atoi(argv[2]);
std::string repub_address;
if (argc == 4)
repub_address = argv[3];
ZMQContext context;
StreamWriter writer(context, logger, argv[1], repub_address);
Pistache::Address addr(Pistache::Ipv4::any(), Pistache::Port(http_port));
httpEndpoint = new Pistache::Http::Endpoint((addr));
auto router = std::make_shared<Pistache::Rest::Router>();
auto opts = Pistache::Http::Endpoint::options().threads(8);
opts.flags(Pistache::Tcp::Options::ReuseAddr);
httpEndpoint->init(opts);
std::vector<int> sigs{SIGQUIT, SIGINT, SIGTERM, SIGHUP};
setUpUnixSignals(sigs);
JFJochWriterHttp writer_http(writer, router);
httpEndpoint->setHandler(router->handler());
httpEndpoint->serve();
httpEndpoint->shutdown();
}
+13 -45
View File
@@ -43,13 +43,11 @@ data-styled.g12[id="sc-kEjbdu"]{content:"jmifsN,"}/*!sc*/
.jGBpue:before{content:'';width:15px;height:15px;background-size:contain;background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgeD0iMCIgeT0iMCIgd2lkdGg9IjUxMiIgaGVpZ2h0PSI1MTIiIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCA1MTIgNTEyIiB4bWw6c3BhY2U9InByZXNlcnZlIj48cGF0aCBmaWxsPSIjMDEwMTAxIiBkPSJNNDU5LjcgMjMzLjRsLTkwLjUgOTAuNWMtNTAgNTAtMTMxIDUwLTE4MSAwIC03LjktNy44LTE0LTE2LjctMTkuNC0yNS44bDQyLjEtNDIuMWMyLTIgNC41LTMuMiA2LjgtNC41IDIuOSA5LjkgOCAxOS4zIDE1LjggMjcuMiAyNSAyNSA2NS42IDI0LjkgOTAuNSAwbDkwLjUtOTAuNWMyNS0yNSAyNS02NS42IDAtOTAuNSAtMjQuOS0yNS02NS41LTI1LTkwLjUgMGwtMzIuMiAzMi4yYy0yNi4xLTEwLjItNTQuMi0xMi45LTgxLjYtOC45bDY4LjYtNjguNmM1MC01MCAxMzEtNTAgMTgxIDBDNTA5LjYgMTAyLjMgNTA5LjYgMTgzLjQgNDU5LjcgMjMzLjR6TTIyMC4zIDM4Mi4ybC0zMi4yIDMyLjJjLTI1IDI0LjktNjUuNiAyNC45LTkwLjUgMCAtMjUtMjUtMjUtNjUuNiAwLTkwLjVsOTAuNS05MC41YzI1LTI1IDY1LjUtMjUgOTAuNSAwIDcuOCA3LjggMTIuOSAxNy4yIDE1LjggMjcuMSAyLjQtMS40IDQuOC0yLjUgNi44LTQuNWw0Mi4xLTQyYy01LjQtOS4yLTExLjYtMTgtMTkuNC0yNS44IC01MC01MC0xMzEtNTAtMTgxIDBsLTkwLjUgOTAuNWMtNTAgNTAtNTAgMTMxIDAgMTgxIDUwIDUwIDEzMSA1MCAxODEgMGw2OC42LTY4LjZDMjc0LjYgMzk1LjEgMjQ2LjQgMzkyLjMgMjIwLjMgMzgyLjJ6Ii8+PC9zdmc+Cg==');opacity:0.5;visibility:hidden;display:inline-block;vertical-align:middle;}/*!sc*/
h1:hover>.jGBpue::before,h2:hover>.jGBpue::before,.jGBpue:hover::before{visibility:visible;}/*!sc*/
data-styled.g14[id="sc-crrtmM"]{content:"jGBpue,"}/*!sc*/
.hHbBnT{height:20px;width:20px;min-width:20px;vertical-align:middle;float:right;transition:transform 0.2s ease-out;transform:rotateZ(0);}/*!sc*/
.hHbBnT polygon{fill:white;}/*!sc*/
.iHKCKT{height:1.5em;width:1.5em;min-width:1.5em;vertical-align:middle;float:left;transition:transform 0.2s ease-out;transform:rotateZ(-90deg);}/*!sc*/
.iHKCKT polygon{fill:#1d8127;}/*!sc*/
.bbipPn{height:1.5em;width:1.5em;min-width:1.5em;vertical-align:middle;float:left;transition:transform 0.2s ease-out;transform:rotateZ(-90deg);}/*!sc*/
.bbipPn polygon{fill:#d41f1c;}/*!sc*/
data-styled.g15[id="sc-dQpIV"]{content:"hHbBnT,iHKCKT,bbipPn,"}/*!sc*/
.hHbBnT{height:20px;width:20px;min-width:20px;vertical-align:middle;float:right;transition:transform 0.2s ease-out;transform:rotateZ(0);}/*!sc*/
.hHbBnT polygon{fill:white;}/*!sc*/
data-styled.g15[id="sc-dQpIV"]{content:"iHKCKT,hHbBnT,"}/*!sc*/
.jVRsAZ >ul{list-style:none;padding:0;margin:0;margin:0 -5px;}/*!sc*/
.jVRsAZ >ul >li{padding:5px 10px;display:inline-block;background-color:#11171a;border-bottom:1px solid rgba(0, 0, 0, 0.5);cursor:pointer;text-align:center;outline:none;color:#ccc;margin:0 5px 5px 5px;border:1px solid #07090b;border-radius:5px;min-width:60px;font-size:0.9em;font-weight:bold;}/*!sc*/
.jVRsAZ >ul >li.react-tabs__tab--selected{color:#333333;background:#ffffff;}/*!sc*/
@@ -214,9 +212,9 @@ data-styled.g111[id="sc-fXoxOd"]{content:"jzevEV,"}/*!sc*/
.jlriCd ..sc-fXoxOd{color:#ffffff;}/*!sc*/
.jlriCd:focus{box-shadow:inset 0 2px 2px rgba(0, 0, 0, 0.45),0 2px 0 rgba(128, 128, 128, 0.25);}/*!sc*/
data-styled.g112[id="sc-FyfbU"]{content:"jlriCd,"}/*!sc*/
.coiChI{font-size:0.929em;line-height:20px;background-color:#186FAF;color:#ffffff;padding:3px 10px;text-transform:uppercase;font-family:Montserrat,sans-serif;margin:0;}/*!sc*/
.gDPfwK{font-size:0.929em;line-height:20px;background-color:#2F8132;color:#ffffff;padding:3px 10px;text-transform:uppercase;font-family:Montserrat,sans-serif;margin:0;}/*!sc*/
data-styled.g113[id="sc-jXkspL"]{content:"coiChI,gDPfwK,"}/*!sc*/
.coiChI{font-size:0.929em;line-height:20px;background-color:#186FAF;color:#ffffff;padding:3px 10px;text-transform:uppercase;font-family:Montserrat,sans-serif;margin:0;}/*!sc*/
data-styled.g113[id="sc-jXkspL"]{content:"gDPfwK,coiChI,"}/*!sc*/
.ciRGmD{position:absolute;width:100%;z-index:100;background:#fafafa;color:#263238;box-sizing:border-box;box-shadow:0 0 6px rgba(0, 0, 0, 0.33);overflow:hidden;border-bottom-left-radius:4px;border-bottom-right-radius:4px;transition:all 0.25s ease;visibility:hidden;transform:translateY(-50%) scaleY(0);}/*!sc*/
data-styled.g114[id="sc-eFtZDC"]{content:"ciRGmD,"}/*!sc*/
.buTZbL{padding:10px;}/*!sc*/
@@ -224,19 +222,13 @@ data-styled.g115[id="sc-fmlKft"]{content:"buTZbL,"}/*!sc*/
.uePtT{padding:5px;border:1px solid #ccc;background:#fff;word-break:break-all;color:#32329f;}/*!sc*/
.uePtT >span{color:#333333;}/*!sc*/
data-styled.g116[id="sc-ljRaSg"]{content:"uePtT,"}/*!sc*/
.iePdRD{display:block;border:0;width:100%;text-align:left;padding:10px;border-radius:2px;margin-bottom:4px;line-height:1.5em;cursor:pointer;color:#1d8127;background-color:rgba(29,129,39,0.07);}/*!sc*/
.iePdRD:focus{outline:auto #1d8127;}/*!sc*/
.eEqsZl{display:block;border:0;width:100%;text-align:left;padding:10px;border-radius:2px;margin-bottom:4px;line-height:1.5em;cursor:pointer;color:#1d8127;background-color:rgba(29,129,39,0.07);cursor:default;}/*!sc*/
.eEqsZl:focus{outline:auto #1d8127;}/*!sc*/
.eEqsZl::before{content:"—";font-weight:bold;width:1.5em;text-align:center;display:inline-block;vertical-align:top;}/*!sc*/
.eEqsZl:focus{outline:0;}/*!sc*/
.iePdRD{display:block;border:0;width:100%;text-align:left;padding:10px;border-radius:2px;margin-bottom:4px;line-height:1.5em;cursor:pointer;color:#1d8127;background-color:rgba(29,129,39,0.07);}/*!sc*/
.iePdRD:focus{outline:auto #1d8127;}/*!sc*/
.jifJmL{display:block;border:0;width:100%;text-align:left;padding:10px;border-radius:2px;margin-bottom:4px;line-height:1.5em;cursor:pointer;color:#d41f1c;background-color:rgba(212,31,28,0.07);cursor:default;}/*!sc*/
.jifJmL:focus{outline:auto #d41f1c;}/*!sc*/
.jifJmL::before{content:"—";font-weight:bold;width:1.5em;text-align:center;display:inline-block;vertical-align:top;}/*!sc*/
.jifJmL:focus{outline:0;}/*!sc*/
.jEuzUJ{display:block;border:0;width:100%;text-align:left;padding:10px;border-radius:2px;margin-bottom:4px;line-height:1.5em;cursor:pointer;color:#d41f1c;background-color:rgba(212,31,28,0.07);}/*!sc*/
.jEuzUJ:focus{outline:auto #d41f1c;}/*!sc*/
data-styled.g119[id="sc-httZfN"]{content:"eEqsZl,iePdRD,jifJmL,jEuzUJ,"}/*!sc*/
data-styled.g119[id="sc-httZfN"]{content:"iePdRD,eEqsZl,"}/*!sc*/
.goojcW{vertical-align:top;}/*!sc*/
data-styled.g122[id="sc-gVgoeb"]{content:"goojcW,"}/*!sc*/
.fCsSHf{font-size:1.3em;padding:0.2em 0;margin:3em 0 1.1em;color:#333333;font-weight:normal;}/*!sc*/
@@ -276,9 +268,7 @@ data-styled.g137[id="sc-cKZHtR"]{content:"lcoFQc,"}/*!sc*/
<body>
<div id="redoc"><div class="sc-kUbfpu bwTiCm redoc-wrap"><div class="sc-irlPvL gXSQkB menu-content" style="top:0px;height:calc(100vh - 0px)"><div role="search" class="sc-eltaTX hwhlAl"><svg class="sc-cKZHtR lcoFQc search-icon" version="1.1" viewBox="0 0 1000 1000" x="0px" xmlns="http://www.w3.org/2000/svg" y="0px"><path d="M968.2,849.4L667.3,549c83.9-136.5,66.7-317.4-51.7-435.6C477.1-25,252.5-25,113.9,113.4c-138.5,138.3-138.5,362.6,0,501C219.2,730.1,413.2,743,547.6,666.5l301.9,301.4c43.6,43.6,76.9,14.9,104.2-12.4C981,928.3,1011.8,893,968.2,849.4z M524.5,522c-88.9,88.7-233,88.7-321.8,0c-88.9-88.7-88.9-232.6,0-321.3c88.9-88.7,233-88.7,321.8,0C613.4,289.4,613.4,433.3,524.5,522z"></path></svg><input placeholder="Search..." aria-label="Search" type="text" class="sc-kiYrGK eWIXbA search-input" value=""/></div><div class="sc-kLgoAE eJckYb scrollbar-container undefined"><ul role="menu" class="sc-XhViZ YKcaq"><li tabindex="0" depth="2" data-item-id="/paths/~1start/post" role="menuitem" class="sc-ikPBrU fhNqYr"><label class="sc-tYqQR CYQVt -depth2"><span type="post" class="sc-dkIYMQ bwwtyo operation-type post">post</span><span tabindex="0" width="calc(100% - 38px)" class="sc-biBryG bkVowu">Start writer</span></label></li><li tabindex="0" depth="2" data-item-id="/paths/~1wait_till_done/get" role="menuitem" class="sc-ikPBrU fhNqYr"><label class="sc-tYqQR CYQVt -depth2"><span type="get" class="sc-dkIYMQ bwwtyo operation-type get">get</span><span tabindex="0" width="calc(100% - 38px)" class="sc-biBryG bkVowu">Will timeout after 5 seconds
If multiple parallel calls are made - only one will result in success
</span></label></li><li tabindex="0" depth="2" data-item-id="/paths/~1cancel/post" role="menuitem" class="sc-ikPBrU fhNqYr"><label class="sc-tYqQR CYQVt -depth2"><span type="post" class="sc-dkIYMQ bwwtyo operation-type post">post</span><span tabindex="0" width="calc(100% - 38px)" class="sc-biBryG bkVowu">Cancel running data collection</span></label></li><li tabindex="0" depth="2" data-item-id="/paths/~1check_if_done/get" role="menuitem" class="sc-ikPBrU fhNqYr"><label class="sc-tYqQR CYQVt -depth2"><span type="get" class="sc-dkIYMQ bwwtyo operation-type get">get</span><span tabindex="0" width="calc(100% - 38px)" class="sc-biBryG bkVowu">Check if detector is done (similar to wait_till_do</span></label></li></ul><div class="sc-eHfQwz jrtoRW"><a target="_blank" rel="noopener noreferrer" href="https://redocly.com/redoc/">API docs by Redocly</a></div></div></div><div class="sc-eWvOCH bEOmaQ"><div class="sc-iGctyi iEVneI"><svg class="" style="transform:translate(2px, -4px) rotate(180deg);transition:transform 0.2s ease" viewBox="0 0 926.23699 573.74994" version="1.1" x="0px" y="0px" width="15" height="15"><g transform="translate(904.92214,-879.1482)"><path d="
<div id="redoc"><div class="sc-kUbfpu bwTiCm redoc-wrap"><div class="sc-irlPvL gXSQkB menu-content" style="top:0px;height:calc(100vh - 0px)"><div role="search" class="sc-eltaTX hwhlAl"><svg class="sc-cKZHtR lcoFQc search-icon" version="1.1" viewBox="0 0 1000 1000" x="0px" xmlns="http://www.w3.org/2000/svg" y="0px"><path d="M968.2,849.4L667.3,549c83.9-136.5,66.7-317.4-51.7-435.6C477.1-25,252.5-25,113.9,113.4c-138.5,138.3-138.5,362.6,0,501C219.2,730.1,413.2,743,547.6,666.5l301.9,301.4c43.6,43.6,76.9,14.9,104.2-12.4C981,928.3,1011.8,893,968.2,849.4z M524.5,522c-88.9,88.7-233,88.7-321.8,0c-88.9-88.7-88.9-232.6,0-321.3c88.9-88.7,233-88.7,321.8,0C613.4,289.4,613.4,433.3,524.5,522z"></path></svg><input placeholder="Search..." aria-label="Search" type="text" class="sc-kiYrGK eWIXbA search-input" value=""/></div><div class="sc-kLgoAE eJckYb scrollbar-container undefined"><ul role="menu" class="sc-XhViZ YKcaq"><li tabindex="0" depth="2" data-item-id="/paths/~1status/get" role="menuitem" class="sc-ikPBrU fhNqYr"><label class="sc-tYqQR CYQVt -depth2"><span type="get" class="sc-dkIYMQ bwwtyo operation-type get">get</span><span tabindex="0" width="calc(100% - 38px)" class="sc-biBryG bkVowu">Get writer status</span></label></li><li tabindex="0" depth="2" data-item-id="/paths/~1cancel/post" role="menuitem" class="sc-ikPBrU fhNqYr"><label class="sc-tYqQR CYQVt -depth2"><span type="post" class="sc-dkIYMQ bwwtyo operation-type post">post</span><span tabindex="0" width="calc(100% - 38px)" class="sc-biBryG bkVowu">Cancel running data collection</span></label></li></ul><div class="sc-eHfQwz jrtoRW"><a target="_blank" rel="noopener noreferrer" href="https://redocly.com/redoc/">API docs by Redocly</a></div></div></div><div class="sc-eWvOCH bEOmaQ"><div class="sc-iGctyi iEVneI"><svg class="" style="transform:translate(2px, -4px) rotate(180deg);transition:transform 0.2s ease" viewBox="0 0 926.23699 573.74994" version="1.1" x="0px" y="0px" width="15" height="15"><g transform="translate(904.92214,-879.1482)"><path d="
m -673.67664,1221.6502 -231.2455,-231.24803 55.6165,
-55.627 c 30.5891,-30.59485 56.1806,-55.627 56.8701,-55.627 0.6894,
0 79.8637,78.60862 175.9427,174.68583 l 174.6892,174.6858 174.6892,
@@ -298,39 +288,17 @@ If multiple parallel calls are made - only one will result in success
-104.0616 -231.873,-231.248 z
" fill="currentColor"></path></g></svg></div></div><div class="sc-dwcvcB dPIjnf api-content"><div class="sc-eCstZk kxmVZO"><div class="sc-iBPTVF keMybc"><div class="sc-hKgKIp gvoNGN api-info"><h1 class="sc-fubDmA sc-eGCbyA djltfY hWeMwQ">Jungfraujoch writer<!-- --> <span>(<!-- -->1.0.0<!-- -->)</span></h1><p>Download OpenAPI specification<!-- -->:<a download="openapi.json" target="_blank" class="sc-ctaXUJ gUXnfH">Download</a></p><div class="sc-iJuWdM sc-cBNeRQ gpkGbA casAkG"></div><div data-role="redoc-summary" html="" class="sc-iJuWdM sc-cBNeRQ gpkGbA casAkG"></div><div data-role="redoc-description" html="&lt;p&gt;Jungfraujoch Writer Web API&lt;/p&gt;
" class="sc-iJuWdM sc-cBNeRQ gpkGbA casAkG"><p>Jungfraujoch Writer Web API</p>
</div></div></div></div><div id="/paths/~1start/post" data-section-id="/paths/~1start/post" class="sc-eCstZk bCpIRB"><div class="sc-iBPTVF keMybc"><div class="sc-hKgKIp gvoNGN"><h2 class="sc-pGaPU biKwui"><a class="sc-crrtmM jGBpue" href="#/paths/~1start/post" aria-label="/paths/~1start/post"></a>Start writer<!-- --> </h2><div><h3 class="sc-fWPdKs fCsSHf">Responses</h3><div><button class="sc-httZfN eEqsZl" disabled=""><strong class="sc-gVgoeb goojcW">200<!-- --> </strong><div html="&lt;p&gt;Initialization started&lt;/p&gt;
" class="sc-iJuWdM sc-cBNeRQ gpkGbA casAkG sc-citwID bzkUsW"><p>Initialization started</p>
</div></button></div></div></div><div class="sc-jSguLX sc-gKsecS QymcT bZqtR"><div class="sc-bQdSiB bhuodb"><button class="sc-FyfbU jlriCd"><span type="post" class="sc-jXkspL coiChI http-verb post">post</span><span class="sc-fXoxOd jzevEV">/start</span><svg class="sc-dQpIV hHbBnT" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-eFtZDC ciRGmD"><div class="sc-fmlKft buTZbL"><div html="" class="sc-iJuWdM sc-cBNeRQ gpkGbA dujygE"></div><div tabindex="0" role="button"><div class="sc-ljRaSg uePtT"><span></span>/start</div></div></div></div></div></div></div></div><div id="/paths/~1wait_till_done/get" data-section-id="/paths/~1wait_till_done/get" class="sc-eCstZk bCpIRB"><div class="sc-iBPTVF keMybc"><div class="sc-hKgKIp gvoNGN"><h2 class="sc-pGaPU biKwui"><a class="sc-crrtmM jGBpue" href="#/paths/~1wait_till_done/get" aria-label="/paths/~1wait_till_done/get"></a>Will timeout after 5 seconds
If multiple parallel calls are made - only one will result in success
<!-- --> </h2><div class="sc-eWVLZl fgfjUV"><div html="&lt;p&gt;Wait for writing done&lt;/p&gt;
" class="sc-iJuWdM sc-cBNeRQ gpkGbA casAkG"><p>Wait for writing done</p>
</div></div><div><h3 class="sc-fWPdKs fCsSHf">Responses</h3><div><button class="sc-httZfN iePdRD"><svg class="sc-dQpIV iHKCKT" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-gVgoeb goojcW">200<!-- --> </strong><div html="&lt;p&gt;Statistics of the last measurement&lt;/p&gt;
</div></div></div></div><div id="/paths/~1status/get" data-section-id="/paths/~1status/get" class="sc-eCstZk bCpIRB"><div class="sc-iBPTVF keMybc"><div class="sc-hKgKIp gvoNGN"><h2 class="sc-pGaPU biKwui"><a class="sc-crrtmM jGBpue" href="#/paths/~1status/get" aria-label="/paths/~1status/get"></a>Get writer status<!-- --> </h2><div><h3 class="sc-fWPdKs fCsSHf">Responses</h3><div><button class="sc-httZfN iePdRD"><svg class="sc-dQpIV iHKCKT" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-gVgoeb goojcW">200<!-- --> </strong><div html="&lt;p&gt;Statistics of the last measurement&lt;/p&gt;
" class="sc-iJuWdM sc-cBNeRQ gpkGbA casAkG sc-citwID bzkUsW"><p>Statistics of the last measurement</p>
</div></button></div><div><button class="sc-httZfN jifJmL" disabled=""><strong class="sc-gVgoeb goojcW">404<!-- --> </strong><div html="&lt;p&gt;No measurement running or finished recently&lt;/p&gt;
" class="sc-iJuWdM sc-cBNeRQ gpkGbA casAkG sc-citwID bzkUsW"><p>No measurement running or finished recently</p>
</div></button></div><div><button class="sc-httZfN jEuzUJ"><svg class="sc-dQpIV bbipPn" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-gVgoeb goojcW">500<!-- --> </strong><div html="&lt;p&gt;Measurement resulted with error&lt;/p&gt;
" class="sc-iJuWdM sc-cBNeRQ gpkGbA casAkG sc-citwID bzkUsW"><p>Measurement resulted with error</p>
</div></button></div><div><button class="sc-httZfN jifJmL" disabled=""><strong class="sc-gVgoeb goojcW">504<!-- --> </strong><div html="&lt;p&gt;5 second timeout reached, need to restart operation&lt;/p&gt;
" class="sc-iJuWdM sc-cBNeRQ gpkGbA casAkG sc-citwID bzkUsW"><p>5 second timeout reached, need to restart operation</p>
</div></button></div></div></div><div class="sc-jSguLX sc-gKsecS QymcT bZqtR"><div class="sc-bQdSiB bhuodb"><button class="sc-FyfbU jlriCd"><span type="get" class="sc-jXkspL gDPfwK http-verb get">get</span><span class="sc-fXoxOd jzevEV">/wait_till_done</span><svg class="sc-dQpIV hHbBnT" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-eFtZDC ciRGmD"><div class="sc-fmlKft buTZbL"><div html="" class="sc-iJuWdM sc-cBNeRQ gpkGbA dujygE"></div><div tabindex="0" role="button"><div class="sc-ljRaSg uePtT"><span></span>/wait_till_done</div></div></div></div></div><div><h3 class="sc-kEjbdu jmifsN"> <!-- -->Response samples<!-- --> </h3><div class="sc-cxFKTC jVRsAZ" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="react-tabs-0" aria-selected="true" aria-disabled="false" aria-controls="react-tabs-1" tabindex="0" data-rttab="true">200</li><li class="tab-error" role="tab" id="react-tabs-2" aria-selected="false" aria-disabled="false" aria-controls="react-tabs-3" data-rttab="true">500</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="react-tabs-1" aria-labelledby="react-tabs-0"><div><div class="sc-cOaiZO eDzWuJ"><span class="sc-bBrOHt etjuEr">Content type</span><div class="sc-dOSSlk bAzVww">application/json</div></div><div class="sc-hTZhMB kTaCsY"><div class="sc-cTkyaV gLzJQv"><div class="sc-giInvV bIDavi"><button><div class="sc-jcVcfa iVrxDL">Copy</div></button></div><div class="sc-iJuWdM gpkGbA sc-jNMdxs jXmkAn"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"nimages"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"performance_MBs"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"performance_Hz"</span>: <span class="token number">0</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div><div class="react-tabs__tab-panel" role="tabpanel" id="react-tabs-3" aria-labelledby="react-tabs-2"></div></div></div></div></div></div><div id="/paths/~1cancel/post" data-section-id="/paths/~1cancel/post" class="sc-eCstZk bCpIRB"><div class="sc-iBPTVF keMybc"><div class="sc-hKgKIp gvoNGN"><h2 class="sc-pGaPU biKwui"><a class="sc-crrtmM jGBpue" href="#/paths/~1cancel/post" aria-label="/paths/~1cancel/post"></a>Cancel running data collection<!-- --> </h2><div class="sc-eWVLZl fgfjUV"><div html="&lt;p&gt;It only instructs writer to cancel, but doesn&amp;#39;t wait for cancellation actually happening.
</div></button></div></div></div><div class="sc-jSguLX sc-gKsecS QymcT bZqtR"><div class="sc-bQdSiB bhuodb"><button class="sc-FyfbU jlriCd"><span type="get" class="sc-jXkspL gDPfwK http-verb get">get</span><span class="sc-fXoxOd jzevEV">/status</span><svg class="sc-dQpIV hHbBnT" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-eFtZDC ciRGmD"><div class="sc-fmlKft buTZbL"><div html="" class="sc-iJuWdM sc-cBNeRQ gpkGbA dujygE"></div><div tabindex="0" role="button"><div class="sc-ljRaSg uePtT"><span></span>/status</div></div></div></div></div><div><h3 class="sc-kEjbdu jmifsN"> <!-- -->Response samples<!-- --> </h3><div class="sc-cxFKTC jVRsAZ" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="react-tabs-0" aria-selected="true" aria-disabled="false" aria-controls="react-tabs-1" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="react-tabs-1" aria-labelledby="react-tabs-0"><div><div class="sc-cOaiZO eDzWuJ"><span class="sc-bBrOHt etjuEr">Content type</span><div class="sc-dOSSlk bAzVww">application/json</div></div><div class="sc-hTZhMB kTaCsY"><div class="sc-cTkyaV gLzJQv"><div class="sc-giInvV bIDavi"><button><div class="sc-jcVcfa iVrxDL">Copy</div></button></div><div class="sc-iJuWdM gpkGbA sc-jNMdxs jXmkAn"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"nimages"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"performance_MBs"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"performance_Hz"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"file_prefix"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"state"</span>: <span class="token string">&quot;idle&quot;</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div></div></div></div></div></div><div id="/paths/~1cancel/post" data-section-id="/paths/~1cancel/post" class="sc-eCstZk bCpIRB"><div class="sc-iBPTVF keMybc"><div class="sc-hKgKIp gvoNGN"><h2 class="sc-pGaPU biKwui"><a class="sc-crrtmM jGBpue" href="#/paths/~1cancel/post" aria-label="/paths/~1cancel/post"></a>Cancel running data collection<!-- --> </h2><div class="sc-eWVLZl fgfjUV"><div html="&lt;p&gt;It only instructs writer to cancel, but doesn&amp;#39;t wait for cancellation actually happening.
It still requires to call &lt;code&gt;/wait_till_done&lt;/code&gt;&lt;/p&gt;
" class="sc-iJuWdM sc-cBNeRQ gpkGbA casAkG"><p>It only instructs writer to cancel, but doesn&#39;t wait for cancellation actually happening.
It still requires to call <code>/wait_till_done</code></p>
</div></div><div><h3 class="sc-fWPdKs fCsSHf">Responses</h3><div><button class="sc-httZfN eEqsZl" disabled=""><strong class="sc-gVgoeb goojcW">200<!-- --> </strong><div html="&lt;p&gt;Cancel message acknowledged&lt;/p&gt;
" class="sc-iJuWdM sc-cBNeRQ gpkGbA casAkG sc-citwID bzkUsW"><p>Cancel message acknowledged</p>
</div></button></div></div></div><div class="sc-jSguLX sc-gKsecS QymcT bZqtR"><div class="sc-bQdSiB bhuodb"><button class="sc-FyfbU jlriCd"><span type="post" class="sc-jXkspL coiChI http-verb post">post</span><span class="sc-fXoxOd jzevEV">/cancel</span><svg class="sc-dQpIV hHbBnT" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-eFtZDC ciRGmD"><div class="sc-fmlKft buTZbL"><div html="" class="sc-iJuWdM sc-cBNeRQ gpkGbA dujygE"></div><div tabindex="0" role="button"><div class="sc-ljRaSg uePtT"><span></span>/cancel</div></div></div></div></div></div></div></div><div id="/paths/~1check_if_done/get" data-section-id="/paths/~1check_if_done/get" class="sc-eCstZk bCpIRB"><div class="sc-iBPTVF keMybc"><div class="sc-hKgKIp gvoNGN"><h2 class="sc-pGaPU biKwui"><a class="sc-crrtmM jGBpue" href="#/paths/~1check_if_done/get" aria-label="/paths/~1check_if_done/get"></a>Check if detector is done (similar to wait_till_do<!-- --> </h2><div class="sc-eWVLZl fgfjUV"><div html="&lt;p&gt;Check if detector is done (similar to wait_till_done, but no timeout)&lt;/p&gt;
" class="sc-iJuWdM sc-cBNeRQ gpkGbA casAkG"><p>Check if detector is done (similar to wait_till_done, but no timeout)</p>
</div></div><div><h3 class="sc-fWPdKs fCsSHf">Responses</h3><div><button class="sc-httZfN iePdRD"><svg class="sc-dQpIV iHKCKT" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-gVgoeb goojcW">200<!-- --> </strong><div html="&lt;p&gt;Statistics of the last measurement&lt;/p&gt;
" class="sc-iJuWdM sc-cBNeRQ gpkGbA casAkG sc-citwID bzkUsW"><p>Statistics of the last measurement</p>
</div></button></div><div><button class="sc-httZfN jifJmL" disabled=""><strong class="sc-gVgoeb goojcW">404<!-- --> </strong><div html="&lt;p&gt;No measurement running or finished recently&lt;/p&gt;
" class="sc-iJuWdM sc-cBNeRQ gpkGbA casAkG sc-citwID bzkUsW"><p>No measurement running or finished recently</p>
</div></button></div><div><button class="sc-httZfN jEuzUJ"><svg class="sc-dQpIV bbipPn" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-gVgoeb goojcW">500<!-- --> </strong><div html="&lt;p&gt;Measurement resulted with error&lt;/p&gt;
" class="sc-iJuWdM sc-cBNeRQ gpkGbA casAkG sc-citwID bzkUsW"><p>Measurement resulted with error</p>
</div></button></div><div><button class="sc-httZfN jifJmL" disabled=""><strong class="sc-gVgoeb goojcW">504<!-- --> </strong><div html="&lt;p&gt;5 second timeout reached, need to restart operation&lt;/p&gt;
" class="sc-iJuWdM sc-cBNeRQ gpkGbA casAkG sc-citwID bzkUsW"><p>5 second timeout reached, need to restart operation</p>
</div></button></div></div></div><div class="sc-jSguLX sc-gKsecS QymcT bZqtR"><div class="sc-bQdSiB bhuodb"><button class="sc-FyfbU jlriCd"><span type="get" class="sc-jXkspL gDPfwK http-verb get">get</span><span class="sc-fXoxOd jzevEV">/check_if_done</span><svg class="sc-dQpIV hHbBnT" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-eFtZDC ciRGmD"><div class="sc-fmlKft buTZbL"><div html="" class="sc-iJuWdM sc-cBNeRQ gpkGbA dujygE"></div><div tabindex="0" role="button"><div class="sc-ljRaSg uePtT"><span></span>/check_if_done</div></div></div></div></div><div><h3 class="sc-kEjbdu jmifsN"> <!-- -->Response samples<!-- --> </h3><div class="sc-cxFKTC jVRsAZ" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="react-tabs-4" aria-selected="true" aria-disabled="false" aria-controls="react-tabs-5" tabindex="0" data-rttab="true">200</li><li class="tab-error" role="tab" id="react-tabs-6" aria-selected="false" aria-disabled="false" aria-controls="react-tabs-7" data-rttab="true">500</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="react-tabs-5" aria-labelledby="react-tabs-4"><div><div class="sc-cOaiZO eDzWuJ"><span class="sc-bBrOHt etjuEr">Content type</span><div class="sc-dOSSlk bAzVww">application/json</div></div><div class="sc-hTZhMB kTaCsY"><div class="sc-cTkyaV gLzJQv"><div class="sc-giInvV bIDavi"><button><div class="sc-jcVcfa iVrxDL">Copy</div></button></div><div class="sc-iJuWdM gpkGbA sc-jNMdxs jXmkAn"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"nimages"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"performance_MBs"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"performance_Hz"</span>: <span class="token number">0</span></div></li></ul><span class="token punctuation">}</span></code></div></div></div></div></div></div><div class="react-tabs__tab-panel" role="tabpanel" id="react-tabs-7" aria-labelledby="react-tabs-6"></div></div></div></div></div></div></div><div class="sc-jtHLPo gfiMgB"></div></div></div>
</div></button></div></div></div><div class="sc-jSguLX sc-gKsecS QymcT bZqtR"><div class="sc-bQdSiB bhuodb"><button class="sc-FyfbU jlriCd"><span type="post" class="sc-jXkspL coiChI http-verb post">post</span><span class="sc-fXoxOd jzevEV">/cancel</span><svg class="sc-dQpIV hHbBnT" style="margin-right:-25px" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></button><div aria-hidden="true" class="sc-eFtZDC ciRGmD"><div class="sc-fmlKft buTZbL"><div html="" class="sc-iJuWdM sc-cBNeRQ gpkGbA dujygE"></div><div tabindex="0" role="button"><div class="sc-ljRaSg uePtT"><span></span>/cancel</div></div></div></div></div></div></div></div></div><div class="sc-jtHLPo gfiMgB"></div></div></div>
<script>
const __redoc_state = {"menu":{"activeItemIdx":-1},"spec":{"data":{"openapi":"3.0.3","info":{"title":"Jungfraujoch writer","description":"Jungfraujoch Writer Web API","version":"1.0.0"},"components":{"schemas":{"writer_statistics":{"type":"object","properties":{"nimages":{"type":"integer","format":"uint64","description":"Number of images written"},"performance_MBs":{"type":"number","format":"float","description":"Performance in MB/s"},"performance_Hz":{"type":"number","format":"float","description":"Performance in images/s"}}}}},"paths":{"/start":{"post":{"summary":"Start writer","responses":{"200":{"description":"Initialization started"}}}},"/wait_till_done":{"get":{"description":"Wait for writing done","summary":"Will timeout after 5 seconds\nIf multiple parallel calls are made - only one will result in success\n","responses":{"200":{"description":"Statistics of the last measurement","content":{"application/json":{"schema":{"$ref":"#/components/schemas/writer_statistics"}}}},"404":{"description":"No measurement running or finished recently"},"500":{"description":"Measurement resulted with error","content":{"application/json":{"schema":{"type":"object","required":["msg"],"properties":{"msg":{"type":"string","description":"Error message"}}}}}},"504":{"description":"5 second timeout reached, need to restart operation"}}}},"/cancel":{"post":{"summary":"Cancel running data collection","description":"It only instructs writer to cancel, but doesn't wait for cancellation actually happening.\nIt still requires to call `/wait_till_done`\n","responses":{"200":{"description":"Cancel message acknowledged"}}}},"/check_if_done":{"get":{"description":"Check if detector is done (similar to wait_till_done, but no timeout)","responses":{"200":{"description":"Statistics of the last measurement","content":{"application/json":{"schema":{"$ref":"#/components/schemas/writer_statistics"}}}},"404":{"description":"No measurement running or finished recently"},"500":{"description":"Measurement resulted with error","content":{"application/json":{"schema":{"type":"object","required":["msg"],"properties":{"msg":{"type":"string","description":"Error message"}}}}}},"504":{"description":"5 second timeout reached, need to restart operation"}}}}}}},"searchIndex":{"store":["/paths/~1start/post","/paths/~1wait_till_done/get","/paths/~1cancel/post","/paths/~1check_if_done/get"],"index":{"version":"2.3.9","fields":["title","description"],"fieldVectors":[["title/0",[0,0.937,1,0.937]],["description/0",[0,1.056]],["title/1",[2,0.492,3,0.854,4,0.854,5,0.854,6,0.854,7,0.492,8,0.854,9,0.854,10,0.854,11,0.854,12,0.854]],["description/1",[13,0.813,14,1.412,15,0.418,16,0.418]],["title/2",[17,0.78,18,1.355,19,1.355,20,1.355]],["description/2",[1,0.481,7,0.481,13,0.481,16,0.247,17,0.885,21,0.835,22,0.835,23,0.835,24,0.835,25,0.835,26,0.835]],["title/3",[15,0.37,27,0.72,28,0.72,29,0.72,30,1.25]],["description/3",[2,0.661,15,0.34,16,0.34,27,0.661,28,0.661,29,0.661,31,1.148]]],"invertedIndex":[["",{"_index":9,"title":{"1":{}},"description":{}}],["5",{"_index":3,"title":{"1":{}},"description":{}}],["actual",{"_index":23,"title":{},"description":{"2":{}}}],["call",{"_index":7,"title":{"1":{}},"description":{"2":{}}}],["cancel",{"_index":17,"title":{"2":{}},"description":{"2":{}}}],["check",{"_index":27,"title":{"3":{}},"description":{"3":{}}}],["check_if_don",{"_index":31,"title":{},"description":{"3":{}}}],["collect",{"_index":20,"title":{"2":{}},"description":{}}],["data",{"_index":19,"title":{"2":{}},"description":{}}],["detector",{"_index":28,"title":{"3":{}},"description":{"3":{}}}],["doesn't",{"_index":22,"title":{},"description":{"2":{}}}],["done",{"_index":15,"title":{"3":{}},"description":{"1":{},"3":{}}}],["happen",{"_index":24,"title":{},"description":{"2":{}}}],["instruct",{"_index":21,"title":{},"description":{"2":{}}}],["made",{"_index":8,"title":{"1":{}},"description":{}}],["multipl",{"_index":5,"title":{"1":{}},"description":{}}],["on",{"_index":10,"title":{"1":{}},"description":{}}],["parallel",{"_index":6,"title":{"1":{}},"description":{}}],["requir",{"_index":26,"title":{},"description":{"2":{}}}],["result",{"_index":11,"title":{"1":{}},"description":{}}],["run",{"_index":18,"title":{"2":{}},"description":{}}],["second",{"_index":4,"title":{"1":{}},"description":{}}],["similar",{"_index":29,"title":{"3":{}},"description":{"3":{}}}],["start",{"_index":0,"title":{"0":{}},"description":{"0":{}}}],["still",{"_index":25,"title":{},"description":{"2":{}}}],["success",{"_index":12,"title":{"1":{}},"description":{}}],["timeout",{"_index":2,"title":{"1":{}},"description":{"3":{}}}],["wait",{"_index":13,"title":{},"description":{"1":{},"2":{}}}],["wait_till_do",{"_index":30,"title":{"3":{}},"description":{}}],["wait_till_don",{"_index":16,"title":{},"description":{"1":{},"2":{},"3":{}}}],["write",{"_index":14,"title":{},"description":{"1":{}}}],["writer",{"_index":1,"title":{"0":{}},"description":{"2":{}}}]],"pipeline":[]}},"options":{}};
const __redoc_state = {"menu":{"activeItemIdx":-1},"spec":{"data":{"openapi":"3.0.3","info":{"title":"Jungfraujoch writer","description":"Jungfraujoch Writer Web API","version":"1.0.0"},"components":{"schemas":{"writer_statistics":{"type":"object","properties":{"nimages":{"type":"integer","format":"int64","description":"Number of images written"},"performance_MBs":{"type":"number","format":"float","description":"Performance in MB/s"},"performance_Hz":{"type":"number","format":"float","description":"Performance in images/s"},"file_prefix":{"type":"string","description":"File prefix for the last written dataset"},"state":{"type":"string","enum":["idle","started","receiving"]}}}}},"paths":{"/status":{"get":{"summary":"Get writer status","responses":{"200":{"description":"Statistics of the last measurement","content":{"application/json":{"schema":{"$ref":"#/components/schemas/writer_statistics"}}}}}}},"/cancel":{"post":{"summary":"Cancel running data collection","description":"It only instructs writer to cancel, but doesn't wait for cancellation actually happening.\nIt still requires to call `/wait_till_done`\n","responses":{"200":{"description":"Cancel message acknowledged"}}}}}}},"searchIndex":{"store":["/paths/~1status/get","/paths/~1cancel/post"],"index":{"version":"2.3.9","fields":["title","description"],"fieldVectors":[["title/0",[0,0.211,1,0.211]],["description/0",[1,0.281]],["title/1",[2,0.16,3,0.61,4,0.61,5,0.61]],["description/1",[0,0.135,2,0.242,6,0.513,7,0.513,8,0.513,9,0.513,10,0.513,11,0.513,12,0.513,13,0.513,14,0.513]]],"invertedIndex":[["actual",{"_index":9,"title":{},"description":{"1":{}}}],["call",{"_index":13,"title":{},"description":{"1":{}}}],["cancel",{"_index":2,"title":{"1":{}},"description":{"1":{}}}],["collect",{"_index":5,"title":{"1":{}},"description":{}}],["data",{"_index":4,"title":{"1":{}},"description":{}}],["doesn't",{"_index":7,"title":{},"description":{"1":{}}}],["happen",{"_index":10,"title":{},"description":{"1":{}}}],["instruct",{"_index":6,"title":{},"description":{"1":{}}}],["requir",{"_index":12,"title":{},"description":{"1":{}}}],["run",{"_index":3,"title":{"1":{}},"description":{}}],["statu",{"_index":1,"title":{"0":{}},"description":{"0":{}}}],["still",{"_index":11,"title":{},"description":{"1":{}}}],["wait",{"_index":8,"title":{},"description":{"1":{}}}],["wait_till_don",{"_index":14,"title":{},"description":{"1":{}}}],["writer",{"_index":0,"title":{"0":{}},"description":{"1":{}}}]],"pipeline":[]}},"options":{}};
var container = document.getElementById('redoc');
Redoc.hydrate(__redoc_state, container);
+13 -55
View File
@@ -10,7 +10,7 @@ components:
properties:
nimages:
type: integer
format: uint64
format: int64
description: Number of images written
performance_MBs:
type: number
@@ -20,19 +20,19 @@ components:
type: number
format: float
description: Performance in images/s
file_prefix:
type: string
description: File prefix for the last written dataset
state:
type: string
enum:
- idle
- started
- receiving
paths:
/start:
post:
summary: Start writer
responses:
"200":
description: Initialization started
/wait_till_done:
/status:
get:
description: Wait for writing done
summary: |
Will timeout after 5 seconds
If multiple parallel calls are made - only one will result in success
summary: Get writer status
responses:
"200":
description: Statistics of the last measurement
@@ -40,22 +40,6 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/writer_statistics'
"404":
description: No measurement running or finished recently
"500":
description: Measurement resulted with error
content:
application/json:
schema:
type: object
required:
- msg
properties:
msg:
type: string
description: Error message
"504":
description: 5 second timeout reached, need to restart operation
/cancel:
post:
summary: Cancel running data collection
@@ -64,30 +48,4 @@ paths:
It still requires to call `/wait_till_done`
responses:
"200":
description: Cancel message acknowledged
/check_if_done:
get:
description: Check if detector is done (similar to wait_till_done, but no timeout)
responses:
"200":
description: Statistics of the last measurement
content:
application/json:
schema:
$ref: '#/components/schemas/writer_statistics'
"404":
description: No measurement running or finished recently
"500":
description: Measurement resulted with error
content:
application/json:
schema:
type: object
required:
- msg
properties:
msg:
type: string
description: Error message
"504":
description: 5 second timeout reached, need to restart operation
description: Cancel message acknowledged