ifw-daq 3.1.0
IFW Data Acquisition modules
Loading...
Searching...
No Matches
startDaqV2.cpp
Go to the documentation of this file.
1/**
2 * @file
3 * @ingroup daq_libjson
4 * @copyright
5 * (c) Copyright ESO 2022
6 * All Rights Reserved
7 * ESO (eso.org) is an Intergovernmental Organisation, and therefore special legal conditions apply.
8 */
10
11#include <fmt/format.h>
12
14
15using Json = nlohmann::json;
16using JsonPointer = nlohmann::json_pointer<Json>;
17
18namespace daq::json {
19
21
22/**
23 * Parse the common parts of PrimaryDataSource and MetadataSource.
24 *
25 * {
26 * "sourceName": <str>,
27 * "rrUri": <str>,
28 * "keywordRules": [<keywordrules]
29 * }
30 */
32 Json const& json,
33 JsonPointer const& breadcrumb) {
34 AssertIsObject<ErrorType>(json, breadcrumb);
35 out.source_name = JsonObject<ErrorType, std::string>::Get(json, "sourceName", breadcrumb);
36 out.rr_uri = JsonObject<ErrorType, std::string>::Get(json, "rrUri", breadcrumb);
37 if (json.contains("initialKeywords")) {
39 ParseInitialKeywords(json["initialKeywords"], breadcrumb / "initialKeywords");
40 }
41 if (json.contains("keywordRules")) {
42 out.keyword_rules = ParseKeywordRules(json["keywordRules"], breadcrumb / "keywordRules");
43 }
44}
45
46StartDaqV2Spec ParseStartDaqV2Spec(nlohmann::json const& json) {
47 try {
48 StartDaqV2Spec result = {};
49
50 JsonPointer breadcrumb("");
51 AssertIsObject<StartDaqV2SpecError>(json, breadcrumb);
52
53 if (json.contains("id")) {
54 result.id = JsonObject<ErrorType, std::string>::Get(json, "id", breadcrumb, true);
55 }
56
57 if (json.contains("filePrefix")) {
58 result.file_prefix =
59 JsonObject<ErrorType, std::string>::Get(json, "filePrefix", breadcrumb, true);
60 }
61 if (json.contains("awaitCompletionInterval")) {
62 auto value =
63 JsonObject<ErrorType, double>::Get(json, "awaitCompletionInterval", breadcrumb);
64 if (value < 0.0) {
65 throw MakeParseException<ErrorType>(breadcrumb / "awaitCompletionInterval",
66 "interval must be > 0.0s");
67 }
69 std::chrono::duration_cast<std::chrono::milliseconds>(
70 std::chrono::duration<double>(value));
71 }
72
73 if (json.contains("mergeTarget")) {
76 json["mergeTarget"], "sourceName", breadcrumb / "mergeTarget");
77 result.merge_target = m;
78 }
79 {
80 // Sources
81 auto [json_sources, breadcrumb_sources] = GetMember<ErrorType>(
82 json, "sources", breadcrumb, [](Json const& member, JsonPointer const& breadcrumb) {
83 AssertIsArray<ErrorType>(member, breadcrumb);
84 });
85 auto index = 0u;
86 auto found_merge_target = 0u;
87 for (auto const& json_source : json_sources) {
88 auto breadcrumb_source = breadcrumb_sources / index;
89 auto source_type =
90 JsonObject<ErrorType, std::string>::Get(json_source, "type", breadcrumb_source);
91 if (source_type == "primarySource") {
93 ParseDataSource(s, json_source, breadcrumb_source);
94 if (result.merge_target && result.merge_target->source_name == s.source_name) {
95 found_merge_target++;
96 }
97 result.sources.emplace_back(std::move(s));
98 } else if (source_type == "metadataSource") {
100 ParseDataSource(s, json_source, breadcrumb_source);
101 if (result.merge_target && result.merge_target->source_name == s.source_name) {
102 found_merge_target++;
103 }
104 result.sources.emplace_back(std::move(s));
105 } else if (source_type == "fitsKeywords") {
106 auto kws = ParseFitsKeywordsSource(json_source, breadcrumb_source);
107 if (result.merge_target &&
108 result.merge_target->source_name == kws.source_name) {
109 // Merge target cannot be keywords
110 throw MakeParseException<ErrorType>(
111 breadcrumb / "mergeTarget" / "sourceName",
112 "Merge target `{}` refers to fitsKeywords which cannot be a merge "
113 "target",
114 kws.source_name);
115 }
116 result.sources.emplace_back(std::move(kws));
117 } else if (source_type == "fitsFile") {
118 auto file = ParseFitsFileSource(json_source, breadcrumb_source);
119 if (result.merge_target &&
120 result.merge_target->source_name == file.source_name) {
121 found_merge_target++;
122 }
123 result.sources.emplace_back(std::move(file));
124 } else {
125 throw MakeUnknownVariantException<ErrorType>(
126 breadcrumb_source / "type",
127 "'primarySource', 'metadataSource', 'fitsFile' or 'fitsKeywords'",
128 source_type.c_str());
129 }
130 index++;
131 }
132 if (result.merge_target) {
133 if (found_merge_target == 0) {
134 throw MakeParseException<ErrorType>(
135 breadcrumb / "mergeTarget" / "sourceName",
136 "Merge target `{}` does not match any sources",
137 result.merge_target->source_name);
138 }
139 else if (found_merge_target > 1) {
140 throw MakeParseException<ErrorType>(
141 breadcrumb / "mergeTarget" / "sourceName",
142 "Merge target `{}` matches more than one source",
143 result.merge_target->source_name);
144 }
145 }
146 }
147 if (json.contains("receivers")) {
148 result.receivers = ParseReceiverList(json["receivers"], breadcrumb / "receivers");
149 }
150 return result;
151 } catch (std::exception const& e) {
152 std::throw_with_nested(ErrorType("Schema error while parsing StartDaqV2 specification"));
153 }
154}
155
157 StartDaqV2Spec::PrimaryDataSource const& rhs) noexcept {
158 return lhs.source_name == rhs.source_name && lhs.rr_uri == rhs.rr_uri &&
159 lhs.keyword_rules == rhs.keyword_rules;
160}
161
163 StartDaqV2Spec::MetadataSource const& rhs) noexcept {
164 return lhs.source_name == rhs.source_name && lhs.rr_uri == rhs.rr_uri &&
165 lhs.keyword_rules == rhs.keyword_rules;
166}
167
169 StartDaqV2Spec::MergeTarget const& rhs) noexcept {
170 return lhs.source_name == rhs.source_name;
171}
172
173bool operator==(StartDaqV2Spec const& lhs, StartDaqV2Spec const& rhs) noexcept {
174 return lhs.id == rhs.id && lhs.file_prefix == rhs.file_prefix &&
175 lhs.await_completion_interval == rhs.await_completion_interval &&
176 lhs.merge_target == rhs.merge_target && lhs.sources == rhs.sources &&
177 lhs.receivers == rhs.receivers;
178}
179
180// NOLINTNEXTLINE
181void to_json(nlohmann::json& out, StartDaqV2Spec::DataSource const& s) {
182 out = Json{{"sourceName", s.source_name}, {"rrUri", s.rr_uri}};
183 if (s.initial_keywords.has_value()) {
184 out["initialKeywords"] = *s.initial_keywords;
185 }
186 if (!s.keyword_rules.empty()) {
187 out["keywordRules"] = s.keyword_rules;
188 }
189}
190
191// NOLINTNEXTLINE
192void to_json(nlohmann::json& out, StartDaqV2Spec::PrimaryDataSource const& s) {
193 to_json(out, static_cast<StartDaqV2Spec::DataSource const&>(s));
194 out["type"] = "primarySource";
195}
196
197// NOLINTNEXTLINE
198void to_json(nlohmann::json& out, StartDaqV2Spec::MetadataSource const& s) {
199 to_json(out, static_cast<StartDaqV2Spec::DataSource const&>(s));
200 out["type"] = "metadataSource";
201}
202
203// NOLINTNEXTLINE
204void to_json(nlohmann::json& out, StartDaqV2Spec::DataSourceTypes const& s) {
205 std::visit([&](auto const& ds) { to_json(out, ds); }, s);
206}
207
208// NOLINTNEXTLINE
209void to_json(nlohmann::json& out, StartDaqV2Spec::MergeTarget const& t) {
210 out = Json{{"sourceName", t.source_name}};
211}
212
213// NOLINTNEXTLINE
214void to_json(nlohmann::json& json, StartDaqV2Spec const& spec) {
215 json = nlohmann::json{
216 {"id", spec.id}, {"filePrefix", spec.file_prefix}, {"sources", spec.sources}};
217 if (spec.await_completion_interval.has_value()) {
218 json["awaitCompletionInterval"] = std::chrono::duration_cast<std::chrono::duration<double>>(
220 .count();
221 }
222 if (spec.merge_target.has_value()) {
223 json["mergeTarget"] = *spec.merge_target;
224 }
225 json["receivers"] = spec.receivers;
226}
227
228} // namespace daq::json
nlohmann::json_pointer< Json > JsonPointer
Definition: json.cpp:19
nlohmann::json Json
Definition: json.cpp:18
StartDaqV2SpecError ErrorType
Definition: startDaqV2.cpp:20
KeywordRules ParseKeywordRules(Json const &json, JsonPointer const &breadcrumb)
InitialKeywords ParseInitialKeywords(nlohmann::json const &json, nlohmann::json_pointer< nlohmann::json > const &breadcrumb)
std::optional< MergeTarget > merge_target
Definition: startDaqV2.hpp:54
nlohmann::json Json
nlohmann::json_pointer< Json > JsonPointer
std::optional< std::chrono::milliseconds > await_completion_interval
Definition: startDaqV2.hpp:55
void ParseDataSource(StartDaqV2Spec::DataSource &out, Json const &json, JsonPointer const &breadcrumb)
Parse the common parts of PrimaryDataSource and MetadataSource.
Definition: startDaqV2.cpp:31
FitsFileSource ParseFitsFileSource(Json const &json, JsonPointer const &breadcrumb)
bool operator==(KeywordFilter const &lhs, KeywordFilter const &rhs) noexcept
FitsKeywordsSource ParseFitsKeywordsSource(Json const &json, JsonPointer const &breadcrumb)
std::variant< PrimaryDataSource, MetadataSource, FitsKeywordsSource, FitsFileSource > DataSourceTypes
Definition: startDaqV2.hpp:44
ReceiverList ParseReceiverList(Json const &json, JsonPointer const &breadcrumb)
StartDaqV2Spec ParseStartDaqV2Spec(nlohmann::json const &json)
Parse StartDaqSpec.
Definition: startDaqV2.cpp:46
void to_json(nlohmann::json &out, KeywordFilter const &s)
std::vector< DataSourceTypes > sources
Definition: startDaqV2.hpp:51
Structure with a close mapping from JSON representation in the StartDaqV2 MAL request.
Definition: startDaqV2.hpp:33
static T Get(Json const &json, char const *name, JsonPointer const &breadcrumb, bool allow_empty=true)
std::optional< InitialKeywords > initial_keywords
Definition: startDaqV2.hpp:37