use zygo_core::supervisor::client::Client;
use zygo_core::supervisor::{Request, Response};
use zygo_core::tokens::Token;
use crate::cli::{Cli, TokenCommand};
use crate::output::{self, Style};
pub fn run(cli: &Cli, command: &TokenCommand) -> anyhow::Result<u8> {
let paths = super::paths(cli);
let exe = std::env::current_exe()?;
let mut client = Client::connect_or_start(&paths, &exe)?;
match command {
TokenCommand::Mint { tenant } => {
let response = client.send(&Request::MintToken {
tenant: tenant.clone(),
})?;
let (tokens, secret) = match response {
Response::Tokens { tokens, secret } => (tokens, secret),
other => return super::supervisor::report_failure(cli, &other),
};
let token = tokens.first();
let secret = secret.unwrap_or_default();
if cli.json {
output::json(&serde_json::json!({ "token": token, "secret": secret }))?;
return Ok(0);
}
let style = Style::stdout();
let id = token.map(|t| t.id.as_str()).unwrap_or("?");
println!("{secret}");
eprintln!(
"{} {id} {}",
style.dim("minted"),
style.dim(&describe(token)),
);
eprintln!(
"{}",
style.dim("the secret is above and is not stored; it cannot be printed again")
);
Ok(0)
}
TokenCommand::Ls => {
let tokens = match client.send(&Request::Tokens)? {
Response::Tokens { tokens, .. } => tokens,
other => return super::supervisor::report_failure(cli, &other),
};
if cli.json {
output::json(&tokens)?;
return Ok(0);
}
if tokens.is_empty() {
eprintln!(
"{}",
Style::stderr().dim("no tokens; `zygo token mint` makes one")
);
return Ok(0);
}
print_table(&tokens);
Ok(0)
}
TokenCommand::Revoke { id } => {
let response = client.send(&Request::RevokeToken { id: id.clone() })?;
match response {
Response::Tokens { .. } => {
if cli.json {
output::json(&serde_json::json!({ "revoked": id }))?;
} else {
eprintln!(
"{} {id} {}",
Style::stderr().dim("revoked"),
Style::stderr().dim("it stops working on the next request")
);
}
Ok(0)
}
other => super::supervisor::report_failure(cli, &other),
}
}
}
}
fn describe(token: Option<&Token>) -> String {
match token.map(|t| t.tenant()) {
Some(Some(tenant)) => format!("tenant `{tenant}`: its own scripts and calls"),
Some(None) => "operator: tenants, functions, pools and tokens".to_string(),
None => String::new(),
}
}
fn print_table(tokens: &[Token]) {
let rows: Vec<Vec<String>> = tokens
.iter()
.map(|token| {
let scope = match token.tenant() {
Some(tenant) => format!("tenant {tenant}"),
None => "operator".to_string(),
};
let state = if token.revoked() { "revoked" } else { "active" };
vec![token.id.clone(), scope, state.to_string()]
})
.collect();
print!("{}", output::table(&["id", "scope", "state"], &rows));
}