mirror of
https://github.com/aramperes/nut-rs.git
synced 2025-09-09 05:28:31 -04:00
version: 0.0.3
feat: list UPS variables docs: improve docs and enforce
This commit is contained in:
parent
b36c855b2c
commit
0ba5e4565f
8 changed files with 66 additions and 13 deletions
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "nut-client"
|
||||
version = "0.0.2"
|
||||
version = "0.0.3"
|
||||
authors = ["Aram Peres <aram.peres@wavy.fm>"]
|
||||
edition = "2018"
|
||||
description = "Network UPS Tools (NUT) client library"
|
||||
|
|
18
README.md
18
README.md
|
@ -10,6 +10,7 @@ A [Network UPS Tools](https://github.com/networkupstools/nut) (NUT) client libra
|
|||
- Connect to `upsd`/`nut-server` using TCP
|
||||
- Login with with username and password
|
||||
- List UPS devices
|
||||
- List variables for a UPS device
|
||||
|
||||
## ⚠️ Safety Goggles Required ⚠️
|
||||
|
||||
|
@ -26,11 +27,10 @@ Check out the `examples` directory for more advanced examples.
|
|||
use std::env;
|
||||
use std::net::ToSocketAddrs;
|
||||
|
||||
use nut_client::{Auth, ConfigBuilder, Host};
|
||||
use nut_client::blocking::Connection;
|
||||
use nut_client::{Auth, ConfigBuilder, Host};
|
||||
|
||||
fn main() -> nut_client::Result<()> {
|
||||
// The TCP host:port for upsd/nut-server
|
||||
let addr = env::var("NUT_ADDR")
|
||||
.unwrap_or_else(|_| "localhost:3493".into())
|
||||
.to_socket_addrs()
|
||||
|
@ -38,25 +38,27 @@ fn main() -> nut_client::Result<()> {
|
|||
.next()
|
||||
.unwrap();
|
||||
|
||||
// Username and password (optional)
|
||||
let username = env::var("NUT_USER").ok();
|
||||
let password = env::var("NUT_PASSWORD").ok();
|
||||
let auth = username.map(|username| Auth::new(username, password));
|
||||
|
||||
// Build the config
|
||||
let config = ConfigBuilder::new()
|
||||
.with_host(Host::Tcp(addr))
|
||||
.with_auth(auth)
|
||||
.build();
|
||||
|
||||
// Open a connection and login
|
||||
let mut conn = Connection::new(config)?;
|
||||
|
||||
// Print a list of all UPS devices
|
||||
// Print a list of all UPS devices and their variables
|
||||
println!("Connected UPS devices:");
|
||||
for (id, description) in conn.list_ups()? {
|
||||
println!("\t- ID: {}", id);
|
||||
for (name, description) in conn.list_ups()? {
|
||||
println!("\t- Name: {}", name);
|
||||
println!("\t Description: {}", description);
|
||||
println!("\t Variables:");
|
||||
|
||||
for (var_name, var_val) in conn.list_vars(&name)? {
|
||||
println!("\t\t- {} = {}", var_name, var_val);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -23,11 +23,16 @@ fn main() -> nut_client::Result<()> {
|
|||
|
||||
let mut conn = Connection::new(config)?;
|
||||
|
||||
// Print a list of all UPS devices
|
||||
// Print a list of all UPS devices and their variables
|
||||
println!("Connected UPS devices:");
|
||||
for (id, description) in conn.list_ups()? {
|
||||
println!("\t- ID: {}", id);
|
||||
for (name, description) in conn.list_ups()? {
|
||||
println!("\t- Name: {}", name);
|
||||
println!("\t Description: {}", description);
|
||||
println!("\t Variables:");
|
||||
|
||||
for (var_name, var_val) in conn.list_vars(&name)? {
|
||||
println!("\t\t- {} = {}", var_name, var_val);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -7,10 +7,12 @@ use crate::{ClientError, Config, Host, NutError};
|
|||
|
||||
/// A blocking NUT client connection.
|
||||
pub enum Connection {
|
||||
/// A TCP connection.
|
||||
Tcp(TcpConnection),
|
||||
}
|
||||
|
||||
impl Connection {
|
||||
/// Initializes a connection to a NUT server (upsd).
|
||||
pub fn new(config: Config) -> crate::Result<Self> {
|
||||
match &config.host {
|
||||
Host::Tcp(socket_addr) => {
|
||||
|
@ -19,11 +21,19 @@ impl Connection {
|
|||
}
|
||||
}
|
||||
|
||||
/// Queries a list of UPS devices.
|
||||
pub fn list_ups(&mut self) -> crate::Result<Vec<(String, String)>> {
|
||||
match self {
|
||||
Self::Tcp(conn) => conn.list_ups(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Queries the list of variables for a UPS device.
|
||||
pub fn list_vars(&mut self, ups_name: &str) -> crate::Result<Vec<(String, String)>> {
|
||||
match self {
|
||||
Self::Tcp(conn) => conn.list_vars(ups_name),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A blocking TCP NUT client connection.
|
||||
|
@ -70,6 +80,17 @@ impl TcpConnection {
|
|||
.collect())
|
||||
}
|
||||
|
||||
fn list_vars(&mut self, ups_name: &str) -> crate::Result<Vec<(String, String)>> {
|
||||
let query = &["VAR", ups_name];
|
||||
Self::write_cmd(&mut self.tcp_stream, Command::List(query))?;
|
||||
let list = Self::read_list(&mut self.tcp_stream, query)?;
|
||||
|
||||
Ok(list
|
||||
.into_iter()
|
||||
.map(|mut row| (row.remove(0), row.remove(0)))
|
||||
.collect())
|
||||
}
|
||||
|
||||
fn write_cmd(stream: &mut TcpStream, line: Command) -> crate::Result<()> {
|
||||
let line = format!("{}\n", line);
|
||||
stream.write_all(line.as_bytes())?;
|
||||
|
|
|
@ -67,6 +67,7 @@ impl Response {
|
|||
let err_type = args.remove(0);
|
||||
match err_type.as_str() {
|
||||
"ACCESS-DENIED" => Err(NutError::AccessDenied.into()),
|
||||
"UNKNOWN-UPS" => Err(NutError::UnknownUps.into()),
|
||||
_ => Err(NutError::Generic(format!(
|
||||
"Server error: {} {}",
|
||||
err_type,
|
||||
|
|
|
@ -31,6 +31,7 @@ pub struct Auth {
|
|||
}
|
||||
|
||||
impl Auth {
|
||||
/// Initializes authentication credentials with a username, and optionally a password.
|
||||
pub fn new(username: String, password: Option<String>) -> Self {
|
||||
Auth { username, password }
|
||||
}
|
||||
|
@ -54,6 +55,7 @@ pub struct Config {
|
|||
}
|
||||
|
||||
impl Config {
|
||||
/// Creates a connection configuration.
|
||||
pub fn new(host: Host, auth: Option<Auth>, timeout: Duration) -> Self {
|
||||
Config {
|
||||
host,
|
||||
|
@ -77,21 +79,26 @@ impl ConfigBuilder {
|
|||
ConfigBuilder::default()
|
||||
}
|
||||
|
||||
/// Sets the connection host, such as the TCP address and port.
|
||||
pub fn with_host(mut self, host: Host) -> Self {
|
||||
self.host = Some(host);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the optional authentication parameters.
|
||||
pub fn with_auth(mut self, auth: Option<Auth>) -> Self {
|
||||
self.auth = auth;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the network connection timeout. This may be ignored by non-network
|
||||
/// connections, such as Unix domain sockets.
|
||||
pub fn with_timeout(mut self, timeout: Duration) -> Self {
|
||||
self.timeout = Some(timeout);
|
||||
self
|
||||
}
|
||||
|
||||
/// Builds the configuration with this builder.
|
||||
pub fn build(self) -> Config {
|
||||
Config::new(
|
||||
self.host.unwrap_or_default(),
|
||||
|
|
11
src/error.rs
11
src/error.rs
|
@ -6,7 +6,11 @@ use std::io;
|
|||
pub enum NutError {
|
||||
/// Occurs when the username/password combination is rejected.
|
||||
AccessDenied,
|
||||
/// Occurs when the specified UPS device does not exist.
|
||||
UnknownUps,
|
||||
/// Occurs when the response type or content wasn't expected at the current stage.
|
||||
UnexpectedResponse,
|
||||
/// Occurs when the response type is not recognized by the client.
|
||||
UnknownResponseType(String),
|
||||
/// Generic (usually internal) client error.
|
||||
Generic(String),
|
||||
|
@ -16,7 +20,8 @@ impl fmt::Display for NutError {
|
|||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::AccessDenied => write!(f, "Authentication failed"),
|
||||
Self::UnexpectedResponse => write!(f, "Unexpected server response"),
|
||||
Self::UnknownUps => write!(f, "Unknown UPS device name"),
|
||||
Self::UnexpectedResponse => write!(f, "Unexpected server response content"),
|
||||
Self::UnknownResponseType(ty) => write!(f, "Unknown response type: {}", ty),
|
||||
Self::Generic(msg) => write!(f, "Internal client error: {}", msg),
|
||||
}
|
||||
|
@ -25,9 +30,12 @@ impl fmt::Display for NutError {
|
|||
|
||||
impl std::error::Error for NutError {}
|
||||
|
||||
/// Encapsulation for errors emitted by the client library.
|
||||
#[derive(Debug)]
|
||||
pub enum ClientError {
|
||||
/// Encapsulates IO errors.
|
||||
Io(io::Error),
|
||||
/// Encapsulates NUT and client-specific errors.
|
||||
Nut(NutError),
|
||||
}
|
||||
|
||||
|
@ -54,4 +62,5 @@ impl From<NutError> for ClientError {
|
|||
}
|
||||
}
|
||||
|
||||
/// Result type for [`ClientError`]
|
||||
pub type Result<T> = std::result::Result<T, ClientError>;
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
#![deny(missing_docs)]
|
||||
|
||||
//! # nut-client
|
||||
//!
|
||||
//! The `nut-client` crate provides a network client implementation
|
||||
//! for Network UPS Tools (NUT) servers.
|
||||
|
||||
pub use config::*;
|
||||
pub use error::*;
|
||||
|
||||
/// Blocking client implementation for NUT.
|
||||
pub mod blocking;
|
||||
|
||||
mod cmd;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue