Skip to content

Commit

Permalink
Merge pull request #49 from kariy/save-account-info-in-credentials
Browse files Browse the repository at this point in the history
refactor: extra account info in credentials
  • Loading branch information
tarrencev authored May 29, 2024
2 parents 937ca9f + c01645e commit 7b9661b
Show file tree
Hide file tree
Showing 15 changed files with 220 additions and 101 deletions.
109 changes: 74 additions & 35 deletions src/api.rs
Original file line number Diff line number Diff line change
@@ -1,59 +1,98 @@
use graphql_client::Response;
use serde::{de::DeserializeOwned, Serialize};
use reqwest::RequestBuilder;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use url::Url;

use crate::credential::Credentials;
use crate::{constant, credential::AccessToken};

#[derive(Debug, thiserror::Error)]
pub enum ApiError {
pub enum Error {
#[error(transparent)]
ReqwestError(reqwest::Error),
#[error(transparent)]
CredentialsError(anyhow::Error),
ReqwestError(#[from] reqwest::Error),
#[error("Invalid token, authenticate with `slot auth login`")]
Unauthorized,
}

pub struct ApiClient {
base_url: String,
#[derive(Debug)]
pub struct Client {
base_url: Url,
client: reqwest::Client,
access_token: Option<AccessToken>,
}

impl ApiClient {
impl Client {
pub fn new() -> Self {
Self {
base_url: "https://api.cartridge.gg/query".to_string(),
access_token: None,
client: reqwest::Client::new(),
base_url: Url::parse(constant::CARTRIDGE_API_URL).expect("valid url"),
}
}

pub async fn post<R: DeserializeOwned, T: Serialize + ?Sized>(
&self,
body: &T,
) -> Result<Response<R>, ApiError> {
let credentials = Credentials::load()
.map_err(|_| {
anyhow::anyhow!("Failed to load credentials. Login with `slot auth login`.")
})
.map_err(ApiError::CredentialsError)?;

let res = self
.client
.post(&self.base_url)
.header(
"Authorization",
format!("Bearer {}", credentials.access_token),
)
pub fn new_with_token(token: AccessToken) -> Self {
let mut client = Self::new();
client.set_token(token);
client
}

pub fn set_token(&mut self, token: AccessToken) {
self.access_token = Some(token);
}

pub async fn query<R, T>(&self, body: &T) -> Result<Response<R>, Error>
where
R: DeserializeOwned,
T: Serialize + ?Sized,
{
let path = "/query";
let token = self.access_token.as_ref().map(|t| t.token.as_str());

// TODO: return this as an error if token is None
let bearer = format!("Bearer {}", token.unwrap_or_default());

let response = self
.post(path)
.header("Authorization", bearer)
.json(body)
.send()
.await
.map_err(ApiError::ReqwestError)?;
.await?;

if response.status() == 403 {
return Err(Error::Unauthorized);
}

Ok(response.json().await?)
}

if res.status() == 403 {
return Err(ApiError::CredentialsError(anyhow::anyhow!(
"Invalid token, authenticate with `slot auth login`"
)));
pub async fn oauth2(&self, code: &str) -> Result<AccessToken, Error> {
#[derive(Deserialize)]
struct OauthToken {
#[serde(rename(deserialize = "access_token"))]
token: String,
#[serde(rename(deserialize = "token_type"))]
r#type: String,
}

let res: Response<R> = res.json().await.map_err(ApiError::ReqwestError)?;
let path = "/oauth2/token";
let form = [("code", code)];

let response = self.post(path).form(&form).send().await?;
let token: OauthToken = response.json().await?;

Ok(AccessToken {
token: token.token,
r#type: token.r#type,
})
}

fn post(&self, path: &str) -> RequestBuilder {
let url = self.get_url(path);
self.client.post(url)
}

Ok(res)
fn get_url(&self, path: &str) -> Url {
let mut url = self.base_url.clone();
url.path_segments_mut().unwrap().extend(path.split('/'));
url
}
}
7 changes: 6 additions & 1 deletion src/command/auth/info.graphql
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
query Me {
me {
id
contractAddress
name
contractAddress
credentials {
webauthn {
publicKey
}
}
}
}
14 changes: 8 additions & 6 deletions src/command/auth/info.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
use anyhow::Result;
use clap::Args;
use graphql_client::{GraphQLQuery, Response};
use me::{ResponseData, Variables};

use crate::api::ApiClient;

use self::me::{ResponseData, Variables};
use crate::{api::Client, credential::Credentials};

#[derive(GraphQLQuery)]
#[graphql(
schema_path = "schema.json",
query_path = "src/command/auth/info.graphql",
response_derives = "Debug"
response_derives = "Debug, Clone, Serialize"
)]
pub struct Me;

#[derive(Debug, Args)]
pub struct InfoArgs {}

impl InfoArgs {
// TODO: find the account info from `credentials.json` first before making a request
pub async fn run(&self) -> Result<()> {
let credentials = Credentials::load()?;
let client = Client::new_with_token(credentials.access_token);

let request_body = Me::build_query(Variables {});
let res: Response<ResponseData> = client.query(&request_body).await?;

let client = ApiClient::new();
let res: Response<ResponseData> = client.post(&request_body).await?;
if let Some(errors) = res.errors {
for err in errors {
println!("Error: {}", err.message);
Expand Down
2 changes: 1 addition & 1 deletion src/command/auth/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use clap::Subcommand;

use self::{info::InfoArgs, login::LoginArgs};

mod info;
pub mod info;
mod login;

#[derive(Subcommand, Debug)]
Expand Down
9 changes: 6 additions & 3 deletions src/command/deployments/accounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ use katana_primitives::genesis::Genesis;
use katana_primitives::genesis::{allocation::GenesisAccountAlloc, json::GenesisJson};
use std::str::FromStr;

use crate::api::ApiClient;
use crate::api::Client;
use crate::credential::Credentials;

use super::services::KatanaAccountCommands;

Expand Down Expand Up @@ -42,8 +43,10 @@ impl AccountsArgs {
project: self.project.clone(),
});

let client = ApiClient::new();
let res: Response<ResponseData> = client.post(&request_body).await?;
let user = Credentials::load()?;
let client = Client::new_with_token(user.access_token);

let res: Response<ResponseData> = client.query(&request_body).await?;
if let Some(errors) = res.errors.clone() {
for err in errors {
println!("Error: {}", err.message);
Expand Down
9 changes: 6 additions & 3 deletions src/command/deployments/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ use clap::Args;
use graphql_client::{GraphQLQuery, Response};

use crate::{
api::ApiClient,
api::Client,
command::deployments::create::create_deployment::{
CreateDeploymentCreateDeployment::{KatanaConfig, MadaraConfig, ToriiConfig},
CreateKatanaConfigInput, CreateMadaraConfigInput, CreateServiceConfigInput,
CreateServiceInput, CreateToriiConfigInput, DeploymentService, DeploymentTier, Variables,
},
credential::Credentials,
};

use super::{services::CreateServiceCommands, Long, Tier};
Expand Down Expand Up @@ -104,8 +105,10 @@ impl CreateArgs {
wait: Some(true),
});

let client = ApiClient::new();
let res: Response<create_deployment::ResponseData> = client.post(&request_body).await?;
let user = Credentials::load()?;
let client = Client::new_with_token(user.access_token);

let res: Response<create_deployment::ResponseData> = client.query(&request_body).await?;
if let Some(errors) = res.errors.clone() {
for err in errors {
println!("Error: {}", err.message);
Expand Down
9 changes: 6 additions & 3 deletions src/command/deployments/delete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ use clap::Args;
use graphql_client::{GraphQLQuery, Response};

use crate::{
api::ApiClient,
api::Client,
command::deployments::delete::delete_deployment::{DeploymentService, Variables},
credential::Credentials,
};

#[derive(GraphQLQuery)]
Expand Down Expand Up @@ -47,8 +48,10 @@ impl DeleteArgs {
service,
});

let client = ApiClient::new();
let res: Response<delete_deployment::ResponseData> = client.post(&request_body).await?;
let user = Credentials::load()?;
let client = Client::new_with_token(user.access_token);

let res: Response<delete_deployment::ResponseData> = client.query(&request_body).await?;
if let Some(errors) = res.errors.clone() {
for err in errors {
println!("Error: {}", err.message);
Expand Down
8 changes: 5 additions & 3 deletions src/command/deployments/describe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use anyhow::Result;
use clap::Args;
use graphql_client::{GraphQLQuery, Response};

use crate::api::ApiClient;
use crate::{api::Client, credential::Credentials};

use self::describe_deployment::{
DeploymentService,
Expand Down Expand Up @@ -47,8 +47,10 @@ impl DescribeArgs {
service,
});

let client = ApiClient::new();
let res: Response<ResponseData> = client.post(&request_body).await?;
let user = Credentials::load()?;
let client = Client::new_with_token(user.access_token);

let res: Response<ResponseData> = client.query(&request_body).await?;
if let Some(errors) = res.errors.clone() {
for err in errors {
println!("Error: {}", err.message);
Expand Down
9 changes: 6 additions & 3 deletions src/command/deployments/fork.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ use starknet::providers::{jsonrpc::HttpTransport, JsonRpcClient, Provider};
use url::Url;

use crate::{
api::ApiClient,
api::Client,
command::deployments::fork::fork_deployment::{
DeploymentTier, ForkDeploymentForkDeployment::KatanaConfig, Variables,
},
credential::Credentials,
};

use super::{services::ForkServiceCommands, Long, Tier};
Expand Down Expand Up @@ -53,8 +54,10 @@ impl ForkArgs {
wait: Some(true),
});

let client = ApiClient::new();
let res: Response<fork_deployment::ResponseData> = client.post(&request_body).await?;
let user = Credentials::load()?;
let client = Client::new_with_token(user.access_token);

let res: Response<fork_deployment::ResponseData> = client.query(&request_body).await?;
if let Some(errors) = res.errors.clone() {
for err in errors {
println!("Error: {}", err.message);
Expand Down
8 changes: 5 additions & 3 deletions src/command/deployments/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use anyhow::Result;
use clap::Args;
use graphql_client::{GraphQLQuery, Response};

use crate::api::ApiClient;
use crate::{api::Client, credential::Credentials};

use self::list_deployments::{ResponseData, Variables};

Expand All @@ -24,8 +24,10 @@ impl ListArgs {
pub async fn run(&self) -> Result<()> {
let request_body = ListDeployments::build_query(Variables {});

let client = ApiClient::new();
let res: Response<ResponseData> = client.post(&request_body).await?;
let user = Credentials::load()?;
let client = Client::new_with_token(user.access_token);

let res: Response<ResponseData> = client.query(&request_body).await?;
if let Some(errors) = res.errors.clone() {
for err in errors {
println!("Error: {}", err.message);
Expand Down
13 changes: 9 additions & 4 deletions src/command/deployments/logs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ use clap::Args;
use graphql_client::{GraphQLQuery, Response};
use tokio::time::sleep;

use crate::{api::ApiClient, command::deployments::logs::deployment_logs::DeploymentService};
use crate::{
api::Client, command::deployments::logs::deployment_logs::DeploymentService,
credential::Credentials,
};

use self::deployment_logs::{DeploymentLogsDeploymentLogs, ResponseData, Variables};

Expand Down Expand Up @@ -66,15 +69,17 @@ impl LogsArgs {
}

pub struct LogReader {
client: ApiClient,
client: Client,
service: Service,
project: String,
}

impl LogReader {
pub fn new(service: Service, project: String) -> Self {
let user = Credentials::load().unwrap();
let client = Client::new_with_token(user.access_token);
LogReader {
client: ApiClient::new(),
client,
service,
project,
}
Expand All @@ -98,7 +103,7 @@ impl LogReader {
limit: Some(limit),
});

let res: Response<ResponseData> = self.client.post(&request_body).await?;
let res: Response<ResponseData> = self.client.query(&request_body).await?;
if let Some(errors) = res.errors {
let error_message = errors
.into_iter()
Expand Down
Loading

0 comments on commit 7b9661b

Please sign in to comment.