From 2720ad6a38fd9b13ebecc02e09cd20f62cda7907 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sat, 1 Feb 2025 23:40:06 -0600 Subject: [PATCH] Add IEM load text product API functionality --- .../provider/iem_warnings_provider.test.cpp | 15 ++++- .../scwx/provider/iem_warnings_provider.hpp | 7 ++- wxdata/source/scwx/awips/wmo_header.cpp | 12 +++- .../scwx/provider/iem_warnings_provider.cpp | 60 +++++++++++++++---- wxdata/source/scwx/types/iem_types.cpp | 16 +++-- 5 files changed, 90 insertions(+), 20 deletions(-) diff --git a/test/source/scwx/provider/iem_warnings_provider.test.cpp b/test/source/scwx/provider/iem_warnings_provider.test.cpp index 4f66e185..6b6809e5 100644 --- a/test/source/scwx/provider/iem_warnings_provider.test.cpp +++ b/test/source/scwx/provider/iem_warnings_provider.test.cpp @@ -7,7 +7,7 @@ namespace scwx namespace provider { -TEST(IemWarningsProviderTest, LoadUpdatedFiles) +TEST(IemWarningsProviderTest, ListTextProducts) { using namespace std::chrono; using sys_days = time_point; @@ -30,5 +30,18 @@ TEST(IemWarningsProviderTest, LoadUpdatedFiles) } } +TEST(IemWarningsProviderTest, LoadTextProducts) +{ + static const std::vector 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 diff --git a/wxdata/include/scwx/provider/iem_warnings_provider.hpp b/wxdata/include/scwx/provider/iem_warnings_provider.hpp index 2061afa4..35c6bbad 100644 --- a/wxdata/include/scwx/provider/iem_warnings_provider.hpp +++ b/wxdata/include/scwx/provider/iem_warnings_provider.hpp @@ -1,5 +1,7 @@ #pragma once +#include + #include #include @@ -21,11 +23,14 @@ public: IemWarningsProvider(IemWarningsProvider&&) noexcept; IemWarningsProvider& operator=(IemWarningsProvider&&) noexcept; - std::vector + static std::vector ListTextProducts(std::chrono::sys_time date, std::optional cccc = {}, std::optional pil = {}); + static std::vector> + LoadTextProducts(const std::vector& textProducts); + private: class Impl; std::unique_ptr p; diff --git a/wxdata/source/scwx/awips/wmo_header.cpp b/wxdata/source/scwx/awips/wmo_header.cpp index eb4501e7..4d502604 100644 --- a/wxdata/source/scwx/awips/wmo_header.cpp +++ b/wxdata/source/scwx/awips/wmo_header.cpp @@ -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()) diff --git a/wxdata/source/scwx/provider/iem_warnings_provider.cpp b/wxdata/source/scwx/provider/iem_warnings_provider.cpp index b40955ca..47c29547 100644 --- a/wxdata/source/scwx/provider/iem_warnings_provider.cpp +++ b/wxdata/source/scwx/provider/iem_warnings_provider.cpp @@ -27,11 +27,6 @@ public: Impl& operator=(const Impl&) = delete; Impl(const Impl&&) = delete; Impl& operator=(const Impl&&) = delete; - - std::vector - ListTextProducts(std::chrono::sys_time date, - std::optional cccc = {}, - std::optional pil = {}); }; IemWarningsProvider::IemWarningsProvider() : p(std::make_unique()) {} @@ -46,14 +41,6 @@ std::vector IemWarningsProvider::ListTextProducts( std::chrono::sys_time date, std::optional cccc, std::optional pil) -{ - return p->ListTextProducts(date, cccc, pil); -} - -std::vector IemWarningsProvider::Impl::ListTextProducts( - std::chrono::sys_time date, - std::optional cccc, - std::optional pil) { using namespace std::chrono; @@ -149,4 +136,51 @@ std::vector IemWarningsProvider::Impl::ListTextProducts( return textProducts; } +std::vector> +IemWarningsProvider::LoadTextProducts( + const std::vector& textProducts) +{ + auto parameters = cpr::Parameters {{"nolimit", "true"}}; + + std::vector> + asyncResponses {}; + + for (auto& productId : textProducts) + { + asyncResponses.emplace_back( + productId, + cpr::GetAsync( + cpr::Url {kBaseUrl_ + kNwsTextProductEndpoint_ + productId}, + network::cpr::GetHeader(), + parameters)); + } + + std::vector> textProductFiles; + + for (auto& asyncResponse : asyncResponses) + { + auto response = asyncResponse.second.get(); + + if (response.status_code == cpr::status::HTTP_OK) + { + // Load file + std::shared_ptr textProductFile { + std::make_shared()}; + 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 diff --git a/wxdata/source/scwx/types/iem_types.cpp b/wxdata/source/scwx/types/iem_types.cpp index c1921ede..ed3884d3 100644 --- a/wxdata/source/scwx/types/iem_types.cpp +++ b/wxdata/source/scwx/types/iem_types.cpp @@ -77,11 +77,19 @@ tag_invoke(boost::json::value_to_tag, detail.type_ = jo.at("type").as_string(); detail.loc_ = boost::json::value_to< std::vector>>(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(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(jo.at("ctx")); + } return detail; }