use clap::Subcommand;
use super::api::{CONJURE_ENDPOINTS, GRPC_HTTP_ENDPOINTS};
use super::descriptor_pool;
#[derive(Subcommand)]
pub enum EndpointCommands {
List {
#[arg(long)]
filter: Option<String>,
},
}
pub fn handle(command: EndpointCommands) -> anyhow::Result<()> {
match command {
EndpointCommands::List { filter } => cmd_list(filter.as_deref()),
}
}
fn cmd_list(filter: Option<&str>) -> anyhow::Result<()> {
let filter = filter.unwrap_or("").to_lowercase();
let mut rows: Vec<(String, String, String, &str)> = Vec::new();
for ep in GRPC_HTTP_ENDPOINTS {
let service_method = format!("{}/{}", ep.service, ep.rpc);
rows.push((
ep.method.to_owned(),
ep.path_template.to_owned(),
service_method,
"grpc-http",
));
}
for ep in CONJURE_ENDPOINTS {
let service_method = format!("{}.{}", ep.service, ep.name);
rows.push((
ep.method.to_owned(),
ep.path_template.to_owned(),
service_method,
"conjure",
));
}
let pool = descriptor_pool();
for svc in pool.services() {
for method in svc.methods() {
let service_method = format!("{}/{}", svc.full_name(), method.name());
rows.push((
String::new(),
service_method.clone(),
service_method,
"grpc",
));
}
}
let rows: Vec<_> = if filter.is_empty() {
rows
} else {
rows.into_iter()
.filter(|(method, path, svc_method, proto)| {
let haystack = format!("{method} {path} {svc_method} {proto}").to_lowercase();
haystack.contains(&filter)
})
.collect()
};
if rows.is_empty() {
if filter.is_empty() {
println!("no endpoints found");
} else {
println!("no endpoints matching `{filter}`");
}
return Ok(());
}
let method_w = rows.iter().map(|(m, ..)| m.len()).max().unwrap_or(0);
let path_w = rows.iter().map(|(_, p, ..)| p.len()).max().unwrap_or(0);
let proto_w = rows
.iter()
.map(|(.., proto)| proto.len())
.max()
.unwrap_or(0);
for (method, path, svc_method, proto) in &rows {
println!(
"{:<method_w$} {:<path_w$} {:<proto_w$} {}",
method, path, proto, svc_method,
);
}
Ok(())
}