diff --git a/nut-client/examples/async.rs b/nut-client/examples/async.rs index f8e5ff5..e3c9bc3 100644 --- a/nut-client/examples/async.rs +++ b/nut-client/examples/async.rs @@ -43,5 +43,6 @@ async fn main() -> nut_client::Result<()> { } } - Ok(()) + // Gracefully shut down the connection using the `LOGOUT` command + conn.close().await } diff --git a/nut-client/examples/blocking.rs b/nut-client/examples/blocking.rs index ce72345..90435e3 100644 --- a/nut-client/examples/blocking.rs +++ b/nut-client/examples/blocking.rs @@ -1,8 +1,8 @@ +use std::convert::TryInto; use std::env; use nut_client::blocking::Connection; use nut_client::{Auth, ConfigBuilder}; -use std::convert::TryInto; fn main() -> nut_client::Result<()> { let host = env::var("NUT_HOST").unwrap_or_else(|_| "localhost".into()); @@ -42,5 +42,6 @@ fn main() -> nut_client::Result<()> { } } - Ok(()) + // Gracefully shut down the connection using the `LOGOUT` command + conn.close() } diff --git a/nut-client/src/blocking/mod.rs b/nut-client/src/blocking/mod.rs index 9697541..563ff8c 100644 --- a/nut-client/src/blocking/mod.rs +++ b/nut-client/src/blocking/mod.rs @@ -26,6 +26,12 @@ impl Connection { Ok(conn) } + /// Gracefully closes the connection. + pub fn close(mut self) -> crate::Result<()> { + self.logout()?; + Ok(()) + } + /// Sends username and password, as applicable. fn login(&mut self, config: &Config) -> crate::Result<()> { if let Some(auth) = config.auth.clone() { diff --git a/nut-client/src/cmd.rs b/nut-client/src/cmd.rs index 9573a4f..eaadc94 100644 --- a/nut-client/src/cmd.rs +++ b/nut-client/src/cmd.rs @@ -15,8 +15,10 @@ pub enum Command<'a> { StartTLS, /// Queries the network version. NetworkVersion, - /// Queries the server version + /// Queries the server version. Version, + /// Gracefully shuts down the connection. + Logout, } impl<'a> Command<'a> { @@ -30,6 +32,7 @@ impl<'a> Command<'a> { Self::StartTLS => "STARTTLS", Self::NetworkVersion => "NETVER", Self::Version => "VER", + Self::Logout => "LOGOUT", } } @@ -503,4 +506,9 @@ implement_action_commands! { pub(crate) fn set_password(password: &str) { Command::SetPassword(password) } + + /// Gracefully shuts down the connection. + pub(crate) fn logout() { + Command::Logout + } } diff --git a/nut-client/src/tokio/mod.rs b/nut-client/src/tokio/mod.rs index df1451b..aaaa662 100644 --- a/nut-client/src/tokio/mod.rs +++ b/nut-client/src/tokio/mod.rs @@ -27,6 +27,12 @@ impl Connection { Ok(conn) } + /// Gracefully closes the connection. + pub async fn close(mut self) -> crate::Result<()> { + self.logout().await?; + Ok(()) + } + /// Sends username and password, as applicable. async fn login(&mut self, config: &Config) -> crate::Result<()> { if let Some(auth) = config.auth.clone() { diff --git a/rupsc/src/cmd.rs b/rupsc/src/cmd.rs index 6f8e6c5..29850d1 100644 --- a/rupsc/src/cmd.rs +++ b/rupsc/src/cmd.rs @@ -15,7 +15,7 @@ pub fn list_devices(config: Config, with_description: bool) -> anyhow::Result<() } } - Ok(()) + logout(conn) } pub fn print_variable(config: Config, ups_name: &str, variable: &str) -> anyhow::Result<()> { @@ -24,7 +24,7 @@ pub fn print_variable(config: Config, ups_name: &str, variable: &str) -> anyhow: let variable = conn.get_var(ups_name, variable)?; println!("{}", variable.value()); - Ok(()) + logout(conn) } pub fn list_variables(config: Config, ups_name: &str) -> anyhow::Result<()> { @@ -34,7 +34,7 @@ pub fn list_variables(config: Config, ups_name: &str) -> anyhow::Result<()> { println!("{}", var); } - Ok(()) + logout(conn) } pub fn list_clients(config: Config, ups_name: &str) -> anyhow::Result<()> { @@ -44,9 +44,13 @@ pub fn list_clients(config: Config, ups_name: &str) -> anyhow::Result<()> { println!("{}", client_ip); } - Ok(()) + logout(conn) } fn connect(config: Config) -> anyhow::Result { Connection::new(&config).with_context(|| format!("Failed to connect to upsd: {:?}", &config)) } + +fn logout(conn: Connection) -> anyhow::Result<()> { + conn.close().with_context(|| "Failed to close gracefully") +}