Generify GET commands

This commit is contained in:
Aram 🍐 2021-07-31 22:13:41 -04:00
parent bab1264364
commit c1d24a8278
3 changed files with 69 additions and 49 deletions

View file

@ -3,7 +3,7 @@ use std::net::{SocketAddr, TcpStream};
use crate::blocking::stream::ConnectionStream; use crate::blocking::stream::ConnectionStream;
use crate::cmd::{Command, Response}; use crate::cmd::{Command, Response};
use crate::{ClientError, Config, Host, NutError, Variable}; use crate::{ClientError, Config, Host, NutError};
mod stream; mod stream;
@ -20,16 +20,6 @@ impl Connection {
Host::Tcp(host) => Ok(Self::Tcp(TcpConnection::new(config.clone(), &host.addr)?)), Host::Tcp(host) => Ok(Self::Tcp(TcpConnection::new(config.clone(), &host.addr)?)),
} }
} }
/// Queries one variable for a UPS device.
pub fn get_var(&mut self, ups_name: &str, variable: &str) -> crate::Result<Variable> {
match self {
Self::Tcp(conn) => {
let var = conn.get_var(ups_name, variable)?;
Ok(Variable::parse(var.0.as_str(), var.1))
}
}
}
} }
/// A blocking TCP NUT client connection. /// A blocking TCP NUT client connection.
@ -129,13 +119,6 @@ impl TcpConnection {
Ok(()) Ok(())
} }
fn get_var(&mut self, ups_name: &str, variable: &str) -> crate::Result<(String, String)> {
let query = &["VAR", ups_name, variable];
self.write_cmd(Command::Get(query))?;
self.read_response()?.expect_var()
}
#[allow(dead_code)] #[allow(dead_code)]
fn get_network_version(&mut self) -> crate::Result<String> { fn get_network_version(&mut self) -> crate::Result<String> {
self.write_cmd(Command::NetworkVersion)?; self.write_cmd(Command::NetworkVersion)?;
@ -170,13 +153,13 @@ impl TcpConnection {
Ok(args) Ok(args)
} }
fn read_response(&mut self) -> crate::Result<Response> { pub(crate) fn read_response(&mut self) -> crate::Result<Response> {
let mut reader = BufReader::new(&mut self.stream); let mut reader = BufReader::new(&mut self.stream);
let args = Self::parse_line(&mut reader, self.config.debug)?; let args = Self::parse_line(&mut reader, self.config.debug)?;
Response::from_args(args) Response::from_args(args)
} }
fn read_plain_response(&mut self) -> crate::Result<String> { pub(crate) fn read_plain_response(&mut self) -> crate::Result<String> {
let mut reader = BufReader::new(&mut self.stream); let mut reader = BufReader::new(&mut self.stream);
let args = Self::parse_line(&mut reader, self.config.debug)?; let args = Self::parse_line(&mut reader, self.config.debug)?;
Ok(args.join(" ")) Ok(args.join(" "))

View file

@ -214,9 +214,9 @@ impl Response {
} }
} }
pub fn expect_var(&self) -> crate::Result<(String, String)> { pub fn expect_var(&self) -> crate::Result<Variable> {
if let Self::Var(name, value) = &self { if let Self::Var(name, value) = &self {
Ok((name.to_owned(), value.to_owned())) Ok(Variable::parse(name, value.to_owned()))
} else { } else {
Err(NutError::UnexpectedResponse.into()) Err(NutError::UnexpectedResponse.into())
} }
@ -289,12 +289,60 @@ macro_rules! implement_list_commands {
}; };
} }
/// A macro for implementing `GET` commands.
///
/// Each function should return a 2-tuple with
/// (1) the query to pass to `GET`
/// (2) a closure for mapping the `Response` row to the return type
macro_rules! implement_get_commands {
(
$(
$(#[$attr:meta])+
fn $name:ident($($argname:ident: $argty:ty),*) -> $retty:ty {
(
$query:block,
$mapper:block,
)
}
)*
) => {
impl crate::blocking::Connection {
$(
$(#[$attr])*
pub fn $name(&mut self$(, $argname: $argty)*) -> crate::Result<$retty> {
match self {
Self::Tcp(conn) => {
conn.write_cmd(Command::Get($query))?;
($mapper)(conn.read_response()?)
},
}
}
)*
}
#[cfg(feature = "async")]
impl crate::tokio::Connection {
$(
$(#[$attr])*
pub async fn $name(&mut self$(, $argname: $argty)*) -> crate::Result<$retty> {
match self {
Self::Tcp(conn) => {
conn.write_cmd(Command::Get($query)).await?;
($mapper)(conn.read_response().await?)
},
}
}
)*
}
};
}
implement_list_commands! { implement_list_commands! {
/// Queries a list of UPS devices. /// Queries a list of UPS devices.
fn list_ups() -> Vec<(String, String)> { fn list_ups() -> Vec<(String, String)> {
( (
{ &["UPS"] }, { &["UPS"] },
{ |row| row.expect_ups() }, { |row: Response| row.expect_ups() },
) )
} }
@ -302,7 +350,7 @@ implement_list_commands! {
fn list_clients(ups_name: &str) -> Vec<String> { fn list_clients(ups_name: &str) -> Vec<String> {
( (
{ &["CLIENT", ups_name] }, { &["CLIENT", ups_name] },
{ |row| row.expect_client() }, { |row: Response| row.expect_client() },
) )
} }
@ -310,7 +358,17 @@ implement_list_commands! {
fn list_vars(ups_name: &str) -> Vec<Variable> { fn list_vars(ups_name: &str) -> Vec<Variable> {
( (
{ &["VAR", ups_name] }, { &["VAR", ups_name] },
{ |row| row.expect_var().map(|var| Variable::parse(var.0.as_str(), var.1)) }, { |row: Response| row.expect_var() },
)
}
}
implement_get_commands! {
/// Queries one variable for a UPS device.
fn get_var(ups_name: &str, variable: &str) -> Variable {
(
{ &["VAR", ups_name, variable] },
{ |row: Response| row.expect_var() },
) )
} }
} }

View file

@ -2,7 +2,7 @@ use std::net::SocketAddr;
use crate::cmd::{Command, Response}; use crate::cmd::{Command, Response};
use crate::tokio::stream::ConnectionStream; use crate::tokio::stream::ConnectionStream;
use crate::{Config, Host, NutError, Variable}; use crate::{Config, Host, NutError};
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader}; use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
use tokio::net::TcpStream; use tokio::net::TcpStream;
@ -23,16 +23,6 @@ impl Connection {
)), )),
} }
} }
/// Queries one variable for a UPS device.
pub async fn get_var(&mut self, ups_name: &str, variable: &str) -> crate::Result<Variable> {
match self {
Self::Tcp(conn) => {
let var = conn.get_var(ups_name, variable).await?;
Ok(Variable::parse(var.0.as_str(), var.1))
}
}
}
} }
/// A blocking TCP NUT client connection. /// A blocking TCP NUT client connection.
@ -136,17 +126,6 @@ impl TcpConnection {
Ok(()) Ok(())
} }
async fn get_var<'a>(
&mut self,
ups_name: &'a str,
variable: &'a str,
) -> crate::Result<(String, String)> {
let query = &["VAR", ups_name, variable];
self.write_cmd(Command::Get(query)).await?;
self.read_response().await?.expect_var()
}
#[allow(dead_code)] #[allow(dead_code)]
async fn get_network_version(&mut self) -> crate::Result<String> { async fn get_network_version(&mut self) -> crate::Result<String> {
self.write_cmd(Command::NetworkVersion).await?; self.write_cmd(Command::NetworkVersion).await?;
@ -181,13 +160,13 @@ impl TcpConnection {
Ok(args) Ok(args)
} }
async fn read_response(&mut self) -> crate::Result<Response> { pub(crate) async fn read_response(&mut self) -> crate::Result<Response> {
let mut reader = BufReader::new(&mut self.stream); let mut reader = BufReader::new(&mut self.stream);
let args = Self::parse_line(&mut reader, self.config.debug).await?; let args = Self::parse_line(&mut reader, self.config.debug).await?;
Response::from_args(args) Response::from_args(args)
} }
async fn read_plain_response(&mut self) -> crate::Result<String> { pub(crate) async fn read_plain_response(&mut self) -> crate::Result<String> {
let mut reader = BufReader::new(&mut self.stream); let mut reader = BufReader::new(&mut self.stream);
let args = Self::parse_line(&mut reader, self.config.debug).await?; let args = Self::parse_line(&mut reader, self.config.debug).await?;
Ok(args.join(" ")) Ok(args.join(" "))