Start implementing new LIST cmd. Fix version cmd

This commit is contained in:
Aram 🍐 2021-08-08 17:15:36 -04:00
parent cc409f853b
commit 8153d848c0
5 changed files with 187 additions and 32 deletions

View file

@ -1,7 +1,7 @@
use std::convert::TryInto;
use std::env;
use rups::blocking::Connection;
use rups::blocking::Client;
use rups::{Auth, ConfigBuilder};
fn main() -> rups::Result<()> {
@ -22,7 +22,7 @@ fn main() -> rups::Result<()> {
.with_debug(false) // Turn this on for debugging network chatter
.build();
let mut conn = Connection::new(&config)?;
let mut conn = Client::new(&config)?;
// Get server information
println!("NUT server:");
@ -34,34 +34,34 @@ fn main() -> rups::Result<()> {
for (name, description) in conn.list_ups()? {
println!("\t- Name: {}", name);
println!("\t Description: {}", description);
println!("\t Number of logins: {}", conn.get_num_logins(&name)?);
// Get list of mutable variables
let mutable_vars = conn.list_mutable_vars(&name)?;
// List UPS variables (key = val)
println!("\t Mutable Variables:");
for var in mutable_vars.iter() {
println!("\t\t- {}", var);
println!("\t\t {:?}", conn.get_var_type(&name, var.name())?);
}
// List UPS immutable properties (key = val)
println!("\t Immutable Properties:");
for var in conn.list_vars(&name)? {
if mutable_vars.iter().any(|v| v.name() == var.name()) {
continue;
}
println!("\t\t- {}", var);
println!("\t\t {:?}", conn.get_var_type(&name, var.name())?);
}
// List UPS commands
println!("\t Commands:");
for cmd in conn.list_commands(&name)? {
let description = conn.get_command_description(&name, &cmd)?;
println!("\t\t- {} ({})", cmd, description);
}
// println!("\t Number of logins: {}", conn.get_num_logins(&name)?);
//
// // Get list of mutable variables
// let mutable_vars = conn.list_mutable_vars(&name)?;
//
// // List UPS variables (key = val)
// println!("\t Mutable Variables:");
// for var in mutable_vars.iter() {
// println!("\t\t- {}", var);
// println!("\t\t {:?}", conn.get_var_type(&name, var.name())?);
// }
//
// // List UPS immutable properties (key = val)
// println!("\t Immutable Properties:");
// for var in conn.list_vars(&name)? {
// if mutable_vars.iter().any(|v| v.name() == var.name()) {
// continue;
// }
// println!("\t\t- {}", var);
// println!("\t\t {:?}", conn.get_var_type(&name, var.name())?);
// }
//
// // List UPS commands
// println!("\t Commands:");
// for cmd in conn.list_commands(&name)? {
// let description = conn.get_command_description(&name, &cmd)?;
// println!("\t\t- {} ({})", cmd, description);
// }
}
// Gracefully shut down the connection using the `LOGOUT` command

View file

@ -107,4 +107,10 @@ impl Client {
fn enable_ssl(self) -> crate::Result<Self> {
Ok(self)
}
/// Gracefully closes the connection.
pub fn close(mut self) -> crate::Result<()> {
self.exec_logout()?;
Ok(())
}
}

View file

@ -743,6 +743,132 @@ macro_rules! implement_client_action_commands {
};
}
/// A macro for implementing client action commands that return a string.
///
/// Each function should return the sentence to pass.
macro_rules! implement_client_simple_commands {
(
$(
$(#[$attr:meta])+
$vis:vis fn $name:ident($($argname:ident: $argty:ty),*) -> String {
$cmd:block
}
)*
) => {
impl crate::blocking::Client {
$(
$(#[$attr])*
#[allow(dead_code)]
$vis fn $name(&mut self$(, $argname: $argty)*) -> crate::Result<String> {
use crate::proto::{Sentence, ServerSentences::*};
self.stream
.write_sentence(&$cmd)?;
self.stream
.read_literal()
.map(|s| String::from(s.trim_end_matches('\n')))
}
)*
}
#[cfg(feature = "async")]
impl crate::tokio::Client {
$(
$(#[$attr])*
#[allow(dead_code)]
$vis async fn $name(&mut self$(, $argname: $argty)*) -> crate::Result<String> {
use crate::proto::{Sentence, ServerSentences::*};
self.stream
.write_sentence(&$cmd)
.await?;
self.stream
.read_literal()
.await
.map(|s| String::from(s.trim_end_matches('\n')))
}
)*
}
};
}
/// A macro for implementing client action commands that return a list of objects.
///
/// Each function should return:
/// 1. The sentence to execute the query
/// 2. The expected 'BEGIN' sentence
/// 3. The expected return sentence
/// 4. The mapper for individual items
/// 5. The expected 'END' sentence
macro_rules! implement_client_list_commands {
(
$(
$(#[$attr:meta])+
$vis:vis fn $name:ident($($argname:ident: $argty:ty),*) -> $ret:ty {
$cmd:expr,
$begin:pat_param,
$itemsentence:pat_param,
$mapper:block,
$end:pat_param
}
)*
) => {
impl crate::blocking::Client {
$(
$(#[$attr])*
#[allow(dead_code)]
$vis fn $name(&mut self$(, $argname: $argty)*) -> crate::Result<$ret> {
use crate::proto::{Sentence, ClientSentences, ClientSentences::*, ServerSentences::*};
self.stream
.write_sentence(&$cmd)?;
self.stream
.read_sentence::<ClientSentences>()?
.matching(|s| matches!(s, $begin))?;
let sentences: Vec<ClientSentences> = self.stream
.read_sentences_until(|s| matches!(s, $end))?;
sentences
.into_iter()
.map(|s| {
match s {
$itemsentence => Ok($mapper),
_ => Err(crate::Error::Nut(crate::NutError::UnexpectedResponse)),
}
})
.collect()
}
)*
}
#[cfg(feature = "async")]
impl crate::tokio::Client {
$(
$(#[$attr])*
#[allow(dead_code)]
$vis async fn $name(&mut self$(, $argname: $argty)*) -> crate::Result<$ret> {
use crate::proto::{Sentence, ClientSentences, ClientSentences::*, ServerSentences::*};
self.stream
.write_sentence(&$cmd)
.await?;
self.stream
.read_sentence::<ClientSentences>()
.await?
.matching(|s| matches!(s, $begin))?;
let sentences: Vec<ClientSentences> = self.stream
.read_sentences_until(|s| matches!(s, $end))
.await?;
sentences
.into_iter()
.map(|s| {
match s {
$itemsentence => Ok($mapper),
_ => Err(crate::Error::Nut(crate::NutError::UnexpectedResponse)),
}
})
.collect()
}
)*
}
};
}
implement_list_commands! {
/// Queries a list of UPS devices.
pub fn list_ups() -> Vec<(String, String)> {
@ -917,3 +1043,26 @@ implement_client_action_commands! {
{ StartTLSOk {} }
}
}
implement_client_simple_commands! {
/// Queries the network protocol version.
pub fn get_network_version() -> String {
{ QueryNetworkVersion {} }
}
/// Queries the server NUT version.
pub fn get_server_version() -> String {
{ QueryVersion {} }
}
}
implement_client_list_commands! {
/// Queries the network protocol version.
pub fn list_ups() -> Vec<(String, String)> {
QueryListUps {},
BeginListUps {},
RespondUps {ups_name, description},
{ (ups_name, description) },
EndListUps {}
}
}

View file

@ -328,7 +328,7 @@ impl_words! {
/// Represents a variable.
Var("VAR"),
/// Client requests the server version.
Version("VERSION"),
Version("VER"),
}
use crate::{Error, NutError};

View file

@ -481,7 +481,7 @@ mod tests {
Sentences::QueryHelp {}
);
test_encode_decode!(
["VERSION"] <=>
["VER"] <=>
Sentences::QueryVersion {}
);
test_encode_decode!(