mirror of
https://github.com/ciphervance/supercell-wx.git
synced 2025-10-30 15:50:05 +00:00
Add text event pruning
- Still need to prune AlertLayer - Still need to test alerts reload after being pruned
This commit is contained in:
parent
4719badc54
commit
f37a77a9f7
6 changed files with 158 additions and 8 deletions
|
|
@ -138,8 +138,10 @@ common::Coordinate AlertManager::Impl::CurrentCoordinate(
|
||||||
void AlertManager::Impl::HandleAlert(const types::TextEventKey& key,
|
void AlertManager::Impl::HandleAlert(const types::TextEventKey& key,
|
||||||
size_t messageIndex) const
|
size_t messageIndex) const
|
||||||
{
|
{
|
||||||
|
auto messages = textEventManager_->message_list(key);
|
||||||
|
|
||||||
// Skip alert if there are more messages to be processed
|
// Skip alert if there are more messages to be processed
|
||||||
if (messageIndex + 1 < textEventManager_->message_count(key))
|
if (messages.empty() || messageIndex + 1 < messages.size())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -153,7 +155,7 @@ void AlertManager::Impl::HandleAlert(const types::TextEventKey& key,
|
||||||
audioSettings.alert_radius().GetValue());
|
audioSettings.alert_radius().GetValue());
|
||||||
std::string alertWFO = audioSettings.alert_wfo().GetValue();
|
std::string alertWFO = audioSettings.alert_wfo().GetValue();
|
||||||
|
|
||||||
auto message = textEventManager_->message_list(key).at(messageIndex);
|
auto message = messages.at(messageIndex);
|
||||||
|
|
||||||
for (auto& segment : message->segments())
|
for (auto& segment : message->segments())
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -116,13 +116,14 @@ public:
|
||||||
Impl(const Impl&&) = delete;
|
Impl(const Impl&&) = delete;
|
||||||
Impl& operator=(const Impl&&) = delete;
|
Impl& operator=(const Impl&&) = delete;
|
||||||
|
|
||||||
void
|
void HandleMessage(const std::shared_ptr<awips::TextProductMessage>& message,
|
||||||
HandleMessage(const std::shared_ptr<awips::TextProductMessage>& message);
|
bool archiveEvent = false);
|
||||||
template<ranges::forward_range DateRange>
|
template<ranges::forward_range DateRange>
|
||||||
requires std::same_as<ranges::range_value_t<DateRange>,
|
requires std::same_as<ranges::range_value_t<DateRange>,
|
||||||
std::chrono::sys_days>
|
std::chrono::sys_days>
|
||||||
void ListArchives(DateRange dates);
|
void ListArchives(DateRange dates);
|
||||||
void LoadArchives(std::chrono::system_clock::time_point dateTime);
|
void LoadArchives(std::chrono::system_clock::time_point dateTime);
|
||||||
|
void PruneArchives();
|
||||||
void RefreshAsync();
|
void RefreshAsync();
|
||||||
void Refresh();
|
void Refresh();
|
||||||
template<ranges::forward_range DateRange>
|
template<ranges::forward_range DateRange>
|
||||||
|
|
@ -155,6 +156,15 @@ public:
|
||||||
std::mutex archiveMutex_ {};
|
std::mutex archiveMutex_ {};
|
||||||
std::list<std::chrono::sys_days> archiveDates_ {};
|
std::list<std::chrono::sys_days> archiveDates_ {};
|
||||||
|
|
||||||
|
std::mutex archiveEventKeyMutex_ {};
|
||||||
|
std::map<std::chrono::sys_days,
|
||||||
|
std::unordered_set<types::TextEventKey,
|
||||||
|
types::TextEventHash<types::TextEventKey>>>
|
||||||
|
archiveEventKeys_ {};
|
||||||
|
std::unordered_set<types::TextEventKey,
|
||||||
|
types::TextEventHash<types::TextEventKey>>
|
||||||
|
liveEventKeys_ {};
|
||||||
|
|
||||||
std::mutex unloadedProductMapMutex_ {};
|
std::mutex unloadedProductMapMutex_ {};
|
||||||
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>>
|
||||||
|
|
@ -249,7 +259,7 @@ void TextEventManager::SelectTime(
|
||||||
const auto today = std::chrono::floor<std::chrono::days>(dateTime);
|
const auto today = std::chrono::floor<std::chrono::days>(dateTime);
|
||||||
const auto yesterday = today - std::chrono::days {1};
|
const auto yesterday = today - std::chrono::days {1};
|
||||||
const auto tomorrow = today + std::chrono::days {1};
|
const auto tomorrow = today + std::chrono::days {1};
|
||||||
const auto dateArray = std::array {today, yesterday, tomorrow};
|
const auto dateArray = std::array {yesterday, today, tomorrow};
|
||||||
|
|
||||||
const auto dates =
|
const auto dates =
|
||||||
dateArray |
|
dateArray |
|
||||||
|
|
@ -265,6 +275,7 @@ void TextEventManager::SelectTime(
|
||||||
p->UpdateArchiveDates(dates);
|
p->UpdateArchiveDates(dates);
|
||||||
p->ListArchives(dates);
|
p->ListArchives(dates);
|
||||||
p->LoadArchives(dateTime);
|
p->LoadArchives(dateTime);
|
||||||
|
p->PruneArchives();
|
||||||
}
|
}
|
||||||
catch (const std::exception& ex)
|
catch (const std::exception& ex)
|
||||||
{
|
{
|
||||||
|
|
@ -274,7 +285,7 @@ void TextEventManager::SelectTime(
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextEventManager::Impl::HandleMessage(
|
void TextEventManager::Impl::HandleMessage(
|
||||||
const std::shared_ptr<awips::TextProductMessage>& message)
|
const std::shared_ptr<awips::TextProductMessage>& message, bool archiveEvent)
|
||||||
{
|
{
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
|
|
@ -335,6 +346,12 @@ void TextEventManager::Impl::HandleMessage(
|
||||||
textEventMap_.emplace(key, std::vector {message});
|
textEventMap_.emplace(key, std::vector {message});
|
||||||
messageIndex = 0;
|
messageIndex = 0;
|
||||||
updated = true;
|
updated = true;
|
||||||
|
|
||||||
|
if (!archiveEvent)
|
||||||
|
{
|
||||||
|
// Add the Text Event Key to the list of live events to prevent pruning
|
||||||
|
liveEventKeys_.insert(key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (std::find_if(it->second.cbegin(),
|
else if (std::find_if(it->second.cbegin(),
|
||||||
it->second.cend(),
|
it->second.cend(),
|
||||||
|
|
@ -368,6 +385,17 @@ void TextEventManager::Impl::HandleMessage(
|
||||||
updated = true;
|
updated = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// If this is an archive event, and the key does not exist in the live events
|
||||||
|
// Assumption: A live event will always be loaded before a duplicate archive
|
||||||
|
// event
|
||||||
|
if (archiveEvent && !liveEventKeys_.contains(key))
|
||||||
|
{
|
||||||
|
// Add the Text Event Key to the current date's archive
|
||||||
|
const std::unique_lock archiveEventKeyLock {archiveEventKeyMutex_};
|
||||||
|
auto& archiveKeys = archiveEventKeys_[wmoDate];
|
||||||
|
archiveKeys.insert(key);
|
||||||
|
}
|
||||||
|
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
|
|
||||||
if (updated)
|
if (updated)
|
||||||
|
|
@ -518,11 +546,87 @@ void TextEventManager::Impl::LoadArchives(
|
||||||
|
|
||||||
for (auto& message : messages)
|
for (auto& message : messages)
|
||||||
{
|
{
|
||||||
HandleMessage(message);
|
HandleMessage(message, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextEventManager::Impl::PruneArchives()
|
||||||
|
{
|
||||||
|
static constexpr std::size_t kMaxArchiveDates_ = 5;
|
||||||
|
|
||||||
|
std::unordered_set<types::TextEventKey,
|
||||||
|
types::TextEventHash<types::TextEventKey>>
|
||||||
|
eventKeysToKeep {};
|
||||||
|
std::unordered_set<types::TextEventKey,
|
||||||
|
types::TextEventHash<types::TextEventKey>>
|
||||||
|
eventKeysToPrune {};
|
||||||
|
|
||||||
|
// Remove oldest dates from the archive
|
||||||
|
while (archiveDates_.size() > kMaxArchiveDates_)
|
||||||
|
{
|
||||||
|
archiveDates_.pop_front();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::unique_lock archiveEventKeyLock {archiveEventKeyMutex_};
|
||||||
|
|
||||||
|
// If there are the same number of dates in both archiveEventKeys_ and
|
||||||
|
// archiveDates_, there is nothing to prune
|
||||||
|
if (archiveEventKeys_.size() == archiveDates_.size())
|
||||||
|
{
|
||||||
|
// Nothing to prune
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::unique_lock unloadedProductMapLock {unloadedProductMapMutex_};
|
||||||
|
|
||||||
|
for (auto it = archiveEventKeys_.begin(); it != archiveEventKeys_.end();)
|
||||||
|
{
|
||||||
|
const auto& date = it->first;
|
||||||
|
const auto& eventKeys = it->second;
|
||||||
|
|
||||||
|
// If date is not in recent days map
|
||||||
|
if (std::find(archiveDates_.cbegin(), archiveDates_.cend(), date) ==
|
||||||
|
archiveDates_.cend())
|
||||||
|
{
|
||||||
|
// Prune these keys (unless they are in the eventKeysToKeep set)
|
||||||
|
eventKeysToPrune.insert(eventKeys.begin(), eventKeys.end());
|
||||||
|
|
||||||
|
// The date is not in the list of recent dates, remove it
|
||||||
|
it = archiveEventKeys_.erase(it);
|
||||||
|
unloadedProductMap_.erase(date);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Make sure these keys don't get pruned
|
||||||
|
eventKeysToKeep.insert(eventKeys.begin(), eventKeys.end());
|
||||||
|
|
||||||
|
// The date is recent, keep it
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove elements from eventKeysToPrune if they are in eventKeysToKeep
|
||||||
|
for (const auto& eventKey : eventKeysToKeep)
|
||||||
|
{
|
||||||
|
eventKeysToPrune.erase(eventKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove eventKeysToPrune from textEventMap
|
||||||
|
for (const auto& eventKey : eventKeysToPrune)
|
||||||
|
{
|
||||||
|
textEventMap_.erase(eventKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If event keys were pruned, emit a signal
|
||||||
|
if (!eventKeysToPrune.empty())
|
||||||
|
{
|
||||||
|
logger_->debug("Pruned {} archive events", eventKeysToPrune.size());
|
||||||
|
|
||||||
|
Q_EMIT self_->AlertsRemoved(eventKeysToPrune);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TextEventManager::Impl::RefreshAsync()
|
void TextEventManager::Impl::RefreshAsync()
|
||||||
{
|
{
|
||||||
boost::asio::post(threadPool_,
|
boost::asio::post(threadPool_,
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
#include <boost/uuid/uuid.hpp>
|
#include <boost/uuid/uuid.hpp>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
@ -35,6 +36,10 @@ public:
|
||||||
static std::shared_ptr<TextEventManager> Instance();
|
static std::shared_ptr<TextEventManager> Instance();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
void AlertsRemoved(
|
||||||
|
const std::unordered_set<types::TextEventKey,
|
||||||
|
types::TextEventHash<types::TextEventKey>>&
|
||||||
|
keys);
|
||||||
void AlertUpdated(const types::TextEventKey& key,
|
void AlertUpdated(const types::TextEventKey& key,
|
||||||
std::size_t messageIndex,
|
std::size_t messageIndex,
|
||||||
boost::uuids::uuid uuid);
|
boost::uuids::uuid uuid);
|
||||||
|
|
|
||||||
|
|
@ -338,7 +338,7 @@ void AlertModel::HandleAlert(const types::TextEventKey& alertKey,
|
||||||
auto alertMessages = p->textEventManager_->message_list(alertKey);
|
auto alertMessages = p->textEventManager_->message_list(alertKey);
|
||||||
|
|
||||||
// Skip alert if this is not the most recent message
|
// Skip alert if this is not the most recent message
|
||||||
if (messageIndex + 1 < alertMessages.size())
|
if (alertMessages.empty() || messageIndex + 1 < alertMessages.size())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -393,6 +393,35 @@ void AlertModel::HandleAlert(const types::TextEventKey& alertKey,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AlertModel::HandleAlertsRemoved(
|
||||||
|
const std::unordered_set<types::TextEventKey,
|
||||||
|
types::TextEventHash<types::TextEventKey>>&
|
||||||
|
alertKeys)
|
||||||
|
{
|
||||||
|
logger_->trace("Handle alerts removed");
|
||||||
|
|
||||||
|
for (const auto& alertKey : alertKeys)
|
||||||
|
{
|
||||||
|
// Remove from the list of text event keys
|
||||||
|
auto it = std::find(
|
||||||
|
p->textEventKeys_.begin(), p->textEventKeys_.end(), alertKey);
|
||||||
|
if (it != p->textEventKeys_.end())
|
||||||
|
{
|
||||||
|
int row = std::distance(p->textEventKeys_.begin(), it);
|
||||||
|
beginRemoveRows(QModelIndex(), row, row);
|
||||||
|
p->textEventKeys_.erase(it);
|
||||||
|
endRemoveRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove from internal maps
|
||||||
|
p->observedMap_.erase(alertKey);
|
||||||
|
p->threatCategoryMap_.erase(alertKey);
|
||||||
|
p->tornadoPossibleMap_.erase(alertKey);
|
||||||
|
p->centroidMap_.erase(alertKey);
|
||||||
|
p->distanceMap_.erase(alertKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AlertModel::HandleMapUpdate(double latitude, double longitude)
|
void AlertModel::HandleMapUpdate(double latitude, double longitude)
|
||||||
{
|
{
|
||||||
logger_->trace("Handle map update: {}, {}", latitude, longitude);
|
logger_->trace("Handle map update: {}, {}", latitude, longitude);
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
#include <scwx/common/geographic.hpp>
|
#include <scwx/common/geographic.hpp>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
#include <QAbstractTableModel>
|
#include <QAbstractTableModel>
|
||||||
|
|
||||||
|
|
@ -51,6 +52,10 @@ public:
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void HandleAlert(const types::TextEventKey& alertKey, size_t messageIndex);
|
void HandleAlert(const types::TextEventKey& alertKey, size_t messageIndex);
|
||||||
|
void HandleAlertsRemoved(
|
||||||
|
const std::unordered_set<types::TextEventKey,
|
||||||
|
types::TextEventHash<types::TextEventKey>>&
|
||||||
|
alertKeys);
|
||||||
void HandleMapUpdate(double latitude, double longitude);
|
void HandleMapUpdate(double latitude, double longitude);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
|
|
@ -131,6 +131,11 @@ void AlertDockWidgetImpl::ConnectSignals()
|
||||||
&QAction::toggled,
|
&QAction::toggled,
|
||||||
proxyModel_.get(),
|
proxyModel_.get(),
|
||||||
&model::AlertProxyModel::SetAlertActiveFilter);
|
&model::AlertProxyModel::SetAlertActiveFilter);
|
||||||
|
connect(textEventManager_.get(),
|
||||||
|
&manager::TextEventManager::AlertsRemoved,
|
||||||
|
alertModel_.get(),
|
||||||
|
&model::AlertModel::HandleAlertsRemoved,
|
||||||
|
Qt::QueuedConnection);
|
||||||
connect(textEventManager_.get(),
|
connect(textEventManager_.get(),
|
||||||
&manager::TextEventManager::AlertUpdated,
|
&manager::TextEventManager::AlertUpdated,
|
||||||
alertModel_.get(),
|
alertModel_.get(),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue