mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 07:50:05 +00:00 
			
		
		
		
	Create a timer to expire alerts and remove them from the map
This commit is contained in:
		
							parent
							
								
									c418995682
								
							
						
					
					
						commit
						655fb5042f
					
				
					 1 changed files with 118 additions and 15 deletions
				
			
		|  | @ -1,10 +1,13 @@ | ||||||
| #include <scwx/qt/map/alert_layer.hpp> | #include <scwx/qt/map/alert_layer.hpp> | ||||||
| #include <scwx/qt/manager/text_event_manager.hpp> | #include <scwx/qt/manager/text_event_manager.hpp> | ||||||
| #include <scwx/util/logger.hpp> | #include <scwx/util/logger.hpp> | ||||||
|  | #include <scwx/util/threads.hpp> | ||||||
| 
 | 
 | ||||||
|  | #include <chrono> | ||||||
| #include <shared_mutex> | #include <shared_mutex> | ||||||
| #include <unordered_set> | #include <unordered_set> | ||||||
| 
 | 
 | ||||||
|  | #include <boost/asio/steady_timer.hpp> | ||||||
| #include <boost/container_hash/hash.hpp> | #include <boost/container_hash/hash.hpp> | ||||||
| 
 | 
 | ||||||
| namespace scwx | namespace scwx | ||||||
|  | @ -52,7 +55,10 @@ class AlertLayerHandler : public QObject | ||||||
| { | { | ||||||
|    Q_OBJECT public : |    Q_OBJECT public : | ||||||
|        explicit AlertLayerHandler() : |        explicit AlertLayerHandler() : | ||||||
|        alertSourceMap_ {}, featureMap_ {} |        alertUpdateTimer_ {util::io_context()}, | ||||||
|  |        alertUpdateTimerActive_ {true}, | ||||||
|  |        alertSourceMap_ {}, | ||||||
|  |        featureMap_ {} | ||||||
|    { |    { | ||||||
|       for (auto& phenomenon : kAlertPhenomena_) |       for (auto& phenomenon : kAlertPhenomena_) | ||||||
|       { |       { | ||||||
|  | @ -66,8 +72,9 @@ class AlertLayerHandler : public QObject | ||||||
|       connect(&manager::TextEventManager::Instance(), |       connect(&manager::TextEventManager::Instance(), | ||||||
|               &manager::TextEventManager::AlertUpdated, |               &manager::TextEventManager::AlertUpdated, | ||||||
|               this, |               this, | ||||||
|               &AlertLayerHandler::HandleAlert, |               &AlertLayerHandler::HandleAlert); | ||||||
|               Qt::QueuedConnection); | 
 | ||||||
|  |       ScheduleAlertUpdate(); | ||||||
|    } |    } | ||||||
|    ~AlertLayerHandler() = default; |    ~AlertLayerHandler() = default; | ||||||
| 
 | 
 | ||||||
|  | @ -75,17 +82,24 @@ class AlertLayerHandler : public QObject | ||||||
| 
 | 
 | ||||||
|    std::list<QMapLibreGL::Feature>* FeatureList(awips::Phenomenon phenomenon, |    std::list<QMapLibreGL::Feature>* FeatureList(awips::Phenomenon phenomenon, | ||||||
|                                                 bool              alertActive); |                                                 bool              alertActive); | ||||||
|  | 
 | ||||||
|    void HandleAlert(const types::TextEventKey& key, size_t messageIndex); |    void HandleAlert(const types::TextEventKey& key, size_t messageIndex); | ||||||
|  |    void CancelAlertTimer(); | ||||||
|  |    void ScheduleAlertUpdate(); | ||||||
|  |    void UpdateAlerts(const boost::system::error_code& e = {}); | ||||||
|  | 
 | ||||||
|  |    boost::asio::steady_timer alertUpdateTimer_; | ||||||
|  |    bool                      alertUpdateTimerActive_; | ||||||
| 
 | 
 | ||||||
|    std::unordered_map<std::pair<awips::Phenomenon, bool>, |    std::unordered_map<std::pair<awips::Phenomenon, bool>, | ||||||
|                       QVariantMap, |                       QVariantMap, | ||||||
|                       AlertTypeHash<std::pair<awips::Phenomenon, bool>>> |                       AlertTypeHash<std::pair<awips::Phenomenon, bool>>> | ||||||
|       alertSourceMap_; |       alertSourceMap_; | ||||||
|    std::unordered_multimap< |    std::unordered_multimap<types::TextEventKey, | ||||||
|       types::TextEventKey, |  | ||||||
|                            std::tuple<awips::Phenomenon, |                            std::tuple<awips::Phenomenon, | ||||||
|                                       bool, |                                       bool, | ||||||
|                  std::list<QMapLibreGL::Feature>::iterator>, |                                       std::list<QMapLibreGL::Feature>::iterator, | ||||||
|  |                                       std::chrono::system_clock::time_point>, | ||||||
|                            types::TextEventHash<types::TextEventKey>> |                            types::TextEventHash<types::TextEventKey>> | ||||||
|                      featureMap_; |                      featureMap_; | ||||||
|    std::shared_mutex alertMutex_; |    std::shared_mutex alertMutex_; | ||||||
|  | @ -106,7 +120,13 @@ public: | ||||||
|               this, |               this, | ||||||
|               &AlertLayerImpl::UpdateSource); |               &AlertLayerImpl::UpdateSource); | ||||||
|    } |    } | ||||||
|    ~AlertLayerImpl() = default; |    ~AlertLayerImpl() | ||||||
|  |    { | ||||||
|  |       // Alert layer should never be destructed until the end of execution, this
 | ||||||
|  |       // allows the alert timer to be cancelled and application cleanup to
 | ||||||
|  |       // continue
 | ||||||
|  |       AlertLayerHandler::Instance().CancelAlertTimer(); | ||||||
|  |    }; | ||||||
| 
 | 
 | ||||||
|    void UpdateSource(awips::Phenomenon phenomenon, bool alertActive); |    void UpdateSource(awips::Phenomenon phenomenon, bool alertActive); | ||||||
| 
 | 
 | ||||||
|  | @ -260,7 +280,7 @@ void AlertLayerHandler::HandleAlert(const types::TextEventKey& key, | ||||||
|    auto existingFeatures = featureMap_.equal_range(key); |    auto existingFeatures = featureMap_.equal_range(key); | ||||||
|    for (auto it = existingFeatures.first; it != existingFeatures.second; ++it) |    for (auto it = existingFeatures.first; it != existingFeatures.second; ++it) | ||||||
|    { |    { | ||||||
|       auto& [phenomenon, alertActive, featureIt] = it->second; |       auto& [phenomenon, alertActive, featureIt, eventEnd] = it->second; | ||||||
|       auto featureList = FeatureList(phenomenon, alertActive); |       auto featureList = FeatureList(phenomenon, alertActive); | ||||||
|       if (featureList != nullptr) |       if (featureList != nullptr) | ||||||
|       { |       { | ||||||
|  | @ -283,6 +303,7 @@ void AlertLayerHandler::HandleAlert(const types::TextEventKey& key, | ||||||
|       auto&             vtec       = segment->header_->vtecString_.front(); |       auto&             vtec       = segment->header_->vtecString_.front(); | ||||||
|       auto              action     = vtec.pVtec_.action(); |       auto              action     = vtec.pVtec_.action(); | ||||||
|       awips::Phenomenon phenomenon = vtec.pVtec_.phenomenon(); |       awips::Phenomenon phenomenon = vtec.pVtec_.phenomenon(); | ||||||
|  |       auto              eventEnd   = vtec.pVtec_.event_end(); | ||||||
|       bool alertActive             = (action != awips::PVtec::Action::Canceled); |       bool alertActive             = (action != awips::PVtec::Action::Canceled); | ||||||
| 
 | 
 | ||||||
|       auto featureList = FeatureList(phenomenon, alertActive); |       auto featureList = FeatureList(phenomenon, alertActive); | ||||||
|  | @ -294,10 +315,10 @@ void AlertLayerHandler::HandleAlert(const types::TextEventKey& key, | ||||||
|             CreateFeature(segment->codedLocation_.value())); |             CreateFeature(segment->codedLocation_.value())); | ||||||
| 
 | 
 | ||||||
|          // Store iterator for created feature in feature map
 |          // Store iterator for created feature in feature map
 | ||||||
|          featureMap_.emplace( |          featureMap_.emplace(std::piecewise_construct, | ||||||
|             std::piecewise_construct, |  | ||||||
|                              std::forward_as_tuple(key), |                              std::forward_as_tuple(key), | ||||||
|             std::forward_as_tuple(phenomenon, alertActive, featureIt)); |                              std::forward_as_tuple( | ||||||
|  |                                 phenomenon, alertActive, featureIt, eventEnd)); | ||||||
| 
 | 
 | ||||||
|          // Mark alert type as updated
 |          // Mark alert type as updated
 | ||||||
|          alertsUpdated.emplace(phenomenon, alertActive); |          alertsUpdated.emplace(phenomenon, alertActive); | ||||||
|  | @ -314,6 +335,88 @@ void AlertLayerHandler::HandleAlert(const types::TextEventKey& key, | ||||||
|    } |    } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void AlertLayerHandler::UpdateAlerts(const boost::system::error_code& e) | ||||||
|  | { | ||||||
|  |    logger_->trace("UpdateAlerts"); | ||||||
|  | 
 | ||||||
|  |    if (e == boost::asio::error::operation_aborted) | ||||||
|  |    { | ||||||
|  |       logger_->debug("Alert update timer cancelled"); | ||||||
|  |       return; | ||||||
|  |    } | ||||||
|  |    else if (e != boost::system::errc::success) | ||||||
|  |    { | ||||||
|  |       logger_->warn("Alert update timer error: {}", e.message()); | ||||||
|  |       return; | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    // Take a unique lock before modifying feature lists
 | ||||||
|  |    std::unique_lock lock(alertMutex_); | ||||||
|  | 
 | ||||||
|  |    std::unordered_set<std::pair<awips::Phenomenon, bool>, | ||||||
|  |                       AlertTypeHash<std::pair<awips::Phenomenon, bool>>> | ||||||
|  |       alertsUpdated {}; | ||||||
|  | 
 | ||||||
|  |    // Evaluate each rendered feature for expiration
 | ||||||
|  |    for (auto it = featureMap_.begin(); it != featureMap_.end();) | ||||||
|  |    { | ||||||
|  |       auto& [phenomenon, alertActive, featureIt, eventEnd] = it->second; | ||||||
|  | 
 | ||||||
|  |       // If the event has ended, remove it from the feature list
 | ||||||
|  |       if (eventEnd < std::chrono::system_clock::now()) | ||||||
|  |       { | ||||||
|  |          logger_->debug("Alert expired: {}", it->first.ToString()); | ||||||
|  | 
 | ||||||
|  |          auto featureList = FeatureList(phenomenon, alertActive); | ||||||
|  |          if (featureList != nullptr) | ||||||
|  |          { | ||||||
|  |             // Remove existing feature for key
 | ||||||
|  |             featureList->erase(featureIt); | ||||||
|  | 
 | ||||||
|  |             // Mark alert type as updated
 | ||||||
|  |             alertsUpdated.emplace(phenomenon, alertActive); | ||||||
|  |          } | ||||||
|  | 
 | ||||||
|  |          // Erase current item and increment iterator
 | ||||||
|  |          it = featureMap_.erase(it); | ||||||
|  |       } | ||||||
|  |       else | ||||||
|  |       { | ||||||
|  |          // Current item is not expired, continue
 | ||||||
|  |          ++it; | ||||||
|  |       } | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    // Release the lock after completing feature list updates
 | ||||||
|  |    lock.unlock(); | ||||||
|  | 
 | ||||||
|  |    for (auto& alert : alertsUpdated) | ||||||
|  |    { | ||||||
|  |       // Emit signal for each updated alert type
 | ||||||
|  |       emit AlertsUpdated(alert.first, alert.second); | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    if (alertUpdateTimerActive_) | ||||||
|  |    { | ||||||
|  |       ScheduleAlertUpdate(); | ||||||
|  |    } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void AlertLayerHandler::ScheduleAlertUpdate() | ||||||
|  | { | ||||||
|  |    using namespace std::chrono; | ||||||
|  | 
 | ||||||
|  |    alertUpdateTimer_.expires_after(15s); | ||||||
|  |    alertUpdateTimer_.async_wait([=](const boost::system::error_code& e) | ||||||
|  |                                 { UpdateAlerts(e); }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void AlertLayerHandler::CancelAlertTimer() | ||||||
|  | { | ||||||
|  |    alertUpdateTimerActive_ = false; | ||||||
|  |    alertUpdateTimer_.cancel(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void AlertLayerImpl::UpdateSource(awips::Phenomenon phenomenon, | void AlertLayerImpl::UpdateSource(awips::Phenomenon phenomenon, | ||||||
|                                   bool              alertActive) |                                   bool              alertActive) | ||||||
| { | { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Paulat
						Dan Paulat