mirror of
https://github.com/ciphervance/supercell-wx.git
synced 2025-10-30 23:30:04 +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