From 470731b24c355a9757a533359155fa4507649a8c Mon Sep 17 00:00:00 2001 From: zeroc Date: Tue, 14 May 2024 21:07:30 +0800 Subject: [PATCH] avm: Optimize `avm list` when GitHub API rate limits are reached (#2962) --- CHANGELOG.md | 1 + Cargo.lock | 1 + avm/Cargo.toml | 1 + avm/src/lib.rs | 33 ++++++++++++++++++++++++--------- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d3da911c..bf5e58a19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ The minor version will be incremented upon a breaking change and the patch versi - idl: Allow overriding the idl build toolchain with the `RUSTUP_TOOLCHAIN` environment variable ([#2941](https://github.com/coral-xyz/anchor/pull/2941])). - avm: Support customizing the installation location using `AVM_HOME` environment variable ([#2917](https://github.com/coral-xyz/anchor/pull/2917)). +- avm: Optimize `avm list` when GitHub API rate limits are reached ([#2962](https://github.com/coral-xyz/anchor/pull/2962)) - idl, ts: Add accounts resolution for associated token accounts ([#2927](https://github.com/coral-xyz/anchor/pull/2927)). - cli: Add `--no-install` option to the `init` command ([#2945](https://github.com/coral-xyz/anchor/pull/2945)). diff --git a/Cargo.lock b/Cargo.lock index 864ca1734..3c51974cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -668,6 +668,7 @@ dependencies = [ "anyhow", "cargo_toml", "cfg-if", + "chrono", "clap 4.4.6", "dirs", "once_cell", diff --git a/avm/Cargo.toml b/avm/Cargo.toml index dd92cfe08..df3827545 100644 --- a/avm/Cargo.toml +++ b/avm/Cargo.toml @@ -23,3 +23,4 @@ reqwest = { version = "0.11.9", default-features = false, features = ["blocking" semver = "1.0.4" serde = { version = "1.0.136", features = ["derive"] } tempfile = "3.3.0" +chrono = "0.4" diff --git a/avm/src/lib.rs b/avm/src/lib.rs index 882c6819e..bbc6b4223 100644 --- a/avm/src/lib.rs +++ b/avm/src/lib.rs @@ -1,5 +1,6 @@ -use anyhow::{anyhow, Result}; +use anyhow::{anyhow, Error, Result}; use cargo_toml::Manifest; +use chrono::{TimeZone, Utc}; use once_cell::sync::Lazy; use reqwest::header::USER_AGENT; use reqwest::StatusCode; @@ -244,7 +245,7 @@ pub fn read_anchorversion_file() -> Result { /// Retrieve a list of installable versions of anchor-cli using the GitHub API and tags on the Anchor /// repository. -pub fn fetch_versions() -> Result> { +pub fn fetch_versions() -> Result, Error> { #[derive(Deserialize)] struct Release { #[serde(rename = "name", deserialize_with = "version_deserializer")] @@ -259,16 +260,30 @@ pub fn fetch_versions() -> Result> { Version::parse(s.trim_start_matches('v')).map_err(de::Error::custom) } - let versions = reqwest::blocking::Client::new() + let response = reqwest::blocking::Client::new() .get("https://api.github.com/repos/coral-xyz/anchor/tags") .header(USER_AGENT, "avm https://github.com/coral-xyz/anchor") - .send()? - .json::>()? - .into_iter() - .map(|release| release.version) - .collect(); + .send()?; - Ok(versions) + if response.status().is_success() { + let releases: Vec = response.json()?; + let versions = releases.into_iter().map(|r| r.version).collect(); + Ok(versions) + } else { + let reset_time_header = response + .headers() + .get("X-RateLimit-Reset") + .map_or("unknown", |v| v.to_str().unwrap()); + let t = Utc.timestamp_opt(reset_time_header.parse::().unwrap(), 0); + let reset_time = t + .single() + .map(|t| t.format("%Y-%m-%d %H:%M:%S").to_string()) + .unwrap_or_else(|| "unknown".to_string()); + Err(anyhow!( + "GitHub API rate limit exceeded. Try again after {} UTC.", + reset_time + )) + } } /// Print available versions and flags indicating installed, current and latest