Update mDNS service announcements when name changes.

This commit is contained in:
Robin Davies
2024-09-19 11:19:24 -04:00
parent 7ecc3de10a
commit 951a7a73de
18 changed files with 348 additions and 257 deletions
+30 -37
View File
@@ -45,6 +45,12 @@ void AvahiService::Announce(
const std::string &mdnsName,
bool addTestGroup)
{
// We should update an existing group if the name doesn't change.
// but in practice, the name is the only thing that's going to change without restarting the server.
if (this->name && strcmp(name.c_str(),this->name) == 0)
{
return;
}
Unannounce();
this->portNumber = portNumber;
@@ -162,7 +168,7 @@ void AvahiService::create_group(AvahiClient *c)
if ((ret = avahi_entry_group_add_service(
group,
AVAHI_IF_UNSPEC,
AVAHI_PROTO_UNSPEC, // IPv4 for now, until we figure out why dnsqmasq borks IPv6 routing.)
AVAHI_PROTO_INET, // IPv4 for now, until we figure out why dnsqmasq borks IPv6 routing.)
(AvahiPublishFlags)0,
name,
PIPEDAL_SERVICE_TYPE,
@@ -307,41 +313,32 @@ void AvahiService::Start()
while (true)
{
/* Allocate main loop object */
if (!(this->threadedPoll = avahi_threaded_poll_new()))
if (!this->threadedPoll)
{
Lv2Log::error("Failed to create Avahi poll object.");
goto fail;
if (!(this->threadedPoll = avahi_threaded_poll_new()))
{
Lv2Log::error("Failed to create Avahi poll object.");
goto fail;
}
avahi_threaded_poll_start(threadedPoll);
}
/* Allocate a new client */
client = avahi_client_new(avahi_threaded_poll_get(threadedPoll), AvahiClientFlags::AVAHI_CLIENT_NO_FAIL, client_callback, (void *)this, &error);
/* Check wether creating the client object succeeded */
if (!client)
{
Lv2Log::error(SS("Failed to create client: " << avahi_strerror(error)));
goto fail;
/* Allocate a new client */
client = avahi_client_new(avahi_threaded_poll_get(threadedPoll), AvahiClientFlags::AVAHI_CLIENT_NO_FAIL, client_callback, (void *)this, &error);
/* Check wether creating the client object succeeded */
if (!client)
{
Lv2Log::error(SS("Failed to create client: " << avahi_strerror(error)));
goto fail;
}
}
avahi_threaded_poll_start(threadedPoll);
ret = 0;
return;
fail:
/* Cleanup things */
if (client)
{
avahi_client_free(client);
client = nullptr;
}
if (group)
{
avahi_entry_group_reset(group);
group = nullptr;
}
if (threadedPoll)
{
avahi_threaded_poll_free(threadedPoll);
threadedPoll = nullptr;
}
Stop();
}
return;
}
@@ -349,27 +346,23 @@ void AvahiService::Start()
void AvahiService::Stop()
{
if (threadedPoll)
/* Cleanup things */
if (group)
{
avahi_threaded_poll_stop(threadedPoll);
avahi_entry_group_reset(group);
avahi_entry_group_free(group);
group = nullptr;
}
/* Cleanup things */
// client owns the group?
// if (group)
// {
// avahi_entry_group_reset(group);
// group = nullptr;
// }`
if (client)
{
avahi_client_free(client);
client = nullptr;
}
if (threadedPoll)
{
avahi_threaded_poll_stop(threadedPoll);
avahi_threaded_poll_free(threadedPoll);
threadedPoll = nullptr;
}
group = nullptr;
}
-3
View File
@@ -43,7 +43,6 @@ namespace pipedal {
int portNumber, const std::string &name, const std::string &instanceId, const std::string&mdnsName,bool addTestGroup = false);
void Unannounce();
private:
void Start();
void Stop();
@@ -56,8 +55,6 @@ namespace pipedal {
void create_group(AvahiClient *c);
void threadProc();
int clientErrno = 0;
int portNumber = -1;
+32 -8
View File
@@ -301,6 +301,9 @@ add_executable(hotspotManagerTest
target_link_libraries(hotspotManagerTest PRIVATE ${PIPEDAL_LIBS})
set_target_properties(hotspotManagerTest PROPERTIES EXCLUDE_FROM_ALL true)
add_executable(pipedaltest testMain.cpp
@@ -329,6 +332,8 @@ target_link_libraries(pipedaltest PRIVATE ${PIPEDAL_LIBS})
target_include_directories(pipedaltest PRIVATE ${PIPEDAL_INCLUDES}
)
set_target_properties(pipedaltest PROPERTIES EXCLUDE_FROM_ALL true)
if (NOT GITHUB_ACTIONS) # Google perftools are not available on Github action servers.
@@ -339,6 +344,9 @@ if (NOT GITHUB_ACTIONS) # Google perftools are not available on Github action se
target_include_directories(profilePlugin PRIVATE ${PIPEDAL_INCLUDES}
)
set_target_properties(profilePlugin PROPERTIES EXCLUDE_FROM_ALL true)
endif()
add_executable(jsonTest
testMain.cpp
@@ -356,7 +364,12 @@ target_link_libraries(jsonTest PRIVATE PiPedalCommon)
target_include_directories(jsonTest PRIVATE ${PIPEDAL_INCLUDES}
)
set_target_properties(jsonTest PROPERTIES EXCLUDE_FROM_ALL true)
target_link_libraries(jsonTest PRIVATE pthread)
add_test(NAME jsonTest COMMAND jsonTest)
@@ -561,18 +574,18 @@ if(ENABLE_VST3)
)
add_executable(vst3test Vst3test.cpp
# add_executable(vst3test Vst3test.cpp
MemDebug.cpp
MemDebug.hpp
# MemDebug.cpp
# MemDebug.hpp
Vst3SdkRepro.cpp
# Vst3SdkRepro.cpp
${VST3_FILES}
# ${VST3_FILES}
#vst3/Vst3PresetFile.hpp Vst3PresetFile.cpp
asan_options.cpp
)
# #vst3/Vst3PresetFile.hpp Vst3PresetFile.cpp
# asan_options.cpp
# )
target_include_directories(vst3test PRIVATE ${PIPEDAL_INCLUDES}
)
@@ -642,6 +655,17 @@ target_include_directories(capturepresets PRIVATE ${PIPEDAL_INCLUDES})
target_link_libraries(capturepresets ${PIPEDAL_LIBS})
add_executable(makeRelease
makeReleaseMain.cpp
CommandLineParser.hpp
)
target_include_directories(makeRelease PRIVATE ${PIPEDAL_INCLUDES})
target_link_libraries(makeRelease ${PIPEDAL_LIBS})
add_executable(pipedal_update
UpdateMain.cpp
+8 -30
View File
@@ -66,7 +66,6 @@ namespace pipedal::impl
{
Initial,
WaitingForNetworkManager,
Disabled,
Monitoring,
HotspotConnecting,
HotspotConnected,
@@ -82,7 +81,6 @@ namespace pipedal::impl
void onDevicesChanged();
void onDisconnect();
void onReload();
void onDisableHotspot();
void DisableHotspot();
void EnableHotspot();
@@ -169,7 +167,7 @@ void HotspotManagerImpl::Open()
void HotspotManagerImpl::onClose()
{
onDisableHotspot();
StopHotspot();
ReleaseNetworkManager();
Lv2Log::debug("HotspotManager: state=Closed");
@@ -201,14 +199,7 @@ void HotspotManagerImpl::onInitialize()
{
wifiConfigSettings.Load();
if (wifiConfigSettings.valid_ && wifiConfigSettings.IsEnabled())
{
onStartMonitoring();
}
else
{
onDisableHotspot();
}
onStartMonitoring();
}
catch (const std::exception &e)
{
@@ -431,17 +422,6 @@ void HotspotManagerImpl::WaitForNetworkManager()
ReleaseNetworkManager();
StartWaitForNetworkManagerTimer();
}
void HotspotManagerImpl::onDisableHotspot()
{
if (this->state != State::Disabled)
{
ReleaseNetworkManager();
Lv2Log::debug("HotspotManager: state=Disabled");
SetState(State::Disabled);
Lv2Log::info("HotspotManager: Hotspot disabled.");
}
}
void HotspotManagerImpl::onReload()
{
if (closed)
@@ -453,17 +433,12 @@ void HotspotManagerImpl::onReload()
switch (state)
{
case State::Initial:
case State::Error:
// ignore.
return;
case State::Disabled:
if (wifiConfigSettings.valid_ && wifiConfigSettings.IsEnabled())
{
onStartMonitoring();
}
default:
MaybeStartHotspot();
return;
default:
this->onDisableHotspot();
break;
}
}
@@ -726,10 +701,12 @@ static std::vector<std::vector<uint8_t>> GetAccessPointSsids(std::vector<AccessP
void HotspotManagerImpl::MaybeStartHotspot()
{
if (this->state == State::Error) return;
if (this->closed) return;
if (!wlanDevice || !wlanWirelessDevice)
{
// devices are transitioning. Do nothing.
return;
}
std::vector<AccessPoint::ptr> allAccessPoints = GetAllAccessPoints();
std::vector<std::vector<uint8_t>> allAccessPointSsids = GetAccessPointSsids(allAccessPoints);
@@ -787,6 +764,7 @@ Connection::ptr HotspotManagerImpl::FindExistingConnection()
}
}
}
return nullptr;
}
+3 -1
View File
@@ -71,6 +71,7 @@ PiPedalModel::PiPedalModel()
atomConverter(pluginHost.GetMapFeature())
{
this->updater = Updater::Create();
this->updater->Start();
this->currentUpdateStatus = updater->GetCurrentStatus();
this->pedalboard = Pedalboard::MakeDefault();
#if JACK_HOST
@@ -980,6 +981,7 @@ void PiPedalModel::SetWifiConfigSettings(const WifiConfigSettings &wifiConfigSet
{
this->hotspotManager->Reload();
}
this->UpdateDnsSd();
}
#else
this->storage.SetWifiConfigSettings(wifiConfigSettings);
@@ -1020,7 +1022,7 @@ static std::string GetP2pdName()
void PiPedalModel::UpdateDnsSd()
{
avahiService.Unannounce();
// avahiService.Unannounce(); let Announce decide whether it wants to unannounce or update.
ServiceConfiguration deviceIdFile;
deviceIdFile.Load();
+202 -147
View File
@@ -48,7 +48,8 @@ namespace fs = std::filesystem;
#undef TEST_UPDATE // do NOT leat this leak into a production build!
#endif
namespace pipedal {
namespace pipedal
{
class GithubResponseHeaders
{
public:
@@ -62,8 +63,8 @@ namespace pipedal {
uint64_t ratelimit_used_ = 0;
std::string ratelimit_resource_;
bool limit_exceeded() const { return code_ != 200 && ratelimit_limit_ != 0 && ratelimit_limit_ == ratelimit_used_; }
void Load();
void Save();
void Load(const std::filesystem::path &filename);
void Save(const std::filesystem::path &filename);
DECLARE_JSON_MAP(GithubResponseHeaders);
private:
@@ -74,24 +75,37 @@ namespace pipedal {
class pipedal::UpdaterImpl : public Updater
{
public:
UpdaterImpl();
UpdaterImpl(const std::filesystem::path &workingDirectory);
UpdaterImpl() : UpdaterImpl("/var/pipedal/updates") {}
virtual ~UpdaterImpl() noexcept;
virtual void SetUpdateListener(UpdateListener &&listener) override;
virtual void Start() override;
virtual void Stop() override;
virtual void CheckNow() override;
virtual void Stop();
virtual UpdatePolicyT GetUpdatePolicy() override;
virtual void SetUpdatePolicy(UpdatePolicyT updatePolicy) override;
virtual void ForceUpdateCheck() override;
virtual void DownloadUpdate(const std::string &url, std::filesystem::path *file, std::filesystem::path *signatureFile) override;
virtual UpdateStatus GetCurrentStatus() const override { return this->currentResult; }
virtual UpdateStatus GetReleaseGeneratorStatus() override;
private:
std::filesystem::path workingDirectory;
std::filesystem::path updateStatusCacheFile;
std::filesystem::path githubResponseHeaderFilename;
GithubResponseHeaders githubResponseHeaders;
using clock = std::chrono::steady_clock;
void SetCachedUpdateStatus(UpdateStatus &updateStatus);
UpdateStatus GetCachedUpdateStatus();
void RetryAfter(clock::duration delay);
template <typename REP, typename PERIOD>
@@ -120,6 +134,7 @@ private:
int event_reader = -1;
int event_writer = -1;
void ThreadProc();
UpdateStatus DoUpdate(bool forReleaseGenerator);
void CheckForUpdate(bool useCache);
UpdateListener listener;
@@ -135,26 +150,27 @@ Updater::ptr Updater::Create()
{
return std::make_unique<UpdaterImpl>();
}
Updater::ptr Updater::Create(const std::filesystem::path &workingDirectory)
{
return std::make_unique<UpdaterImpl>(workingDirectory);
}
static constexpr uint64_t CLOSE_EVENT = 0;
static constexpr uint64_t CHECK_NOW_EVENT = 1;
static constexpr uint64_t UNCACHED_CHECK_NOW_EVENT = 2;
static std::filesystem::path WORKING_DIRECTORY = "/var/pipedal/updates";
static std::filesystem::path UPDATE_STATUS_CACHE_FILE = WORKING_DIRECTORY / "updateStatus.json";
UpdaterImpl::clock::duration UpdaterImpl::updateRate = std::chrono::duration_cast<UpdaterImpl::clock::duration>(std::chrono::days(1));
static std::chrono::system_clock::duration CACHE_DURATION = std::chrono::duration_cast<std::chrono::system_clock::duration>(std::chrono::minutes(30));
std::mutex cacheMutex;
static UpdateStatus GetCachedUpdateStatus()
UpdateStatus UpdaterImpl::GetCachedUpdateStatus()
{
std::lock_guard lock{cacheMutex};
try
{
if (std::filesystem::exists(UPDATE_STATUS_CACHE_FILE))
if (std::filesystem::exists(updateStatusCacheFile))
{
std::ifstream f{UPDATE_STATUS_CACHE_FILE};
std::ifstream f{updateStatusCacheFile};
if (f.is_open())
{
json_reader reader(f);
@@ -174,13 +190,13 @@ static UpdateStatus GetCachedUpdateStatus()
return UpdateStatus();
}
static void SetCachedUpdateStatus(UpdateStatus &updateStatus)
void UpdaterImpl::SetCachedUpdateStatus(UpdateStatus &updateStatus)
{
std::lock_guard lock{cacheMutex};
updateStatus.LastUpdateTime(std::chrono::system_clock::now());
try
{
pipedal::ofstream_synced f{UPDATE_STATUS_CACHE_FILE};
pipedal::ofstream_synced f{updateStatusCacheFile};
json_writer writer{f};
writer.write(updateStatus);
}
@@ -189,13 +205,22 @@ static void SetCachedUpdateStatus(UpdateStatus &updateStatus)
Lv2Log::error(SS("Unable to write cached UpdateStatus. " << e.what()));
}
}
UpdaterImpl::UpdaterImpl()
UpdaterImpl::UpdaterImpl(const std::filesystem::path &workingDirectory)
: workingDirectory(workingDirectory),
updateStatusCacheFile(workingDirectory / "updateStatus.json"),
githubResponseHeaderFilename(workingDirectory / "githubHeaders.json")
{
this->githubResponseHeaders.Load();
this->githubResponseHeaders.Load(githubResponseHeaderFilename);
cachedUpdateStatus = GetCachedUpdateStatus();
this->updatePolicy = cachedUpdateStatus.UpdatePolicy();
currentResult = cachedUpdateStatus;
}
void UpdaterImpl::Start()
{
#if !ENABLE_AUTO_UPDATE
return;
#endif
int fds[2];
int rc = pipe(fds);
if (rc != 0)
@@ -225,6 +250,9 @@ void UpdaterImpl::Stop()
{
return;
}
#if !ENABLE_AUTO_UPDATE
return;
#endif
stopped = true;
if (event_writer != -1)
@@ -563,8 +591,7 @@ JSON_MAP_REFERENCE(GithubResponseHeaders, ratelimit_used)
JSON_MAP_REFERENCE(GithubResponseHeaders, ratelimit_resource)
JSON_MAP_END();
std::filesystem::path GithubResponseHeaders::FILENAME = WORKING_DIRECTORY / "githubHeaders.json";
void GithubResponseHeaders::Load()
void GithubResponseHeaders::Load(const std::filesystem::path &FILENAME)
{
std::ifstream f(FILENAME);
if (f.is_open())
@@ -581,9 +608,9 @@ void GithubResponseHeaders::Load()
}
}
}
void GithubResponseHeaders::Save()
void GithubResponseHeaders::Save(const std::filesystem::path &FILENAME)
{
std::filesystem::create_directories(WORKING_DIRECTORY);
std::filesystem::create_directories(FILENAME.parent_path());
ofstream_synced f(FILENAME);
if (!f.is_open())
{
@@ -622,7 +649,7 @@ GithubResponseHeaders::GithubResponseHeaders(const std::filesystem::path path)
auto trimPos = line.find_last_not_of("\r\n");
if (trimPos != std::string::npos)
{
line = line.substr(0,trimPos + 1);
line = line.substr(0, trimPos + 1);
}
if (!f)
@@ -675,6 +702,12 @@ GithubResponseHeaders::GithubResponseHeaders(const std::filesystem::path path)
}
}
UpdateStatus UpdaterImpl::GetReleaseGeneratorStatus()
{
UpdateStatus result = DoUpdate(true);
return result;
}
void UpdaterImpl::CheckForUpdate(bool useCache)
{
UpdateStatus updateResult;
@@ -702,133 +735,11 @@ void UpdaterImpl::CheckForUpdate(bool useCache)
}
}
// set default next retry time. github failures may postpone even further.
Lv2Log::info("Checking for updates.");
// const std::string responseOption = "-w \"%{response_code}\"";
#ifdef WIN32
responseOption = "-w \"%%{response_code}\""; // windows shell requires doubling of the %%.
#endif
TemporaryFile headerFile{WORKING_DIRECTORY};
std::string args = SS("-s -L " << GITHUB_RELEASES_URL << " -D " << headerFile.str());
updateResult.errorMessage_ = "";
try
{
auto result = sysExecForOutput("curl", args);
if (result.exitCode != EXIT_SUCCESS)
{
RetryAfter(std::chrono::duration_cast<clock::duration>(std::chrono::hours(4)));
throw std::runtime_error("Server has no internet access.");
}
else
{
// hard throttling for github.
RetryAfter(std::chrono::duration_cast<clock::duration>(std::chrono::hours(8)));
GithubResponseHeaders githubHeaders{headerFile.Path()};
this->githubResponseHeaders = githubHeaders;
this->githubResponseHeaders.Save();
if (githubHeaders.code_ != 200)
{
if (
githubHeaders.ratelimit_limit_ != 0 &&
githubHeaders.ratelimit_limit_ == githubHeaders.ratelimit_used_)
{
std::time_t time = std::chrono::system_clock::to_time_t(githubHeaders.ratelimit_reset_);
std::string strTime = std::ctime(&time);
this->RetryAfter(githubHeaders.ratelimit_reset_ - githubHeaders.date_);
throw std::runtime_error(SS("Github API rate limit exceeded. Retrying at " << strTime));
}
}
if (result.output.length() == 0)
{
throw std::runtime_error("Server has no internet access.");
}
std::stringstream ss(result.output);
json_reader reader(ss);
json_variant vResult(reader);
if (vResult.is_object())
{
// an HTML error.
updateResult.isOnline_ = false;
auto o = vResult.as_object();
std::string message = "Unknown error.";
if (o->at("message").is_string())
{
message = o->at("message").as_string();
}
throw std::runtime_error(SS("Github Service error: " << message));
}
else if (!vResult.is_array())
{
throw std::runtime_error("Invalid file format error.");
}
else
{
json_variant::array_ptr vArray = vResult.as_array();
std::vector<GithubRelease> releases;
for (size_t i = 0; i < vArray->size(); ++i)
{
auto &el = vArray->at(i);
GithubRelease release{el};
if (!release.draft && release.GetDownloadForCurrentArchitecture() != nullptr)
{
if (release.name.find("Experimental") == std::string::npos) // experimental releases do not participate in auto-updates (not even for dev stream)
{
releases.push_back(std::move(release));
}
}
}
std::sort(
releases.begin(),
releases.end(),
[](const GithubRelease &left, const GithubRelease &right)
{
return left.published_at > right.published_at; // latest date first.
});
updateResult.releaseOnlyRelease_ = getUpdateRelease(
releases,
updateResult.currentVersion_,
[](const GithubRelease &githubRelease)
{
return !githubRelease.prerelease &&
githubRelease.name.find("Release") != std::string::npos;
});
updateResult.releaseOrBetaRelease_ = getUpdateRelease(
releases,
updateResult.currentVersion_,
[](const GithubRelease &githubRelease)
{
return !githubRelease.prerelease &&
(githubRelease.name.find("Release") != std::string::npos ||
githubRelease.name.find("Beta") != std::string::npos);
});
updateResult.devRelease_ = getUpdateRelease(
releases,
updateResult.currentVersion_,
[](const GithubRelease &githubRelease)
{
return true;
});
#ifdef TEST_UPDATE
updateResult.releaseOrBetaRelease_.upgradeVersionDisplayName_ = "PiPedal v1.2.41-Beta";
updateResult.devRelease_.upgradeVersionDisplayName_ = "PiPedal v1.2.39-Experimental";
updateResult.devRelease_.upgradeVersion_ = "1.2.39";
updateResult.devRelease_.updateAvailable_ = false;
#endif
updateResult.isValid_ = true;
updateResult.isOnline_ = true;
}
}
updateResult = DoUpdate(false);
}
catch (const std::exception &e)
{
@@ -851,6 +762,142 @@ void UpdaterImpl::CheckForUpdate(bool useCache)
}
}
}
UpdateStatus UpdaterImpl::DoUpdate(bool forReleaseGenerator)
{
UpdateStatus updateResult;
if (forReleaseGenerator)
{
updateResult.currentVersion_ = "0.0.0";
}
// set default next retry time. github failures may postpone even further.
Lv2Log::info("Checking for updates.");
// const std::string responseOption = "-w \"%{response_code}\"";
#ifdef WIN32
responseOption = "-w \"%%{response_code}\""; // windows shell requires doubling of the %%.
#endif
TemporaryFile headerFile{workingDirectory};
std::string args = SS("-s -L " << GITHUB_RELEASES_URL << " -D " << headerFile.str());
updateResult.errorMessage_ = "";
auto result = sysExecForOutput("curl", args);
if (result.exitCode != EXIT_SUCCESS)
{
RetryAfter(std::chrono::duration_cast<clock::duration>(std::chrono::hours(4)));
throw std::runtime_error("Server has no internet access.");
}
else
{
// hard throttling for github.
RetryAfter(std::chrono::duration_cast<clock::duration>(std::chrono::hours(8)));
GithubResponseHeaders githubHeaders{headerFile.Path()};
this->githubResponseHeaders = githubHeaders;
this->githubResponseHeaders.Save(githubResponseHeaderFilename);
if (githubHeaders.code_ != 200)
{
if (
githubHeaders.ratelimit_limit_ != 0 &&
githubHeaders.ratelimit_limit_ == githubHeaders.ratelimit_used_)
{
std::time_t time = std::chrono::system_clock::to_time_t(githubHeaders.ratelimit_reset_);
std::string strTime = std::ctime(&time);
this->RetryAfter(githubHeaders.ratelimit_reset_ - githubHeaders.date_);
throw std::runtime_error(SS("Github API rate limit exceeded. Retrying at " << strTime));
}
}
if (result.output.length() == 0)
{
throw std::runtime_error("Server has no internet access.");
}
std::stringstream ss(result.output);
json_reader reader(ss);
json_variant vResult(reader);
if (vResult.is_object())
{
// an HTML error.
updateResult.isOnline_ = false;
auto o = vResult.as_object();
std::string message = "Unknown error.";
if (o->at("message").is_string())
{
message = o->at("message").as_string();
}
throw std::runtime_error(SS("Github Service error: " << message));
}
else if (!vResult.is_array())
{
throw std::runtime_error("Invalid file format error.");
}
else
{
json_variant::array_ptr vArray = vResult.as_array();
std::vector<GithubRelease> releases;
for (size_t i = 0; i < vArray->size(); ++i)
{
auto &el = vArray->at(i);
GithubRelease release{el};
if (!release.draft && release.GetDownloadForCurrentArchitecture() != nullptr)
{
if (release.name.find("Experimental") == std::string::npos) // experimental releases do not participate in auto-updates (not even for dev stream)
{
releases.push_back(std::move(release));
}
}
}
std::sort(
releases.begin(),
releases.end(),
[](const GithubRelease &left, const GithubRelease &right)
{
return left.published_at > right.published_at; // latest date first.
});
updateResult.releaseOnlyRelease_ = getUpdateRelease(
releases,
updateResult.currentVersion_,
[](const GithubRelease &githubRelease)
{
return !githubRelease.prerelease &&
githubRelease.name.find("Release") != std::string::npos;
});
updateResult.releaseOrBetaRelease_ = getUpdateRelease(
releases,
updateResult.currentVersion_,
[](const GithubRelease &githubRelease)
{
return !githubRelease.prerelease &&
(githubRelease.name.find("Release") != std::string::npos ||
githubRelease.name.find("Beta") != std::string::npos);
});
updateResult.devRelease_ = getUpdateRelease(
releases,
updateResult.currentVersion_,
[](const GithubRelease &githubRelease)
{
return true;
});
#ifdef TEST_UPDATE
updateResult.releaseOrBetaRelease_.upgradeVersionDisplayName_ = "PiPedal v1.2.41-Beta";
updateResult.devRelease_.upgradeVersionDisplayName_ = "PiPedal v1.2.39-Experimental";
updateResult.devRelease_.upgradeVersion_ = "1.2.39";
updateResult.devRelease_.updateAvailable_ = false;
#endif
updateResult.isValid_ = true;
updateResult.isOnline_ = true;
}
}
return updateResult;
}
bool UpdateRelease::operator==(const UpdateRelease &other) const
{
return (updateAvailable_ == other.updateAvailable_) &&
@@ -1216,7 +1263,7 @@ void UpdaterImpl::RetryAfter(clock::duration delay)
}
void UpdaterImpl::SaveRetryTime(const std::chrono::system_clock::time_point &time)
{
fs::path retryTimePath = WORKING_DIRECTORY / "retryTime.json";
fs::path retryTimePath = workingDirectory / "retryTime.json";
pipedal::ofstream_synced f{retryTimePath};
if (f.is_open())
{
@@ -1229,7 +1276,7 @@ UpdaterImpl::clock::time_point UpdaterImpl::LoadRetryTime()
{
using namespace std::chrono;
fs::path retryTimePath = WORKING_DIRECTORY / "retryTime.json";
fs::path retryTimePath = workingDirectory / "retryTime.json";
std::ifstream f{retryTimePath};
if (f.is_open())
{
@@ -1273,7 +1320,7 @@ void UpdaterImpl::DownloadUpdate(const std::string &url, std::filesystem::path *
{
throw std::runtime_error(SS("Invalid update url. Downloads from this address are not permitted: " << signatureUrl));
}
auto downloadDirectory = WORKING_DIRECTORY / "downloads";
auto downloadDirectory = workingDirectory / "downloads";
std::filesystem::create_directories(downloadDirectory);
auto downloadFilePath = downloadDirectory / filename;
@@ -1336,6 +1383,14 @@ void UpdaterImpl::DownloadUpdate(const std::string &url, std::filesystem::path *
throw;
}
}
void UpdateStatus::AddRelease(const std::string&packageName)
{
this->isValid_ = true;
this->errorMessage_ = "";
}
///////////////////////////////////////////////////////////////////////////////////////////////
JSON_MAP_BEGIN(UpdateRelease)
+6 -2
View File
@@ -47,18 +47,22 @@ namespace pipedal
using ptr = std::unique_ptr<self>;
static Updater::ptr Create();
static Updater::ptr Create(const std::filesystem::path & workingDirectory);
static void ValidateSignature(const std::filesystem::path&file, const std::filesystem::path&signatureFile);
using UpdateListener = std::function<void(const UpdateStatus &upateResult)>;
virtual void SetUpdateListener(UpdateListener &&listener) = 0;
virtual void CheckNow() = 0;
virtual void Start() = 0;
virtual void Stop() = 0;
virtual void CheckNow() = 0;
virtual UpdatePolicyT GetUpdatePolicy() = 0;
virtual void SetUpdatePolicy(UpdatePolicyT updatePolicy) = 0;
virtual void ForceUpdateCheck() = 0;
virtual void DownloadUpdate(const std::string &url, std::filesystem::path*file, std::filesystem::path*signatureFile) = 0;
UpdateStatus virtual GetCurrentStatus() const = 0;
virtual UpdateStatus GetCurrentStatus() const = 0;
virtual UpdateStatus GetReleaseGeneratorStatus() = 0; // only used when generating releases. Absolutely no caching.
};
+5 -1
View File
@@ -24,6 +24,7 @@
#pragma once
#include <string>
/*
PiPedal uses whitelisting and GPG signatures to verify that updates are valid.
You must modify these defines appropriately if you want to host a fork.
@@ -32,6 +33,9 @@
installs published on github/rerdavies/pipedal.
*/
#ifndef ENABLE_AUTO_UPDATE
#define ENABLE_AUTO_UPDATE 1
#endif
#ifndef GITHUB_PROJECT
#define GITHUB_PROJECT "rerdavies/pipedal"
#endif
@@ -43,7 +47,7 @@
#define UPDATE_GPG_ADDRESS "Robin Davies <rerdavies@gmail.com>"
#endif
#ifndef UPDATE_GPG_ADDRESS2
#define UPDATE_GPG_ADDRESS2 "PiPedal Project <rerdavies@gmail.com>"
#define UPDATE_GPG_ADDRESS2 "PiPedal Project <rerdavies@gmail.com>"
#endif
+2
View File
@@ -92,6 +92,8 @@ namespace pipedal {
const UpdateRelease &DevRelease() const { return devRelease_; }
bool operator==(const UpdateStatus &other) const;
void AddRelease(const std::string&packageName); // Release Generator ONLY
DECLARE_JSON_MAP(UpdateStatus);
};
+2
View File
@@ -43,6 +43,8 @@ TEST_CASE( "updater test", "[updater]" ) {
++nCalls;
}
);
updater->Start();
}
REQUIRE(nCalls == 1);
+5 -2
View File
@@ -29,6 +29,7 @@
#include "ZipFile.hpp"
#include "PiPedalUI.hpp"
#include "ofstream_synced.hpp"
#include "UpdaterSecurity.hpp"
#define PRESET_EXTENSION ".piPreset"
@@ -524,8 +525,10 @@ public:
std::stringstream s;
s << "{ \"socket_server_port\": " << portNumber
<< ", \"socket_server_address\": \"" << webSocketAddress <<
"\", \"ui_plugins\": [ ], \"max_upload_size\": " << maxUploadSize << " }";
<< ", \"socket_server_address\": \"" << webSocketAddress
<< "\", \"ui_plugins\": [ ], \"max_upload_size\": " << maxUploadSize
<< ", \"enable_auto_update\": " << (ENABLE_AUTO_UPDATE ? " true": "false")
<< " }";
return s.str();
}
@@ -1,6 +0,0 @@
[Adding or changing system-wide NetworkManager connections]
Identity=unix-group:pipedal_d
Action=org.freedesktop.NetworkManager.settings.modify.system
ResultAny=yes
ResultInactive=yes
ResultActive=yes
@@ -1,5 +1,5 @@
// grant NetworkManager dbus permissions (no-prompts) to the pipedald systemd service.
polpolkit.addRule(function(action, subject) {
polkit.addRule(function(action, subject) {
if (action.id.indexOf("org.freedesktop.NetworkManager.") == 0 && subject.isInGroup("pipedal_d")) {
return polkit.Result.YES;
}