Finish windowed load. Not all polygon updates are shown on the map.

This commit is contained in:
Dan Paulat 2025-04-16 23:29:40 -05:00
parent 33e18765b7
commit 1a1c668d62
3 changed files with 65 additions and 62 deletions

View file

@ -10,6 +10,7 @@
#include <algorithm> #include <algorithm>
#include <list> #include <list>
#include <map> #include <map>
#include <ranges>
#include <shared_mutex> #include <shared_mutex>
#include <unordered_map> #include <unordered_map>
@ -148,9 +149,8 @@ public:
std::mutex archiveMutex_ {}; std::mutex archiveMutex_ {};
std::list<std::chrono::sys_days> archiveDates_ {}; std::list<std::chrono::sys_days> archiveDates_ {};
std::map<std::chrono::sys_days,
std::vector<std::shared_ptr<awips::TextProductFile>>> std::mutex unloadedProductMapMutex_ {};
archiveMap_;
std::map<std::chrono::sys_days, std::map<std::chrono::sys_days,
boost::container::stable_vector<scwx::types::iem::AfosEntry>> boost::container::stable_vector<scwx::types::iem::AfosEntry>>
unloadedProductMap_; unloadedProductMap_;
@ -248,6 +248,9 @@ void TextEventManager::SelectTime(
date < p->archiveLimit_; date < p->archiveLimit_;
}); });
std::unique_lock lock {p->archiveMutex_};
p->UpdateArchiveDates(dates);
p->ListArchives(dates); p->ListArchives(dates);
p->LoadArchives(dateTime); p->LoadArchives(dateTime);
} }
@ -334,18 +337,12 @@ void TextEventManager::Impl::HandleMessage(
void TextEventManager::Impl::ListArchives( void TextEventManager::Impl::ListArchives(
ranges::any_view<std::chrono::sys_days> dates) ranges::any_view<std::chrono::sys_days> dates)
{ {
std::unique_lock lock {archiveMutex_};
UpdateArchiveDates(dates);
// Don't reload data that has already been loaded // Don't reload data that has already been loaded
ranges::any_view<std::chrono::sys_days> filteredDates = ranges::any_view<std::chrono::sys_days> filteredDates =
dates | dates |
ranges::views::filter([this](const auto& date) ranges::views::filter([this](const auto& date)
{ return !unloadedProductMap_.contains(date); }); { return !unloadedProductMap_.contains(date); });
lock.unlock();
const auto dv = ranges::to<std::vector>(filteredDates); const auto dv = ranges::to<std::vector>(filteredDates);
std::for_each( std::for_each(
@ -359,13 +356,14 @@ void TextEventManager::Impl::ListArchives(
auto productEntries = auto productEntries =
iemApiProvider_->ListTextProducts(dateArray, {}, kPils_); iemApiProvider_->ListTextProducts(dateArray, {}, kPils_);
std::unique_lock lock {archiveMutex_}; std::unique_lock lock {unloadedProductMapMutex_};
if (productEntries.has_value()) if (productEntries.has_value())
{ {
unloadedProductMap_.try_emplace( unloadedProductMap_.try_emplace(
date, date,
{std::make_move_iterator(productEntries.value().begin()), boost::container::stable_vector<scwx::types::iem::AfosEntry> {
std::make_move_iterator(productEntries.value().begin()),
std::make_move_iterator(productEntries.value().end())}); std::make_move_iterator(productEntries.value().end())});
} }
}); });
@ -409,9 +407,7 @@ void TextEventManager::Impl::LoadArchives(
df::format(kDateFormat, (dateTime + loadWindow.second.second))}); df::format(kDateFormat, (dateTime + loadWindow.second.second))});
} }
std::vector<scwx::types::iem::AfosEntry> loadList {}; std::vector<scwx::types::iem::AfosEntry> loadListEntries {};
std::unique_lock lock {archiveMutex_};
for (auto date : boost::irange(startDate, endDate)) for (auto date : boost::irange(startDate, endDate))
{ {
@ -441,7 +437,7 @@ void TextEventManager::Impl::LoadArchives(
if (windowStart <= productId && productId <= windowEnd) if (windowStart <= productId && productId <= windowEnd)
{ {
// Product matches, move it to the load list // Product matches, move it to the load list
loadList.emplace_back(std::move(*it)); loadListEntries.emplace_back(std::move(*it));
it = mapIt->second.erase(it); it = mapIt->second.erase(it);
continue; continue;
} }
@ -453,13 +449,13 @@ void TextEventManager::Impl::LoadArchives(
} }
} }
if (productIds.has_value()) // Load the load list
{ auto loadView = loadListEntries |
logger_->debug("Loading {} products", productIds.value().size()); std::ranges::views::transform([](const auto& entry)
{ return entry.productId_; });
// Load listed products auto products = iemApiProvider_->LoadTextProducts(loadView);
auto products = iemApiProvider_->LoadTextProducts(productIds.value());
// Process loaded products
for (auto& product : products) for (auto& product : products)
{ {
const auto& messages = product->messages(); const auto& messages = product->messages();
@ -469,18 +465,6 @@ void TextEventManager::Impl::LoadArchives(
HandleMessage(message); HandleMessage(message);
} }
} }
lock.lock();
for (const auto& date : dates)
{
archiveMap_[date];
// TODO: Store the products in the archive
}
lock.unlock();
}
} }
void TextEventManager::Impl::RefreshAsync() void TextEventManager::Impl::RefreshAsync()

View file

@ -1,12 +1,16 @@
#pragma once #pragma once
#include <scwx/awips/text_product_file.hpp> #include <scwx/awips/text_product_file.hpp>
#include <scwx/network/cpr.hpp>
#include <scwx/types/iem_types.hpp> #include <scwx/types/iem_types.hpp>
#include <memory> #include <memory>
#include <ranges>
#include <string> #include <string>
#include <vector>
#include <boost/outcome/result.hpp> #include <boost/outcome/result.hpp>
#include <cpr/cpr.h>
#if defined(_MSC_VER) #if defined(_MSC_VER)
# pragma warning(push) # pragma warning(push)
@ -47,12 +51,41 @@ public:
ranges::any_view<std::string_view> ccccs = {}, ranges::any_view<std::string_view> ccccs = {},
ranges::any_view<std::string_view> pils = {}); ranges::any_view<std::string_view> pils = {});
template<std::ranges::forward_range Range>
requires std::same_as<std::ranges::range_value_t<Range>, std::string>
static std::vector<std::shared_ptr<awips::TextProductFile>> static std::vector<std::shared_ptr<awips::TextProductFile>>
LoadTextProducts(const std::vector<std::string>& textProducts); 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);
}
private: private:
class Impl; class Impl;
std::unique_ptr<Impl> p; std::unique_ptr<Impl> p;
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 } // namespace scwx::provider

View file

@ -1,10 +1,10 @@
#include <scwx/provider/iem_api_provider.hpp> #include <scwx/provider/iem_api_provider.hpp>
#include <scwx/network/cpr.hpp>
#include <scwx/util/json.hpp> #include <scwx/util/json.hpp>
#include <scwx/util/logger.hpp> #include <scwx/util/logger.hpp>
#include <boost/json.hpp> #include <boost/json.hpp>
#include <cpr/cpr.h> #include <cpr/cpr.h>
#include <range/v3/iterator/operations.hpp>
#include <range/v3/range/conversion.hpp> #include <range/v3/range/conversion.hpp>
#include <range/v3/view/cartesian_product.hpp> #include <range/v3/view/cartesian_product.hpp>
#include <range/v3/view/single.hpp> #include <range/v3/view/single.hpp>
@ -19,10 +19,12 @@ namespace scwx::provider
static const std::string logPrefix_ = "scwx::provider::iem_api_provider"; static const std::string logPrefix_ = "scwx::provider::iem_api_provider";
static const auto logger_ = util::Logger::Create(logPrefix_); static const auto logger_ = util::Logger::Create(logPrefix_);
static const std::string kBaseUrl_ = "https://mesonet.agron.iastate.edu/api/1"; const std::string IemApiProvider::kBaseUrl_ =
"https://mesonet.agron.iastate.edu/api/1";
static const std::string kListNwsTextProductsEndpoint_ = "/nws/afos/list.json"; const std::string IemApiProvider::kListNwsTextProductsEndpoint_ =
static const std::string kNwsTextProductEndpoint_ = "/nwstext/"; "/nws/afos/list.json";
const std::string IemApiProvider::kNwsTextProductEndpoint_ = "/nwstext/";
class IemApiProvider::Impl class IemApiProvider::Impl
{ {
@ -199,25 +201,9 @@ IemApiProvider::ListTextProducts(
} }
std::vector<std::shared_ptr<awips::TextProductFile>> std::vector<std::shared_ptr<awips::TextProductFile>>
IemApiProvider::LoadTextProducts(const std::vector<std::string>& textProducts) IemApiProvider::ProcessTextProductResponses(
std::vector<std::pair<std::string, cpr::AsyncResponse>>& asyncResponses)
{ {
auto parameters = cpr::Parameters {{"nolimit", "true"}};
std::vector<std::pair<const std::string&, cpr::AsyncResponse>>
asyncResponses {};
asyncResponses.reserve(textProducts.size());
const std::string endpointUrl = kBaseUrl_ + kNwsTextProductEndpoint_;
for (auto& productId : textProducts)
{
asyncResponses.emplace_back(
productId,
cpr::GetAsync(cpr::Url {endpointUrl + productId},
network::cpr::GetHeader(),
parameters));
}
std::vector<std::shared_ptr<awips::TextProductFile>> textProductFiles; std::vector<std::shared_ptr<awips::TextProductFile>> textProductFiles;
for (auto& asyncResponse : asyncResponses) for (auto& asyncResponse : asyncResponses)