1use std::{convert::TryInto, sync::Arc, time::Duration};
6
7use once_cell::sync::Lazy;
8use serde::de::DeserializeOwned;
9use surf::*;
10
11use crate::prelude::*;
12
13#[allow(dead_code)]
14fn logger(
15 req: Request,
16 client: Client,
17 next: middleware::Next,
18) -> futures::future::BoxFuture<Result<Response>> {
19 Box::pin(async move {
20 let url = req.url().to_string();
21 let should_log = std::env::var("SCL_HTTP_LOG")
22 .map(|x| &x == "true")
23 .unwrap_or(false);
24 if should_log {
25 println!("[SCL-Core-HTTP] 正在请求 {url}");
26 }
27 let res = next.run(req, client).await?;
28 if let Some(content_type) = res.content_type() {
29 if should_log {
30 println!(
31 "[SCL-Core-HTTP] 请求 {} 完成 状态码:{} 响应类型:{}",
32 url,
33 res.status(),
34 content_type
35 );
36 if res.status().is_redirection() {
37 println!(
38 "[SCL-Core-HTTP] 正在重定向至 {}",
39 res.header("Location").map(|x| x.as_str()).unwrap_or("")
40 );
41 }
42 }
43 } else if should_log {
44 println!(
45 "[SCL-Core-HTTP] 请求 {} 完成 状态码:{} 响应类型:无",
46 url,
47 res.status()
48 );
49 if res.status().is_redirection() {
50 println!(
51 "[SCL-Core-HTTP] 正在重定向至 {}",
52 res.header("Location").map(|x| x.as_str()).unwrap_or("")
53 );
54 }
55 }
56 Ok(res)
57 })
58}
59
60static GLOBAL_CLIENT: Lazy<Arc<Client>> = Lazy::new(|| {
61 let client = Config::new()
62 .add_header(
63 "User-Agent",
64 "github.com/Steve-xmh/SharpCraftLauncher (stevexmh@qq.com)",
65 )
66 .unwrap()
67 .set_timeout(Some(Duration::from_secs(30)));
68 let client = if let Ok(mut proxy) = std::env::var("HTTP_PROXY") {
69 let proxy = if proxy.ends_with('/') {
70 proxy
71 } else {
72 proxy.push('/');
73 proxy
74 };
75 if let Ok(uri) = url::Url::parse(&proxy) {
76 println!("Using http proxy: {uri}");
77 client.set_base_url(uri)
78 } else {
79 client
80 }
81 } else {
82 client
83 };
84 let client: Client = client.try_into().unwrap();
85 Arc::new(client.with(middleware::Redirect::default()))
86});
87
88pub async fn retry_future<O, F: std::future::Future<Output = O>>(
92 max_retries: usize,
93 future_builder: impl Fn() -> F,
94 error_handler: impl Fn(&O) -> bool,
95) -> DynResult<O> {
96 let mut retries = 0;
97 loop {
98 retries += 1;
99 let f = future_builder();
100 let r = f.await;
101 if error_handler(&r) || retries >= max_retries {
102 return Ok(r);
103 }
104 }
105}
106
107pub async fn download(
113 uris: &[impl AsRef<str> + std::fmt::Debug],
114 dest_path: &str,
115 _size: usize,
116) -> DynResult {
117 for uri in uris {
118 let res = retry_future(5, || get(uri), surf::Result::is_ok).await;
120 match res {
121 Ok(Ok(res)) => {
122 if res.status().is_success() {
123 let tmp_dest_path = format!("{dest_path}.tmp");
124 let tmp_file = inner_future::fs::OpenOptions::new()
125 .create(true)
126 .write(true)
127 .truncate(true)
128 .open(&tmp_dest_path)
129 .await?;
130 if inner_future::io::copy(res, tmp_file).await.is_ok() {
131 inner_future::fs::rename(tmp_dest_path, dest_path).await?;
132 return Ok(());
133 }
134 } else {
135 println!("Error {:?} 状态码错误 {}", uri, res.status());
136 }
137 }
138 Ok(Err(e)) => {
139 println!("Error {uri:?} {e}")
140 }
141 Err(e) => {
142 println!("Error {uri:?} {e}")
143 }
144 }
145 }
146 anyhow::bail!(
147 "轮询下载文件到 {} 失败,请检查你的网络连接,已尝试的链接 {:?}",
148 dest_path,
149 uris
150 )
151}
152
153pub async fn retry_get_json<D: DeserializeOwned>(uri: impl AsRef<str>) -> DynResult<D> {
157 let res = retry_future(5, || get(uri.as_ref()).recv_json(), surf::Result::is_ok).await;
158 let err = match res {
159 Ok(Ok(body)) => return Ok(body),
160 Ok(Err(e)) => {
161 anyhow::anyhow!("{}", e)
162 }
163 Err(e) => e,
164 };
165 anyhow::bail!(
166 "轮询请求链接 {} 失败,请检查你的网络连接:{}",
167 uri.as_ref(),
168 err
169 )
170}
171
172pub async fn retry_get_bytes(uri: impl AsRef<str>) -> DynResult<Vec<u8>> {
174 let res = retry_future(5, || get(uri.as_ref()).recv_bytes(), surf::Result::is_ok).await;
175 let err = match res {
176 Ok(Ok(body)) => return Ok(body),
177 Ok(Err(e)) => {
178 anyhow::anyhow!("{}", e)
179 }
180 Err(e) => e,
181 };
182 anyhow::bail!(
183 "轮询请求链接 {} 失败,请检查你的网络连接:{}",
184 uri.as_ref(),
185 err
186 )
187}
188
189pub async fn retry_get_string(uri: impl AsRef<str>) -> DynResult<String> {
191 let res = retry_future(5, || get(uri.as_ref()).recv_string(), surf::Result::is_ok).await;
192 let err = match res {
193 Ok(Ok(body)) => return Ok(body),
194 Ok(Err(e)) => {
195 anyhow::anyhow!("{}", e)
196 }
197 Err(e) => e,
198 };
199 anyhow::bail!(
200 "轮询请求链接 {} 失败,请检查你的网络连接:{}",
201 uri.as_ref(),
202 err
203 )
204}
205
206pub async fn retry_get(uri: impl AsRef<str>) -> DynResult<Response> {
210 let res = retry_future(5, || get(uri.as_ref()), surf::Result::is_ok).await;
211 let err = match res {
212 Ok(Ok(body)) => return Ok(body),
213 Ok(Err(e)) => {
214 anyhow::anyhow!(
215 "{}: {}",
216 e,
217 e.backtrace().map(|x| x.to_string()).unwrap_or_default()
218 )
219 }
220 Err(e) => e,
221 };
222 anyhow::bail!(
223 "轮询请求链接 {} 失败,请检查你的网络连接:{}",
224 uri.as_ref(),
225 err
226 )
227}
228
229pub fn get(uri: impl AsRef<str>) -> RequestBuilder {
231 GLOBAL_CLIENT.get(uri)
232}
233
234pub fn post(uri: impl AsRef<str>) -> RequestBuilder {
236 GLOBAL_CLIENT.post(uri)
237}
238
239#[derive(Debug, Clone)]
241pub enum RequestResult<T> {
242 Ok(T),
244 Err(crate::auth::structs::mojang::ErrorResponse),
246}
247
248pub mod no_retry {
250 use serde::{de::DeserializeOwned, Serialize};
251 pub use surf::get;
252
253 use super::RequestResult;
254 use crate::prelude::DynResult;
255
256 pub async fn get_data<D: DeserializeOwned>(uri: &str) -> DynResult<RequestResult<D>> {
260 let result = surf::get(uri)
261 .middleware(surf::middleware::Redirect::default())
262 .recv_string()
263 .await
264 .map_err(|e| anyhow::anyhow!("无法接收来自 {} 的响应:{:?}", uri, e))?;
265 if let Ok(result) = serde_json::from_str(&result) {
266 Ok(RequestResult::Ok(result))
267 } else {
268 let result = serde_json::from_str(&result)?;
269 Ok(RequestResult::Err(result))
270 }
271 }
272
273 pub async fn post_data<D: DeserializeOwned, S: Serialize + std::fmt::Debug>(
279 uri: &str,
280 body: &S,
281 ) -> DynResult<RequestResult<D>> {
282 let result = surf::post(uri)
283 .header("Content-Type", "application/json; charset=utf-8")
284 .body_json(body)
285 .map_err(|e| anyhow::anyhow!("无法解析请求主体给 {}:{:?}", uri, e))?
286 .recv_string()
287 .await
288 .map_err(|e| anyhow::anyhow!("无法接收来自 {} 的响应:{:?}", uri, e))?;
289 if let Ok(result) = serde_json::from_str(&result) {
290 Ok(RequestResult::Ok(result))
291 } else {
292 let result = serde_json::from_str(&result)?;
293 Ok(RequestResult::Err(result))
294 }
295 }
296}