add `my-ips` impl for Linux and refactor it into a module

main
_ 2021-12-08 16:45:39 -06:00
parent cf283a2eaa
commit 2b4695934e
2 changed files with 78 additions and 37 deletions

62
src/ip.rs Normal file
View File

@ -0,0 +1,62 @@
use std::{
net::Ipv4Addr,
process::Command,
str::FromStr,
};
use crate::AppError;
pub fn get_ip_addr_output () -> Result <String, AppError> {
let output = Command::new ("ip")
.arg ("addr")
.output ()?;
let output = output.stdout.as_slice ();
let output = String::from_utf8 (output.to_vec ())?;
Ok (output)
}
pub fn parse_ip_addr_output (output: &str) -> Vec <Ipv4Addr> {
// I wrote this in FP style because I was bored.
output.lines ()
.map (|l| l.trim_start ())
.filter_map (|l| l.strip_prefix ("inet "))
.filter_map (|l| l.find ('/').map (|x| &l [0..x]))
.filter_map (|l| Ipv4Addr::from_str (l).ok ())
.collect ()
}
pub fn get_ip_config_output () -> Result <String, AppError> {
let output = Command::new ("ipconfig")
.output ()?;
let output = output.stdout.as_slice ();
let output = String::from_utf8 (output.to_vec ())?;
Ok (output)
}
pub fn parse_ip_config_output (output: &str) -> Vec <Ipv4Addr> {
let mut addrs = vec! [];
for line in output.lines () {
let line = line.trim_start ();
// Maybe only works on English locales?
if ! line.starts_with ("IPv4 Address") {
continue;
}
let colon_pos = match line.find (':') {
None => continue,
Some (x) => x,
};
let line = &line [colon_pos + 2..];
let addr = match Ipv4Addr::from_str (line) {
Err (_) => continue,
Ok (x) => x,
};
addrs.push (addr);
}
addrs
}

View File

@ -17,6 +17,7 @@ use mac_address::{
};
use thiserror::Error;
mod ip;
mod message;
mod tlv;
@ -26,12 +27,14 @@ use message::{
};
#[derive (Debug, Error)]
enum AppError {
pub enum AppError {
#[error (transparent)]
AddrParse (#[from] std::net::AddrParseError),
#[error (transparent)]
CliArgs (#[from] CliArgError),
#[error (transparent)]
FromUtf8 (#[from] std::string::FromUtf8Error),
#[error (transparent)]
Io (#[from] std::io::Error),
#[error (transparent)]
MacAddr (#[from] mac_address::MacAddressError),
@ -44,7 +47,7 @@ enum AppError {
}
#[derive (Debug, Error)]
enum CliArgError {
pub enum CliArgError {
#[error ("Missing value for argument `{0}`")]
MissingArgumentValue (String),
#[error ("First argument should be a subcommand")]
@ -100,7 +103,15 @@ fn main () -> Result <(), AppError> {
#[cfg(target_os = "linux")]
fn my_ips () -> Result <(), AppError> {
println! ("my-ips subcommand not implemented for linux yet");
let output = ip::get_ip_addr_output ()?;
for addr in ip::parse_ip_addr_output (&output)
.iter ()
.filter (|a| ! a.is_loopback ())
{
println! ("{:?}", addr);
}
Ok (())
}
@ -112,47 +123,15 @@ fn my_ips () -> Result <(), AppError> {
#[cfg(target_os = "windows")]
fn my_ips () -> Result <(), AppError> {
use std::process::Command;
let output = ip::get_ip_config_output ()?;
let output = Command::new ("ipconfig")
.output ()?;
let output = output.stdout.as_slice ();
let output = std::str::from_utf8 (output)?;
for addr in parse_ip_config_output (output) {
for addr in ip::parse_ip_config_output (&output) {
println! ("{:?}", addr);
}
Ok (())
}
fn parse_ip_config_output (output: &str) -> Vec <Ipv4Addr> {
let mut addrs = vec! [];
for line in output.lines () {
let line = line.trim_start ();
// Maybe only works on English locales?
if ! line.starts_with ("IPv4 Address") {
continue;
}
let colon_pos = match line.find (":") {
None => continue,
Some (x) => x,
};
let line = &line [colon_pos + 2..];
let addr = match Ipv4Addr::from_str (line) {
Err (_) => continue,
Ok (x) => x,
};
addrs.push (addr);
}
addrs
}
struct ServerResponse {
mac: Option <[u8; 6]>,
nickname: Option <String>,