Prechádzať zdrojové kódy

avm: Optimize `avm list` when GitHub API rate limits are reached (#2962)

zeroc 1 rok pred
rodič
commit
470731b24c
4 zmenil súbory, kde vykonal 27 pridanie a 9 odobranie
  1. 1 0
      CHANGELOG.md
  2. 1 0
      Cargo.lock
  3. 1 0
      avm/Cargo.toml
  4. 24 9
      avm/src/lib.rs

+ 1 - 0
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)).
 

+ 1 - 0
Cargo.lock

@@ -668,6 +668,7 @@ dependencies = [
  "anyhow",
  "cargo_toml",
  "cfg-if",
+ "chrono",
  "clap 4.4.6",
  "dirs",
  "once_cell",

+ 1 - 0
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"

+ 24 - 9
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<Version> {
 
 /// Retrieve a list of installable versions of anchor-cli using the GitHub API and tags on the Anchor
 /// repository.
-pub fn fetch_versions() -> Result<Vec<Version>> {
+pub fn fetch_versions() -> Result<Vec<Version>, Error> {
     #[derive(Deserialize)]
     struct Release {
         #[serde(rename = "name", deserialize_with = "version_deserializer")]
@@ -259,16 +260,30 @@ pub fn fetch_versions() -> Result<Vec<Version>> {
         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::<Vec<Release>>()?
-        .into_iter()
-        .map(|release| release.version)
-        .collect();
+        .send()?;
 
-    Ok(versions)
+    if response.status().is_success() {
+        let releases: Vec<Release> = 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::<i64>().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