Enable placefile auto-refresh (no more frequent than every 15 seconds)

This commit is contained in:
Dan Paulat 2023-08-23 21:39:17 -05:00
parent 170e30ca6c
commit 80c307c5fc
3 changed files with 125 additions and 11 deletions

View file

@ -22,6 +22,7 @@
#include <boost/json.hpp>
#include <boost/tokenizer.hpp>
#include <cpr/cpr.h>
#include <fmt/chrono.h>
namespace scwx
{
@ -85,10 +86,16 @@ public:
}
~PlacefileRecord()
{
std::unique_lock lock(refreshMutex_);
std::unique_lock refreshLock(refreshMutex_);
std::unique_lock timerLock(timerMutex_);
refreshTimer_.cancel();
}
bool refresh_enabled() const;
std::chrono::seconds refresh_time() const;
void CancelRefresh();
void ScheduleRefresh();
void Update();
void UpdateAsync();
void UpdatePlacefile(const std::shared_ptr<gr::Placefile>& placefile);
@ -125,6 +132,10 @@ public:
boost::asio::thread_pool threadPool_ {1u};
boost::asio::steady_timer refreshTimer_ {threadPool_};
std::mutex refreshMutex_ {};
std::mutex timerMutex_ {};
std::string lastRadarSite_ {};
std::chrono::system_clock::time_point lastUpdateTime_ {};
};
PlacefileManager::PlacefileManager() : p(std::make_unique<Impl>(this))
@ -210,11 +221,26 @@ void PlacefileManager::set_placefile_enabled(const std::string& name,
Q_EMIT PlacefileEnabled(name, enabled);
using namespace std::chrono_literals;
// Update the placefile
// TODO: Only update if it's out of date, or if the radar site has changed
if (enabled)
{
it->second->UpdateAsync();
if (p->radarSite_ != nullptr &&
record->lastRadarSite_ != p->radarSite_->id())
{
// If the radar site has changed, update now
record->UpdateAsync();
}
else
{
// Otherwise, schedule an update
record->ScheduleRefresh();
}
}
else if (!enabled)
{
record->CancelRefresh();
}
}
}
@ -262,6 +288,31 @@ void PlacefileManager::set_placefile_url(const std::string& name,
}
}
bool PlacefileManager::Impl::PlacefileRecord::refresh_enabled() const
{
if (placefile_ != nullptr)
{
using namespace std::chrono_literals;
return placefile_->refresh() > 0s;
}
return false;
}
std::chrono::seconds
PlacefileManager::Impl::PlacefileRecord::refresh_time() const
{
using namespace std::chrono_literals;
if (refresh_enabled())
{
// Don't refresh more often than every 15 seconds
return std::max(placefile_->refresh(), 15s);
}
return -1s;
}
void PlacefileManager::Impl::InitializePlacefileSettings()
{
std::string appDataPath {
@ -407,8 +458,11 @@ void PlacefileManager::AddUrl(const std::string& urlString,
Q_EMIT PlacefileUpdated(normalizedUrl);
// Queue a placefile update
// Queue a placefile update, either if enabled, or if we don't know the title
if (enabled || title.empty())
{
record->UpdateAsync();
}
}
void PlacefileManager::LoadFile(const std::string& filename)
@ -491,6 +545,9 @@ void PlacefileManager::Impl::PlacefileRecord::Update()
{
logger_->debug("Update: {}", name_);
// Take unique lock before refreshing
std::unique_lock lock {refreshMutex_};
// Make a copy of name in the event it changes.
const std::string name {name_};
@ -581,15 +638,64 @@ void PlacefileManager::Impl::PlacefileRecord::Update()
// Update the placefile
placefile_ = updatedPlacefile;
title_ = placefile_->title();
lastUpdateTime_ = std::chrono::system_clock::now();
if (p->radarSite_ != nullptr)
{
lastRadarSite_ = p->radarSite_->id();
}
// Notify slots of the placefile update
Q_EMIT p->self_->PlacefileUpdated(name);
}
}
// TODO: Update refresh timer
// TODO: Can running this function out of sync with an existing refresh timer
// cause issues?
// Update refresh timer
ScheduleRefresh();
}
void PlacefileManager::Impl::PlacefileRecord::ScheduleRefresh()
{
using namespace std::chrono_literals;
if (!enabled_ || !refresh_enabled())
{
// Refresh is disabled
return;
}
std::unique_lock lock {timerMutex_};
auto nextUpdateTime = lastUpdateTime_ + refresh_time();
auto timeUntilNextUpdate = nextUpdateTime - std::chrono::system_clock::now();
logger_->debug(
"Scheduled refresh in {:%M:%S} ({})",
std::chrono::duration_cast<std::chrono::seconds>(timeUntilNextUpdate),
name_);
refreshTimer_.expires_after(timeUntilNextUpdate);
refreshTimer_.async_wait(
[this](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
{
Update();
}
});
}
void PlacefileManager::Impl::PlacefileRecord::CancelRefresh()
{
refreshTimer_.cancel();
}
void PlacefileManager::Impl::PlacefileRecord::UpdateAsync()
@ -603,7 +709,8 @@ void PlacefileManager::Impl::PlacefileRecord::UpdatePlacefile(
// Update placefile
placefile_ = placefile;
// TODO: Update refresh timer
// Update refresh timer
ScheduleRefresh();
}
std::shared_ptr<PlacefileManager> PlacefileManager::Instance()

View file

@ -2,6 +2,7 @@
#include <scwx/common/geographic.hpp>
#include <chrono>
#include <istream>
#include <memory>
#include <optional>
@ -174,6 +175,7 @@ public:
std::string name() const;
std::string title() const;
std::chrono::seconds refresh() const;
std::unordered_map<std::size_t, std::shared_ptr<Font>> fonts();
std::shared_ptr<Font> font(std::size_t i);

View file

@ -113,6 +113,11 @@ std::string Placefile::title() const
return p->title_;
}
std::chrono::seconds Placefile::refresh() const
{
return p->refresh_;
}
std::unordered_map<std::size_t, std::shared_ptr<Placefile::Font>>
Placefile::fonts()
{