Skip to content

Commit f2dfc0a

Browse files
committed
feat: 支持设置代理。
1 parent 02e8c53 commit f2dfc0a

File tree

10 files changed

+133
-35
lines changed

10 files changed

+133
-35
lines changed

Cargo.lock

Lines changed: 39 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ anyhow = "1.0.68"
1414
bytes = "1.4.0"
1515
clap = { version = "4.1.1", features = ["derive"] }
1616
compress-tools = "0.14.0"
17-
reqwest = { version = "0.11.13", features = ["blocking"] }
17+
reqwest = { version = "0.11.13", features = ["blocking", "socks"] }
1818
select = "0.6.0"
1919
serde = { version = "1.0.152", features = ["serde_derive"] }
2020
serde_json = "1.0"

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,20 @@ Download `Firefox 98`:
3636
fb --firefox 98
3737
```
3838

39+
使用 socks5 代理:
40+
41+
Using SOCKS5 proxy:
42+
43+
```powershell
44+
# 使用 socks5h 以使 DNS 通过代理解析。
45+
# Use socks5h to resolve DNS through the proxy.
46+
fb --proxy socks5h://127.0.0.1:10801 98
47+
48+
# 或仅使用 socks5 代理。
49+
# Or simply use socks5 proxy.
50+
fb --proxy socks5://127.0.0.1:10801 98
51+
```
52+
3953
## 许可(License)
4054

4155
MIT @ 2023 hamflx

src/chromium/builds.rs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
11
use std::{fs::File, io::BufReader};
22

33
use anyhow::{anyhow, Result};
4+
use reqwest::blocking::Client;
45
use serde::{Deserialize, Serialize};
56

67
use crate::{platform::Platform, utils::get_cached_file_path};
78

89
pub(crate) struct ChromiumBuilds(Vec<String>);
910

1011
impl ChromiumBuilds {
11-
pub(crate) fn init(platform: Platform) -> Result<Self> {
12+
pub(crate) fn init(platform: Platform, client: Client) -> Result<Self> {
1213
let prefix = platform.prefix();
1314
let builds_json_path = get_cached_file_path(&format!("builds-{prefix}.json"))?;
1415
let build_list = if std::fs::try_exists(&builds_json_path).unwrap_or_default() {
1516
println!("==> using cached builds.");
1617
serde_json::from_reader(BufReader::new(File::open(&builds_json_path)?))?
1718
} else {
1819
println!("==> retrieving builds ...");
19-
let pages = ChromiumBuildsPage::new(prefix)?;
20+
let pages = ChromiumBuildsPage::new(prefix, client)?;
2021
let mut unwrapped_page_list = Vec::new();
2122
for page in pages {
2223
unwrapped_page_list.push(page?);
@@ -54,14 +55,16 @@ pub(crate) struct ChromiumBuildsPage {
5455
prefix: &'static str,
5556
next_page_token: Option<String>,
5657
done: bool,
58+
client: Client,
5759
}
5860

5961
impl ChromiumBuildsPage {
60-
pub fn new(prefix: &'static str) -> Result<Self> {
62+
pub fn new(prefix: &'static str, client: Client) -> Result<Self> {
6163
Ok(Self {
6264
next_page_token: None,
6365
done: false,
6466
prefix,
67+
client,
6568
})
6669
}
6770
}
@@ -80,7 +83,10 @@ impl Iterator for ChromiumBuildsPage {
8083
.unwrap_or_default();
8184
let url = format!("https://www.googleapis.com/storage/v1/b/chromium-browser-snapshots/o?delimiter=/&prefix={}/&fields=items(kind,mediaLink,metadata,name,size,updated),kind,prefixes,nextPageToken{}", self.prefix, next_page_token);
8285

83-
let prefixes = reqwest::blocking::get(&url)
86+
let prefixes = self
87+
.client
88+
.get(&url)
89+
.send()
8490
.map_err(|err| anyhow!("请求 {} 时出错:{:?}", url, err))
8591
.and_then(|response| {
8692
let page: ChromiumBuildPage = serde_json::from_reader(response)?;
@@ -96,10 +102,13 @@ impl Iterator for ChromiumBuildsPage {
96102
}
97103
}
98104

99-
pub(crate) fn fetch_build_detail(prefix: &str) -> Result<Vec<GoogleApiStorageObject>> {
105+
pub(crate) fn fetch_build_detail(
106+
prefix: &str,
107+
client: &Client,
108+
) -> Result<Vec<GoogleApiStorageObject>> {
100109
let url = format!("https://www.googleapis.com/storage/v1/b/chromium-browser-snapshots/o?delimiter=/&prefix={prefix}&fields=items(kind,mediaLink,metadata,name,size,updated),kind,prefixes,nextPageToken");
101110
println!("==> fetching history {url} ...");
102-
let response = reqwest::blocking::get(url)?;
111+
let response = client.get(url).send()?;
103112
let build_detail: ChromiumBuildPage = serde_json::from_reader(response)?;
104113
println!("==> files:");
105114
for file in &build_detail.items {

src/chromium/download.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
use std::{fs::OpenOptions, io::copy, path::Path};
22

33
use anyhow::anyhow;
4+
use reqwest::blocking::Client;
45
use zip::read::read_zipfile_from_stream;
56

67
use super::builds::GoogleApiStorageObject;
78

89
pub(crate) fn download_chromium_zip_file(
910
zip_file: &GoogleApiStorageObject,
1011
base_path: &Path,
12+
client: &Client,
1113
) -> std::result::Result<(), anyhow::Error> {
1214
// 开始下载压缩文件。
1315
println!("==> downloading {}", zip_file.media_link);
14-
let mut win_zip_response = reqwest::blocking::get(&zip_file.media_link)?;
16+
let mut win_zip_response = client.get(&zip_file.media_link).send()?;
1517

1618
loop {
1719
let mut zip = match read_zipfile_from_stream(&mut win_zip_response) {

src/chromium/history.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
use std::{fs::File, io::BufReader};
22

33
use anyhow::Result;
4+
use reqwest::blocking::Client;
45
use serde::{Deserialize, Serialize};
56

67
use crate::{platform::Platform, utils::get_cached_file_path};
78

89
pub(crate) struct ChromiumHistory(Vec<ChromiumHistoryInfo>);
910

1011
impl ChromiumHistory {
11-
pub(crate) fn init(platform: Platform) -> Result<Self> {
12+
pub(crate) fn init(platform: Platform, client: Client) -> Result<Self> {
1213
let os_arg = platform.arg_name();
1314
let history_json_path = get_cached_file_path(&format!("history-{os_arg}.json"))?;
1415
let history_list = if std::fs::try_exists(&history_json_path).unwrap_or_default() {
@@ -18,7 +19,7 @@ impl ChromiumHistory {
1819
println!("==> retrieving history.json ...");
1920
let url =
2021
format!("https://omahaproxy.appspot.com/history.json?os={os_arg}&channel=stable");
21-
let response = reqwest::blocking::get(url)?;
22+
let response = client.get(url).send()?;
2223
let history_list: Vec<ChromiumHistoryInfo> = serde_json::from_reader(response)?;
2324
std::fs::write(&history_json_path, serde_json::to_string(&history_list)?)?;
2425
history_list
@@ -48,13 +49,13 @@ pub(crate) struct ChromiumHistoryInfo {
4849
}
4950

5051
impl ChromiumHistoryInfo {
51-
pub(crate) fn deps(&self) -> Result<ChromiumDepsInfo> {
52+
pub(crate) fn deps(&self, client: &Client) -> Result<ChromiumDepsInfo> {
5253
let url = format!(
5354
"https://omahaproxy.appspot.com/deps.json?version={}",
5455
self.version
5556
);
5657
println!("==> fetching deps {url} ...");
57-
let response = reqwest::blocking::get(url)?;
58+
let response = client.get(url).send()?;
5859
Ok(serde_json::from_reader(response)?)
5960
}
6061
}

src/chromium/mod.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::vec::IntoIter;
22

33
use anyhow::{anyhow, Result};
4+
use reqwest::blocking::Client;
45

56
use crate::{
67
common::{BrowserReleaseItem, BrowserReleases},
@@ -22,24 +23,26 @@ pub(crate) struct ChromiumReleases {
2223
platform: Platform,
2324
history: ChromiumHistory,
2425
builds: ChromiumBuilds,
26+
client: Client,
2527
}
2628

2729
impl BrowserReleases for ChromiumReleases {
2830
type ReleaseItem = ChromiumReleaseItem;
2931
type Matches<'r> = ChromiumReleaseMatches<'r>;
3032

31-
fn init(platform: Platform) -> anyhow::Result<Self>
33+
fn init(platform: Platform, client: Client) -> anyhow::Result<Self>
3234
where
3335
Self: Sized,
3436
{
3537
// history.json 包含了 base_position 和版本号。
36-
let history = ChromiumHistory::init(platform)?;
38+
let history = ChromiumHistory::init(platform, client.clone())?;
3739
// builds 包含了所有可下载的 position 信息。
38-
let builds = ChromiumBuilds::init(platform)?;
40+
let builds = ChromiumBuilds::init(platform, client.clone())?;
3941
Ok(Self {
4042
platform,
4143
history,
4244
builds,
45+
client,
4346
})
4447
}
4548

@@ -70,7 +73,7 @@ impl<'r> Iterator for ChromiumReleaseMatches<'r> {
7073

7174
fn next(&mut self) -> Option<Self::Item> {
7275
for history in self.iter.by_ref() {
73-
let deps = match history.deps() {
76+
let deps = match history.deps(&self.releases.client) {
7477
Ok(deps) => deps,
7578
Err(err) => return Some(Err(err)),
7679
};
@@ -81,6 +84,7 @@ impl<'r> Iterator for ChromiumReleaseMatches<'r> {
8184
return Some(Ok(ChromiumReleaseItem {
8285
rev_prefix: rev_prefix.clone(),
8386
version: deps.chromium_version,
87+
client: self.releases.client.clone(),
8488
}))
8589
}
8690
None => println!("==> no build found for rev: {pos}"),
@@ -103,12 +107,13 @@ impl<'r> Iterator for ChromiumReleaseMatches<'r> {
103107
pub(crate) struct ChromiumReleaseItem {
104108
rev_prefix: String,
105109
version: String,
110+
client: Client,
106111
}
107112

108113
impl BrowserReleaseItem for ChromiumReleaseItem {
109114
fn download(&self) -> Result<()> {
110115
// 根据 prefix 找到该版本文件列表,以及 chrome-win.zip 文件信息。
111-
let build_files = fetch_build_detail(&self.rev_prefix)?;
116+
let build_files = fetch_build_detail(&self.rev_prefix, &self.client)?;
112117
let zip_file = [
113118
"chrome-win.zip",
114119
"chrome-win32.zip",
@@ -127,6 +132,6 @@ impl BrowserReleaseItem for ChromiumReleaseItem {
127132
// 先保存到临时目录里面,待解压的时候,找到里面的版本信息,再重命名一下文件夹。
128133
let base_path = std::env::current_dir()?.join(format!("chromium-{}", self.version));
129134
std::fs::create_dir_all(&base_path)?;
130-
download_chromium_zip_file(zip_file, &base_path)
135+
download_chromium_zip_file(zip_file, &base_path, &self.client)
131136
}
132137
}

src/common.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use anyhow::Result;
2+
use reqwest::blocking::Client;
23

34
use crate::platform::Platform;
45

@@ -8,7 +9,7 @@ pub(crate) trait BrowserReleases {
89
where
910
Self: 'r;
1011

11-
fn init(platform: Platform) -> Result<Self>
12+
fn init(platform: Platform, client: Client) -> Result<Self>
1213
where
1314
Self: Sized;
1415

src/firefox/mod.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,26 @@ use std::{cmp::Ordering, env::current_dir, fs::create_dir_all, io::Cursor};
33
use anyhow::{anyhow, Result};
44
use bytes::Bytes;
55
use compress_tools::{uncompress_archive, Ownership};
6+
use reqwest::blocking::Client;
67
use select::{
78
document::Document,
89
predicate::{self, Predicate},
910
};
1011

1112
use crate::utils::{find_sequence, get_cached_file_path};
1213

13-
pub(crate) fn download_firefox(version: &str) -> Result<()> {
14+
pub(crate) fn download_firefox(version: &str, client: &Client) -> Result<()> {
1415
let cur_dir = current_dir()?;
1516

16-
let spider = FirefoxVersionSpider::init()?;
17+
let spider = FirefoxVersionSpider::init(client)?;
1718
let matched_version_list = spider.find(version);
1819
let matched_version = matched_version_list
1920
.first()
2021
.ok_or_else(|| anyhow!("No matched version found"))?;
2122

22-
let zip_content = download_firefox_zip(matched_version, "win64").or_else(|err| {
23+
let zip_content = download_firefox_zip(matched_version, "win64", client).or_else(|err| {
2324
println!("==> download firefox win64 failed: {err}, trying win32 ...");
24-
download_firefox_zip(matched_version, "win32")
25+
download_firefox_zip(matched_version, "win32", client)
2526
})?;
2627

2728
let base_path = cur_dir.join(format!(".tmp-firefox-{matched_version}"));
@@ -46,13 +47,13 @@ pub(crate) fn download_firefox(version: &str) -> Result<()> {
4647
Ok(())
4748
}
4849

49-
fn download_firefox_zip(version: &str, arch: &str) -> Result<Bytes> {
50+
fn download_firefox_zip(version: &str, arch: &str, client: &Client) -> Result<Bytes> {
5051
let cur_dir = current_dir()?;
5152
let url = format!(
5253
"https://ftp.mozilla.org/pub/firefox/releases/{version}/{arch}/zh-CN/Firefox%20Setup%20{version}.exe"
5354
);
5455
println!("==> download firefox: {url}");
55-
let response = reqwest::blocking::get(url)?;
56+
let response = client.get(url).send()?;
5657
if !response.status().is_success() {
5758
return Err(anyhow!("Download firefox failed: {}", response.status()));
5859
}
@@ -75,16 +76,18 @@ fn download_firefox_zip(version: &str, arch: &str) -> Result<Bytes> {
7576
struct FirefoxVersionSpider(Vec<String>);
7677

7778
impl FirefoxVersionSpider {
78-
fn init() -> Result<Self> {
79+
fn init(client: &Client) -> Result<Self> {
7980
let cached_releases_path = get_cached_file_path("firefox-releases.json")?;
8081
if cached_releases_path.exists() {
8182
println!("==> using cached firefox releases");
8283
let releases = serde_json::from_reader(std::fs::File::open(cached_releases_path)?)?;
8384
Ok(Self(releases))
8485
} else {
8586
println!("==> fetching firefox releases from ftp.mozilla.org ...");
86-
let response =
87-
reqwest::blocking::get("https://ftp.mozilla.org/pub/firefox/releases/")?.text()?;
87+
let response = client
88+
.get("https://ftp.mozilla.org/pub/firefox/releases/")
89+
.send()?
90+
.text()?;
8891
let doc = Document::from(response.as_str());
8992
let releases = doc
9093
.find(

0 commit comments

Comments
 (0)