mirror of
https://github.com/cargo-bins/cargo-binstall.git
synced 2025-06-17 08:06:38 +00:00
Refactor: Extract new fn GhApiClient::do_fetch
Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
This commit is contained in:
parent
361aca4d8f
commit
1350ac342f
3 changed files with 66 additions and 87 deletions
|
@ -1,5 +1,6 @@
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
|
future::Future,
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicBool, Ordering::Relaxed},
|
atomic::{AtomicBool, Ordering::Relaxed},
|
||||||
|
@ -132,19 +133,57 @@ impl GhApiClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GhApiClient {
|
impl GhApiClient {
|
||||||
async fn do_fetch_release_artifacts(
|
fn check_retry_after(&self) -> Result<(), GhApiError> {
|
||||||
&self,
|
let mut guard = self.0.retry_after.lock().unwrap();
|
||||||
release: &GhRelease,
|
|
||||||
auth_token: Option<&str>,
|
if let Some(retry_after) = *guard {
|
||||||
) -> Result<Option<release_artifacts::Artifacts>, GhApiError> {
|
if retry_after.elapsed().is_zero() {
|
||||||
match release_artifacts::fetch_release_artifacts(&self.0.client, release, auth_token).await
|
return Err(GhApiError::RateLimit {
|
||||||
{
|
retry_after: Some(retry_after - Instant::now()),
|
||||||
Ok(artifacts) => Ok(Some(artifacts)),
|
});
|
||||||
Err(GhApiError::NotFound) => Ok(None),
|
} else {
|
||||||
Err(err) => Err(err),
|
// Instant retry_after is already reached.
|
||||||
|
*guard = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
async fn do_fetch<T, U, GraphQLFn, RestfulFn, GraphQLFut, RestfulFut>(
|
||||||
|
&self,
|
||||||
|
graphql_func: GraphQLFn,
|
||||||
|
restful_func: RestfulFn,
|
||||||
|
data: &T,
|
||||||
|
) -> Result<U, GhApiError>
|
||||||
|
where
|
||||||
|
GraphQLFn: Fn(&remote::Client, &T, &str) -> GraphQLFut,
|
||||||
|
RestfulFn: Fn(&remote::Client, &T, Option<&str>) -> RestfulFut,
|
||||||
|
GraphQLFut: Future<Output = Result<U, GhApiError>> + Send + Sync + 'static,
|
||||||
|
RestfulFut: Future<Output = Result<U, GhApiError>> + Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
self.check_retry_after()?;
|
||||||
|
|
||||||
|
if self.0.is_auth_token_valid.load(Relaxed) {
|
||||||
|
if let Some(auth_token) = self.0.auth_token.as_deref() {
|
||||||
|
match graphql_func(&self.0.client, data, auth_token).await {
|
||||||
|
Err(GhApiError::Unauthorized) => {
|
||||||
|
self.0.is_auth_token_valid.store(false, Relaxed);
|
||||||
|
}
|
||||||
|
res => return res.map_err(|err| err.context("GraphQL API")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match restful_func(&self.0.client, data, self.0.auth_token.as_deref()).await {
|
||||||
|
Err(GhApiError::Unauthorized) => {
|
||||||
|
self.0.is_auth_token_valid.store(false, Relaxed);
|
||||||
|
restful_func(&self.0.client, data, None).await
|
||||||
|
}
|
||||||
|
res => res,
|
||||||
|
}
|
||||||
|
.map_err(|err| err.context("Restful API"))
|
||||||
|
}
|
||||||
|
|
||||||
/// Return `Ok(Some(api_artifact_url))` if exists.
|
/// Return `Ok(Some(api_artifact_url))` if exists.
|
||||||
///
|
///
|
||||||
/// The returned future is guaranteed to be pointer size.
|
/// The returned future is guaranteed to be pointer size.
|
||||||
|
@ -159,34 +198,18 @@ impl GhApiClient {
|
||||||
let res = once_cell
|
let res = once_cell
|
||||||
.get_or_try_init(|| {
|
.get_or_try_init(|| {
|
||||||
Box::pin(async {
|
Box::pin(async {
|
||||||
{
|
|
||||||
let mut guard = self.0.retry_after.lock().unwrap();
|
|
||||||
|
|
||||||
if let Some(retry_after) = *guard {
|
|
||||||
if retry_after.elapsed().is_zero() {
|
|
||||||
return Err(GhApiError::RateLimit {
|
|
||||||
retry_after: Some(retry_after - Instant::now()),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// Instant retry_after is already reached.
|
|
||||||
*guard = None;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.0.is_auth_token_valid.load(Relaxed) {
|
|
||||||
match self
|
match self
|
||||||
.do_fetch_release_artifacts(&release, self.0.auth_token.as_deref())
|
.do_fetch(
|
||||||
|
release_artifacts::fetch_release_artifacts_graphql_api,
|
||||||
|
release_artifacts::fetch_release_artifacts_restful_api,
|
||||||
|
&release,
|
||||||
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Err(GhApiError::Unauthorized) => {
|
Ok(artifacts) => Ok(Some(artifacts)),
|
||||||
self.0.is_auth_token_valid.store(false, Relaxed);
|
Err(GhApiError::NotFound) => Ok(None),
|
||||||
|
Err(err) => Err(err),
|
||||||
}
|
}
|
||||||
res => return res,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.do_fetch_release_artifacts(&release, None).await
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
|
|
@ -11,7 +11,7 @@ use compact_str::{CompactString, ToCompactString};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
common::{issue_graphql_query, issue_restful_api, percent_encode_http_url_path},
|
common::{issue_graphql_query, issue_restful_api},
|
||||||
GhApiError, GhRelease, GhRepo,
|
GhApiError, GhRelease, GhRepo,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ impl Artifacts {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_release_artifacts_restful_api(
|
pub(super) fn fetch_release_artifacts_restful_api(
|
||||||
client: &remote::Client,
|
client: &remote::Client,
|
||||||
GhRelease {
|
GhRelease {
|
||||||
repo: GhRepo { owner, repo },
|
repo: GhRepo { owner, repo },
|
||||||
|
@ -130,7 +130,7 @@ impl fmt::Display for FilterCondition {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_release_artifacts_graphql_api(
|
pub(super) fn fetch_release_artifacts_graphql_api(
|
||||||
client: &remote::Client,
|
client: &remote::Client,
|
||||||
GhRelease {
|
GhRelease {
|
||||||
repo: GhRepo { owner, repo },
|
repo: GhRepo { owner, repo },
|
||||||
|
@ -192,25 +192,3 @@ releaseAssets({cond}) {{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) async fn fetch_release_artifacts(
|
|
||||||
client: &remote::Client,
|
|
||||||
release: &GhRelease,
|
|
||||||
auth_token: Option<&str>,
|
|
||||||
) -> Result<Artifacts, GhApiError> {
|
|
||||||
if let Some(auth_token) = auth_token {
|
|
||||||
let res = fetch_release_artifacts_graphql_api(client, release, auth_token)
|
|
||||||
.await
|
|
||||||
.map_err(|err| err.context("GraphQL API"));
|
|
||||||
|
|
||||||
match res {
|
|
||||||
// Fallback to Restful API
|
|
||||||
Err(GhApiError::Unauthorized) => (),
|
|
||||||
res => return res,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fetch_release_artifacts_restful_api(client, release, auth_token)
|
|
||||||
.await
|
|
||||||
.map_err(|err| err.context("Restful API"))
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use compact_str::{CompactString, ToCompactString};
|
use compact_str::CompactString;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
common::{issue_graphql_query, issue_restful_api, percent_encode_http_url_path},
|
common::{issue_graphql_query, issue_restful_api},
|
||||||
remote, GhApiError, GhRepo,
|
remote, GhApiError, GhRepo,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ impl RepoInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn fetch_repo_info_restful_api(
|
pub(super) async fn fetch_repo_info_restful_api(
|
||||||
client: &remote::Client,
|
client: &remote::Client,
|
||||||
GhRepo { owner, repo }: &GhRepo,
|
GhRepo { owner, repo }: &GhRepo,
|
||||||
auth_token: Option<&str>,
|
auth_token: Option<&str>,
|
||||||
|
@ -44,7 +44,7 @@ struct GraphQLData {
|
||||||
repository: Option<RepoInfo>,
|
repository: Option<RepoInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn fetch_repo_info_graphql_api(
|
pub(super) async fn fetch_repo_info_graphql_api(
|
||||||
client: &remote::Client,
|
client: &remote::Client,
|
||||||
GhRepo { owner, repo }: &GhRepo,
|
GhRepo { owner, repo }: &GhRepo,
|
||||||
auth_token: &str,
|
auth_token: &str,
|
||||||
|
@ -64,25 +64,3 @@ query {{
|
||||||
|
|
||||||
issue_graphql_query(client, query, auth_token).await
|
issue_graphql_query(client, query, auth_token).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) async fn fetch_repo_info(
|
|
||||||
client: &remote::Client,
|
|
||||||
repo: &GhRepo,
|
|
||||||
auth_token: Option<&str>,
|
|
||||||
) -> Result<RepoInfo, GhApiError> {
|
|
||||||
if let Some(auth_token) = auth_token {
|
|
||||||
let res = fetch_repo_info_graphql_api(client, repo, auth_token)
|
|
||||||
.await
|
|
||||||
.map_err(|err| err.context("GraphQL API"));
|
|
||||||
|
|
||||||
match res {
|
|
||||||
// Fallback to Restful API
|
|
||||||
Err(GhApiError::Unauthorized) => (),
|
|
||||||
res => return res,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fetch_repo_info_restful_api(client, repo, auth_token)
|
|
||||||
.await
|
|
||||||
.map_err(|err| err.context("Restful API"))
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue