13 #include <fmt/format.h>
14 #include <fmt/ostream.h>
15 #include <log4cplus/loggingmacros.h>
16 #include <mal/rr/qos/ConnectionTime.hpp>
17 #include <nlohmann/json.hpp>
29 using boost::enable_current_exception;
30 using boost::make_exceptional_future;
33 using std::chrono::duration_cast;
34 using std::chrono::milliseconds;
38 std::vector<daq::DaqContext::Source>
ParseSource(std::string
const& str) {
39 std::vector<daq::DaqContext::Source> sources;
42 sources.reserve(raw_sources.size());
43 for (
auto const& raw : raw_sources) {
44 sources.push_back({raw.name, raw.rr_uri});
50 void ValidateFilePrefix(
char const* file_prefix) {
51 auto file_regex = std::regex(R
"(^[-a-zA-Z0-9_\.]*$)");
53 if (!std::regex_match(file_prefix, file_regex)) {
54 throw std::invalid_argument(
55 fmt::format(
"file_prefix \"{}\" contains illegal characters, allowed: [a-zA-Z-0-9-_.]",
76 using std::chrono::duration_cast;
77 using std::chrono::milliseconds;
78 using Seconds = std::chrono::duration<double>;
81 if (json_properties.empty()) {
86 auto json = nlohmann::json::parse(json_properties);
87 if (!json.is_object()) {
88 throw boost::enable_current_exception(std::invalid_argument(
89 fmt::format(
"expected type object but got type {}", json.type_name())));
91 if (json.contains(
"keywords")) {
94 if (json.contains(
"awaitInterval")) {
95 auto& value = json[
"awaitInterval"];
96 if (!value.is_number()) {
97 throw boost::enable_current_exception(std::invalid_argument(
98 fmt::format(
"'awaitInterval': unsupported type: {}", value.type_name())));
100 auto await_interval = value.get<
double>();
101 if (await_interval < 0.0) {
102 throw boost::enable_current_exception(std::invalid_argument(
103 fmt::format(
"'awaitInterval' must be positive number, got {}", await_interval)));
105 properties.
await_interval = duration_cast<milliseconds>(Seconds(value.get<
double>()));
115 : name(std::move(name)), rr_uri(std::move(rr_uri)) {
118 os <<
"name: '" << s.
name <<
"', rr_uri='" << s.
rr_uri <<
"'";
123 auto start = s.find_first_not_of(
' ');
124 auto name_end_pos = s.find_first_of(
'@');
126 if (name_end_pos == std::string_view::npos) {
127 throw boost::enable_current_exception(
128 std::invalid_argument(
"separator '@' not found in expected format 'name@rr-uri'"));
130 auto name = s.substr(start, name_end_pos - start);
132 throw boost::enable_current_exception(
133 std::invalid_argument(
"name part in 'name@rr-uri' is empty"));
136 start = name_end_pos + 1;
137 if (start >= s.size()) {
138 throw boost::enable_current_exception(
139 std::invalid_argument(
"invalid format string, expected format 'name@rr-uri'"));
141 auto rr_uri_end_pos = s.find_first_of(
" ,", start);
142 if (name_end_pos == std::string_view::npos) {
143 throw boost::enable_current_exception(std::invalid_argument(
"separator ',' not found"));
146 auto rr_uri = s.substr(start, rr_uri_end_pos - start);
147 if (rr_uri.empty()) {
148 throw boost::enable_current_exception(
149 std::invalid_argument(
"rr_uri part in 'name@rr-uri' is empty"));
151 return ParsedSource(std::string(name), std::string(rr_uri));
160 std::vector<ParsedSource> result;
163 while (begin < s.size()) {
164 const auto end = s.find_first_of(
' ', begin);
167 result.emplace_back(
ParseSourceUri(s.substr(begin, end - begin)));
170 if (end == std::string_view::npos) {
183 std::string proc_name,
184 std::string output_path,
185 std::shared_ptr<daq::ObservableEventLog> event_log)
187 , m_executor(m_io_ctx)
190 , m_proc_name(std::move(proc_name))
191 , m_output_path(std::move(output_path))
192 , m_event_log(std::move(event_log))
193 , m_log_observer_connection()
196 m_log_observer_connection =
197 m_event_log->ConnectObserver(std::reference_wrapper(m_log_observer));
198 if (m_proc_name.empty()) {
199 throw boost::enable_current_exception(
200 std::invalid_argument(
"OcmDaqService: Process name cannot be empty"));
205 m_log_observer_connection.disconnect();
208 boost::future<std::shared_ptr<::daqif::DaqReply>>
210 const std::string& file_prefix,
211 const std::string& primary_sources,
212 const std::string& metadata_sources,
213 const std::string& json_properties) {
216 [=,
self = shared_from_this()]()
mutable {
219 fmt::format(
"Request received: "
220 "StartDaq(id='{0}', file_prefix='{1}', "
221 "primary_sources='{2}', metadata_sources='{3}', "
222 "json_properties='{4}'",
230 ValidateFilePrefix(file_prefix.c_str());
231 }
catch (std::exception
const& e) {
232 self->m_event_log->AddEvent(
234 return boost::make_exceptional_future<std::shared_ptr<::daqif::DaqReply>>(
235 daqif::DaqException(
id, e.what()));
242 }
catch (std::exception
const& e) {
244 fmt::format(
"Failed to parse StartDaq JSON properties: {}", e.what());
245 self->m_event_log->AddEvent(
daq::ErrorEvent(
id, msg, std::nullopt,
"user"));
246 return boost::make_exceptional_future<std::shared_ptr<::daqif::DaqReply>>(
247 daqif::DaqException(
id, msg));
251 auto validated_id = id;
252 if (validated_id.empty()) {
254 validated_id = context.
file_id;
257 fmt::format(
"StartDaq(id='{0}'): Created and assigned DAQ id='{0}'",
261 if (self->m_mgr.HaveDaq(validated_id)) {
264 fmt::format(
"StartDaq(id='{0}'): DAQ with id='{0}' already exist",
266 return boost::make_exceptional_future<std::shared_ptr<daqif::DaqReply>>(
267 daqif::DaqException(
id,
268 "Data acquisition with same id already exist"));
273 context.
id = validated_id;
282 return self->StartDaq(context,
"StartDaq");
283 }
catch (daqif::DaqException
const&) {
286 }
catch (std::invalid_argument
const& e) {
287 LOG4CPLUS_INFO(self->m_logger,
288 fmt::format(
"StartDaq(id='{}'): Invalid argument error while "
289 "processing request: {}",
292 return boost::make_exceptional_future<std::shared_ptr<daqif::DaqReply>>(
293 daqif::DaqException(validated_id, e.what()));
294 }
catch (std::exception
const& e) {
295 LOG4CPLUS_INFO(self->m_logger,
296 fmt::format(
"StartDaq(id='{}'): Error while"
297 "processing request: {}",
300 return boost::make_exceptional_future<std::shared_ptr<daqif::DaqReply>>(
301 daqif::DaqException(validated_id, e.what()));
305 fmt::format(
"StartDaq(id='{}'): Unknown error while processing request",
307 return boost::make_exceptional_future<std::shared_ptr<daqif::DaqReply>>(
308 daqif::DaqException(validated_id,
"Uknown error"));
315 boost::future<std::shared_ptr<::daqif::DaqReply>>
319 [=,
self = shared_from_this()]()
mutable {
320 self->m_event_log->AddEvent(
322 fmt::format(
"Request received: "
323 "StartDaqV2(specification=\n'{0}')",
334 UpdateFrom(context, parsed);
338 ValidateDaqContext(context);
343 LOG4CPLUS_DEBUG(self->m_logger,
344 "Resulting specification after parsing: \n"
349 return self->StartDaq(context,
"StartDaqV2");
350 }
catch (daqif::DaqException
const&) {
353 }
catch (nlohmann::json::exception
const& e) {
354 throw boost::enable_current_exception(daqif::DaqException(
355 "", fmt::format(
"JSON parsing error: {}", e.what())));
357 throw boost::enable_current_exception(
358 daqif::DaqException(
"", fmt::format(
"JSON Schema error: {}", e.what())));
359 }
catch (std::invalid_argument
const& e) {
360 throw boost::enable_current_exception(
361 daqif::DaqException(
"", fmt::format(
"Invalid argument: {}", e.what())));
362 }
catch (std::exception
const& e) {
363 throw boost::enable_current_exception(daqif::DaqException(
"", e.what()));
372 [
self = shared_from_this(),
id]() {
374 fmt::format(
"Request received: "
378 return self->StopDaq(
id,
false);
383 boost::future<std::shared_ptr<::daqif::DaqReply>>
385 return boost::async(m_executor,
386 [
self = shared_from_this(),
id]() {
387 self->m_event_log->AddEvent(
389 fmt::format(
"Request received: "
390 "ForceStopDaq(id='{0}')",
393 return self->StopDaq(
id,
true);
398 boost::future<std::shared_ptr<::daqif::DaqReply>>
402 [
function, weak_self = std::weak_ptr(shared_from_this()),
id = context.
id](
403 boost::future<daq::State> f) -> std::shared_ptr<daqif::DaqReply> {
404 auto self = weak_self.lock();
406 LOG4CPLUS_WARN(LOGGER_NAME,
407 fmt::format(
"{}(id='{}'): StartDaqAsync is "
408 "complete but MAL service has "
409 "been abandoned. Throwing exception.",
412 throw boost::enable_current_exception(
413 daqif::DaqException(id,
"Service has been abandoned"));
417 auto rep = self->m_mal.createDataEntity<daqif::DaqReply>();
420 rep->setError(false);
423 auto what =
self->MakeExceptionMessageWithStatus(
id, std::current_exception());
424 LOG4CPLUS_ERROR(self->m_logger,
425 fmt::format(
"{}(id='{}'): StartDaqAsync "
426 "completed with failure: {}",
430 throw boost::enable_current_exception(
431 daqif::DaqException(
id, fmt::format(
"{}() failed: {}",
function, what)));
436 boost::future<std::shared_ptr<::daqif::DaqReply>>
440 [
self = shared_from_this(),
id, forced]() {
446 [weak_self = std::weak_ptr(self->shared_from_this()),
447 id](boost::future<daq::Status> f) -> std::shared_ptr<daqif::DaqReply> {
448 auto self = weak_self.lock();
450 LOG4CPLUS_WARN(LOGGER_NAME,
451 fmt::format(
"StopDaq(id='{}'): StopDaqAsync is "
452 "complete but MAL service has "
453 "been abandoned. Throwing exception.",
455 throw boost::enable_current_exception(
456 daqif::DaqException(id,
"Service has been abandoned"));
460 auto rep = self->m_mal.createDataEntity<daqif::DaqReply>();
463 rep->setError(false);
466 auto what =
self->MakeExceptionMessageWithStatus(
467 id, std::current_exception());
468 LOG4CPLUS_INFO(self->m_logger,
469 fmt::format(
"StopDaq(id='{}'): "
470 "completed with failure: {}",
473 throw boost::enable_current_exception(daqif::DaqException(
474 id, fmt::format(
"Stop failed\n\n{}", what)));
483 return boost::async(m_executor,
484 [
self = shared_from_this(),
id]() {
485 self->m_event_log->AddEvent(
487 fmt::format(
"Request received: "
488 "AbortDaq(id='{0}')",
491 return self->AbortDaq(
id,
false);
496 boost::future<std::shared_ptr<::daqif::DaqReply>>
498 return boost::async(m_executor,
499 [
self = shared_from_this(),
id]() {
500 self->m_event_log->AddEvent(
502 fmt::format(
"Request received: "
503 "ForceAbortDaq(id='{0}')",
506 return self->AbortDaq(
id,
true);
511 boost::future<std::shared_ptr<::daqif::DaqReply>>
515 [
self = shared_from_this(),
id, forced]() {
521 [weak_self = std::weak_ptr(self->shared_from_this()),
id, forced](
522 boost::future<daq::Status> f) -> std::shared_ptr<daqif::DaqReply> {
523 auto self = weak_self.lock();
527 fmt::format(
"AbortDaq(id='{}', forced={}): AbortDaqAsync is "
528 "complete but MAL service has "
529 "been abandoned. Throwing exception.",
532 throw boost::enable_current_exception(
533 daqif::DaqException(id,
"Service has been abandoned"));
536 auto result = f.get();
539 fmt::format(
"AbortDaq(id='{}', forced={}): "
540 "AbortDaqAsync Completed successfully",
543 auto rep = self->m_mal.createDataEntity<daqif::DaqReply>();
546 rep->setError(result.error);
549 fmt::format(
"AbortDaq(id='{}', forced={}): "
550 "AbortDaqAsync Completed, returning reply now.",
555 auto what =
self->MakeExceptionMessageWithStatus(
556 id, std::current_exception());
557 LOG4CPLUS_ERROR(self->m_logger,
558 fmt::format(
"AbortDaq(id='{}', forced={}): "
559 "AbortDaqAsync Completed "
560 "with fatal error:\n{}",
564 throw boost::enable_current_exception(daqif::DaqException(
565 id, fmt::format(
"Abort failed\n\n{}", what)));
573 boost::future<std::shared_ptr<::daqif::DaqReply>>
577 [
self = shared_from_this(),
id, keywords]() -> std::shared_ptr<::daqif::DaqReply> {
578 self->m_event_log->AddEvent(
580 fmt::format(
"Request received: "
581 "UpdateKeywords(id='{0}', keywords='{1}')",
588 }
catch (nlohmann::json::exception
const& e) {
591 fmt::format(
"UpdateKeywords(id='{}', ...): Failed to parse JSON",
id));
592 throw boost::enable_current_exception(
593 daqif::DaqException(
id, fmt::format(
"Invalid JSON string: {}", e.what())));
594 }
catch (std::invalid_argument
const& e) {
598 "UpdateKeywords(id='{}', ...): JSON could be parsed but was invalid "
601 throw boost::enable_current_exception(
602 daqif::DaqException(
id, fmt::format(
"Invalid JSON schema: {}", e.what())));
603 }
catch (std::exception
const& e) {
607 "UpdateKeywords(id='{}', ...): std::exception: '{}'",
id, e.what()));
608 throw boost::enable_current_exception(
609 daqif::DaqException(
id, fmt::format(
"std::exception: {}", e.what())));
611 throw boost::enable_current_exception(daqif::DaqException(
id,
"unknown error"));
614 self->m_mgr.UpdateKeywords(
id, parsed_keywords);
615 auto rep =
self->m_mal.createDataEntity<daqif::DaqReply>();
617 rep->setError(
false);
619 }
catch (std::invalid_argument
const& e) {
622 fmt::format(
"UpdateKeywords(id='{}'): Invalid data acquisition id",
id));
623 throw boost::enable_current_exception(
624 daqif::DaqException(
id, fmt::format(
"No data acquisition with id='{}'",
id)));
625 }
catch (std::exception
const& e) {
629 "UpdateKeywords(id='{}', ...): std::exception: '{}'",
id, e.what()));
630 throw boost::enable_current_exception(
631 daqif::DaqException(
id, fmt::format(
"std::exception: {}", e.what())));
633 throw boost::enable_current_exception(daqif::DaqException(
id,
"unknown error"));
641 [
self = shared_from_this(),
id]() {
642 self->m_event_log->AddEvent(
644 fmt::format(
"Request received: "
645 "GetStatus(id='{0}')",
649 LOG4CPLUS_INFO(self->m_logger, fmt::format(
"GetStatus(id='{}'): Enter",
id));
650 auto status =
self->m_mgr.GetStatus(
id);
651 auto rep =
self->m_mal.createDataEntity<daqif::DaqStatus>();
656 fmt::format(
"GetStatus(id='{}'): Set result -> {}",
id, status.state));
657 return boost::make_ready_future<std::shared_ptr<daqif::DaqStatus>>(rep);
658 }
catch (std::invalid_argument
const&) {
661 fmt::format(
"GetStatus(id='{}'): Invalid data acquisition id",
id));
662 return boost::make_exceptional_future<std::shared_ptr<daqif::DaqStatus>>(
663 boost::enable_current_exception(daqif::DaqException(
664 id, fmt::format(
"No data acquisition with id='{}'",
id))));
673 [
self = shared_from_this()]() -> std::vector<std::shared_ptr<::daqif::DaqStatus>> {
678 auto daqs =
self->m_mgr.GetDaqControllers();
679 std::vector<std::shared_ptr<daq::DaqController const>> active;
680 std::vector<std::shared_ptr<daqif::DaqStatus>> reply;
681 std::copy_if(daqs.begin(), daqs.end(), std::back_inserter(active), [](
auto daq_ctl) {
682 return !daq::IsFinalState(daq_ctl->GetState());
686 std::back_inserter(reply),
687 [&
mal = self->m_mal](
auto daq_ctl) {
688 auto mal_status = mal.createDataEntity<daqif::DaqStatus>();
689 *mal_status << daq_ctl->GetStatus()->GetStatus();
697 const std::string&
id, daqif::DaqState state, daqif::DaqSubState substate,
double timeout) {
698 using Seconds = std::chrono::duration<double>;
702 [=,
self = shared_from_this()]() {
704 format(
"Request received: "
705 "AwaitDaqState(id='{}', "
706 "state={}, substate={}, "
714 return boost::make_exceptional_future<daq::Result<daq::Status>>(
715 std::invalid_argument(
716 format(
"Invalid argument `timeout`. Must be > 0", timeout)));
719 return boost::make_exceptional_future<daq::Result<daq::Status>>(
720 std::invalid_argument(fmt::format(
721 "Invalid state combination: {} and {}", state, substate)));
724 return self->m_mgr.AwaitDaqStateAsync(
725 id, daq_state, duration_cast<milliseconds>(Seconds(timeout)));
730 [
id,
self = shared_from_this()](boost::future<daq::Result<daq::Status>> fut) {
732 auto [timeout, status] = fut.get();
733 auto mal_reply =
self->m_mal.createDataEntity<daqif::AwaitDaqReply>();
735 mal_reply->setTimeout(timeout);
736 auto mal_status_ptr = mal_reply->getStatus();
737 assert(mal_status_ptr);
738 *mal_status_ptr << status;
740 fmt::format(
"Request completed: {}",
741 (timeout ?
"condition not yet satisfied (timeout)"
742 :
"condition satisfied")),
745 }
catch (std::exception
const& e) {
746 auto what =
self->MakeExceptionMessageWithStatus(
id, std::current_exception());
749 fmt::format(
"Await state completed exceptionally\n\n{}", what),
751 throw boost::enable_current_exception(
752 daqif::DaqException(
id, fmt::format(
"Await state failed\n\n{}", what)));
755 id,
"Request completed exceptionally: Unknown exception", std::nullopt);
756 throw boost::enable_current_exception(
757 daqif::DaqException(
id,
"Uknown exception"));
763 OcmDaqService::MakeExceptionMessageWithStatus(std::string
const&
id,
764 std::exception_ptr
const& exception)
const {
766 auto alerts_msg = std::string(
"n/a");
769 alerts_msg = fmt::format(
"{}", status.alerts);
770 }
catch (std::exception
const& e) {
771 LOG4CPLUS_WARN(m_logger, fmt::format(
"GetStatus({}) failed:",
id, e.what()));
773 return fmt::format(
"Errors(s):\n{}\nActive alert(s):\n{}", nested_msg, alerts_msg);
783 if (context.
id.empty()) {
796 for (
auto const& variant : spec.
sources) {
797 if (
auto const* ds = std::get_if<PrimaryDataSource>(&variant); ds !=
nullptr) {
798 context.
prim_sources.push_back({ds->source_name, ds->rr_uri});
799 }
else if (
auto const* ds = std::get_if<MetadataSource>(&variant); ds !=
nullptr) {
800 context.
meta_sources.push_back({ds->source_name, ds->rr_uri});
801 }
else if (
auto const* ds = std::get_if<FitsKeywordsSource>(&variant); ds !=
nullptr) {
802 context.
results.emplace_back(ds->source_name, ds->keywords);
803 }
else if (
auto const* ds = std::get_if<FitsFileSource>(&variant); ds !=
nullptr) {
804 context.
results.emplace_back(ds->source_name, ds->location);
806 LOG4CPLUS_ERROR(m_logger,
"Unknown variant encountered");
812 auto msg = fmt::format(
"DAQ with id='{0}' already exist", context.
id);
813 LOG4CPLUS_INFO(m_logger, msg);
814 throw boost::enable_current_exception(std::invalid_argument(msg));
Manager owns DaqController and FitsController (active data acquisitions) instances and multiplexes re...
virtual boost::future< State > StartDaqAsync(DaqContext ctx)=0
Start DaqController identified by id.
virtual Status GetStatus(std::string_view id) const =0
Get status.
virtual std::string MakeDaqId(std::chrono::system_clock::time_point *time=nullptr) const =0
Creates a new unique identifier based on the instrument id and current time.
virtual bool HaveDaq(std::string_view id, std::string_view file_id={}) const DAQ_NOEXCEPT=0
Query existing data acquisition by id and optional file_id.
Adapter object intended to be used in contexts without direct access to the output-stream object.
std::string Str() const
Convenience function for constructing a std::string from the exception.
Contains data structure for FITS keywords.
Contains support functions for daqif.
Contains State support functions for daqif.
boost::future< std::vector< std::shared_ptr<::daqif::DaqStatus > > > GetActiveList() override
OcmDaqService(boost::asio::io_context &io_ctx, mal::Mal &mal, daq::Manager &mgr, std::string proc_name, std::string output_path, std::shared_ptr< daq::ObservableEventLog > event_log)
boost::future< std::shared_ptr<::daqif::DaqReply > > StopDaq(const std::string &id) override
boost::future< std::shared_ptr<::daqif::AwaitDaqReply > > AwaitDaqState(const std::string &id, daqif::DaqState state, daqif::DaqSubState substate, double timeout) override
boost::future< std::shared_ptr<::daqif::DaqReply > > AbortDaq(const std::string &id) override
boost::future< std::shared_ptr<::daqif::DaqReply > > StartDaqV2(const std::string &specification) override
boost::future< std::shared_ptr<::daqif::DaqReply > > UpdateKeywords(const std::string &id, const std::string &keywords) override
boost::future< std::shared_ptr<::daqif::DaqReply > > StartDaq(const std::string &id, const std::string &file_prefix, const std::string &primary_sources, const std::string &metadata_sources, const std::string &properties) override
boost::future< std::shared_ptr<::daqif::DaqReply > > ForceStopDaq(const std::string &id) override
boost::future< std::shared_ptr<::daqif::DaqStatus > > GetStatus(const std::string &id) override
boost::future< std::shared_ptr<::daqif::DaqReply > > ForceAbortDaq(const std::string &id) override
const std::string LOGGER_NAME
std::vector< KeywordVariant > KeywordVector
Vector of keywords.
std::vector< KeywordVariant > ParseJsonKeywords(char const *keywords)
Parse and return FITS keywords.
std::optional< std::chrono::milliseconds > await_completion_interval
DpSpec::SourceTypes ParseSource(Json const &json, JsonPointer const &breadcrumb)
StartDaqV2Spec ParseStartDaqV2Spec(nlohmann::json const &json)
Parse StartDaqSpec.
std::vector< DataSourceTypes > sources
Structure with a close mapping from JSON representation in the StartDaqV2 MAL request.
daqif::FullState MakeState(State state) noexcept
Converts daq::State to DaqSubstate.
std::string_view ToString(daqif::DaqState state) noexcept
@ Strict
Any error is considered fatal and may lead to the operation being aborted.
@ Tolerant
Errors that can be ignored with partial completion of a command will be tolerated and is reported as ...
NLOHMANN_JSON_SERIALIZE_ENUM(State, { {State::NotStarted, "NotStarted"}, {State::Starting, "Starting"}, {State::Acquiring, "Acquiring"}, {State::Stopping, "Stopping"}, {State::Stopped, "Stopped"}, {State::NotScheduled, "NotScheduled"}, {State::Scheduled, "Scheduled"}, {State::Transferring, "Transferring"}, {State::Merging, "Merging"}, {State::Releasing, "Releasing"}, {State::AbortingAcquiring, "AbortingAcquiring"}, {State::AbortingMerging, "AbortingMerging"}, {State::Aborted, "Aborted"}, {State::Completed, "Completed"}, }) void to_json(nlohmann void to_json(nlohmann::json &j, Alert const &p)
bool IsStateValid(DaqState state, DaqSubState substate)
Validate state combination.
const std::string LOGGER_NAME_EVENTLOG
daq::DaqContext ParseStartDaqContext(std::string const &json_properties)
Parse the JSON properties user provides with StartDaq.
ParsedSource ParseSourceUri(std::string_view s)
Parse user provided string in the format "<name>@<rr-uri>".
std::vector< ParsedSource > ParseSourceUris(std::string_view s)
Parse user provided string in the format "<name>@<rr-uri>[ <name>@...]".
std::ostream & operator<<(std::ostream &os, ParsedSource const &s)
Declaration of OcmDaqService.
Contains declaration for for DaqController.
bool operator==(ParsedSource const &rhs) const
Event related to an action being requested or performed.
Structure carrying context needed to start a Data Acquisition and construct a Data Product Specificat...
std::vector< Source > meta_sources
DpParts results
Results from Data Acquisition (FITS files and keywords).
std::string process_name
User defined process name.
std::vector< daq::fits::KeywordVariant > keywords
Keyword list provided by OCM to Data Product.
std::vector< Source > prim_sources
std::chrono::milliseconds await_interval
Interval (and thus duration) of the requests sent to primary sources to await end of recording.
std::optional< json::StartDaqV2Spec > specification
Optional specification, if DAQ was started using StartDaqV2.
std::string file_id
Data Product FileId as specified by OLAS ICD.
std::string dp_name_prefix
Data product file name prefix.
std::chrono::system_clock::time_point creation_time
Time when DAQ was created.
std::string id
DAQ identfier, possibly provided by user.
Event directly related to user action, such as a command to do something.