pub mod whoami;
use reqwest::blocking::{Client, RequestBuilder, Response};
use reqwest::header::AUTHORIZATION;
use std::time::Duration;
use crate::auth::ApiKey;
use crate::error::{Result, ToriiError};
const UA: &str = concat!("torii/", env!("CARGO_PKG_VERSION"));
pub struct CloudClient {
http: Client,
key: ApiKey,
}
impl CloudClient {
pub fn new(key: ApiKey) -> Self {
let http = Client::builder()
.user_agent(UA)
.timeout(Duration::from_secs(15))
.build()
.expect("reqwest client builds");
Self { http, key }
}
pub fn endpoint(&self) -> &str {
&self.key.endpoint
}
fn url(&self, path: &str) -> String {
format!("{}{}", self.key.endpoint.trim_end_matches('/'), path)
}
fn get(&self, path: &str) -> RequestBuilder {
self.http
.get(self.url(path))
.header(AUTHORIZATION, format!("Bearer {}", self.key.key))
}
#[allow(dead_code)] fn post(&self, path: &str) -> RequestBuilder {
self.http
.post(self.url(path))
.header(AUTHORIZATION, format!("Bearer {}", self.key.key))
}
}
pub(crate) fn check_status(resp: Response) -> Result<Response> {
let status = resp.status();
if status.is_success() {
return Ok(resp);
}
let body = resp.text().unwrap_or_default();
let msg = match status.as_u16() {
401 => "API key rejected. Run `torii auth login` to refresh.".to_string(),
402 => format!(
"your plan does not include this feature. Upgrade at https://gitorii.com/upgrade ({})",
short_body(&body)
),
403 => "organization suspended. Contact support@gitorii.com.".to_string(),
404 => "endpoint not found — CLI may be outdated.".to_string(),
s if (500..=599).contains(&s) => format!("server error {}: {}", s, short_body(&body)),
s => format!("unexpected HTTP {}: {}", s, short_body(&body)),
};
Err(ToriiError::InvalidConfig(msg))
}
fn short_body(body: &str) -> String {
let trimmed = body.trim();
if trimmed.chars().count() > 200 {
let head: String = trimmed.chars().take(200).collect();
format!("{}…", head)
} else {
trimmed.to_string()
}
}