From abd38f0a99c936d1410576437d3012afa6f6c06c Mon Sep 17 00:00:00 2001 From: Aram Peres Date: Sat, 31 Jul 2021 03:44:45 -0400 Subject: [PATCH] rupsc: Implement listing clients --- nut-client/src/blocking/mod.rs | 19 +++++++++++++++++++ nut-client/src/cmd.rs | 33 +++++++++++++++++++++++++++++++++ rupsc/src/cmd.rs | 13 +++++++++++++ rupsc/src/main.rs | 2 +- 4 files changed, 66 insertions(+), 1 deletion(-) diff --git a/nut-client/src/blocking/mod.rs b/nut-client/src/blocking/mod.rs index 8b9a203..b5d5d7a 100644 --- a/nut-client/src/blocking/mod.rs +++ b/nut-client/src/blocking/mod.rs @@ -28,6 +28,13 @@ impl Connection { } } + /// Queries a list of client IP addresses connected to the given device. + pub fn list_clients(&mut self, ups_name: &str) -> crate::Result> { + match self { + Self::Tcp(conn) => conn.list_clients(ups_name), + } + } + /// Queries the list of variables for a UPS device. pub fn list_vars(&mut self, ups_name: &str) -> crate::Result> { match self { @@ -103,6 +110,18 @@ impl TcpConnection { list.into_iter().map(|row| row.expect_ups()).collect() } + fn list_clients(&mut self, ups_name: &str) -> crate::Result> { + let query = &["CLIENT", ups_name]; + Self::write_cmd( + &mut self.tcp_stream, + Command::List(query), + self.config.debug, + )?; + let list = Self::read_list(&mut self.tcp_stream, query, self.config.debug)?; + + list.into_iter().map(|row| row.expect_client()).collect() + } + fn list_vars(&mut self, ups_name: &str) -> crate::Result> { let query = &["VAR", ups_name]; Self::write_cmd( diff --git a/nut-client/src/cmd.rs b/nut-client/src/cmd.rs index c1185f4..45b92d1 100644 --- a/nut-client/src/cmd.rs +++ b/nut-client/src/cmd.rs @@ -52,9 +52,17 @@ pub enum Response { /// Marks the end of a list response. EndList(String), /// A variable (VAR) response. + /// + /// Params: (var name, var value) Var(String, String), /// A UPS (UPS) response. + /// + /// Params: (device name, device description) Ups(String, String), + /// A client (CLIENT) response. + /// + /// Params: (client IP) + Client(String), } impl Response { @@ -157,6 +165,23 @@ impl Response { }?; Ok(Response::Ups(name, description)) } + "CLIENT" => { + let _device = if args.is_empty() { + Err(ClientError::from(NutError::Generic( + "Unspecified CLIENT device in response".into(), + ))) + } else { + Ok(args.remove(0)) + }?; + let ip_address = if args.is_empty() { + Err(ClientError::from(NutError::Generic( + "Unspecified CLIENT IP in response".into(), + ))) + } else { + Ok(args.remove(0)) + }?; + Ok(Response::Client(ip_address)) + } _ => Err(NutError::UnknownResponseType(cmd_name).into()), } } @@ -196,4 +221,12 @@ impl Response { Err(NutError::UnexpectedResponse.into()) } } + + pub fn expect_client(&self) -> crate::Result { + if let Self::Client(client_ip) = &self { + Ok(client_ip.to_owned()) + } else { + Err(NutError::UnexpectedResponse.into()) + } + } } diff --git a/rupsc/src/cmd.rs b/rupsc/src/cmd.rs index ad911ae..1d44f5b 100644 --- a/rupsc/src/cmd.rs +++ b/rupsc/src/cmd.rs @@ -43,6 +43,19 @@ pub fn list_variables(server: UpsdName, debug: bool) -> anyhow::Result<()> { Ok(()) } +pub fn list_clients(server: UpsdName, debug: bool) -> anyhow::Result<()> { + let ups_name = server + .upsname + .with_context(|| "ups name must be specified: [@[:]]")?; + let mut conn = connect(server, debug)?; + + for client_ip in conn.list_clients(ups_name)? { + println!("{}", client_ip); + } + + Ok(()) +} + fn connect(server: UpsdName, debug: bool) -> anyhow::Result { let host = server.try_into()?; let config = nut_client::ConfigBuilder::new() diff --git a/rupsc/src/main.rs b/rupsc/src/main.rs index f221fff..d367f6e 100644 --- a/rupsc/src/main.rs +++ b/rupsc/src/main.rs @@ -73,7 +73,7 @@ fn main() -> anyhow::Result<()> { } if args.is_present("clients") { - todo!("listing clients") + return cmd::list_clients(server, debug); } // Fallback: prints one variable (or all of them)