txtx-cloud 0.1.14

Crate for interacting with txtx Cloud Services
Documentation
use serde::Deserialize;
use serde_json::json;
use txtx_addon_kit::{reqwest, uuid::Uuid};

pub async fn fetch_svm_workspaces(
    access_token: &str,
    service_gql_url: &str,
) -> Result<Vec<Workspace>, String> {
    let client = reqwest::Client::new();
    let max_attempts = 3;
    let mut attempts = 0;
    loop {
        attempts += 1;
        let res = client
            .post(service_gql_url)
            .bearer_auth(access_token)
            .json(&json!({
                "query": r#"
                    query GetWorkspaces {
                        svm_workspaces {
                            name
                            id
                        }
                    }
                "#.to_string(),
            }))
            .send()
            .await
            .map_err(|e| e.to_string())?;

        if !res.status().is_success() {
            let err = res.text().await.unwrap_or_else(|_| "Unknown error".to_string());
            return Err(format!("received error from server: {}", err));
        }

        let response: GqlResponse<WorkspaceResponse> =
            res.json().await.map_err(|e| format!("failed to parse response: {}", e))?;

        if let Some(workspace_response) = response.data {
            return Ok(workspace_response.svm_workspaces.clone());
        } else {
            if attempts >= max_attempts {
                return Err("no workspaces found for user after multiple attempts".to_string());
            }
            tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
        }
    }
}

pub async fn get_workspace_id(
    workspace_name: &str,
    access_token: &str,
    service_gql_url: &str,
) -> Result<Workspace, String> {
    let client = reqwest::Client::new();
    let res = client
        .post(service_gql_url)
        .bearer_auth(access_token)
        .json(&json!({
            "query": r#"
                query GetWorkspaceByName($_eq: String = "") {
                    svm_workspaces(where: {name: {_eq: $_eq}}) {
                        name
                        id
                    }
                }
            "#.to_string(),
            "variables": {
                "_eq": workspace_name
            }
        }))
        .send()
        .await
        .map_err(|e| e.to_string())?;

    if !res.status().is_success() {
        let err = res.text().await.unwrap_or_else(|_| "Unknown error".to_string());
        return Err(format!("received error from server: {}", err));
    }

    let response: GqlResponse<WorkspaceResponse> =
        res.json().await.map_err(|e| format!("failed to parse response: {}", e))?;

    if let Some(workspace_response) = response.data {
        if workspace_response.svm_workspaces.is_empty() {
            return Err(format!("workspace '{}' not found", workspace_name));
        }
        Ok(workspace_response.svm_workspaces[0].clone())
    } else {
        Err("No data returned from server".to_string())
    }
}

#[derive(Debug, Clone, Deserialize)]
pub struct GqlResponse<T> {
    pub data: Option<T>,
}

#[derive(Debug, Clone, Deserialize)]
pub struct WorkspaceResponse {
    pub svm_workspaces: Vec<Workspace>,
}

#[derive(Debug, Clone, Deserialize)]
pub struct Workspace {
    pub id: Uuid,
    pub name: String,
}