1use clap::Subcommand;
2
3use crate::api::HtbClient;
4use crate::output::{self, OutputFormat};
5
6#[derive(Subcommand)]
7pub enum VpnCommand {
8 Status,
10 List,
12 Switch {
14 server_id: u32,
16 },
17 Download {
19 server_id: Option<u32>,
21 },
22}
23
24pub async fn handle(
25 client: &HtbClient,
26 cmd: VpnCommand,
27 format: OutputFormat,
28) -> anyhow::Result<()> {
29 match cmd {
30 VpnCommand::Status => {
31 let status = client.vpn().status().await?;
32 if status.is_empty() {
33 output::print_message("Not connected to VPN.");
34 } else {
35 match format {
36 OutputFormat::Json => output::json::print_json(&status),
37 OutputFormat::Table => {
38 for entry in &status {
39 output::print_message(
40 &serde_json::to_string_pretty(entry)
41 .expect("serde_json::Value always serializes"),
42 );
43 }
44 }
45 }
46 }
47 }
48
49 VpnCommand::List => {
50 let connections = client.vpn().connections().await?;
51 output::print_list(&connections, format);
52 }
53
54 VpnCommand::Switch { server_id } => {
55 let resp = client.vpn().switch(server_id).await?;
56 if let Some(msg) = &resp.message {
57 output::print_message(msg);
58 }
59 if let Some(server) = &resp.data {
60 output::print_message(&format!(
61 "Switched to {} ({} clients)",
62 server.friendly_name, server.current_clients
63 ));
64 }
65 }
66
67 VpnCommand::Download { server_id } => {
68 let sid = server_id.unwrap_or(1);
69 let bytes = client.vpn().download_ovpn(sid).await?;
70 let filename = format!("lab-vpn-{sid}.ovpn");
71 std::fs::write(&filename, &bytes)?;
72 output::print_message(&format!("Downloaded {} ({} bytes)", filename, bytes.len()));
73 }
74 }
75 Ok(())
76}