mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 01:40:04 +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
	
	 Dan Paulat
						Dan Paulat