Re-organize network stuff

This commit is contained in:
Daniele Tricoli 2019-05-15 02:00:40 +02:00
parent b7cc65dca9
commit 1d84088aa6
3 changed files with 92 additions and 93 deletions

View file

@ -11,7 +11,7 @@ use log::{error, info};
use pretty_env_logger;
use commands::Command;
use network::SimpleUDPServer;
use network::udp::{send_to, Server};
const ABOUT: &str = "
Display custom icons on system tray.
@ -57,8 +57,7 @@ fn main() {
let command = Arc::new(RwLock::new(Command::from("black")));
info!("Starting UDP server on port {}...", port);
let mut server =
SimpleUDPServer::new(address.clone(), Arc::clone(&command));
let mut server = Server::new(address.clone(), Arc::clone(&command));
thread::spawn(move || {
if let Err(e) = server.serve_forever() {
error!("{}", e);
@ -77,7 +76,7 @@ fn main() {
info!("Sending command: {}", command);
if let Err(e) = network::send_to(command, address) {
if let Err(e) = send_to(command, address) {
error!("{}", e);
process::exit(1);
}

View file

@ -1,90 +1,2 @@
mod errors;
use std::io;
use std::net::UdpSocket;
use std::result;
use std::sync::{Arc, RwLock};
use log::debug;
use super::commands::Command;
use errors::UDPServerError;
// Maximum buffer size for commands.
//
// Traditionally (so excluding neologisms) the longest word in Italian is
// precipitevolissimevolmente, made by 26 letters. For our use case is more
// than enough.
const MAX_BUF_SIZE: usize = 26;
pub type Result<'a, T> = result::Result<T, UDPServerError<'a>>;
/// A simple server listening on UDP.
///
/// The server receives commands as String, with a max len of MAX_BUF_SIZE.
/// Commands that exceed MAX_BUF_SIZE are simply truncated.
pub struct SimpleUDPServer {
address: String,
command: Arc<RwLock<Command>>,
socket: Option<io::Result<UdpSocket>>,
}
impl SimpleUDPServer {
/// Create a new server.
pub fn new(address: String, command: Arc<RwLock<Command>>) -> Self {
SimpleUDPServer {
address,
command,
socket: None,
}
}
fn bind(&mut self) {
self.socket = Some(UdpSocket::bind(&self.address));
}
fn recv_command(&self) -> Result<()> {
let mut buf = [0; MAX_BUF_SIZE];
match self.socket.as_ref() {
Some(socket) => match socket {
Ok(socket) => {
let (bytes, src) = socket.recv_from(&mut buf)?;
let mut command = self.command.write()?;
*command = Command::from(String::from_utf8(
buf[..bytes].to_vec(),
)?);
debug!("Received command '{}' from {}", *command, src);
Ok(())
}
// io::Error doesn't support Clone trait so we create a new one.
Err(e) => Err(UDPServerError::from(io::Error::new(
e.kind(),
format!(
"Error on binding to {}: {}",
&self.address,
e.to_string()
),
))),
},
None => panic!("SimpleUDPServer::bind must be called!"),
}
}
/// Listen forever for incoming commands.
pub fn serve_forever(&mut self) -> Result<()> {
self.bind();
loop {
self.recv_command()?
}
}
}
/// Send over UDP the specified command to the specified address.
pub fn send_to(command: &str, address: String) -> io::Result<usize> {
let socket = UdpSocket::bind("0.0.0.0:0")?;
let bytes = socket.send_to(command.as_bytes(), address)?;
Ok(bytes)
}
pub mod udp;

88
src/network/udp.rs Normal file
View file

@ -0,0 +1,88 @@
use std::io;
use std::net::UdpSocket;
use std::result;
use std::sync::{Arc, RwLock};
use log::debug;
use super::errors::UDPServerError;
use crate::commands::Command;
// Maximum buffer size for commands.
//
// Traditionally (so excluding neologisms) the longest word in Italian is
// precipitevolissimevolmente, made by 26 letters. For our use case is more
// than enough.
const MAX_BUF_SIZE: usize = 26;
pub type Result<'a, T> = result::Result<T, UDPServerError<'a>>;
/// A simple server listening on UDP.
///
/// The server receives commands as String, with a max len of MAX_BUF_SIZE.
/// Commands that exceed MAX_BUF_SIZE are simply truncated.
pub struct Server {
address: String,
command: Arc<RwLock<Command>>,
socket: Option<io::Result<UdpSocket>>,
}
impl Server {
/// Create a new server.
pub fn new(address: String, command: Arc<RwLock<Command>>) -> Self {
Server {
address,
command,
socket: None,
}
}
fn bind(&mut self) {
self.socket = Some(UdpSocket::bind(&self.address));
}
fn recv_command(&self) -> Result<()> {
let mut buf = [0; MAX_BUF_SIZE];
match self.socket.as_ref() {
Some(socket) => match socket {
Ok(socket) => {
let (bytes, src) = socket.recv_from(&mut buf)?;
let mut command = self.command.write()?;
*command = Command::from(String::from_utf8(
buf[..bytes].to_vec(),
)?);
debug!("Received command '{}' from {}", *command, src);
Ok(())
}
// io::Error doesn't support Clone trait so we create a new one.
Err(e) => Err(UDPServerError::from(io::Error::new(
e.kind(),
format!(
"Error on binding to {}: {}",
&self.address,
e.to_string()
),
))),
},
None => panic!("SimpleUDPServer::bind must be called!"),
}
}
/// Listen forever for incoming commands.
pub fn serve_forever(&mut self) -> Result<()> {
self.bind();
loop {
self.recv_command()?
}
}
}
/// Send over UDP the specified command to the specified address.
pub fn send_to(command: &str, address: String) -> io::Result<usize> {
let socket = UdpSocket::bind("0.0.0.0:0")?;
let bytes = socket.send_to(command.as_bytes(), address)?;
Ok(bytes)
}