mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 02:40:05 +00:00 
			
		
		
		
	Integrate Warnings Provider auto-refresh into Text Event Manager
This commit is contained in:
		
							parent
							
								
									a2616b0ee0
								
							
						
					
					
						commit
						c7a69a76be
					
				
					 7 changed files with 131 additions and 36 deletions
				
			
		|  | @ -46,9 +46,11 @@ public: | |||
|        activeMap_ {nullptr}, | ||||
|        level2ProductsWidget_ {nullptr}, | ||||
|        level2SettingsWidget_ {nullptr}, | ||||
|        level3ProductsWidget_ {nullptr}, | ||||
|        alertDockWidget_ {nullptr}, | ||||
|        radarSiteDialog_ {nullptr}, | ||||
|        radarProductModel_ {nullptr}, | ||||
|        textEventManager_ {manager::TextEventManager::Instance()}, | ||||
|        maps_ {}, | ||||
|        elevationCuts_ {}, | ||||
|        elevationButtonsChanged_ {false}, | ||||
|  | @ -109,7 +111,8 @@ public: | |||
|    ui::AlertDockWidget* alertDockWidget_; | ||||
|    ui::RadarSiteDialog* radarSiteDialog_; | ||||
| 
 | ||||
|    std::unique_ptr<model::RadarProductModel> radarProductModel_; | ||||
|    std::unique_ptr<model::RadarProductModel>  radarProductModel_; | ||||
|    std::shared_ptr<manager::TextEventManager> textEventManager_; | ||||
| 
 | ||||
|    std::vector<map::MapWidget*> maps_; | ||||
|    std::vector<float>           elevationCuts_; | ||||
|  | @ -306,8 +309,7 @@ void MainWindow::on_actionOpenTextEvent_triggered() | |||
|            [=](const QString& file) | ||||
|            { | ||||
|               logger_->info("Selected: {}", file.toStdString()); | ||||
|               manager::TextEventManager::Instance().LoadFile( | ||||
|                  file.toStdString()); | ||||
|               p->textEventManager_->LoadFile(file.toStdString()); | ||||
|            }); | ||||
| 
 | ||||
|    dialog->open(); | ||||
|  |  | |||
|  | @ -1,11 +1,14 @@ | |||
| #include <scwx/qt/manager/text_event_manager.hpp> | ||||
| #include <scwx/awips/text_product_file.hpp> | ||||
| #include <scwx/provider/warnings_provider.hpp> | ||||
| #include <scwx/util/logger.hpp> | ||||
| #include <scwx/util/threads.hpp> | ||||
| 
 | ||||
| #include <shared_mutex> | ||||
| #include <unordered_map> | ||||
| 
 | ||||
| #include <boost/asio/steady_timer.hpp> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
|  | @ -16,25 +19,44 @@ namespace manager | |||
| static const std::string logPrefix_ = "scwx::qt::manager::text_event_manager"; | ||||
| static const auto        logger_    = scwx::util::Logger::Create(logPrefix_); | ||||
| 
 | ||||
| static const std::string& kDefaultWarningsProviderUrl { | ||||
|    "https://warnings.allisonhouse.com"}; | ||||
| 
 | ||||
| class TextEventManager::Impl | ||||
| { | ||||
| public: | ||||
|    explicit Impl(TextEventManager* self) : | ||||
|        self_ {self}, textEventMap_ {}, textEventMutex_ {} | ||||
|        self_ {self}, | ||||
|        refreshTimer_ {util::io_context()}, | ||||
|        refreshMutex_ {}, | ||||
|        textEventMap_ {}, | ||||
|        textEventMutex_ {}, | ||||
|        warningsProvider_ {kDefaultWarningsProviderUrl} | ||||
|    { | ||||
|       util::async([=]() { Refresh(); }); | ||||
|    } | ||||
| 
 | ||||
|    ~Impl() {} | ||||
|    ~Impl() | ||||
|    { | ||||
|       std::unique_lock lock(refreshMutex_); | ||||
|       refreshTimer_.cancel(); | ||||
|    } | ||||
| 
 | ||||
|    void HandleMessage(std::shared_ptr<awips::TextProductMessage> message); | ||||
|    void Refresh(); | ||||
| 
 | ||||
|    TextEventManager* self_; | ||||
| 
 | ||||
|    boost::asio::steady_timer refreshTimer_; | ||||
|    std::mutex                refreshMutex_; | ||||
| 
 | ||||
|    std::unordered_map<types::TextEventKey, | ||||
|                       std::vector<std::shared_ptr<awips::TextProductMessage>>, | ||||
|                       types::TextEventHash<types::TextEventKey>> | ||||
|                      textEventMap_; | ||||
|    std::shared_mutex textEventMutex_; | ||||
| 
 | ||||
|    provider::WarningsProvider warningsProvider_; | ||||
| }; | ||||
| 
 | ||||
| TextEventManager::TextEventManager() : p(std::make_unique<Impl>(this)) {} | ||||
|  | @ -159,10 +181,74 @@ void TextEventManager::Impl::HandleMessage( | |||
|    } | ||||
| } | ||||
| 
 | ||||
| TextEventManager& TextEventManager::Instance() | ||||
| void TextEventManager::Impl::Refresh() | ||||
| { | ||||
|    static TextEventManager textEventManager_ {}; | ||||
|    return textEventManager_; | ||||
|    using namespace std::chrono; | ||||
| 
 | ||||
|    logger_->trace("Refresh"); | ||||
| 
 | ||||
|    // Take a unique lock before refreshing
 | ||||
|    std::unique_lock lock(refreshMutex_); | ||||
| 
 | ||||
|    // Set threshold to last 30 hours
 | ||||
|    auto newerThan = std::chrono::system_clock::now() - 30h; | ||||
| 
 | ||||
|    // Update the file listing from the warnings provider
 | ||||
|    auto [newFiles, totalFiles] = warningsProvider_.ListFiles(newerThan); | ||||
| 
 | ||||
|    if (newFiles > 0) | ||||
|    { | ||||
|       // Load new files
 | ||||
|       auto updatedFiles = warningsProvider_.LoadUpdatedFiles(newerThan); | ||||
| 
 | ||||
|       // Handle messages
 | ||||
|       for (auto& file : updatedFiles) | ||||
|       { | ||||
|          for (auto& message : file->messages()) | ||||
|          { | ||||
|             HandleMessage(message); | ||||
|          } | ||||
|       } | ||||
|    } | ||||
| 
 | ||||
|    // Schedule another update in 15 seconds
 | ||||
|    using namespace std::chrono; | ||||
|    refreshTimer_.expires_after(15s); | ||||
|    refreshTimer_.async_wait( | ||||
|       [=](const boost::system::error_code& e) | ||||
|       { | ||||
|          if (e == boost::asio::error::operation_aborted) | ||||
|          { | ||||
|             logger_->debug("Refresh timer cancelled"); | ||||
|          } | ||||
|          else if (e != boost::system::errc::success) | ||||
|          { | ||||
|             logger_->warn("Refresh timer error: {}", e.message()); | ||||
|          } | ||||
|          else | ||||
|          { | ||||
|             Refresh(); | ||||
|          } | ||||
|       }); | ||||
| } | ||||
| 
 | ||||
| std::shared_ptr<TextEventManager> TextEventManager::Instance() | ||||
| { | ||||
|    static std::weak_ptr<TextEventManager> textEventManagerReference_ {}; | ||||
|    static std::mutex                      instanceMutex_ {}; | ||||
| 
 | ||||
|    std::unique_lock lock(instanceMutex_); | ||||
| 
 | ||||
|    std::shared_ptr<TextEventManager> textEventManager = | ||||
|       textEventManagerReference_.lock(); | ||||
| 
 | ||||
|    if (textEventManager == nullptr) | ||||
|    { | ||||
|       textEventManager           = std::make_shared<TextEventManager>(); | ||||
|       textEventManagerReference_ = textEventManager; | ||||
|    } | ||||
| 
 | ||||
|    return textEventManager; | ||||
| } | ||||
| 
 | ||||
| } // namespace manager
 | ||||
|  |  | |||
|  | @ -29,7 +29,7 @@ public: | |||
| 
 | ||||
|    void LoadFile(const std::string& filename); | ||||
| 
 | ||||
|    static TextEventManager& Instance(); | ||||
|    static std::shared_ptr<TextEventManager> Instance(); | ||||
| 
 | ||||
| signals: | ||||
|    void AlertUpdated(const types::TextEventKey& key, size_t messageIndex); | ||||
|  |  | |||
|  | @ -55,6 +55,7 @@ class AlertLayerHandler : public QObject | |||
| { | ||||
|    Q_OBJECT public : | ||||
|        explicit AlertLayerHandler() : | ||||
|        textEventManager_ {manager::TextEventManager::Instance()}, | ||||
|        alertUpdateTimer_ {util::io_context()}, | ||||
|        alertSourceMap_ {}, | ||||
|        featureMap_ {} | ||||
|  | @ -68,7 +69,7 @@ class AlertLayerHandler : public QObject | |||
|          } | ||||
|       } | ||||
| 
 | ||||
|       connect(&manager::TextEventManager::Instance(), | ||||
|       connect(textEventManager_.get(), | ||||
|               &manager::TextEventManager::AlertUpdated, | ||||
|               this, | ||||
|               &AlertLayerHandler::HandleAlert); | ||||
|  | @ -87,6 +88,8 @@ class AlertLayerHandler : public QObject | |||
|    void HandleAlert(const types::TextEventKey& key, size_t messageIndex); | ||||
|    void UpdateAlerts(); | ||||
| 
 | ||||
|    std::shared_ptr<manager::TextEventManager> textEventManager_; | ||||
| 
 | ||||
|    boost::asio::steady_timer alertUpdateTimer_; | ||||
|    std::unordered_map<std::pair<awips::Phenomenon, bool>, | ||||
|                       QVariantMap, | ||||
|  | @ -252,15 +255,13 @@ AlertLayerHandler::FeatureList(awips::Phenomenon phenomenon, bool alertActive) | |||
| void AlertLayerHandler::HandleAlert(const types::TextEventKey& key, | ||||
|                                     size_t                     messageIndex) | ||||
| { | ||||
|    auto& textEventManager = manager::TextEventManager::Instance(); | ||||
| 
 | ||||
|    // Skip alert if there are more messages to be processed
 | ||||
|    if (messageIndex + 1 < textEventManager.message_count(key)) | ||||
|    if (messageIndex + 1 < textEventManager_->message_count(key)) | ||||
|    { | ||||
|       return; | ||||
|    } | ||||
| 
 | ||||
|    auto message = textEventManager.message_list(key).at(messageIndex); | ||||
|    auto message = textEventManager_->message_list(key).at(messageIndex); | ||||
|    std::unordered_set<std::pair<awips::Phenomenon, bool>, | ||||
|                       AlertTypeHash<std::pair<awips::Phenomenon, bool>>> | ||||
|       alertsUpdated {}; | ||||
|  |  | |||
|  | @ -45,6 +45,8 @@ public: | |||
|    static std::string GetStartTime(const types::TextEventKey& key); | ||||
|    static std::string GetEndTime(const types::TextEventKey& key); | ||||
| 
 | ||||
|    std::shared_ptr<manager::TextEventManager> textEventManager_; | ||||
| 
 | ||||
|    QList<types::TextEventKey> textEventKeys_; | ||||
| 
 | ||||
|    GeographicLib::Geodesic geodesic_; | ||||
|  | @ -199,8 +201,7 @@ void AlertModel::HandleAlert(const types::TextEventKey& alertKey, | |||
|    double distanceInMeters; | ||||
| 
 | ||||
|    // Get the most recent segment for the event
 | ||||
|    auto alertMessages = | ||||
|       manager::TextEventManager::Instance().message_list(alertKey); | ||||
|    auto alertMessages = p->textEventManager_->message_list(alertKey); | ||||
|    std::shared_ptr<const awips::Segment> alertSegment = | ||||
|       alertMessages[messageIndex]->segments().back(); | ||||
| 
 | ||||
|  | @ -273,6 +274,7 @@ void AlertModel::HandleMapUpdate(double latitude, double longitude) | |||
| } | ||||
| 
 | ||||
| AlertModelImpl::AlertModelImpl() : | ||||
|     textEventManager_ {manager::TextEventManager::Instance()}, | ||||
|     textEventKeys_ {}, | ||||
|     geodesic_(GeographicLib::Constants::WGS84_a(), | ||||
|               GeographicLib::Constants::WGS84_f()), | ||||
|  | @ -284,8 +286,8 @@ AlertModelImpl::AlertModelImpl() : | |||
| 
 | ||||
| std::string AlertModelImpl::GetCounties(const types::TextEventKey& key) | ||||
| { | ||||
|    auto   messageList = manager::TextEventManager::Instance().message_list(key); | ||||
|    auto&  lastMessage = messageList.back(); | ||||
|    auto  messageList = manager::TextEventManager::Instance()->message_list(key); | ||||
|    auto& lastMessage = messageList.back(); | ||||
|    size_t segmentCount = lastMessage->segment_count(); | ||||
|    auto   lastSegment  = lastMessage->segment(segmentCount - 1); | ||||
|    auto   fipsIds      = lastSegment->header_->ugc_.fips_ids(); | ||||
|  | @ -303,8 +305,8 @@ std::string AlertModelImpl::GetCounties(const types::TextEventKey& key) | |||
| 
 | ||||
| std::string AlertModelImpl::GetState(const types::TextEventKey& key) | ||||
| { | ||||
|    auto   messageList = manager::TextEventManager::Instance().message_list(key); | ||||
|    auto&  lastMessage = messageList.back(); | ||||
|    auto  messageList = manager::TextEventManager::Instance()->message_list(key); | ||||
|    auto& lastMessage = messageList.back(); | ||||
|    size_t segmentCount = lastMessage->segment_count(); | ||||
|    auto   lastSegment  = lastMessage->segment(segmentCount - 1); | ||||
|    return util::ToString(lastSegment->header_->ugc_.states()); | ||||
|  | @ -312,7 +314,7 @@ std::string AlertModelImpl::GetState(const types::TextEventKey& key) | |||
| 
 | ||||
| std::string AlertModelImpl::GetStartTime(const types::TextEventKey& key) | ||||
| { | ||||
|    auto  messageList  = manager::TextEventManager::Instance().message_list(key); | ||||
|    auto  messageList = manager::TextEventManager::Instance()->message_list(key); | ||||
|    auto& firstMessage = messageList.front(); | ||||
|    auto  firstSegment = firstMessage->segment(0); | ||||
|    return util::TimeString( | ||||
|  | @ -321,8 +323,8 @@ std::string AlertModelImpl::GetStartTime(const types::TextEventKey& key) | |||
| 
 | ||||
| std::string AlertModelImpl::GetEndTime(const types::TextEventKey& key) | ||||
| { | ||||
|    auto   messageList = manager::TextEventManager::Instance().message_list(key); | ||||
|    auto&  lastMessage = messageList.back(); | ||||
|    auto  messageList = manager::TextEventManager::Instance()->message_list(key); | ||||
|    auto& lastMessage = messageList.back(); | ||||
|    size_t segmentCount = lastMessage->segment_count(); | ||||
|    auto   lastSegment  = lastMessage->segment(segmentCount - 1); | ||||
|    return util::TimeString( | ||||
|  |  | |||
|  | @ -22,6 +22,7 @@ class AlertDialogImpl : public QObject | |||
| public: | ||||
|    explicit AlertDialogImpl(AlertDialog* self) : | ||||
|        self_ {self}, | ||||
|        textEventManager_ {manager::TextEventManager::Instance()}, | ||||
|        goButton_ {nullptr}, | ||||
|        key_ {}, | ||||
|        centroid_ {}, | ||||
|  | @ -34,7 +35,10 @@ public: | |||
|    void SelectIndex(size_t newIndex); | ||||
|    void UpdateAlertInfo(); | ||||
| 
 | ||||
|    AlertDialog*        self_; | ||||
|    AlertDialog* self_; | ||||
| 
 | ||||
|    std::shared_ptr<manager::TextEventManager> textEventManager_; | ||||
| 
 | ||||
|    QPushButton*        goButton_; | ||||
|    types::TextEventKey key_; | ||||
|    common::Coordinate  centroid_; | ||||
|  | @ -67,7 +71,7 @@ AlertDialog::~AlertDialog() | |||
| void AlertDialogImpl::ConnectSignals() | ||||
| { | ||||
|    connect( | ||||
|       &manager::TextEventManager::Instance(), | ||||
|       textEventManager_.get(), | ||||
|       &manager::TextEventManager::AlertUpdated, | ||||
|       this, | ||||
|       [=](const types::TextEventKey& key) | ||||
|  | @ -94,7 +98,7 @@ bool AlertDialog::SelectAlert(const types::TextEventKey& key) | |||
| 
 | ||||
|    setWindowTitle(QString::fromStdString(key.ToFullString())); | ||||
| 
 | ||||
|    auto messages = manager::TextEventManager::Instance().message_list(key); | ||||
|    auto messages = p->textEventManager_->message_list(key); | ||||
|    if (messages.empty()) | ||||
|    { | ||||
|       return false; | ||||
|  | @ -107,15 +111,14 @@ bool AlertDialog::SelectAlert(const types::TextEventKey& key) | |||
| 
 | ||||
| void AlertDialogImpl::SelectIndex(size_t newIndex) | ||||
| { | ||||
|    size_t messageCount = | ||||
|       manager::TextEventManager::Instance().message_count(key_); | ||||
|    size_t messageCount = textEventManager_->message_count(key_); | ||||
| 
 | ||||
|    if (newIndex >= messageCount) | ||||
|    { | ||||
|       return; | ||||
|    } | ||||
| 
 | ||||
|    auto messages = manager::TextEventManager::Instance().message_list(key_); | ||||
|    auto messages = textEventManager_->message_list(key_); | ||||
| 
 | ||||
|    currentIndex_ = newIndex; | ||||
| 
 | ||||
|  | @ -127,7 +130,7 @@ void AlertDialogImpl::SelectIndex(size_t newIndex) | |||
| 
 | ||||
| void AlertDialogImpl::UpdateAlertInfo() | ||||
| { | ||||
|    auto   messages = manager::TextEventManager::Instance().message_list(key_); | ||||
|    auto   messages     = textEventManager_->message_list(key_); | ||||
|    size_t messageCount = messages.size(); | ||||
| 
 | ||||
|    bool firstSelected = (currentIndex_ == 0u); | ||||
|  | @ -170,8 +173,7 @@ void AlertDialog::on_nextButton_clicked() | |||
| 
 | ||||
| void AlertDialog::on_lastButton_clicked() | ||||
| { | ||||
|    p->SelectIndex(manager::TextEventManager::Instance().message_count(p->key_) - | ||||
|                   1u); | ||||
|    p->SelectIndex(p->textEventManager_->message_count(p->key_) - 1u); | ||||
| } | ||||
| 
 | ||||
| #include "alert_dialog.moc" | ||||
|  |  | |||
|  | @ -25,6 +25,7 @@ class AlertDockWidgetImpl : QObject | |||
| public: | ||||
|    explicit AlertDockWidgetImpl(AlertDockWidget* self) : | ||||
|        self_ {self}, | ||||
|        textEventManager_ {manager::TextEventManager::Instance()}, | ||||
|        alertModel_ {std::make_unique<model::AlertModel>()}, | ||||
|        proxyModel_ {std::make_unique<QSortFilterProxyModel>()}, | ||||
|        alertDialog_ {new AlertDialog(self)}, | ||||
|  | @ -42,9 +43,10 @@ public: | |||
| 
 | ||||
|    void ConnectSignals(); | ||||
| 
 | ||||
|    AlertDockWidget*                       self_; | ||||
|    std::unique_ptr<model::AlertModel>     alertModel_; | ||||
|    std::unique_ptr<QSortFilterProxyModel> proxyModel_; | ||||
|    AlertDockWidget*                           self_; | ||||
|    std::shared_ptr<manager::TextEventManager> textEventManager_; | ||||
|    std::unique_ptr<model::AlertModel>         alertModel_; | ||||
|    std::unique_ptr<QSortFilterProxyModel>     proxyModel_; | ||||
| 
 | ||||
|    AlertDialog* alertDialog_; | ||||
| 
 | ||||
|  | @ -109,7 +111,7 @@ void AlertDockWidgetImpl::ConnectSignals() | |||
|            &QLineEdit::textChanged, | ||||
|            proxyModel_.get(), | ||||
|            &QSortFilterProxyModel::setFilterWildcard); | ||||
|    connect(&manager::TextEventManager::Instance(), | ||||
|    connect(textEventManager_.get(), | ||||
|            &manager::TextEventManager::AlertUpdated, | ||||
|            alertModel_.get(), | ||||
|            &model::AlertModel::HandleAlert, | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Paulat
						Dan Paulat