Add IEM load text product API functionality

This commit is contained in:
Dan Paulat 2025-02-01 23:40:06 -06:00
parent f06191f290
commit 2720ad6a38
5 changed files with 90 additions and 20 deletions

View file

@ -7,7 +7,7 @@ namespace scwx
namespace provider
{
TEST(IemWarningsProviderTest, LoadUpdatedFiles)
TEST(IemWarningsProviderTest, ListTextProducts)
{
using namespace std::chrono;
using sys_days = time_point<system_clock, days>;
@ -30,5 +30,18 @@ TEST(IemWarningsProviderTest, LoadUpdatedFiles)
}
}
TEST(IemWarningsProviderTest, LoadTextProducts)
{
static const std::vector<std::string> productIds {
"202303250016-KMEG-WFUS54-TORMEG", //
"202303252015-KFFC-WFUS52-TORFFC"};
IemWarningsProvider provider {};
auto textProducts = provider.LoadTextProducts(productIds);
EXPECT_EQ(textProducts.size(), 2);
}
} // namespace provider
} // namespace scwx

View file

@ -1,5 +1,7 @@
#pragma once
#include <scwx/awips/text_product_file.hpp>
#include <memory>
#include <string>
@ -21,11 +23,14 @@ public:
IemWarningsProvider(IemWarningsProvider&&) noexcept;
IemWarningsProvider& operator=(IemWarningsProvider&&) noexcept;
std::vector<std::string>
static std::vector<std::string>
ListTextProducts(std::chrono::sys_time<std::chrono::days> date,
std::optional<std::string_view> cccc = {},
std::optional<std::string_view> pil = {});
static std::vector<std::shared_ptr<awips::TextProductFile>>
LoadTextProducts(const std::vector<std::string>& textProducts);
private:
class Impl;
std::unique_ptr<Impl> p;

View file

@ -132,9 +132,19 @@ bool WmoHeader::Parse(std::istream& is)
{
util::getline(is, sohLine);
util::getline(is, sequenceLine);
util::getline(is, wmoLine);
}
else
{
// The next line could be the WMO line or the sequence line
util::getline(is, wmoLine);
if (wmoLine.length() < 18)
{
sequenceLine.swap(wmoLine);
util::getline(is, wmoLine);
}
}
util::getline(is, wmoLine);
util::getline(is, awipsLine);
if (is.eof())

View file

@ -27,11 +27,6 @@ public:
Impl& operator=(const Impl&) = delete;
Impl(const Impl&&) = delete;
Impl& operator=(const Impl&&) = delete;
std::vector<std::string>
ListTextProducts(std::chrono::sys_time<std::chrono::days> date,
std::optional<std::string_view> cccc = {},
std::optional<std::string_view> pil = {});
};
IemWarningsProvider::IemWarningsProvider() : p(std::make_unique<Impl>()) {}
@ -46,14 +41,6 @@ std::vector<std::string> IemWarningsProvider::ListTextProducts(
std::chrono::sys_time<std::chrono::days> date,
std::optional<std::string_view> cccc,
std::optional<std::string_view> pil)
{
return p->ListTextProducts(date, cccc, pil);
}
std::vector<std::string> IemWarningsProvider::Impl::ListTextProducts(
std::chrono::sys_time<std::chrono::days> date,
std::optional<std::string_view> cccc,
std::optional<std::string_view> pil)
{
using namespace std::chrono;
@ -149,4 +136,51 @@ std::vector<std::string> IemWarningsProvider::Impl::ListTextProducts(
return textProducts;
}
std::vector<std::shared_ptr<awips::TextProductFile>>
IemWarningsProvider::LoadTextProducts(
const std::vector<std::string>& textProducts)
{
auto parameters = cpr::Parameters {{"nolimit", "true"}};
std::vector<std::pair<std::string_view, cpr::AsyncResponse>>
asyncResponses {};
for (auto& productId : textProducts)
{
asyncResponses.emplace_back(
productId,
cpr::GetAsync(
cpr::Url {kBaseUrl_ + kNwsTextProductEndpoint_ + productId},
network::cpr::GetHeader(),
parameters));
}
std::vector<std::shared_ptr<awips::TextProductFile>> textProductFiles;
for (auto& asyncResponse : asyncResponses)
{
auto response = asyncResponse.second.get();
if (response.status_code == cpr::status::HTTP_OK)
{
// Load file
std::shared_ptr<awips::TextProductFile> textProductFile {
std::make_shared<awips::TextProductFile>()};
std::istringstream responseBody {response.text};
if (textProductFile->LoadData(responseBody))
{
textProductFiles.push_back(textProductFile);
}
}
else
{
logger_->warn("Could not load text product: {} ({})",
asyncResponse.first,
response.status_line);
}
}
return textProductFiles;
}
} // namespace scwx::provider

View file

@ -77,11 +77,19 @@ tag_invoke(boost::json::value_to_tag<ValidationError::Detail>,
detail.type_ = jo.at("type").as_string();
detail.loc_ = boost::json::value_to<
std::vector<std::variant<std::int64_t, std::string>>>(jo.at("loc"));
detail.msg_ = jo.at("msg").as_string();
detail.input_ = jo.at("input").as_string();
detail.msg_ = jo.at("msg").as_string();
detail.ctx_ =
boost::json::value_to<ValidationError::Detail::Context>(jo.at("ctx"));
// Optional parameters
if (jo.contains("input"))
{
detail.input_ = jo.at("input").as_string();
}
if (jo.contains("ctx"))
{
detail.ctx_ =
boost::json::value_to<ValidationError::Detail::Context>(jo.at("ctx"));
}
return detail;
}