use Result
s and not unwraps (#10)
* use `Result`s and not unwraps * fix test assertion
This commit is contained in:
parent
c453a88c99
commit
233d03ea75
|
@ -7,11 +7,12 @@ struct CmdArgs {
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
mac: Option<String>,
|
mac: Option<String>,
|
||||||
}
|
}
|
||||||
fn main() {
|
|
||||||
|
fn main() -> wakey::Result<()> {
|
||||||
let args = CmdArgs::parse();
|
let args = CmdArgs::parse();
|
||||||
if let Some(m) = args.mac {
|
if let Some(m) = args.mac {
|
||||||
let sep = m.chars().find(|ch| *ch == ':' || *ch == '-').unwrap_or('/');
|
let sep = m.chars().find(|ch| *ch == ':' || *ch == '-').unwrap_or('/');
|
||||||
let wol = wakey::WolPacket::from_string(&m, sep);
|
let wol = wakey::WolPacket::from_string(&m, sep)?;
|
||||||
if wol.send_magic().is_ok() {
|
if wol.send_magic().is_ok() {
|
||||||
println!("sent the magic packet.");
|
println!("sent the magic packet.");
|
||||||
} else {
|
} else {
|
||||||
|
@ -20,4 +21,6 @@ fn main() {
|
||||||
} else {
|
} else {
|
||||||
println!("give mac address to wake up");
|
println!("give mac address to wake up");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
113
wakey/src/lib.rs
113
wakey/src/lib.rs
|
@ -1,7 +1,7 @@
|
||||||
//! Library for managing Wake-on-LAN packets.
|
//! Library for managing Wake-on-LAN packets.
|
||||||
//! # Example
|
//! # Example
|
||||||
//! ```
|
//! ```
|
||||||
//! let wol = wakey::WolPacket::from_string("01:02:03:04:05:06", ':');
|
//! let wol = wakey::WolPacket::from_string("01:02:03:04:05:06", ':').unwrap();
|
||||||
//! if wol.send_magic().is_ok() {
|
//! if wol.send_magic().is_ok() {
|
||||||
//! println!("Sent the magic packet!");
|
//! println!("Sent the magic packet!");
|
||||||
//! } else {
|
//! } else {
|
||||||
|
@ -9,8 +9,9 @@
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use std::iter;
|
use std::error::Error;
|
||||||
use std::net::{SocketAddr, ToSocketAddrs, UdpSocket};
|
use std::net::{SocketAddr, ToSocketAddrs, UdpSocket};
|
||||||
|
use std::{fmt, iter};
|
||||||
|
|
||||||
use arrayvec::ArrayVec;
|
use arrayvec::ArrayVec;
|
||||||
|
|
||||||
|
@ -20,6 +21,41 @@ const HEADER: [u8; 6] = [0xFF; 6];
|
||||||
const PACKET_LEN: usize = HEADER.len() + MAC_SIZE * MAC_PER_MAGIC;
|
const PACKET_LEN: usize = HEADER.len() + MAC_SIZE * MAC_PER_MAGIC;
|
||||||
|
|
||||||
type Packet = ArrayVec<u8, PACKET_LEN>;
|
type Packet = ArrayVec<u8, PACKET_LEN>;
|
||||||
|
type Mac = ArrayVec<u8, MAC_SIZE>;
|
||||||
|
|
||||||
|
/// Wrapper `Result` for the module errors.
|
||||||
|
pub type Result<T> = std::result::Result<T, WakeyError>;
|
||||||
|
|
||||||
|
/// Wrapper Error for fiascoes occuring in this module.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum WakeyError {
|
||||||
|
/// The provided MAC address has invalid length.
|
||||||
|
InvalidMacLength,
|
||||||
|
/// The provided MAC address has invalid format.
|
||||||
|
InvalidMacFormat,
|
||||||
|
/// There was an error sending the WoL packet.
|
||||||
|
SendFailure(std::io::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for WakeyError {}
|
||||||
|
|
||||||
|
impl fmt::Display for WakeyError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
WakeyError::InvalidMacLength => {
|
||||||
|
write!(f, "Invalid MAC address length")
|
||||||
|
}
|
||||||
|
WakeyError::InvalidMacFormat => write!(f, "Invalid MAC address format"),
|
||||||
|
WakeyError::SendFailure(e) => write!(f, "Couldn't send WoL packet: {e}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<std::io::Error> for WakeyError {
|
||||||
|
fn from(error: std::io::Error) -> Self {
|
||||||
|
WakeyError::SendFailure(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Wake-on-LAN packet
|
/// Wake-on-LAN packet
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
@ -34,10 +70,10 @@ impl WolPacket {
|
||||||
/// ```
|
/// ```
|
||||||
/// let wol = wakey::WolPacket::from_bytes(&vec![0x00, 0x01, 0x02, 0x03, 0x04, 0x05]);
|
/// let wol = wakey::WolPacket::from_bytes(&vec![0x00, 0x01, 0x02, 0x03, 0x04, 0x05]);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn from_bytes(mac: &[u8]) -> WolPacket {
|
pub fn from_bytes(mac: &[u8]) -> Result<WolPacket> {
|
||||||
WolPacket {
|
Ok(WolPacket {
|
||||||
packet: WolPacket::create_packet_bytes(mac),
|
packet: WolPacket::create_packet_bytes(mac)?,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates WOL packet from string MAC representation (e.x. 00:01:02:03:04:05)
|
/// Creates WOL packet from string MAC representation (e.x. 00:01:02:03:04:05)
|
||||||
|
@ -47,8 +83,8 @@ impl WolPacket {
|
||||||
/// ```
|
/// ```
|
||||||
/// # Panic
|
/// # Panic
|
||||||
/// Panics when input MAC is invalid (i.e. contains non-byte characters)
|
/// Panics when input MAC is invalid (i.e. contains non-byte characters)
|
||||||
pub fn from_string<T: AsRef<str>>(data: T, sep: char) -> WolPacket {
|
pub fn from_string<T: AsRef<str>>(data: T, sep: char) -> Result<WolPacket> {
|
||||||
WolPacket::from_bytes(&WolPacket::mac_to_byte(data, sep))
|
WolPacket::from_bytes(&WolPacket::mac_to_byte(data, sep)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Broadcasts the magic packet from / to default address
|
/// Broadcasts the magic packet from / to default address
|
||||||
|
@ -56,10 +92,10 @@ impl WolPacket {
|
||||||
/// Destination 255.255.255.255:9
|
/// Destination 255.255.255.255:9
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// let wol = wakey::WolPacket::from_bytes(&vec![0x00, 0x01, 0x02, 0x03, 0x04, 0x05]);
|
/// let wol = wakey::WolPacket::from_bytes(&vec![0x00, 0x01, 0x02, 0x03, 0x04, 0x05]).unwrap();
|
||||||
/// wol.send_magic();
|
/// wol.send_magic();
|
||||||
/// ```
|
/// ```
|
||||||
pub fn send_magic(&self) -> std::io::Result<()> {
|
pub fn send_magic(&self) -> Result<()> {
|
||||||
self.send_magic_to(
|
self.send_magic_to(
|
||||||
SocketAddr::from(([0, 0, 0, 0], 0)),
|
SocketAddr::from(([0, 0, 0, 0], 0)),
|
||||||
SocketAddr::from(([255, 255, 255, 255], 9)),
|
SocketAddr::from(([255, 255, 255, 255], 9)),
|
||||||
|
@ -70,12 +106,12 @@ impl WolPacket {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// use std::net::SocketAddr;
|
/// use std::net::SocketAddr;
|
||||||
/// let wol = wakey::WolPacket::from_bytes(&vec![0x00, 0x01, 0x02, 0x03, 0x04, 0x05]);
|
/// let wol = wakey::WolPacket::from_bytes(&vec![0x00, 0x01, 0x02, 0x03, 0x04, 0x05]).unwrap();
|
||||||
/// let src = SocketAddr::from(([0,0,0,0], 0));
|
/// let src = SocketAddr::from(([0,0,0,0], 0));
|
||||||
/// let dst = SocketAddr::from(([255,255,255,255], 9));
|
/// let dst = SocketAddr::from(([255,255,255,255], 9));
|
||||||
/// wol.send_magic_to(src, dst);
|
/// wol.send_magic_to(src, dst);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn send_magic_to<A: ToSocketAddrs>(&self, src: A, dst: A) -> std::io::Result<()> {
|
pub fn send_magic_to<A: ToSocketAddrs>(&self, src: A, dst: A) -> Result<()> {
|
||||||
let udp_sock = UdpSocket::bind(src)?;
|
let udp_sock = UdpSocket::bind(src)?;
|
||||||
udp_sock.set_broadcast(true)?;
|
udp_sock.set_broadcast(true)?;
|
||||||
udp_sock.send_to(&self.packet, dst)?;
|
udp_sock.send_to(&self.packet, dst)?;
|
||||||
|
@ -91,16 +127,24 @@ impl WolPacket {
|
||||||
/// Converts string representation of MAC address (e.x. 00:01:02:03:04:05) to raw bytes.
|
/// Converts string representation of MAC address (e.x. 00:01:02:03:04:05) to raw bytes.
|
||||||
/// # Panic
|
/// # Panic
|
||||||
/// Panics when input MAC is invalid (i.e. contains non-byte characters)
|
/// Panics when input MAC is invalid (i.e. contains non-byte characters)
|
||||||
fn mac_to_byte<T: AsRef<str>>(data: T, sep: char) -> ArrayVec<u8, MAC_SIZE> {
|
fn mac_to_byte<T: AsRef<str>>(data: T, sep: char) -> Result<Mac> {
|
||||||
|
// hex-encoded bytes * 2 plus separators
|
||||||
|
if data.as_ref().len() != MAC_SIZE * 3 - 1 {
|
||||||
|
return Err(WakeyError::InvalidMacLength);
|
||||||
|
}
|
||||||
|
|
||||||
let bytes = data
|
let bytes = data
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.split(sep)
|
.split(sep)
|
||||||
.flat_map(|x| hex::decode(x).expect("Invalid mac!"))
|
.map(|x| hex::decode(x).map_err(|_| WakeyError::InvalidMacFormat))
|
||||||
.collect::<ArrayVec<u8, MAC_SIZE>>();
|
.collect::<Result<ArrayVec<_, MAC_SIZE>>>()?
|
||||||
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
|
.collect::<Mac>();
|
||||||
|
|
||||||
debug_assert_eq!(MAC_SIZE, bytes.len());
|
debug_assert_eq!(MAC_SIZE, bytes.len());
|
||||||
|
|
||||||
bytes
|
Ok(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extends the MAC address to fill the magic packet
|
/// Extends the MAC address to fill the magic packet
|
||||||
|
@ -117,7 +161,10 @@ impl WolPacket {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates bytes of the magic packet from MAC address
|
/// Creates bytes of the magic packet from MAC address
|
||||||
fn create_packet_bytes(mac: &[u8]) -> Packet {
|
fn create_packet_bytes(mac: &[u8]) -> Result<Packet> {
|
||||||
|
if mac.len() != MAC_SIZE {
|
||||||
|
return Err(WakeyError::InvalidMacLength);
|
||||||
|
}
|
||||||
let mut packet = Packet::new();
|
let mut packet = Packet::new();
|
||||||
|
|
||||||
packet.extend(HEADER);
|
packet.extend(HEADER);
|
||||||
|
@ -125,7 +172,7 @@ impl WolPacket {
|
||||||
|
|
||||||
debug_assert_eq!(PACKET_LEN, packet.len());
|
debug_assert_eq!(PACKET_LEN, packet.len());
|
||||||
|
|
||||||
packet
|
Ok(packet)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,42 +210,50 @@ mod tests {
|
||||||
let result = WolPacket::mac_to_byte(mac, ':');
|
let result = WolPacket::mac_to_byte(mac, ':');
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.into_inner().unwrap(),
|
result.unwrap().into_inner().unwrap(),
|
||||||
[0x01, 0x02, 0x03, 0x04, 0x05, 0x06]
|
[0x01, 0x02, 0x03, 0x04, 0x05, 0x06]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
|
||||||
fn mac_to_byte_invalid_chars_test() {
|
fn mac_to_byte_invalid_chars_test() {
|
||||||
let mac = "ZZ:02:03:04:05:06";
|
let mac = "ZZ:02:03:04:05:06";
|
||||||
WolPacket::mac_to_byte(mac, ':');
|
assert!(matches!(
|
||||||
|
WolPacket::mac_to_byte(mac, ':'),
|
||||||
|
Err(WakeyError::InvalidMacFormat)
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
|
||||||
fn mac_to_byte_invalid_separator_test() {
|
fn mac_to_byte_invalid_separator_test() {
|
||||||
let mac = "01002:03:04:05:06";
|
let mac = "01002:03:04:05:06";
|
||||||
WolPacket::mac_to_byte(mac, ':');
|
assert!(matches!(
|
||||||
|
WolPacket::mac_to_byte(mac, ':'),
|
||||||
|
Err(WakeyError::InvalidMacFormat)
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
|
||||||
fn mac_to_byte_mac_too_long_test() {
|
fn mac_to_byte_mac_too_long_test() {
|
||||||
let mac = "01:02:03:04:05:06:07";
|
let mac = "01:02:03:04:05:06:07";
|
||||||
WolPacket::mac_to_byte(mac, ':');
|
assert!(matches!(
|
||||||
|
WolPacket::mac_to_byte(mac, ':'),
|
||||||
|
Err(WakeyError::InvalidMacLength)
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
|
||||||
fn mac_to_byte_mac_too_short_test() {
|
fn mac_to_byte_mac_too_short_test() {
|
||||||
let mac = "01:02:03:04:05";
|
let mac = "01:02:03:04:05";
|
||||||
WolPacket::mac_to_byte(mac, ':');
|
assert!(matches!(
|
||||||
|
WolPacket::mac_to_byte(mac, ':'),
|
||||||
|
Err(WakeyError::InvalidMacLength)
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn create_packet_bytes_test() {
|
fn create_packet_bytes_test() {
|
||||||
let bytes = WolPacket::create_packet_bytes(&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]);
|
let bytes = WolPacket::create_packet_bytes(&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]).unwrap();
|
||||||
|
|
||||||
assert_eq!(bytes.len(), MAC_SIZE * MAC_PER_MAGIC + HEADER.len());
|
assert_eq!(bytes.len(), MAC_SIZE * MAC_PER_MAGIC + HEADER.len());
|
||||||
assert!(bytes.iter().all(|&x| x == 0xFF));
|
assert!(bytes.iter().all(|&x| x == 0xFF));
|
||||||
|
@ -207,7 +262,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn create_wol_packet() {
|
fn create_wol_packet() {
|
||||||
let mac = vec![0x00, 0x01, 0x02, 0x03, 0x04, 0x05];
|
let mac = vec![0x00, 0x01, 0x02, 0x03, 0x04, 0x05];
|
||||||
let wol = WolPacket::from_bytes(&mac);
|
let wol = WolPacket::from_bytes(&mac).unwrap();
|
||||||
let packet = wol.into_inner();
|
let packet = wol.into_inner();
|
||||||
|
|
||||||
assert_eq!(packet.len(), PACKET_LEN);
|
assert_eq!(packet.len(), PACKET_LEN);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user