mirror of
https://github.com/EasyTier/EasyTier.git
synced 2025-09-26 20:51:17 +08:00
easytier-cli部分命令支持json输出 (#882)
Some checks failed
EasyTier Core / pre_job (push) Has been cancelled
EasyTier GUI / pre_job (push) Has been cancelled
EasyTier Mobile / pre_job (push) Has been cancelled
EasyTier Test / pre_job (push) Has been cancelled
EasyTier Core / build_web (push) Has been cancelled
EasyTier Core / build (freebsd-13.2-x86_64, 13.2, ubuntu-22.04, x86_64-unknown-freebsd) (push) Has been cancelled
EasyTier Core / build (linux-aarch64, ubuntu-22.04, aarch64-unknown-linux-musl) (push) Has been cancelled
EasyTier Core / build (linux-arm, ubuntu-22.04, arm-unknown-linux-musleabi) (push) Has been cancelled
EasyTier Core / build (linux-armhf, ubuntu-22.04, arm-unknown-linux-musleabihf) (push) Has been cancelled
EasyTier Core / build (linux-armv7, ubuntu-22.04, armv7-unknown-linux-musleabi) (push) Has been cancelled
EasyTier Core / build (linux-armv7hf, ubuntu-22.04, armv7-unknown-linux-musleabihf) (push) Has been cancelled
EasyTier Core / build (linux-mips, ubuntu-22.04, mips-unknown-linux-musl) (push) Has been cancelled
EasyTier Core / build (linux-mipsel, ubuntu-22.04, mipsel-unknown-linux-musl) (push) Has been cancelled
EasyTier Core / build (linux-x86_64, ubuntu-22.04, x86_64-unknown-linux-musl) (push) Has been cancelled
EasyTier Core / build (macos-aarch64, macos-latest, aarch64-apple-darwin) (push) Has been cancelled
EasyTier Core / build (macos-x86_64, macos-latest, x86_64-apple-darwin) (push) Has been cancelled
EasyTier Core / build (windows-arm64, windows-latest, aarch64-pc-windows-msvc) (push) Has been cancelled
EasyTier Core / build (windows-i686, windows-latest, i686-pc-windows-msvc) (push) Has been cancelled
EasyTier Core / build (windows-x86_64, windows-latest, x86_64-pc-windows-msvc) (push) Has been cancelled
EasyTier Core / core-result (push) Has been cancelled
EasyTier Core / magisk_build (push) Has been cancelled
EasyTier GUI / build-gui (linux-aarch64, aarch64-unknown-linux-gnu, ubuntu-22.04, aarch64-unknown-linux-musl) (push) Has been cancelled
EasyTier GUI / build-gui (linux-x86_64, x86_64-unknown-linux-gnu, ubuntu-22.04, x86_64-unknown-linux-musl) (push) Has been cancelled
EasyTier GUI / build-gui (macos-aarch64, aarch64-apple-darwin, macos-latest, aarch64-apple-darwin) (push) Has been cancelled
EasyTier GUI / build-gui (macos-x86_64, x86_64-apple-darwin, macos-latest, x86_64-apple-darwin) (push) Has been cancelled
EasyTier GUI / build-gui (windows-arm64, aarch64-pc-windows-msvc, windows-latest, aarch64-pc-windows-msvc) (push) Has been cancelled
EasyTier GUI / build-gui (windows-i686, i686-pc-windows-msvc, windows-latest, i686-pc-windows-msvc) (push) Has been cancelled
EasyTier GUI / build-gui (windows-x86_64, x86_64-pc-windows-msvc, windows-latest, x86_64-pc-windows-msvc) (push) Has been cancelled
EasyTier GUI / gui-result (push) Has been cancelled
EasyTier Mobile / build-mobile (android, ubuntu-22.04, android) (push) Has been cancelled
EasyTier Mobile / mobile-result (push) Has been cancelled
EasyTier Test / test (push) Has been cancelled
Some checks failed
EasyTier Core / pre_job (push) Has been cancelled
EasyTier GUI / pre_job (push) Has been cancelled
EasyTier Mobile / pre_job (push) Has been cancelled
EasyTier Test / pre_job (push) Has been cancelled
EasyTier Core / build_web (push) Has been cancelled
EasyTier Core / build (freebsd-13.2-x86_64, 13.2, ubuntu-22.04, x86_64-unknown-freebsd) (push) Has been cancelled
EasyTier Core / build (linux-aarch64, ubuntu-22.04, aarch64-unknown-linux-musl) (push) Has been cancelled
EasyTier Core / build (linux-arm, ubuntu-22.04, arm-unknown-linux-musleabi) (push) Has been cancelled
EasyTier Core / build (linux-armhf, ubuntu-22.04, arm-unknown-linux-musleabihf) (push) Has been cancelled
EasyTier Core / build (linux-armv7, ubuntu-22.04, armv7-unknown-linux-musleabi) (push) Has been cancelled
EasyTier Core / build (linux-armv7hf, ubuntu-22.04, armv7-unknown-linux-musleabihf) (push) Has been cancelled
EasyTier Core / build (linux-mips, ubuntu-22.04, mips-unknown-linux-musl) (push) Has been cancelled
EasyTier Core / build (linux-mipsel, ubuntu-22.04, mipsel-unknown-linux-musl) (push) Has been cancelled
EasyTier Core / build (linux-x86_64, ubuntu-22.04, x86_64-unknown-linux-musl) (push) Has been cancelled
EasyTier Core / build (macos-aarch64, macos-latest, aarch64-apple-darwin) (push) Has been cancelled
EasyTier Core / build (macos-x86_64, macos-latest, x86_64-apple-darwin) (push) Has been cancelled
EasyTier Core / build (windows-arm64, windows-latest, aarch64-pc-windows-msvc) (push) Has been cancelled
EasyTier Core / build (windows-i686, windows-latest, i686-pc-windows-msvc) (push) Has been cancelled
EasyTier Core / build (windows-x86_64, windows-latest, x86_64-pc-windows-msvc) (push) Has been cancelled
EasyTier Core / core-result (push) Has been cancelled
EasyTier Core / magisk_build (push) Has been cancelled
EasyTier GUI / build-gui (linux-aarch64, aarch64-unknown-linux-gnu, ubuntu-22.04, aarch64-unknown-linux-musl) (push) Has been cancelled
EasyTier GUI / build-gui (linux-x86_64, x86_64-unknown-linux-gnu, ubuntu-22.04, x86_64-unknown-linux-musl) (push) Has been cancelled
EasyTier GUI / build-gui (macos-aarch64, aarch64-apple-darwin, macos-latest, aarch64-apple-darwin) (push) Has been cancelled
EasyTier GUI / build-gui (macos-x86_64, x86_64-apple-darwin, macos-latest, x86_64-apple-darwin) (push) Has been cancelled
EasyTier GUI / build-gui (windows-arm64, aarch64-pc-windows-msvc, windows-latest, aarch64-pc-windows-msvc) (push) Has been cancelled
EasyTier GUI / build-gui (windows-i686, i686-pc-windows-msvc, windows-latest, i686-pc-windows-msvc) (push) Has been cancelled
EasyTier GUI / build-gui (windows-x86_64, x86_64-pc-windows-msvc, windows-latest, x86_64-pc-windows-msvc) (push) Has been cancelled
EasyTier GUI / gui-result (push) Has been cancelled
EasyTier Mobile / build-mobile (android, ubuntu-22.04, android) (push) Has been cancelled
EasyTier Mobile / mobile-result (push) Has been cancelled
EasyTier Test / test (push) Has been cancelled
* add cli options to json output * add cli verbose output in json format for some sub command - easytier-cli -v peer list - easytier-cli -v peer list-foreign - easytier-cli -o json peer list-foreign - easytier-cli -v peer list-global-foreign - easytier-cli -o json peer list-global-foreign - easytier-cli -v route list - easytier-cli -v connector - easytier-cli -o json connector - easytier-cli -o json stun - easytier-cli -v proxy - easytier-cli -v node info --------- Co-authored-by: xzzpig <w2xzzig@hotmail.com>
This commit is contained in:
@@ -3,12 +3,14 @@ use std::{
|
||||
fmt::Write,
|
||||
net::{IpAddr, SocketAddr},
|
||||
path::PathBuf,
|
||||
str::FromStr,
|
||||
sync::Mutex,
|
||||
time::Duration,
|
||||
vec,
|
||||
};
|
||||
|
||||
use anyhow::Context;
|
||||
use cidr::Ipv4Inet;
|
||||
use clap::{command, Args, Parser, Subcommand};
|
||||
use humansize::format_size;
|
||||
use service_manager::*;
|
||||
@@ -51,6 +53,15 @@ struct Cli {
|
||||
#[arg(short, long, default_value = "false", help = "verbose output")]
|
||||
verbose: bool,
|
||||
|
||||
#[arg(
|
||||
short = 'o',
|
||||
long = "output",
|
||||
value_enum,
|
||||
default_value = "table",
|
||||
help = "output format"
|
||||
)]
|
||||
output_format: OutputFormat,
|
||||
|
||||
#[command(subcommand)]
|
||||
sub_command: SubCommand,
|
||||
}
|
||||
@@ -77,23 +88,23 @@ enum SubCommand {
|
||||
Proxy,
|
||||
}
|
||||
|
||||
#[derive(clap::ValueEnum, Debug, Clone, PartialEq)]
|
||||
enum OutputFormat {
|
||||
Table,
|
||||
Json,
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
struct PeerArgs {
|
||||
#[command(subcommand)]
|
||||
sub_command: Option<PeerSubCommand>,
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
struct PeerListArgs {
|
||||
#[arg(short, long)]
|
||||
verbose: bool,
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
enum PeerSubCommand {
|
||||
Add,
|
||||
Remove,
|
||||
List(PeerListArgs),
|
||||
List,
|
||||
ListForeign,
|
||||
ListGlobalForeign,
|
||||
}
|
||||
@@ -193,14 +204,15 @@ struct InstallArgs {
|
||||
|
||||
type Error = anyhow::Error;
|
||||
|
||||
struct CommandHandler {
|
||||
struct CommandHandler<'a> {
|
||||
client: Mutex<RpcClient>,
|
||||
verbose: bool,
|
||||
output_format: &'a OutputFormat,
|
||||
}
|
||||
|
||||
type RpcClient = StandAloneClient<TcpTunnelConnector>;
|
||||
|
||||
impl CommandHandler {
|
||||
impl CommandHandler<'_> {
|
||||
async fn get_peer_manager_client(
|
||||
&self,
|
||||
) -> Result<Box<dyn PeerManageRpc<Controller = BaseController>>, Error> {
|
||||
@@ -294,9 +306,12 @@ impl CommandHandler {
|
||||
println!("remove peer");
|
||||
}
|
||||
|
||||
async fn handle_peer_list(&self, _args: &PeerArgs) -> Result<(), Error> {
|
||||
#[derive(tabled::Tabled)]
|
||||
async fn handle_peer_list(&self) -> Result<(), Error> {
|
||||
#[derive(tabled::Tabled, serde::Serialize)]
|
||||
struct PeerTableItem {
|
||||
#[tabled(rename = "ipv4")]
|
||||
cidr: String,
|
||||
#[tabled(skip)]
|
||||
ipv4: String,
|
||||
hostname: String,
|
||||
cost: String,
|
||||
@@ -314,7 +329,12 @@ impl CommandHandler {
|
||||
fn from(p: PeerRoutePair) -> Self {
|
||||
let route = p.route.clone().unwrap_or_default();
|
||||
PeerTableItem {
|
||||
ipv4: route.ipv4_addr.map(|ip| ip.to_string()).unwrap_or_default(),
|
||||
cidr: route.ipv4_addr.map(|ip| ip.to_string()).unwrap_or_default(),
|
||||
ipv4: route
|
||||
.ipv4_addr
|
||||
.map(|ip: easytier::proto::common::Ipv4Inet| ip.address.unwrap_or_default())
|
||||
.map(|ip| ip.to_string())
|
||||
.unwrap_or_default(),
|
||||
hostname: route.hostname.clone(),
|
||||
cost: cost_to_str(route.cost),
|
||||
lat_ms: if route.cost == 1 {
|
||||
@@ -344,7 +364,10 @@ impl CommandHandler {
|
||||
impl From<NodeInfo> for PeerTableItem {
|
||||
fn from(p: NodeInfo) -> Self {
|
||||
PeerTableItem {
|
||||
ipv4: p.ipv4_addr.clone(),
|
||||
cidr: p.ipv4_addr.clone(),
|
||||
ipv4: Ipv4Inet::from_str(&p.ipv4_addr)
|
||||
.map(|ip| ip.address().to_string())
|
||||
.unwrap_or_default(),
|
||||
hostname: p.hostname.clone(),
|
||||
cost: "Local".to_string(),
|
||||
lat_ms: "-".to_string(),
|
||||
@@ -366,7 +389,7 @@ impl CommandHandler {
|
||||
let mut items: Vec<PeerTableItem> = vec![];
|
||||
let peer_routes = self.list_peer_route_pair().await?;
|
||||
if self.verbose {
|
||||
println!("{:#?}", peer_routes);
|
||||
println!("{}", serde_json::to_string_pretty(&peer_routes)?);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -382,7 +405,7 @@ impl CommandHandler {
|
||||
items.push(p.into());
|
||||
}
|
||||
|
||||
println!("{}", tabled::Table::new(items).with(Style::modern()));
|
||||
print_output(&items, self.output_format)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -404,8 +427,9 @@ impl CommandHandler {
|
||||
.list_foreign_network(BaseController::default(), request)
|
||||
.await?;
|
||||
let network_map = response;
|
||||
if self.verbose {
|
||||
println!("{:#?}", network_map);
|
||||
if self.verbose || *self.output_format == OutputFormat::Json {
|
||||
let json = serde_json::to_string_pretty(&network_map.foreign_networks)?;
|
||||
println!("{}", json);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -445,8 +469,11 @@ impl CommandHandler {
|
||||
let response = client
|
||||
.list_global_foreign_network(BaseController::default(), request)
|
||||
.await?;
|
||||
if self.verbose {
|
||||
println!("{:#?}", response);
|
||||
if self.verbose || *self.output_format == OutputFormat::Json {
|
||||
println!(
|
||||
"{}",
|
||||
serde_json::to_string_pretty(&response.foreign_networks)?
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -464,7 +491,7 @@ impl CommandHandler {
|
||||
}
|
||||
|
||||
async fn handle_route_list(&self) -> Result<(), Error> {
|
||||
#[derive(tabled::Tabled)]
|
||||
#[derive(tabled::Tabled, serde::Serialize)]
|
||||
struct RouteTableItem {
|
||||
ipv4: String,
|
||||
hostname: String,
|
||||
@@ -491,6 +518,23 @@ impl CommandHandler {
|
||||
.await?
|
||||
.node_info
|
||||
.ok_or(anyhow::anyhow!("node info not found"))?;
|
||||
let peer_routes = self.list_peer_route_pair().await?;
|
||||
|
||||
if self.verbose {
|
||||
#[derive(serde::Serialize)]
|
||||
struct VerboseItem {
|
||||
node_info: NodeInfo,
|
||||
peer_routes: Vec<PeerRoutePair>,
|
||||
}
|
||||
println!(
|
||||
"{}",
|
||||
serde_json::to_string_pretty(&VerboseItem {
|
||||
node_info,
|
||||
peer_routes
|
||||
})?
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
items.push(RouteTableItem {
|
||||
ipv4: node_info.ipv4_addr.clone(),
|
||||
@@ -510,7 +554,6 @@ impl CommandHandler {
|
||||
|
||||
version: node_info.version.clone(),
|
||||
});
|
||||
let peer_routes = self.list_peer_route_pair().await?;
|
||||
for p in peer_routes.iter() {
|
||||
let Some(next_hop_pair) = peer_routes.iter().find(|pair| {
|
||||
pair.route.clone().unwrap_or_default().peer_id
|
||||
@@ -634,7 +677,7 @@ impl CommandHandler {
|
||||
}
|
||||
}
|
||||
|
||||
println!("{}", tabled::Table::new(items).with(Style::modern()));
|
||||
print_output(&items, self.output_format)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -645,6 +688,10 @@ impl CommandHandler {
|
||||
let response = client
|
||||
.list_connector(BaseController::default(), request)
|
||||
.await?;
|
||||
if self.verbose || *self.output_format == OutputFormat::Json {
|
||||
println!("{}", serde_json::to_string_pretty(&response.connectors)?);
|
||||
return Ok(());
|
||||
}
|
||||
println!("response: {:#?}", response);
|
||||
Ok(())
|
||||
}
|
||||
@@ -912,6 +959,21 @@ impl Service {
|
||||
}
|
||||
}
|
||||
|
||||
fn print_output<T>(items: &[T], format: &OutputFormat) -> Result<(), Error>
|
||||
where
|
||||
T: tabled::Tabled + serde::Serialize,
|
||||
{
|
||||
match format {
|
||||
OutputFormat::Table => {
|
||||
println!("{}", tabled::Table::new(items).with(Style::modern()));
|
||||
}
|
||||
OutputFormat::Json => {
|
||||
println!("{}", serde_json::to_string_pretty(items)?);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
#[tracing::instrument]
|
||||
async fn main() -> Result<(), Error> {
|
||||
@@ -924,6 +986,7 @@ async fn main() -> Result<(), Error> {
|
||||
let handler = CommandHandler {
|
||||
client: Mutex::new(client),
|
||||
verbose: cli.verbose,
|
||||
output_format: &cli.output_format,
|
||||
};
|
||||
|
||||
match cli.sub_command {
|
||||
@@ -934,12 +997,8 @@ async fn main() -> Result<(), Error> {
|
||||
Some(PeerSubCommand::Remove) => {
|
||||
println!("remove peer");
|
||||
}
|
||||
Some(PeerSubCommand::List(arg)) => {
|
||||
if arg.verbose {
|
||||
println!("{:#?}", handler.list_peer_route_pair().await?);
|
||||
} else {
|
||||
handler.handle_peer_list(&peer_args).await?;
|
||||
}
|
||||
Some(PeerSubCommand::List) => {
|
||||
handler.handle_peer_list().await?;
|
||||
}
|
||||
Some(PeerSubCommand::ListForeign) => {
|
||||
handler.handle_foreign_network_list().await?;
|
||||
@@ -948,7 +1007,7 @@ async fn main() -> Result<(), Error> {
|
||||
handler.handle_global_foreign_network_list().await?;
|
||||
}
|
||||
None => {
|
||||
handler.handle_peer_list(&peer_args).await?;
|
||||
handler.handle_peer_list().await?;
|
||||
}
|
||||
},
|
||||
SubCommand::Connector(conn_args) => match conn_args.sub_command {
|
||||
@@ -975,7 +1034,14 @@ async fn main() -> Result<(), Error> {
|
||||
loop {
|
||||
let ret = collector.get_stun_info();
|
||||
if ret.udp_nat_type != NatType::Unknown as i32 {
|
||||
println!("stun info: {:#?}", ret);
|
||||
if cli.output_format == OutputFormat::Json {
|
||||
match serde_json::to_string_pretty(&ret) {
|
||||
Ok(json) => println!("{}", json),
|
||||
Err(e) => eprintln!("Error serializing to JSON: {}", e),
|
||||
}
|
||||
} else {
|
||||
println!("stun info: {:#?}", ret);
|
||||
}
|
||||
break;
|
||||
}
|
||||
tokio::time::sleep(Duration::from_millis(200)).await;
|
||||
@@ -993,27 +1059,45 @@ async fn main() -> Result<(), Error> {
|
||||
)
|
||||
.await?;
|
||||
|
||||
#[derive(tabled::Tabled)]
|
||||
#[derive(tabled::Tabled, serde::Serialize)]
|
||||
struct PeerCenterTableItem {
|
||||
node_id: String,
|
||||
direct_peers: String,
|
||||
#[tabled(rename = "direct_peers")]
|
||||
#[serde(skip_serializing)]
|
||||
direct_peers_str: String,
|
||||
#[tabled(skip)]
|
||||
direct_peers: Vec<DirectPeerItem>,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
struct DirectPeerItem {
|
||||
node_id: String,
|
||||
latency_ms: i32,
|
||||
}
|
||||
|
||||
let mut table_rows = vec![];
|
||||
for (k, v) in resp.global_peer_map.iter() {
|
||||
let node_id = k;
|
||||
let direct_peers = v
|
||||
let direct_peers_strs = v
|
||||
.direct_peers
|
||||
.iter()
|
||||
.map(|(k, v)| format!("{}: {:?}ms", k, v.latency_ms,))
|
||||
.collect::<Vec<_>>();
|
||||
let direct_peers: Vec<_> = v.direct_peers
|
||||
.iter()
|
||||
.map(|(k, v)| DirectPeerItem {
|
||||
node_id: k.to_string(),
|
||||
latency_ms: v.latency_ms,
|
||||
})
|
||||
.collect();
|
||||
table_rows.push(PeerCenterTableItem {
|
||||
node_id: node_id.to_string(),
|
||||
direct_peers: direct_peers.join("\n"),
|
||||
direct_peers_str: direct_peers_strs.join("\n"),
|
||||
direct_peers,
|
||||
});
|
||||
}
|
||||
|
||||
println!("{}", tabled::Table::new(table_rows).with(Style::modern()));
|
||||
print_output(&table_rows, &cli.output_format)?;
|
||||
}
|
||||
SubCommand::VpnPortal => {
|
||||
let vpn_portal_client = handler.get_vpn_portal_client().await?;
|
||||
@@ -1045,6 +1129,11 @@ async fn main() -> Result<(), Error> {
|
||||
.ok_or(anyhow::anyhow!("node info not found"))?;
|
||||
match sub_cmd.sub_command {
|
||||
Some(NodeSubCommand::Info) | None => {
|
||||
if cli.verbose || cli.output_format == OutputFormat::Json {
|
||||
println!("{}", serde_json::to_string_pretty(&node_info)?);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let stun_info = node_info.stun_info.clone().unwrap_or_default();
|
||||
let ip_list = node_info.ip_list.clone().unwrap_or_default();
|
||||
|
||||
@@ -1186,7 +1275,12 @@ async fn main() -> Result<(), Error> {
|
||||
.await;
|
||||
entries.extend(ret.unwrap_or_default().entries);
|
||||
|
||||
#[derive(tabled::Tabled)]
|
||||
if cli.verbose {
|
||||
println!("{}", serde_json::to_string_pretty(&entries)?);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
#[derive(tabled::Tabled, serde::Serialize)]
|
||||
struct TableItem {
|
||||
src: String,
|
||||
dst: String,
|
||||
@@ -1215,7 +1309,7 @@ async fn main() -> Result<(), Error> {
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
println!("{}", tabled::Table::new(table_rows).with(Style::modern()));
|
||||
print_output(&table_rows, &cli.output_format)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user