Skip to content

Commit

Permalink
Break up Client trait
Browse files Browse the repository at this point in the history
  • Loading branch information
Zertsov committed Feb 14, 2024
1 parent a711383 commit 6701c71
Show file tree
Hide file tree
Showing 5 changed files with 212 additions and 175 deletions.
187 changes: 97 additions & 90 deletions crates/turborepo-api-client/src/lib.rs
Expand Up @@ -44,41 +44,45 @@ pub trait Client {
) -> Result<CachingStatusResponse>;
async fn get_spaces(&self, token: &str, team_id: Option<&str>) -> Result<SpacesResponse>;
async fn verify_sso_token(&self, token: &str, token_name: &str) -> Result<VerifiedSsoUser>;
#[allow(clippy::too_many_arguments)]
async fn put_artifact(
async fn handle_403(response: Response) -> Error;
fn make_url(&self, endpoint: &str) -> Result<Url>;
}

#[async_trait]
pub trait ArtifactClient {
async fn get_artifact(
&self,
hash: &str,
artifact_body: &[u8],
duration: u64,
tag: Option<&str>,
token: &str,
team_id: Option<&str>,
team_slug: Option<&str>,
) -> Result<()>;
async fn handle_403(response: Response) -> Error;
method: Method,
) -> Result<Option<Response>>;
async fn fetch_artifact(
&self,
hash: &str,
token: &str,
team_id: Option<&str>,
team_slug: Option<&str>,
) -> Result<Option<Response>>;
async fn artifact_exists(
#[allow(clippy::too_many_arguments)]
async fn put_artifact(
&self,
hash: &str,
artifact_body: &[u8],
duration: u64,
tag: Option<&str>,
token: &str,
team_id: Option<&str>,
team_slug: Option<&str>,
) -> Result<Option<Response>>;
async fn get_artifact(
) -> Result<()>;
async fn artifact_exists(
&self,
hash: &str,
token: &str,
team_id: Option<&str>,
team_slug: Option<&str>,
method: Method,
) -> Result<Option<Response>>;
fn make_url(&self, endpoint: &str) -> Result<Url>;
}

#[derive(Clone)]
Expand Down Expand Up @@ -220,64 +224,6 @@ impl Client for APIClient {
})
}

#[tracing::instrument(skip_all)]
async fn put_artifact(
&self,
hash: &str,
artifact_body: &[u8],
duration: u64,
tag: Option<&str>,
token: &str,
team_id: Option<&str>,
team_slug: Option<&str>,
) -> Result<()> {
let mut request_url = self.make_url(&format!("/v8/artifacts/{}", hash))?;
let mut allow_auth = true;

if self.use_preflight {
let preflight_response = self
.do_preflight(
token,
request_url.clone(),
"PUT",
"Authorization, Content-Type, User-Agent, x-artifact-duration, x-artifact-tag",
)
.await?;

allow_auth = preflight_response.allow_authorization_header;
request_url = preflight_response.location.clone();
}

let mut request_builder = self
.client
.put(request_url)
.header("Content-Type", "application/octet-stream")
.header("x-artifact-duration", duration.to_string())
.header("User-Agent", self.user_agent.clone())
.body(artifact_body.to_vec());

if allow_auth {
request_builder = request_builder.header("Authorization", format!("Bearer {}", token));
}

request_builder = Self::add_team_params(request_builder, team_id, team_slug);

request_builder = Self::add_ci_header(request_builder);

if let Some(tag) = tag {
request_builder = request_builder.header("x-artifact-tag", tag);
}

let response = retry::make_retryable_request(request_builder).await?;

if response.status() == StatusCode::FORBIDDEN {
return Err(Self::handle_403(response).await);
}

response.error_for_status()?;
Ok(())
}

async fn handle_403(response: Response) -> Error {
#[derive(Deserialize)]
struct WrappedAPIError {
Expand Down Expand Up @@ -325,16 +271,57 @@ impl Client for APIClient {
}
}

#[tracing::instrument(skip_all)]
async fn fetch_artifact(
fn make_url(&self, endpoint: &str) -> Result<Url> {
let url = format!("{}{}", self.base_url, endpoint);
Url::parse(&url).map_err(|err| Error::InvalidUrl { url, err })
}
}

#[async_trait]
impl ArtifactClient for APIClient {
async fn get_artifact(
&self,
hash: &str,
token: &str,
team_id: Option<&str>,
team_slug: Option<&str>,
method: Method,
) -> Result<Option<Response>> {
self.get_artifact(hash, token, team_id, team_slug, Method::GET)
.await
let mut request_url = self.make_url(&format!("/v8/artifacts/{}", hash))?;
let mut allow_auth = true;

if self.use_preflight {
let preflight_response = self
.do_preflight(
token,
request_url.clone(),
"GET",
"Authorization, User-Agent",
)
.await?;

allow_auth = preflight_response.allow_authorization_header;
request_url = preflight_response.location;
};

let mut request_builder = self
.client
.request(method, request_url)
.header("User-Agent", self.user_agent.clone());

if allow_auth {
request_builder = request_builder.header("Authorization", format!("Bearer {}", token));
}

request_builder = Self::add_team_params(request_builder, team_id, team_slug);

let response = retry::make_retryable_request(request_builder).await?;

match response.status() {
StatusCode::FORBIDDEN => Err(Self::handle_403(response).await),
StatusCode::NOT_FOUND => Ok(None),
_ => Ok(Some(response.error_for_status()?)),
}
}

#[tracing::instrument(skip_all)]
Expand All @@ -349,14 +336,29 @@ impl Client for APIClient {
.await
}

async fn get_artifact(
#[tracing::instrument(skip_all)]
async fn fetch_artifact(
&self,
hash: &str,
token: &str,
team_id: Option<&str>,
team_slug: Option<&str>,
method: Method,
) -> Result<Option<Response>> {
self.get_artifact(hash, token, team_id, team_slug, Method::GET)
.await
}

#[tracing::instrument(skip_all)]
async fn put_artifact(
&self,
hash: &str,
artifact_body: &[u8],
duration: u64,
tag: Option<&str>,
token: &str,
team_id: Option<&str>,
team_slug: Option<&str>,
) -> Result<()> {
let mut request_url = self.make_url(&format!("/v8/artifacts/{}", hash))?;
let mut allow_auth = true;

Expand All @@ -365,38 +367,43 @@ impl Client for APIClient {
.do_preflight(
token,
request_url.clone(),
"GET",
"Authorization, User-Agent",
"PUT",
"Authorization, Content-Type, User-Agent, x-artifact-duration, x-artifact-tag",
)
.await?;

allow_auth = preflight_response.allow_authorization_header;
request_url = preflight_response.location;
};
request_url = preflight_response.location.clone();
}

let mut request_builder = self
.client
.request(method, request_url)
.header("User-Agent", self.user_agent.clone());
.put(request_url)
.header("Content-Type", "application/octet-stream")
.header("x-artifact-duration", duration.to_string())
.header("User-Agent", self.user_agent.clone())
.body(artifact_body.to_vec());

if allow_auth {
request_builder = request_builder.header("Authorization", format!("Bearer {}", token));
}

request_builder = Self::add_team_params(request_builder, team_id, team_slug);

request_builder = Self::add_ci_header(request_builder);

if let Some(tag) = tag {
request_builder = request_builder.header("x-artifact-tag", tag);
}

let response = retry::make_retryable_request(request_builder).await?;

match response.status() {
StatusCode::FORBIDDEN => Err(Self::handle_403(response).await),
StatusCode::NOT_FOUND => Ok(None),
_ => Ok(Some(response.error_for_status()?)),
if response.status() == StatusCode::FORBIDDEN {
return Err(Self::handle_403(response).await);
}
}

fn make_url(&self, endpoint: &str) -> Result<Url> {
let url = format!("{}{}", self.base_url, endpoint);
Url::parse(&url).map_err(|err| Error::InvalidUrl { url, err })
response.error_for_status()?;
Ok(())
}
}

Expand Down
42 changes: 1 addition & 41 deletions crates/turborepo-auth/src/auth/login.rs
Expand Up @@ -99,7 +99,7 @@ mod tests {
use std::{assert_matches::assert_matches, sync::atomic::AtomicUsize};

use async_trait::async_trait;
use reqwest::{Method, RequestBuilder, Response};
use reqwest::{RequestBuilder, Response};
use turborepo_api_client::Client;
use turborepo_ui::UI;
use turborepo_vercel_api::{
Expand Down Expand Up @@ -229,49 +229,9 @@ mod tests {
team_id: Some("team_id".to_string()),
})
}
async fn put_artifact(
&self,
_hash: &str,
_artifact_body: &[u8],
_duration: u64,
_tag: Option<&str>,
_token: &str,
_team_id: Option<&str>,
_team_slug: Option<&str>,
) -> turborepo_api_client::Result<()> {
unimplemented!("put_artifact")
}
async fn handle_403(_response: Response) -> turborepo_api_client::Error {
unimplemented!("handle_403")
}
async fn fetch_artifact(
&self,
_hash: &str,
_token: &str,
_team_id: Option<&str>,
_team_slug: Option<&str>,
) -> turborepo_api_client::Result<Option<Response>> {
unimplemented!("fetch_artifact")
}
async fn artifact_exists(
&self,
_hash: &str,
_token: &str,
_team_id: Option<&str>,
_team_slug: Option<&str>,
) -> turborepo_api_client::Result<Option<Response>> {
unimplemented!("artifact_exists")
}
async fn get_artifact(
&self,
_hash: &str,
_token: &str,
_team_id: Option<&str>,
_team_slug: Option<&str>,
_method: Method,
) -> turborepo_api_client::Result<Option<Response>> {
unimplemented!("get_artifact")
}
fn make_url(&self, endpoint: &str) -> turborepo_api_client::Result<Url> {
let url = format!("{}{}", self.base_url, endpoint);
Url::parse(&url).map_err(|err| turborepo_api_client::Error::InvalidUrl { url, err })
Expand Down
42 changes: 1 addition & 41 deletions crates/turborepo-auth/src/auth/sso.rs
Expand Up @@ -126,7 +126,7 @@ mod tests {
use std::sync::atomic::AtomicUsize;

use async_trait::async_trait;
use reqwest::{Method, RequestBuilder, Response};
use reqwest::{RequestBuilder, Response};
use turborepo_api_client::Client;
use turborepo_ui::UI;
use turborepo_vercel_api::{
Expand Down Expand Up @@ -245,49 +245,9 @@ mod tests {
team_id: Some("team_id".to_string()),
})
}
async fn put_artifact(
&self,
_hash: &str,
_artifact_body: &[u8],
_duration: u64,
_tag: Option<&str>,
_token: &str,
_team_id: Option<&str>,
_team_slug: Option<&str>,
) -> turborepo_api_client::Result<()> {
unimplemented!("put_artifact")
}
async fn handle_403(_response: Response) -> turborepo_api_client::Error {
unimplemented!("handle_403")
}
async fn fetch_artifact(
&self,
_hash: &str,
_token: &str,
_team_id: Option<&str>,
_team_slug: Option<&str>,
) -> turborepo_api_client::Result<Option<Response>> {
unimplemented!("fetch_artifact")
}
async fn artifact_exists(
&self,
_hash: &str,
_token: &str,
_team_id: Option<&str>,
_team_slug: Option<&str>,
) -> turborepo_api_client::Result<Option<Response>> {
unimplemented!("artifact_exists")
}
async fn get_artifact(
&self,
_hash: &str,
_token: &str,
_team_id: Option<&str>,
_team_slug: Option<&str>,
_method: Method,
) -> turborepo_api_client::Result<Option<Response>> {
unimplemented!("get_artifact")
}
fn make_url(&self, endpoint: &str) -> turborepo_api_client::Result<Url> {
let url = format!("{}{}", self.base_url, endpoint);
Url::parse(&url).map_err(|err| turborepo_api_client::Error::InvalidUrl { url, err })
Expand Down

0 comments on commit 6701c71

Please sign in to comment.