mirror of
https://github.com/InstanceBrick/nightcap.git
synced 2026-10-20 15:00:31 +02:00
The coordinator constructed ApkPureProvider directly in three places and rejected every other configuration with "native updater supports only the direct APKPure provider". A single unreachable host therefore failed the whole update with no way to try anything else, and the reported error named neither the provider nor the host: on 2026-08-18 api.pureapk.com answered 503 to every request, including metadata for unrelated packages, and a first launch could only say "Roblox update preflight failed". Introduce an ApkProvider interface and a ProviderChain that consults providers in order, returns the first answer, and reports every failure with the provider that produced it when none answer. Each provider downloads into its own directory, so a failed attempt cannot block the next. Adding a source is now one line in BuildProviderChain instead of a change spread across the coordinator. The chain currently holds APKPure alone. The repository already ships a pinned Uptodown provider as a build script, but it no longer works against Uptodown's current pages, so wiring it in would add a second way to fail rather than a fallback; that is reported separately. Payload receipts now record which provider produced an archive, and updates.source accepts auto alongside apk-pure so existing configuration files keep working.
70 lines
2.1 KiB
C++
70 lines
2.1 KiB
C++
#ifndef MOCKTAIL_UPDATE_APK_PROVIDER_H_
|
|
#define MOCKTAIL_UPDATE_APK_PROVIDER_H_
|
|
|
|
#include <cstdint>
|
|
#include <filesystem>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <string_view>
|
|
#include <vector>
|
|
|
|
namespace mocktail::update {
|
|
|
|
struct ProviderVersion {
|
|
std::string version_name;
|
|
std::uint64_t version_code = 0;
|
|
std::string error;
|
|
|
|
explicit operator bool() const { return error.empty(); }
|
|
};
|
|
|
|
struct ProviderDownloadResult {
|
|
std::vector<std::filesystem::path> archives;
|
|
// Provider that produced the archives, so a stored payload can be traced
|
|
// back to where it came from.
|
|
std::string source;
|
|
std::string error;
|
|
|
|
explicit operator bool() const { return error.empty(); }
|
|
};
|
|
|
|
// A source of Roblox APK archives. Providers are interchangeable: whichever
|
|
// one answers first wins, and every archive still passes the same signature,
|
|
// Build-ID, and ABI verification afterwards.
|
|
class ApkProvider {
|
|
public:
|
|
virtual ~ApkProvider() = default;
|
|
|
|
// Short stable identifier, recorded in payload receipts and error messages.
|
|
virtual std::string_view name() const = 0;
|
|
|
|
// Latest published version. A provider that only serves pinned versions
|
|
// reports an error here and stays usable through DownloadExact.
|
|
virtual ProviderVersion CheckLatest() const = 0;
|
|
|
|
virtual ProviderDownloadResult DownloadExact(
|
|
std::string_view version, const std::filesystem::path& output_directory,
|
|
int progress_fd) const = 0;
|
|
};
|
|
|
|
// Tries every provider in order. One unreachable provider is the most common
|
|
// first-run failure, and on its own it must not fail the whole update.
|
|
class ProviderChain final : public ApkProvider {
|
|
public:
|
|
void Add(std::unique_ptr<ApkProvider> provider);
|
|
bool empty() const { return providers_.empty(); }
|
|
|
|
std::string_view name() const override { return "provider-chain"; }
|
|
ProviderVersion CheckLatest() const override;
|
|
ProviderDownloadResult DownloadExact(
|
|
std::string_view version, const std::filesystem::path& output_directory,
|
|
int progress_fd) const override;
|
|
|
|
private:
|
|
std::vector<std::unique_ptr<ApkProvider>> providers_;
|
|
};
|
|
|
|
} // namespace mocktail::update
|
|
|
|
#endif // MOCKTAIL_UPDATE_APK_PROVIDER_H_
|