Skip to main content

outlayer_cli/commands/
status.rs

1use anyhow::Result;
2
3use crate::api::ApiClient;
4use crate::config::{self, NetworkConfig, ProjectConfig};
5use crate::near::NearClient;
6
7/// `outlayer status [call_id]` — project info or poll async call
8pub async fn status(
9    network: &NetworkConfig,
10    project_config: &ProjectConfig,
11    call_id: Option<String>,
12) -> Result<()> {
13    if let Some(call_id) = call_id {
14        poll_call(network, project_config, &call_id).await
15    } else {
16        project_info(network, project_config).await
17    }
18}
19
20async fn project_info(network: &NetworkConfig, project_config: &ProjectConfig) -> Result<()> {
21    let near = NearClient::new(network);
22
23    let project_id = format!(
24        "{}/{}",
25        project_config.project.owner, project_config.project.name
26    );
27
28    let project = near.get_project(&project_id).await?;
29
30    match project {
31        Some(p) => {
32            println!("Project:  {}", p.project_id);
33            println!("UUID:     {}", p.uuid);
34            println!("Version:  {} (active)", p.active_version);
35            if let Some(deposit) = &p.storage_deposit {
36                let near_amount = deposit.parse::<u128>().unwrap_or(0) as f64 / 1e24;
37                println!("Storage:  {:.4} NEAR", near_amount);
38            }
39        }
40        None => {
41            eprintln!("Project not found: {project_id}");
42            eprintln!("Run 'outlayer deploy' to create it.");
43        }
44    }
45
46    Ok(())
47}
48
49async fn poll_call(
50    network: &NetworkConfig,
51    project_config: &ProjectConfig,
52    call_id: &str,
53) -> Result<()> {
54    let creds = config::load_credentials(network)?;
55    let api = ApiClient::new(network);
56
57    // Build payment key for auth
58    let payment_key = load_payment_key(&creds.account_id, project_config)?;
59
60    let response = api.get_call_result(call_id, &payment_key).await?;
61
62    println!("Call ID:  {}", response.call_id);
63    println!("Status:   {}", response.status);
64
65    if let Some(output) = &response.output {
66        println!(
67            "Output:   {}",
68            serde_json::to_string_pretty(output).unwrap_or_else(|_| output.to_string())
69        );
70    }
71    if let Some(error) = &response.error {
72        println!("Error:    {error}");
73    }
74    if let Some(cost) = &response.compute_cost {
75        println!("Cost:     {cost}");
76    }
77    if let Some(time_ms) = response.time_ms {
78        println!("Time:     {time_ms}ms");
79    }
80
81    Ok(())
82}
83
84fn load_payment_key(account_id: &str, config: &ProjectConfig) -> Result<String> {
85    if let Ok(key) = std::env::var("PAYMENT_KEY") {
86        return Ok(key);
87    }
88
89    let cwd = std::env::current_dir()?;
90    let env_path = cwd.join(".env");
91    if env_path.exists() {
92        let content = std::fs::read_to_string(&env_path)?;
93        for line in content.lines() {
94            if let Some(val) = line.strip_prefix("PAYMENT_KEY=") {
95                return Ok(val.to_string());
96            }
97        }
98    }
99
100    if let Some(ref run) = config.run {
101        if let Some(nonce) = run.payment_key_nonce {
102            anyhow::bail!(
103                "Payment key secret not found. Set PAYMENT_KEY env var.\n\
104                 Expected format: {account_id}:{nonce}:<secret>"
105            );
106        }
107    }
108
109    anyhow::bail!("No payment key configured. Set PAYMENT_KEY env var.");
110}