Initial import
This commit is contained in:
commit
c227d67ebb
|
@ -0,0 +1,2 @@
|
|||
/target
|
||||
**/*.rs.bk
|
|
@ -0,0 +1,6 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "dotted"
|
||||
version = "0.1.0"
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
[package]
|
||||
name = "dotted"
|
||||
version = "0.1.0"
|
||||
authors = ["Daniele Tricoli <eriol@mornie.org>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
|
@ -0,0 +1 @@
|
|||
max_width = 80
|
|
@ -0,0 +1,15 @@
|
|||
mod network;
|
||||
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use network::SimpleUDPServer;
|
||||
|
||||
fn main() {
|
||||
let shared_state = Arc::new(RwLock::new(String::new()));
|
||||
let s = shared_state.clone();
|
||||
|
||||
let mut server = SimpleUDPServer::new("127.0.0.1:1234", s);
|
||||
if let Err(e) = server.serve_forever() {
|
||||
println!("{}", e);
|
||||
};
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
mod errors;
|
||||
|
||||
use std::io;
|
||||
use std::net::UdpSocket;
|
||||
use std::result;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
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 excede MAX_BUF_SIZE are simply truncated.
|
||||
pub struct SimpleUDPServer<'a> {
|
||||
address: &'a str,
|
||||
command: Arc<RwLock<String>>,
|
||||
socket: Option<io::Result<UdpSocket>>,
|
||||
}
|
||||
|
||||
impl<'a> SimpleUDPServer<'a> {
|
||||
/// Create a new server.
|
||||
pub fn new(address: &'a str, command: Arc<RwLock<String>>) -> 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_addr) = socket.recv_from(&mut buf)?;
|
||||
let mut command = self.command.write()?;
|
||||
*command = String::from_utf8(buf[..bytes].to_vec())?;
|
||||
|
||||
println!("{:?}", src_addr);
|
||||
println!("In recv udp {:?}", *command);
|
||||
|
||||
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!"),
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
pub fn serve_forever(&mut self) -> Result<()> {
|
||||
self.bind();
|
||||
loop {
|
||||
self.recv_command()?
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
use std::fmt;
|
||||
use std::io;
|
||||
use std::string;
|
||||
use std::sync;
|
||||
|
||||
// Aggregate all kind of different errors for SimpleUDPServer.
|
||||
#[derive(Debug)]
|
||||
pub struct UDPServerError<'a> {
|
||||
detail: ErrorDetail<'a>,
|
||||
}
|
||||
|
||||
impl fmt::Display for UDPServerError<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.detail)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<io::Error> for UDPServerError<'a> {
|
||||
fn from(err: io::Error) -> UDPServerError<'a> {
|
||||
UDPServerError {
|
||||
detail: ErrorDetail::IOError(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<sync::PoisonError<sync::RwLockWriteGuard<'a, String>>>
|
||||
for UDPServerError<'a>
|
||||
{
|
||||
fn from(
|
||||
err: sync::PoisonError<sync::RwLockWriteGuard<'a, String>>,
|
||||
) -> UDPServerError {
|
||||
UDPServerError {
|
||||
detail: ErrorDetail::PoisonError(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<string::FromUtf8Error> for UDPServerError<'a> {
|
||||
fn from(err: string::FromUtf8Error) -> UDPServerError<'a> {
|
||||
UDPServerError {
|
||||
detail: ErrorDetail::FromUtf8Error(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ErrorDetail<'a> {
|
||||
IOError(io::Error),
|
||||
PoisonError(sync::PoisonError<sync::RwLockWriteGuard<'a, String>>),
|
||||
FromUtf8Error(string::FromUtf8Error),
|
||||
}
|
||||
|
||||
impl fmt::Display for ErrorDetail<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
ErrorDetail::IOError(err) => write!(f, "{}", err.to_string()),
|
||||
ErrorDetail::PoisonError(err) => write!(f, "{}", err.to_string()),
|
||||
ErrorDetail::FromUtf8Error(err) => write!(f, "{}", err.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue