From 4f66c0495e383cdccda4aabe4fc138bbd8ced69f Mon Sep 17 00:00:00 2001 From: _ <_@_> Date: Thu, 9 Dec 2021 16:46:55 +0000 Subject: [PATCH] :heavy_plus_sign: add `find-nick` command --- README.md | 13 +++++++++ ideas.md | 1 - src/app_common.rs | 4 +++ src/client.rs | 67 ++++++++++++++++++++++++++++++++++++++++++++++- src/main.rs | 9 +------ src/server.rs | 8 ++++++ 6 files changed, 92 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index f578830..2c685c3 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,19 @@ Run the server manually: (If you haven't installed it with systemd yet) lookaround server --nickname my-desktop ``` +Use `find-nick` to find an IP, or ping it, or SSH into it, or pull a file from it: + +```bash +lookaround find-nick laptop + +ping $(lookaround find-nick laptop) + +ssh user@$(lookaround find-nick laptop) + +# After starting `nc -l -p 9000 < some-file` on the laptop +nc $(lookaround find-nick laptop) 9000 +`` + Run a client to ping all servers in the same multi-cast domain: ```bash diff --git a/ideas.md b/ideas.md index 399370b..20c3991 100644 --- a/ideas.md +++ b/ideas.md @@ -1,7 +1,6 @@ Cool ideas that can be done but probably won't be. - Exit faster if the user only wants to see known servers -- Command for shell substituting IPs into commands - Arbitrary TCP forwarding of (stdin? stdout? TCP?) - Netcat replacement "Just send a file" _including filename_ - Public-key crypto for trusting peers on first use (Hard cause it requires mutable disk state) diff --git a/src/app_common.rs b/src/app_common.rs index 5b04d56..068b468 100644 --- a/src/app_common.rs +++ b/src/app_common.rs @@ -6,6 +6,8 @@ pub enum AppError { AddrParse (#[from] std::net::AddrParseError), #[error (transparent)] CliArgs (#[from] CliArgError), + #[error ("Operation timed out")] + Elapsed (#[from] tokio::time::error::Elapsed), #[error (transparent)] Io (#[from] std::io::Error), #[error (transparent)] @@ -26,6 +28,8 @@ pub enum AppError { pub enum CliArgError { #[error ("Missing value for argument `{0}`")] MissingArgumentValue (String), + #[error ("Missing required argument <{0}>")] + MissingRequiredArg (String), #[error ("First argument should be a subcommand")] MissingSubcommand, #[error ("Unknown subcommand `{0}`")] diff --git a/src/client.rs b/src/client.rs index 91202cb..1f45376 100644 --- a/src/client.rs +++ b/src/client.rs @@ -12,10 +12,17 @@ struct ClientParams { } pub async fn client > (args: I) -> Result <(), AppError> { + match get_mac_address() { + Ok(Some(ma)) => { + println!("Our MAC addr = {}", ma); + } + Ok(None) => println!("No MAC address found."), + Err(e) => println!("{:?}", e), + } + let params = configure_client (args)?; let socket = make_socket (¶ms).await?; let msg = Message::new_request1 ().to_vec ()?; - tokio::spawn (send_requests (Arc::clone (&socket), params.common, msg)); let mut peers = HashMap::with_capacity (10); @@ -49,6 +56,64 @@ pub async fn client > (args: I) -> Result <(), AppErro Ok (()) } +pub async fn find_nick > (mut args: I) -> Result <(), AppError> +{ + let mut nick = None; + let mut timeout_ms = 500; + + while let Some (arg) = args.next () { + match arg.as_str () { + "--timeout-ms" => { + timeout_ms = match args.next () { + None => return Err (CliArgError::MissingArgumentValue (arg).into ()), + Some (x) => u64::from_str (&x)?, + }; + }, + _ => nick = Some (arg), + } + } + + let needle_nick = nick.ok_or_else (|| CliArgError::MissingRequiredArg ("nickname".to_string ()))?; + let needle_nick = Some (needle_nick); + + let params = ClientParams { + common: Default::default (), + bind_addrs: get_ips ()?, + timeout_ms, + }; + + let socket = make_socket (¶ms).await?; + let msg = Message::new_request1 ().to_vec ()?; + tokio::spawn (send_requests (Arc::clone (&socket), params.common, msg)); + + timeout (Duration::from_millis (params.timeout_ms), async move { loop { + let (msgs, remote_addr) = match recv_msg_from (&socket).await { + Err (_) => continue, + Ok (x) => x, + }; + + let mut resp = ServerResponse { + mac: None, + nickname: None, + }; + + for msg in msgs.into_iter () { + match msg { + Message::Response1 (x) => resp.mac = x, + Message::Response2 (x) => resp.nickname = Some (x.nickname), + _ => (), + } + } + + if resp.nickname == needle_nick { + println! ("{}", remote_addr.ip ()); + return; + } + }}).await?; + + Ok (()) +} + fn configure_client > (mut args: I) -> Result { diff --git a/src/main.rs b/src/main.rs index 1412bad..ccc88c7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,19 +24,12 @@ async fn async_main () -> Result <(), AppError> { let _exe_name = args.next (); - match get_mac_address() { - Ok(Some(ma)) => { - println!("Our MAC addr = {}", ma); - } - Ok(None) => println!("No MAC address found."), - Err(e) => println!("{:?}", e), - } - let subcommand: Option = args.next (); match subcommand.as_ref ().map (|x| &x[..]) { None => return Err (CliArgError::MissingSubcommand.into ()), Some ("client") => client::client (args).await?, + Some ("find-nick") => client::find_nick (args).await?, Some ("my-ips") => my_ips ()?, Some ("server") => server::server (args).await?, Some (x) => return Err (CliArgError::UnknownSubcommand (x.to_string ()).into ()), diff --git a/src/server.rs b/src/server.rs index 1513078..f33ce92 100644 --- a/src/server.rs +++ b/src/server.rs @@ -10,6 +10,14 @@ struct Params { pub async fn server > (args: I) -> Result <(), AppError> { + match get_mac_address() { + Ok(Some(ma)) => { + println!("Our MAC addr = {}", ma); + } + Ok(None) => println!("No MAC address found."), + Err(e) => println!("{:?}", e), + } + let params = configure (args)?; let socket = UdpSocket::bind (SocketAddrV4::new (Ipv4Addr::UNSPECIFIED, params.common.server_port)).await?;