Update IemApiProvider to use template functions

This commit is contained in:
Dan Paulat 2025-04-25 00:15:05 -05:00
parent 1a1c668d62
commit 65e3a66750
5 changed files with 159 additions and 115 deletions

View file

@ -1,24 +1,21 @@
#pragma once
#include <scwx/awips/text_product_file.hpp>
#include <scwx/network/cpr.hpp>
#include <scwx/types/iem_types.hpp>
#include <memory>
#include <ranges>
#include <string>
#include <vector>
#include <boost/outcome/result.hpp>
#include <cpr/cpr.h>
#include <cpr/session.h>
#include <range/v3/range/concepts.hpp>
#if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable : 4702)
#endif
#include <range/v3/view/any_view.hpp>
#if defined(_MSC_VER)
# pragma warning(pop)
#endif
@ -42,50 +39,41 @@ public:
IemApiProvider& operator=(IemApiProvider&&) noexcept;
static boost::outcome_v2::result<std::vector<types::iem::AfosEntry>>
ListTextProducts(std::chrono::sys_time<std::chrono::days> date,
std::optional<std::string_view> cccc = {},
std::optional<std::string_view> pil = {});
ListTextProducts(std::chrono::sys_days date,
std::optional<std::string_view> cccc = {},
std::optional<std::string_view> pil = {});
template<ranges::forward_range DateRange,
ranges::forward_range CcccRange,
ranges::forward_range PilRange>
requires std::same_as<ranges::range_value_t<DateRange>,
std::chrono::sys_days> &&
std::same_as<ranges::range_value_t<CcccRange>,
std::string_view> &&
std::same_as<ranges::range_value_t<PilRange>, std::string_view>
static boost::outcome_v2::result<std::vector<types::iem::AfosEntry>>
ListTextProducts(
ranges::any_view<std::chrono::sys_time<std::chrono::days>> dates,
ranges::any_view<std::string_view> ccccs = {},
ranges::any_view<std::string_view> pils = {});
ListTextProducts(DateRange dates, CcccRange ccccs, PilRange pils);
template<std::ranges::forward_range Range>
requires std::same_as<std::ranges::range_value_t<Range>, std::string>
template<ranges::forward_range Range>
requires std::same_as<ranges::range_value_t<Range>, std::string>
static std::vector<std::shared_ptr<awips::TextProductFile>>
LoadTextProducts(const Range& textProducts)
{
auto parameters = cpr::Parameters {{"nolimit", "true"}};
std::vector<std::pair<std::string, cpr::AsyncResponse>> asyncResponses {};
asyncResponses.reserve(textProducts.size());
const std::string endpointUrl = kBaseUrl_ + kNwsTextProductEndpoint_;
for (const auto& productId : textProducts)
{
asyncResponses.emplace_back(
productId,
cpr::GetAsync(cpr::Url {endpointUrl + productId},
network::cpr::GetHeader(),
parameters));
}
return ProcessTextProductResponses(asyncResponses);
}
LoadTextProducts(const Range& textProducts);
private:
class Impl;
std::unique_ptr<Impl> p;
static boost::outcome_v2::result<std::vector<types::iem::AfosEntry>>
ProcessTextProductLists(std::vector<cpr::AsyncResponse>& asyncResponses);
static std::vector<std::shared_ptr<awips::TextProductFile>>
ProcessTextProductFiles(
std::vector<std::pair<std::string, cpr::AsyncResponse>>& asyncResponses);
static const std::string kBaseUrl_;
static const std::string kListNwsTextProductsEndpoint_;
static const std::string kNwsTextProductEndpoint_;
static std::vector<std::shared_ptr<awips::TextProductFile>>
ProcessTextProductResponses(
std::vector<std::pair<std::string, cpr::AsyncResponse>>& asyncResponses);
};
} // namespace scwx::provider
#include <scwx/provider/iem_api_provider.ipp>

View file

@ -0,0 +1,95 @@
#pragma once
#include <scwx/provider/iem_api_provider.hpp>
#include <scwx/network/cpr.hpp>
#include <cpr/cpr.h>
#include <range/v3/view/cartesian_product.hpp>
#include <range/v3/view/single.hpp>
#if (__cpp_lib_chrono < 201907L)
# include <date/date.h>
#endif
namespace scwx::provider
{
template<ranges::forward_range DateRange,
ranges::forward_range CcccRange,
ranges::forward_range PilRange>
requires std::same_as<ranges::range_value_t<DateRange>,
std::chrono::sys_days> &&
std::same_as<ranges::range_value_t<CcccRange>, std::string_view> &&
std::same_as<ranges::range_value_t<PilRange>, std::string_view>
boost::outcome_v2::result<std::vector<types::iem::AfosEntry>>
IemApiProvider::ListTextProducts(DateRange dates,
CcccRange ccccs,
PilRange pils)
{
using namespace std::chrono;
#if (__cpp_lib_chrono >= 201907L)
namespace df = std;
static constexpr std::string_view kDateFormat {"{:%Y-%m-%d}"};
#else
using namespace date;
namespace df = date;
# define kDateFormat "%Y-%m-%d"
#endif
std::vector<cpr::AsyncResponse> asyncResponses {};
for (const auto& [date, cccc, pil] :
ranges::views::cartesian_product(dates, ccccs, pils))
{
auto parameters =
cpr::Parameters {{"date", df::format(kDateFormat, date)}};
// WMO Source Code
if (!cccc.empty())
{
parameters.Add({"cccc", std::string {cccc}});
}
// AFOS / AWIPS ID / 3-6 length identifier
if (!pil.empty())
{
parameters.Add({"pil", std::string {pil}});
}
asyncResponses.emplace_back(
cpr::GetAsync(cpr::Url {kBaseUrl_ + kListNwsTextProductsEndpoint_},
network::cpr::GetHeader(),
parameters));
}
return ProcessTextProductLists(asyncResponses);
}
template<ranges::forward_range Range>
requires std::same_as<ranges::range_value_t<Range>, std::string>
std::vector<std::shared_ptr<awips::TextProductFile>>
IemApiProvider::LoadTextProducts(const Range& textProducts)
{
auto parameters = cpr::Parameters {{"nolimit", "true"}};
std::vector<std::pair<std::string, cpr::AsyncResponse>> asyncResponses {};
asyncResponses.reserve(textProducts.size());
const std::string endpointUrl = kBaseUrl_ + kNwsTextProductEndpoint_;
for (const auto& productId : textProducts)
{
asyncResponses.emplace_back(
productId,
cpr::GetAsync(cpr::Url {endpointUrl + productId},
network::cpr::GetHeader(),
parameters));
}
return ProcessTextProductFiles(asyncResponses);
}
} // namespace scwx::provider

View file

@ -44,7 +44,7 @@ IemApiProvider::IemApiProvider(IemApiProvider&&) noexcept = default;
IemApiProvider& IemApiProvider::operator=(IemApiProvider&&) noexcept = default;
boost::outcome_v2::result<std::vector<types::iem::AfosEntry>>
IemApiProvider::ListTextProducts(std::chrono::sys_time<std::chrono::days> date,
IemApiProvider::ListTextProducts(std::chrono::sys_days date,
std::optional<std::string_view> optionalCccc,
std::optional<std::string_view> optionalPil)
{
@ -61,67 +61,12 @@ IemApiProvider::ListTextProducts(std::chrono::sys_time<std::chrono::days> date,
}
boost::outcome_v2::result<std::vector<types::iem::AfosEntry>>
IemApiProvider::ListTextProducts(
ranges::any_view<std::chrono::sys_time<std::chrono::days>> dates,
ranges::any_view<std::string_view> ccccs,
ranges::any_view<std::string_view> pils)
IemApiProvider::ProcessTextProductLists(
std::vector<cpr::AsyncResponse>& asyncResponses)
{
using namespace std::chrono;
#if (__cpp_lib_chrono >= 201907L)
namespace df = std;
static constexpr std::string_view kDateFormat {"{:%Y-%m-%d}"};
#else
using namespace date;
namespace df = date;
# define kDateFormat "%Y-%m-%d"
#endif
if (ccccs.begin() == ccccs.end())
{
ccccs = ranges::views::single(std::string_view {});
}
if (pils.begin() == pils.end())
{
pils = ranges::views::single(std::string_view {});
}
const auto dv = ranges::to<std::vector>(dates);
const auto cv = ranges::to<std::vector>(ccccs);
const auto pv = ranges::to<std::vector>(pils);
std::vector<cpr::AsyncResponse> responses {};
for (const auto& [date, cccc, pil] :
ranges::views::cartesian_product(dv, cv, pv))
{
auto parameters =
cpr::Parameters {{"date", df::format(kDateFormat, date)}};
// WMO Source Code
if (!cccc.empty())
{
parameters.Add({"cccc", std::string {cccc}});
}
// AFOS / AWIPS ID / 3-6 length identifier
if (!pil.empty())
{
parameters.Add({"pil", std::string {pil}});
}
responses.emplace_back(
cpr::GetAsync(cpr::Url {kBaseUrl_ + kListNwsTextProductsEndpoint_},
network::cpr::GetHeader(),
parameters));
}
std::vector<types::iem::AfosEntry> textProducts {};
for (auto& asyncResponse : responses)
for (auto& asyncResponse : asyncResponses)
{
auto response = asyncResponse.get();
@ -201,7 +146,7 @@ IemApiProvider::ListTextProducts(
}
std::vector<std::shared_ptr<awips::TextProductFile>>
IemApiProvider::ProcessTextProductResponses(
IemApiProvider::ProcessTextProductFiles(
std::vector<std::pair<std::string, cpr::AsyncResponse>>& asyncResponses)
{
std::vector<std::shared_ptr<awips::TextProductFile>> textProductFiles;

View file

@ -63,6 +63,7 @@ set(HDR_PROVIDER include/scwx/provider/aws_level2_data_provider.hpp
include/scwx/provider/aws_level3_data_provider.hpp
include/scwx/provider/aws_nexrad_data_provider.hpp
include/scwx/provider/iem_api_provider.hpp
include/scwx/provider/iem_api_provider.ipp
include/scwx/provider/nexrad_data_provider.hpp
include/scwx/provider/nexrad_data_provider_factory.hpp
include/scwx/provider/warnings_provider.hpp)