use std::fmt;
use rust_i18n::t;
use tabled::Tabled;
use timeweb_rs::{
apis::{configuration::Configuration, vpc_api},
models
};
use crate::{error::TwcError, output::OutputFormat};
fn fmt_id<T: std::fmt::Display>(v: T) -> String {
v.to_string()
}
#[derive(Tabled)]
struct VpcRow {
#[tabled(rename = "ID")]
id: String,
#[tabled(rename = "Name")]
name: String,
#[tabled(rename = "Subnet")]
subnet: String,
#[tabled(rename = "Location")]
location: String,
#[tabled(rename = "PublicIP")]
public_ip: String
}
impl fmt::Display for VpcRow {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{} {} {} {} {}",
self.id, self.name, self.subnet, self.location, self.public_ip
)
}
}
pub async fn list(config: &Configuration, format: OutputFormat) -> Result<(), TwcError> {
let resp = vpc_api::get_vpcs(config).await?;
let rows: Vec<VpcRow> = resp
.vpcs
.iter()
.map(|v| VpcRow {
id: v.id.clone(),
name: v.name.clone(),
subnet: v.subnet_v4.clone(),
location: v.location.clone(),
public_ip: v.public_ip.clone().unwrap_or_default()
})
.collect();
match format {
OutputFormat::Table => {
if rows.is_empty() {
println!("{}", t!("cli.no_vpcs"));
} else {
let table = crate::output::render_table(&rows);
println!("{table}");
}
}
OutputFormat::Json | OutputFormat::Yaml => {
let out = crate::output::serialized(format, &resp.vpcs)
.transpose()?
.unwrap_or_default();
println!("{out}");
}
OutputFormat::Quiet => {
for v in &resp.vpcs {
println!("{}\t{}", v.id, v.name);
}
}
}
Ok(())
}
pub async fn delete(config: &Configuration, id: &str) -> Result<(), TwcError> {
vpc_api::delete_vpc(config, id).await?;
println!("{}", t!("cli.vpc_deleted", id => id));
Ok(())
}
pub async fn info(config: &Configuration, id: &str, format: OutputFormat) -> Result<(), TwcError> {
let resp = vpc_api::get_vpc(config, id).await?;
let v = &resp.vpc;
match format {
OutputFormat::Table => {
println!("ID: {}", fmt_id(&v.id));
println!("Name: {}", v.name);
println!("Subnet: {}", v.subnet_v4);
println!("Location: {}", v.location);
println!("Public IP: {}", v.public_ip.clone().unwrap_or_default());
println!(
"Description: {}",
v.description.clone().unwrap_or_default()
);
}
OutputFormat::Json | OutputFormat::Yaml => {
if let Some(out) = crate::output::serialized(format, &resp.vpc) {
println!("{}", out?);
}
}
OutputFormat::Quiet => {
println!("{}\t{}", fmt_id(&v.id), v.name);
}
}
Ok(())
}
pub async fn create(
config: &Configuration,
name: &str,
subnet_v4: &str,
location: &str,
format: OutputFormat
) -> Result<(), TwcError> {
let req = models::CreateVpc::new(
name.to_string(),
subnet_v4.to_string(),
location.to_string()
);
let resp = vpc_api::create_vpc(config, req).await?;
let v = &resp.vpc;
match format {
OutputFormat::Table => {
println!(
"{}",
t!("cli.vpc_created", name => v.name, id => fmt_id(&v.id))
);
}
OutputFormat::Json | OutputFormat::Yaml => {
if let Some(out) = crate::output::serialized(format, &resp.vpc) {
println!("{}", out?);
}
}
OutputFormat::Quiet => {
println!("{}\t{}", fmt_id(&v.id), v.name);
}
}
Ok(())
}
pub async fn set(
config: &Configuration,
id: &str,
name: Option<&str>,
description: Option<&str>
) -> Result<(), TwcError> {
let mut update = models::UpdateVpc::new();
if let Some(n) = name {
update.name = Some(n.to_string());
}
if let Some(d) = description {
update.description = Some(d.to_string());
}
let resp = vpc_api::update_vpcs(config, id, update).await?;
let v = &resp.vpc;
println!(
"{}",
t!("cli.vpc_updated", name => v.name, id => fmt_id(&v.id))
);
Ok(())
}
#[derive(Tabled)]
struct VpcPortRow {
#[tabled(rename = "ID")]
id: String,
#[tabled(rename = "IP")]
ip: String,
#[tabled(rename = "Resource")]
resource: String
}
impl fmt::Display for VpcPortRow {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} {} {}", self.id, self.ip, self.resource)
}
}
pub async fn list_ports(
config: &Configuration,
id: &str,
format: OutputFormat
) -> Result<(), TwcError> {
let resp = vpc_api::get_vpc_ports(config, id).await?;
let rows: Vec<VpcPortRow> = resp
.vpc_ports
.iter()
.map(|p| VpcPortRow {
id: p.id.clone(),
ip: p.ipv4.clone(),
resource: p.service.name.clone()
})
.collect();
match format {
OutputFormat::Table => {
if rows.is_empty() {
println!("{}", t!("cli.no_vpc_ports"));
} else {
let table = crate::output::render_table(&rows);
println!("{table}");
}
}
OutputFormat::Json | OutputFormat::Yaml => {
if let Some(out) = crate::output::serialized(format, &resp.vpc_ports) {
println!("{}", out?);
}
}
OutputFormat::Quiet => {
for p in &resp.vpc_ports {
println!("{}\t{}\t{}", fmt_id(&p.id), p.ipv4, p.service.name);
}
}
}
Ok(())
}