Update mDNS service announcements when name changes.
This commit is contained in:
Vendored
+26
@@ -66,6 +66,32 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "(gdb) makeRelease",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
// Resolved by CMake Tools:
|
||||
"program": "${command:cmake.launchTargetPath}",
|
||||
"args": [ ],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}/../..",
|
||||
"environment": [
|
||||
{
|
||||
"name": "PATH",
|
||||
"value": "$PATH:${command:cmake.launchTargetDirectory}"
|
||||
}
|
||||
],
|
||||
"externalConsole": true,
|
||||
"MIMode": "gdb",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"name": "(gdb) pipedal_nm_p2pd",
|
||||
"type": "cppdbg",
|
||||
|
||||
+2
-3
@@ -4,7 +4,7 @@ project(pipedal
|
||||
DESCRIPTION "PiPedal Guitar Effect Pedal For Raspberry Pi"
|
||||
HOMEPAGE_URL "https://rerdavies.github.io/pipedal"
|
||||
)
|
||||
set (DISPLAY_VERSION "PiPedal v1.2.49-Release")
|
||||
set (DISPLAY_VERSION "PiPedal v1.2.49-Development")
|
||||
set (PACKAGE_ARCHITECTURE "arm64")
|
||||
set (CMAKE_INSTALL_PREFIX "/usr/")
|
||||
|
||||
@@ -22,7 +22,6 @@ add_subdirectory("src")
|
||||
# Replaced with hotspot.
|
||||
#add_subdirectory("NetworkManagerP2P")
|
||||
|
||||
|
||||
# install (TARGETS pipedal_p2pd DESTINATION ${CMAKE_INSTALL_PREFIX}/sbin
|
||||
# )
|
||||
|
||||
@@ -56,7 +55,7 @@ install(
|
||||
#)
|
||||
|
||||
install (
|
||||
FILES ${PROJECT_SOURCE_DIR}/src/polkit-1/rules/55-pipedal-networkmanager.rule DESTINATION /etc/polkit-1/rules.d/
|
||||
FILES ${PROJECT_SOURCE_DIR}/src/polkit-1/rules/10-pipedal-networkmanager.rules DESTINATION /etc/polkit-1/rules.d/
|
||||
)
|
||||
install (
|
||||
DIRECTORY ${REACT_BUILD_DIRECTORY} DESTINATION /etc/pipedal/react
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
"debug": true,
|
||||
"max_upload_size": 536870912,
|
||||
"fakeAndroid": false,
|
||||
"ui_plugins": []
|
||||
"ui_plugins": [],
|
||||
"enable_auto_update": true
|
||||
}
|
||||
+13
-9
@@ -1,10 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
#sign a package with rerdavies@gmail.com's private key.
|
||||
cd build
|
||||
for filename in *.deb; do
|
||||
echo gpg --armor --output "$filename".asc -b "$filename"
|
||||
|
||||
gpg --armor --output "$filename".asc -b "$filename"
|
||||
done
|
||||
cd ..
|
||||
# Sign the built .deb package with the private key used in the Auto-update process.
|
||||
#
|
||||
# Won't work for you, because you don't have MY private key.
|
||||
#
|
||||
# Auto-update requires that .deb files be distributed from the GitHub rerdavies/pipedal project.
|
||||
# And auto-updates WILL update installs of your forked binary unless you take steps to prevent that.
|
||||
#
|
||||
# If you are distributing a fork, you should see the file UpdaterSecurity.hpp for details on how to
|
||||
# modify pipedal to perform updates from an alternate github site. Or you could modify your fork
|
||||
# to NOT do auto-updating (probably best). The build doesn't currently have a procedure for
|
||||
# knocking out Auto-Update from UpdaterSecurity.hpp. But I would happily accept a pull request
|
||||
# to bring such a feature back into mainline if you do it.
|
||||
build/src/makeRelease
|
||||
|
||||
+30
-37
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -43,6 +43,8 @@ TEST_CASE( "updater test", "[updater]" ) {
|
||||
++nCalls;
|
||||
}
|
||||
);
|
||||
updater->Start();
|
||||
|
||||
}
|
||||
REQUIRE(nCalls == 1);
|
||||
|
||||
|
||||
@@ -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
-1
@@ -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;
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
- X test reconnect sequence in client.
|
||||
|
||||
-X remove 10-pipedal-networkmanager.rules before testing installer.
|
||||
|
||||
- new signing procedure.
|
||||
|
||||
- verify that scanning doesn't cause overruns.
|
||||
- address change handlers in client (and browser?)
|
||||
- Keybaord escape for hotspotManager.
|
||||
- verify address change behaviour in client
|
||||
- verify stripping in installer.
|
||||
- verify update with no keyring.
|
||||
-verify clean removal of dhcpcd and nm_p2p2d
|
||||
@@ -14,12 +18,11 @@ Localisation: support non-UTF8 code pages.
|
||||
- unicode commandline arguments.
|
||||
- review unicode filenames (this is probably ok)
|
||||
|
||||
|
||||
|
||||
- make app use the same theme settings as the website.
|
||||
- make app use the same theme settings as the website. (make the website use the same theme as the app)
|
||||
- BUG: gcs when we have an animated output control
|
||||
- versioning.
|
||||
- do we want to take a second crack at establishin multi-p2p connections with the driver_param?
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user