Skip to content

Commit ac5911e

Browse files
committed
feat: add GitHub API proxy support with fallback
1 parent 841132e commit ac5911e

File tree

5 files changed

+79
-12
lines changed

5 files changed

+79
-12
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ version = "0.1.0"
44
edition = "2024"
55

66
[dependencies]
7-
clap = { version = "4.6.0", features = ["derive"] }
7+
clap = { version = "4.6.0", features = ["derive", "env"] }
88
hex = "0.4.3"
99
serde = { version = "1.0.228", features = ["derive"] }
1010
serde_json = "1.0.149"

src/config.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
use std::sync::OnceLock;
2+
3+
static GITHUB_API_PROXIES: OnceLock<Vec<String>> = OnceLock::new();
4+
5+
pub fn init(proxies: Option<String>) {
6+
let proxies = proxies
7+
.or_else(|| std::env::var("GITHUB_API_PROXY").ok())
8+
.map(|s| {
9+
s.split(',')
10+
.map(|s| s.trim().to_string())
11+
.filter(|s| !s.is_empty())
12+
.collect()
13+
})
14+
.unwrap_or_default();
15+
16+
let _ = GITHUB_API_PROXIES.set(proxies);
17+
}
18+
19+
pub fn get_proxies() -> &'static [String] {
20+
GITHUB_API_PROXIES
21+
.get()
22+
.map(|v| v.as_slice())
23+
.unwrap_or(&[])
24+
}
25+
26+
pub fn build_api_url(path: &str, proxy: Option<&str>) -> String {
27+
match proxy {
28+
Some(proxy) => {
29+
let proxy = proxy.trim_end_matches('/');
30+
format!("{}{}", proxy, path)
31+
}
32+
None => format!("https://api.github.com{}", path),
33+
}
34+
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
pub mod appimage;
2+
pub mod config;
23
pub mod error;
34
pub mod update_info;
45
pub mod updater;

src/main.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::path::PathBuf;
33
use clap::Parser;
44
use clap::Subcommand;
55

6+
use appimageupdate::config;
67
use appimageupdate::{Error, Updater};
78

89
#[derive(Parser)]
@@ -25,11 +26,17 @@ enum Commands {
2526

2627
#[arg(short, long, value_name = "DIR")]
2728
output: Option<PathBuf>,
29+
30+
#[arg(long, value_name = "URL", env = "GITHUB_API_PROXY")]
31+
github_api_proxy: Option<String>,
2832
},
2933

3034
Check {
3135
#[arg(value_name = "APPIMAGE")]
3236
path: PathBuf,
37+
38+
#[arg(long, value_name = "URL", env = "GITHUB_API_PROXY")]
39+
github_api_proxy: Option<String>,
3340
},
3441
}
3542

@@ -64,7 +71,10 @@ fn run(cli: Cli) -> Result<(), Error> {
6471
path,
6572
overwrite,
6673
output,
74+
github_api_proxy,
6775
} => {
76+
config::init(github_api_proxy);
77+
6878
let mut updater = Updater::new(&path)?;
6979

7080
if overwrite {
@@ -120,7 +130,12 @@ fn run(cli: Cli) -> Result<(), Error> {
120130
println!("Already up to date!");
121131
}
122132
}
123-
Commands::Check { path } => {
133+
Commands::Check {
134+
path,
135+
github_api_proxy,
136+
} => {
137+
config::init(github_api_proxy);
138+
124139
let updater = Updater::new(&path)?;
125140

126141
let source_path = updater.source_path();

src/update_info/github.rs

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::cell::OnceCell;
22

33
use serde::Deserialize;
44

5+
use crate::config;
56
use crate::error::{Error, Result};
67

78
#[derive(Debug, Clone)]
@@ -46,21 +47,37 @@ impl GitHubUpdateInfo {
4647
}
4748

4849
fn resolve_url(&self) -> Result<String> {
49-
let api_url = match self.tag.as_str() {
50-
"latest" => format!(
51-
"https://api.github.com/repos/{}/{}/releases/latest",
52-
self.username, self.repo
53-
),
54-
"latest-pre" | "latest-all" => format!(
55-
"https://api.github.com/repos/{}/{}/releases",
56-
self.username, self.repo
57-
),
50+
let api_path = match self.tag.as_str() {
51+
"latest" => format!("/repos/{}/{}/releases/latest", self.username, self.repo),
52+
"latest-pre" | "latest-all" => {
53+
format!("/repos/{}/{}/releases", self.username, self.repo)
54+
}
5855
tag => format!(
59-
"https://api.github.com/repos/{}/{}/releases/tags/{}",
56+
"/repos/{}/{}/releases/tags/{}",
6057
self.username, self.repo, tag
6158
),
6259
};
6360

61+
let proxies = config::get_proxies();
62+
let mut last_error = None;
63+
64+
if proxies.is_empty() {
65+
return self.fetch_release_url(&api_path, None);
66+
}
67+
68+
for proxy in proxies {
69+
match self.fetch_release_url(&api_path, Some(proxy)) {
70+
Ok(url) => return Ok(url),
71+
Err(e) => last_error = Some(e),
72+
}
73+
}
74+
75+
Err(last_error.unwrap_or_else(|| Error::GitHubApi("All proxies failed".into())))
76+
}
77+
78+
fn fetch_release_url(&self, api_path: &str, proxy: Option<&str>) -> Result<String> {
79+
let api_url = config::build_api_url(api_path, proxy);
80+
6481
let response = ureq::get(&api_url)
6582
.header("User-Agent", "appimageupdate-rs")
6683
.call()

0 commit comments

Comments
 (0)