#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include "atomicmutex.h" #include "loggable.h" class Collection; class Download : protected Loggable { struct RepoInfo; struct CurlDeleter { void operator() (CURL* curl) const; }; struct FileDeleter { void operator() (FILE* file) const; }; class CurlError; class FileError; public: explicit Download( const std::string& url, const std::filesystem::path& destination, const std::shared_ptr& logger ); ~Download(); void proceed(); std::optional getLocation() const; private: std::optional testRepo() const; std::optional downloadAsRepo(const RepoInfo& repo); std::optional repoInfoGiteaApi1(const RepoInfo& repo); std::optional downloadRepoGiteaApi1(const RepoInfo& repo, const std::string& branch); bool extract(const std::filesystem::path& source, const std::filesystem::path& destination) const; int copy(struct archive *ar, struct archive *aw) const; CURLcode httpGet(const std::string& url, std::string& result, const std::vector& headers = {}); CURLcode httpDownload(const std::string& url, const std::filesystem::path& path, const std::vector& headers = {}); void setHeaders (const std::vector& headers); static size_t writeString(void* data, size_t size, size_t nmemb, void* mem); static int trace(CURL *handle, curl_infotype type, char *data, size_t size, void *clientp); void createCurl(); private: static AtomicMutex amx; static unsigned int instances; std::unique_ptr curl; std::string url; std::filesystem::path destination; std::optional location; }; struct Download::RepoInfo { std::string protocol; std::string host; std::string owner; std::string name; std::string origin() const; std::string project() const; }; class Download::CurlError : public std::runtime_error { public: explicit CurlError(const std::string& message); }; class Download::FileError : public std::runtime_error { public: explicit FileError(const std::string& message); };