mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 01:20:06 +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, | ||||
|                                      size_t messageIndex) const | ||||
| { | ||||
|    auto messages = textEventManager_->message_list(key); | ||||
| 
 | ||||
|    // 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; | ||||
|    } | ||||
|  | @ -153,7 +155,7 @@ void AlertManager::Impl::HandleAlert(const types::TextEventKey& key, | |||
|       audioSettings.alert_radius().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()) | ||||
|    { | ||||
|  |  | |||
|  | @ -116,13 +116,14 @@ public: | |||
|    Impl(const Impl&&)            = delete; | ||||
|    Impl& operator=(const Impl&&) = delete; | ||||
| 
 | ||||
|    void | ||||
|    HandleMessage(const std::shared_ptr<awips::TextProductMessage>& message); | ||||
|    void HandleMessage(const std::shared_ptr<awips::TextProductMessage>& message, | ||||
|                       bool archiveEvent = false); | ||||
|    template<ranges::forward_range DateRange> | ||||
|       requires std::same_as<ranges::range_value_t<DateRange>, | ||||
|                             std::chrono::sys_days> | ||||
|    void ListArchives(DateRange dates); | ||||
|    void LoadArchives(std::chrono::system_clock::time_point dateTime); | ||||
|    void PruneArchives(); | ||||
|    void RefreshAsync(); | ||||
|    void Refresh(); | ||||
|    template<ranges::forward_range DateRange> | ||||
|  | @ -155,6 +156,15 @@ public: | |||
|    std::mutex                       archiveMutex_ {}; | ||||
|    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::map<std::chrono::sys_days, | ||||
|             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 yesterday = 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 = | ||||
|                dateArray | | ||||
|  | @ -265,6 +275,7 @@ void TextEventManager::SelectTime( | |||
|             p->UpdateArchiveDates(dates); | ||||
|             p->ListArchives(dates); | ||||
|             p->LoadArchives(dateTime); | ||||
|             p->PruneArchives(); | ||||
|          } | ||||
|          catch (const std::exception& ex) | ||||
|          { | ||||
|  | @ -274,7 +285,7 @@ void TextEventManager::SelectTime( | |||
| } | ||||
| 
 | ||||
| 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; | ||||
| 
 | ||||
|  | @ -335,6 +346,12 @@ void TextEventManager::Impl::HandleMessage( | |||
|       textEventMap_.emplace(key, std::vector {message}); | ||||
|       messageIndex = 0; | ||||
|       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(), | ||||
|                          it->second.cend(), | ||||
|  | @ -368,6 +385,17 @@ void TextEventManager::Impl::HandleMessage( | |||
|       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(); | ||||
| 
 | ||||
|    if (updated) | ||||
|  | @ -518,11 +546,87 @@ void TextEventManager::Impl::LoadArchives( | |||
| 
 | ||||
|       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() | ||||
| { | ||||
|    boost::asio::post(threadPool_, | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ | |||
| #include <chrono> | ||||
| #include <memory> | ||||
| #include <string> | ||||
| #include <unordered_set> | ||||
| 
 | ||||
| #include <boost/uuid/uuid.hpp> | ||||
| #include <QObject> | ||||
|  | @ -35,6 +36,10 @@ public: | |||
|    static std::shared_ptr<TextEventManager> Instance(); | ||||
| 
 | ||||
| signals: | ||||
|    void AlertsRemoved( | ||||
|       const std::unordered_set<types::TextEventKey, | ||||
|                                types::TextEventHash<types::TextEventKey>>& | ||||
|          keys); | ||||
|    void AlertUpdated(const types::TextEventKey& key, | ||||
|                      std::size_t                messageIndex, | ||||
|                      boost::uuids::uuid         uuid); | ||||
|  |  | |||
|  | @ -338,7 +338,7 @@ void AlertModel::HandleAlert(const types::TextEventKey& alertKey, | |||
|    auto alertMessages = p->textEventManager_->message_list(alertKey); | ||||
| 
 | ||||
|    // Skip alert if this is not the most recent message
 | ||||
|    if (messageIndex + 1 < alertMessages.size()) | ||||
|    if (alertMessages.empty() || messageIndex + 1 < alertMessages.size()) | ||||
|    { | ||||
|       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) | ||||
| { | ||||
|    logger_->trace("Handle map update: {}, {}", latitude, longitude); | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ | |||
| #include <scwx/common/geographic.hpp> | ||||
| 
 | ||||
| #include <memory> | ||||
| #include <unordered_set> | ||||
| 
 | ||||
| #include <QAbstractTableModel> | ||||
| 
 | ||||
|  | @ -51,6 +52,10 @@ public: | |||
| 
 | ||||
| public slots: | ||||
|    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); | ||||
| 
 | ||||
| private: | ||||
|  |  | |||
|  | @ -131,6 +131,11 @@ void AlertDockWidgetImpl::ConnectSignals() | |||
|            &QAction::toggled, | ||||
|            proxyModel_.get(), | ||||
|            &model::AlertProxyModel::SetAlertActiveFilter); | ||||
|    connect(textEventManager_.get(), | ||||
|            &manager::TextEventManager::AlertsRemoved, | ||||
|            alertModel_.get(), | ||||
|            &model::AlertModel::HandleAlertsRemoved, | ||||
|            Qt::QueuedConnection); | ||||
|    connect(textEventManager_.get(), | ||||
|            &manager::TextEventManager::AlertUpdated, | ||||
|            alertModel_.get(), | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Paulat
						Dan Paulat