19 if (!std::filesystem::exists(configdir)) {
20 std::filesystem::create_directories(configdir);
21 }
else if (!std::filesystem::is_directory(configdir)) {
22 throw std::filesystem::filesystem_error(
"Cannot access config directory ",
24 std::make_error_code(std::errc::not_a_directory));
28 if (!std::filesystem::exists(cert_path)) {
29 std::ofstream out(cert_path);
31 throw std::runtime_error(
"Failed to create certificate file at " + cert_path.string());
37 client->set_follow_location(
true);
38 client->set_connection_timeout(5, 0);
39 client->set_read_timeout(60, 0);
40 client->set_write_timeout(1, 0);
41 client->set_ca_cert_path(cert_path.string());
46std::future<GitHubDownloader::Result>
48 bool use_octet_stream)
const {
50 std::launch::async, [
this, remote_url, if_modified_since, use_octet_stream]() ->
Result {
52 httplib::Headers headers{
53 {
"X-GitHub-Api-Version",
"2022-11-28"},
55 use_octet_stream ?
"application/octet-stream" :
"application/vnd.github+json"}};
57 if (!if_modified_since.empty()) {
58 headers.emplace(
"if-modified-since", if_modified_since);
63 if (
auto *token = std::getenv(
"GITHUB_TOKEN"); token) {
64 headers.emplace(
"Authorization", fmt::format(
"Bearer {}", token));
65 }
else if (!if_modified_since.empty()) {
66 headers.emplace(
"Authorization",
67 "avoids-an-increase-in-ratelimits-used-if-304-is-returned");
70 auto response = client->Get(remote_url, headers);
76 if (response.error() == httplib::Error::Unknown) {
77 return Result{304,
"",
"", {}};
79 throw std::runtime_error(fmt::format(
"Error downloading '{}': {}", remote_url,
80 httplib::to_string(response.error())));
85 if (response->has_header(
"x-ratelimit-remaining")) {
87 std::stoi(response->get_header_value(
"x-ratelimit-remaining"));
89 if (response->has_header(
"x-ratelimit-reset")) {
91 std::stoi(response->get_header_value(
"x-ratelimit-reset"));
93 if (response->has_header(
"last-modified")) {
94 result.
last_modified = response->get_header_value(
"last-modified");
96 result.
body = response->body;
104 Result result = download(
"/rate_limit",
"",
false).get();
106 throw std::runtime_error(
107 fmt::format(
"Failed obtaining the rate limit: status code {}.", result.
status_code));
112std::string GitHubDownloader::get_host()
const {
return "https://" + host; }
std::string last_modified
virtual std::future< Result > download(const std::string &remote_url, const std::string &if_modified_since="", bool use_octet_stream=false) const
virtual ~GitHubDownloader()
std::filesystem::path get_config_directory()