Skip to content

Commit 5683b45

Browse files
ashu17706claude
andcommitted
feat: add IP address display for connect/disconnect/status commands
New features: - Show current IP address in status command - Show IP before/after when connecting to WARP - Show IP before/after when disconnecting from WARP - JSON output includes IP information - Graceful fallback if IP fetch fails (doesn't block command) Implementation: - New src/ip.rs module with public IP fetching - Uses ipify.org API with ifconfig.me fallback - 5-second timeout to prevent hanging - Colored output (cyan for before, green for after) Usage examples: warp status # Shows current IP warp up # Shows before/after IPs warp down # Shows before/after IPs warp status --json # Includes IP in JSON output Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
1 parent 03fb4f1 commit 5683b45

4 files changed

Lines changed: 129 additions & 6 deletions

File tree

src/commands/connect.rs

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,71 @@
11
use anyhow::Result;
2+
use serde_json::json;
3+
use colored::Colorize;
24
use crate::format;
35
use crate::warp_cli;
6+
use crate::ip;
47

58
pub fn run(connect: bool, json: bool, quiet: bool) -> Result<()> {
69
if connect {
10+
// Get IP before connecting
11+
let before_ip = ip::get_public_ip().ok();
12+
713
warp_cli::connect()?;
8-
format::success(json, quiet, "✓ Connected to WARP");
14+
15+
// Get IP after connecting
16+
let after_ip = ip::get_public_ip().ok();
17+
18+
if json {
19+
let obj = json!({
20+
"status": "success",
21+
"message": "Connected to WARP",
22+
"before_ip": before_ip,
23+
"after_ip": after_ip
24+
});
25+
if !quiet {
26+
println!("{}", obj.to_string());
27+
}
28+
} else {
29+
if !quiet {
30+
format::success(false, false, "✓ Connected to WARP");
31+
if let Some(ref before) = before_ip {
32+
println!(" Before: {}", before.cyan());
33+
}
34+
if let Some(ref after) = after_ip {
35+
println!(" After: {}", after.green());
36+
}
37+
}
38+
}
939
} else {
40+
// Get IP before disconnecting
41+
let before_ip = ip::get_public_ip().ok();
42+
1043
warp_cli::disconnect()?;
11-
format::success(json, quiet, "✓ Disconnected from WARP");
44+
45+
// Get IP after disconnecting
46+
let after_ip = ip::get_public_ip().ok();
47+
48+
if json {
49+
let obj = json!({
50+
"status": "success",
51+
"message": "Disconnected from WARP",
52+
"before_ip": before_ip,
53+
"after_ip": after_ip
54+
});
55+
if !quiet {
56+
println!("{}", obj.to_string());
57+
}
58+
} else {
59+
if !quiet {
60+
format::success(false, false, "✓ Disconnected from WARP");
61+
if let Some(ref before) = before_ip {
62+
println!(" Before: {}", before.cyan());
63+
}
64+
if let Some(ref after) = after_ip {
65+
println!(" After: {}", after.green());
66+
}
67+
}
68+
}
1269
}
1370

1471
Ok(())

src/commands/status.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,33 @@
11
use anyhow::Result;
22
use serde_json::json;
3+
use colored::Colorize;
34
use crate::format;
45
use crate::warp_cli;
6+
use crate::ip;
57

6-
pub fn run(json: bool, _quiet: bool) -> Result<()> {
8+
pub fn run(json: bool, quiet: bool) -> Result<()> {
79
let status_output = warp_cli::get_status()?;
10+
let is_connected = status_output.contains("Connected");
11+
12+
// Try to get current IP
13+
let current_ip = ip::get_public_ip().ok();
814

915
if json {
10-
let is_connected = status_output.contains("Connected");
1116
let obj = json!({
1217
"connected": is_connected,
18+
"ip": current_ip,
1319
"raw": status_output
1420
});
15-
println!("{}", obj.to_string());
21+
if !quiet {
22+
println!("{}", obj.to_string());
23+
}
1624
} else {
17-
println!("{}", status_output);
25+
if !quiet {
26+
println!("{}", status_output);
27+
if let Some(ip_addr) = current_ip {
28+
println!("Current IP: {}", ip_addr.cyan());
29+
}
30+
}
1831
}
1932

2033
Ok(())

src/ip.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
use anyhow::Result;
2+
3+
/// Get user's public IP address
4+
pub fn get_public_ip() -> Result<String> {
5+
// Try to get IP from ipify API (fast, reliable, no auth needed)
6+
match get_ip_from_ipify() {
7+
Ok(ip) => Ok(ip),
8+
Err(_) => {
9+
// Fallback to ifconfig.me
10+
get_ip_from_ifconfig()
11+
}
12+
}
13+
}
14+
15+
/// Get IP from ipify.org API
16+
fn get_ip_from_ipify() -> Result<String> {
17+
let client = reqwest::blocking::Client::new();
18+
let response = client
19+
.get("https://api.ipify.org?format=text")
20+
.timeout(std::time::Duration::from_secs(5))
21+
.send()?;
22+
23+
let ip = response.text()?.trim().to_string();
24+
25+
if ip.is_empty() {
26+
anyhow::bail!("Empty IP response");
27+
}
28+
29+
Ok(ip)
30+
}
31+
32+
/// Get IP from ifconfig.me as fallback
33+
fn get_ip_from_ifconfig() -> Result<String> {
34+
let client = reqwest::blocking::Client::new();
35+
let response = client
36+
.get("https://ifconfig.me")
37+
.timeout(std::time::Duration::from_secs(5))
38+
.send()?;
39+
40+
let ip = response.text()?.trim().to_string();
41+
42+
if ip.is_empty() {
43+
anyhow::bail!("Empty IP response");
44+
}
45+
46+
Ok(ip)
47+
}
48+
49+
/// Format IP address for display
50+
pub fn format_ip(ip: &str) -> String {
51+
format!("IP: {}", ip)
52+
}

src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::process;
55
mod commands;
66
mod format;
77
mod warp_cli;
8+
mod ip;
89

910
use commands::*;
1011

0 commit comments

Comments
 (0)