Public Access
Updates from Gitea, step 2: the connection (check and list work on the device)
The roots (ISRG X1 and X2), an HTTPS client that reads the answer as a stream, GiteaReleases (the latest and a list of ten), the Update Service's requests, install from Gitea through the existing install path, the daily check's schedule, the Check for updates setting, and console commands: update check | list | status | install <tag>. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
#include "services/gitea_releases.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "platform/https_get.h"
|
||||
#include "update_check.h"
|
||||
|
||||
namespace roro {
|
||||
|
||||
namespace {
|
||||
struct Guard {
|
||||
explicit Guard(SemaphoreHandle_t l) : l_(l) { xSemaphoreTake(l_, portMAX_DELAY); }
|
||||
~Guard() { xSemaphoreGive(l_); }
|
||||
SemaphoreHandle_t l_;
|
||||
};
|
||||
|
||||
std::string api(const std::string& what) { return std::string("/api/v1/repos/") + release::kGiteaRepo + "/releases" + what; }
|
||||
} // namespace
|
||||
|
||||
bool GiteaReleases::fetch(const std::string& path, size_t max, std::vector<release::Release>& out) {
|
||||
HttpsGet get(net::User::Updates);
|
||||
std::string why = get.open(release::kGiteaHost, path, "application/json");
|
||||
if (!why.empty()) {
|
||||
finish(false, why);
|
||||
return false;
|
||||
}
|
||||
release::ReleaseReader reader(max);
|
||||
std::unique_ptr<uint8_t[]> buf(new (std::nothrow) uint8_t[512]);
|
||||
if (!buf) {
|
||||
finish(false, "Not enough memory");
|
||||
return false;
|
||||
}
|
||||
for (;;) {
|
||||
int n = get.read(buf.get(), 512);
|
||||
if (n < 0) {
|
||||
finish(false, "The connection broke off");
|
||||
return false;
|
||||
}
|
||||
if (n == 0) break;
|
||||
reader.feed(reinterpret_cast<const char*>(buf.get()), n);
|
||||
if (!reader.ok()) break;
|
||||
}
|
||||
reader.end();
|
||||
if (!reader.ok() || !reader.complete()) {
|
||||
finish(false, "Gitea's answer isn't what was expected");
|
||||
return false;
|
||||
}
|
||||
out = reader.releases();
|
||||
return true;
|
||||
}
|
||||
|
||||
void GiteaReleases::finish(bool ok, const std::string& error) {
|
||||
Guard g(lock_);
|
||||
status_ = ok ? Status::Done : Status::Failed;
|
||||
error_ = error;
|
||||
seq_++;
|
||||
}
|
||||
|
||||
bool GiteaReleases::fetchLatest() {
|
||||
{
|
||||
Guard g(lock_);
|
||||
status_ = Status::Busy;
|
||||
error_.clear();
|
||||
}
|
||||
std::vector<release::Release> got;
|
||||
if (!fetch(api("/latest"), 1, got)) return false;
|
||||
if (got.empty() || !got[0].usable()) {
|
||||
finish(false, "No release to install on the server");
|
||||
return false;
|
||||
}
|
||||
{
|
||||
Guard g(lock_);
|
||||
latest_ = got[0];
|
||||
haveLatest_ = true;
|
||||
}
|
||||
finish(true, "");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GiteaReleases::fetchList() {
|
||||
{
|
||||
Guard g(lock_);
|
||||
status_ = Status::Busy;
|
||||
error_.clear();
|
||||
}
|
||||
std::vector<release::Release> got;
|
||||
if (!fetch(api("?limit=" + std::to_string(kListSize) + "&draft=false&pre-release=false"), kListSize, got)) return false;
|
||||
std::vector<release::Release> usable;
|
||||
for (auto& r : got)
|
||||
if (r.usable()) usable.push_back(std::move(r));
|
||||
{
|
||||
Guard g(lock_);
|
||||
list_ = std::move(usable);
|
||||
if (!list_.empty() && (!haveLatest_ || release::versionNewer(list_[0].tag, latest_.tag))) {
|
||||
latest_ = list_[0];
|
||||
haveLatest_ = true;
|
||||
}
|
||||
}
|
||||
finish(true, "");
|
||||
return true;
|
||||
}
|
||||
|
||||
GiteaReleases::Status GiteaReleases::status() const {
|
||||
Guard g(lock_);
|
||||
return status_;
|
||||
}
|
||||
|
||||
std::string GiteaReleases::error() const {
|
||||
Guard g(lock_);
|
||||
return error_;
|
||||
}
|
||||
|
||||
uint32_t GiteaReleases::seq() const {
|
||||
Guard g(lock_);
|
||||
return seq_;
|
||||
}
|
||||
|
||||
bool GiteaReleases::latest(release::Release& out) const {
|
||||
Guard g(lock_);
|
||||
if (haveLatest_) out = latest_;
|
||||
return haveLatest_;
|
||||
}
|
||||
|
||||
std::vector<release::Release> GiteaReleases::list() const {
|
||||
Guard g(lock_);
|
||||
return list_;
|
||||
}
|
||||
|
||||
bool GiteaReleases::find(const std::string& tag, release::Release& out) const {
|
||||
Guard g(lock_);
|
||||
for (const auto& r : list_)
|
||||
if (r.tag == tag) return out = r, true;
|
||||
if (haveLatest_ && latest_.tag == tag) return out = latest_, true;
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace roro
|
||||
Reference in New Issue
Block a user