ifw-daq  3.0.0-pre2
IFW Data Acquisition modules
dpSpec.cpp
Go to the documentation of this file.
1 /**
2  * @file
3  * @ingroup daq_dpm_libmerge
4  * @copyright ESO - European Southern Observatory
5  */
6 #include <daq/json/dpSpec.hpp>
7 #include <iostream>
8 
9 #include <fmt/format.h>
10 
11 #include <daq/fits/json.hpp>
12 
13 #include "internalParseUtils.hpp"
14 
15 using Json = nlohmann::json;
16 using JsonPointer = nlohmann::json_pointer<Json>;
17 
18 namespace daq::json {
19 
20 DpSpec::Target ParseTarget(Json const& json, JsonPointer const& breadcrumb) {
21  AssertIsObject<DpSpecError>(json, breadcrumb);
22  DpSpec::Target obj{};
23  obj.file_id = JsonObject<DpSpecError, std::string>::Get(json, "fileId", breadcrumb);
24  if (json.contains("source")) {
25  obj.source = ParseFitsFileSource(json["source"], breadcrumb / "source");
26  }
27  if (json.contains("filePrefix")) {
28  obj.file_prefix =
29  JsonObject<DpSpecError, std::string>::Get(json, "filePrefix", breadcrumb, true);
30  }
31  return obj;
32 }
33 
34 DpSpec::SourceTypes ParseSource(Json const& json, JsonPointer const& breadcrumb) {
35  AssertIsObject<DpSpecError>(json, breadcrumb);
36  auto type = JsonObject<DpSpecError, std::string>::Get(json, "type", breadcrumb);
37  if (type == "fitsKeywords") {
38  return ParseFitsKeywordsSource(json, breadcrumb);
39  } else if (type == "fitsFile") {
40  return ParseFitsFileSource(json, breadcrumb);
41  } else {
42  throw MakeUnknownVariantException<DpSpecError>(
43  breadcrumb / "type", "'fitsKeywords' or 'fitsFile'", type.c_str());
44  }
45 }
46 
47 DpSpec ParseDpSpec(Json const& json) {
48  try {
49  JsonPointer breadcrumb("");
50  AssertIsObject<DpSpecError>(json, breadcrumb);
51 
52  DpSpec spec{};
53  spec.id = JsonObject<DpSpecError, std::string>::Get(json, "id", breadcrumb);
54  if (!json.contains("target")) {
55  throw MakeValueMissingException<DpSpecError>(breadcrumb / "target");
56  }
57  spec.target = ParseTarget(json["target"], breadcrumb / "target");
58 
59  if (json.contains("sources")) {
60  auto const& json_sources = json["sources"];
61  if (!json_sources.is_array()) {
62  throw MakeWrongTypeException<DpSpecError>(
63  breadcrumb / "sources", "array", json_sources.type_name());
64  }
65 
66  auto index = 0u;
67  for (auto const& json_source : json_sources) {
68  // cppcheck-suppress zerodiv
69  spec.sources.emplace_back(ParseSource(json_source, breadcrumb / "sources" / index));
70  index++;
71  }
72  }
73  // Check that there's at least one source
74  if (!spec.target.source && spec.sources.empty()) {
75  throw MakeParseException<DpSpecError>(
76  breadcrumb / "sources",
77  "At least one source must be provided if '/target/source' is not used");
78  }
79  return spec;
80  } catch (DpSpecError const&) {
81  throw;
82  } catch (SchemaError const& e) {
83  std::throw_with_nested(DpSpecError("Schema error"));
84  } catch (...) { // GCOVR_EXCL_START
85  std::throw_with_nested(DpSpecError("Unknown parsing error"));
86  // GCOVR_EXCL_STOP
87  }
88 }
89 
90 Location ParseSourceLocation(std::string const& location_str) {
91  Location location;
92  // location str may contain a 'user@' component which we don't care about
93  auto start_pos = location_str.find('@');
94  if (start_pos == std::string::npos) {
95  // no '@' found -> start at 0
96  start_pos = 0u;
97  } else {
98  if (start_pos > location_str.size()) {
99  throw std::invalid_argument(
100  fmt::format("Invalid format of location string: '{}'", location_str));
101  }
102  // skip '@' sign
103  start_pos++;
104  }
105 
106  auto pos = location_str.find(':', start_pos);
107  if (pos != std::string::npos) {
108  // Split at 'pos'
109  location.host = location_str.substr(start_pos, pos - start_pos);
110  location.path = location_str.substr(pos + 1, std::string::npos);
111  } else {
112  location.path = location_str.substr(start_pos);
113  }
114  if (location.path.empty()) {
115  throw std::invalid_argument(
116  fmt::format("Invalid format of location string: '{}'", location_str));
117  }
118  return location;
119 }
120 
121 std::string Location::RsyncPath() const {
122  if (host.empty()) {
123  return path;
124  }
125  return (host + std::string(":") + path.native());
126 }
127 
128 // NOLINTNEXTLINE
129 void to_json(nlohmann::json& j, DpSpec const& s) {
130  j = Json{{"id", s.id}, {"sources", s.sources}, {"target", s.target}};
131 }
132 
133 // NOLINTNEXTLINE
134 void to_json(nlohmann::json& j, DpSpec::Target const& s) {
135  j = Json{{"fileId", s.file_id}, {"filePrefix", s.file_prefix}};
136  if (s.source.has_value()) {
137  j["source"] = *s.source;
138  }
139 }
140 
141 // NOLINTNEXTLINE
142 void to_json(nlohmann::json& j, DpSpec::SourceTypes const& s) {
143  std::visit([&](auto const& val) { j = Json(val); }, s);
144 }
145 
146 } // namespace daq::json
Contains data structure for FITS keywords.
nlohmann::json_pointer< Json > JsonPointer
Definition: json.cpp:19
nlohmann::json Json
Definition: json.cpp:18
nlohmann::json Json
Definition: dpSpec.cpp:15
std::string id
Definition: dpSpec.hpp:42
Location ParseSourceLocation(std::string const &location_str)
Parse location string from DpSpec into component parts.
Definition: dpSpec.cpp:90
DpSpec ParseDpSpec(Json const &json)
Parse JSON to construct the DpSpec structure.
Definition: dpSpec.cpp:47
std::optional< FitsFileSource > source
Definition: dpSpec.hpp:37
std::vector< SourceTypes > sources
Definition: dpSpec.hpp:44
std::variant< FitsKeywordsSource, FitsFileSource > SourceTypes
Definition: dpSpec.hpp:40
DpSpec::SourceTypes ParseSource(Json const &json, JsonPointer const &breadcrumb)
Definition: dpSpec.cpp:34
std::string file_prefix
Optioal user chosen file prefix to make it easier to identify the produced file.
Definition: dpSpec.hpp:36
FitsFileSource ParseFitsFileSource(Json const &json, JsonPointer const &breadcrumb)
FitsKeywordsSource ParseFitsKeywordsSource(Json const &json, JsonPointer const &breadcrumb)
void to_json(nlohmann::json &out, KeywordFilter const &s)
DpSpec::Target ParseTarget(Json const &json, JsonPointer const &breadcrumb)
Definition: dpSpec.cpp:20
Close representation of the JSON structure but with stronger types.
Definition: dpSpec.hpp:30
static T Get(Json const &json, char const *name, JsonPointer const &breadcrumb, bool allow_empty=true)
Describes parsed location string into its components "host" and "path".
Definition: dpSpec.hpp:58
std::filesystem::path path
Definition: dpSpec.hpp:64
std::string RsyncPath() const
Definition: dpSpec.cpp:121
std::string host
Definition: dpSpec.hpp:63
JSON Schema error.
Definition: schemaError.hpp:18