use async_executor::Executor;
use async_io::Async;
use async_lock::Mutex;
use std::collections::HashSet;
use std::net::{SocketAddr, UdpSocket};
use std::path::Path;
use std::sync::Arc;
use std::time::Duration;
use super::handlers::{DirHandler, DirHandlerMode};
use super::{Handler, ServerConfig, TftpServer};
use crate::error::{Error, Result};
pub struct TftpServerBuilder<H: Handler> {
handle: H,
addr: SocketAddr,
socket: Option<Async<UdpSocket>>,
timeout: Duration,
block_size_limit: Option<u16>,
max_send_retries: u32,
ignore_client_timeout: bool,
ignore_client_block_size: bool,
}
impl TftpServerBuilder<DirHandler> {
pub fn with_dir_ro<P>(dir: P) -> Result<TftpServerBuilder<DirHandler>>
where
P: AsRef<Path>,
{
let handler = DirHandler::new(dir, DirHandlerMode::ReadOnly)?;
Ok(TftpServerBuilder::with_handler(handler))
}
pub fn with_dir_wo<P>(dir: P) -> Result<TftpServerBuilder<DirHandler>>
where
P: AsRef<Path>,
{
let handler = DirHandler::new(dir, DirHandlerMode::WriteOnly)?;
Ok(TftpServerBuilder::with_handler(handler))
}
pub fn with_dir_rw<P>(dir: P) -> Result<TftpServerBuilder<DirHandler>>
where
P: AsRef<Path>,
{
let handler = DirHandler::new(dir, DirHandlerMode::ReadWrite)?;
Ok(TftpServerBuilder::with_handler(handler))
}
}
impl<H: Handler> TftpServerBuilder<H> {
pub fn with_handler(handler: H) -> Self {
TftpServerBuilder {
handle: handler,
addr: "0.0.0.0:69".parse().unwrap(),
socket: None,
timeout: Duration::from_secs(3),
block_size_limit: None,
max_send_retries: 100,
ignore_client_timeout: false,
ignore_client_block_size: false,
}
}
pub fn bind(self, addr: SocketAddr) -> Self {
TftpServerBuilder {
addr,
..self
}
}
pub fn socket(self, socket: Async<UdpSocket>) -> Self {
TftpServerBuilder {
socket: Some(socket),
..self
}
}
pub fn std_socket(self, socket: UdpSocket) -> Result<Self> {
let socket = Async::new(socket)?;
Ok(TftpServerBuilder {
socket: Some(socket),
..self
})
}
pub fn timeout(self, timeout: Duration) -> Self {
TftpServerBuilder {
timeout,
..self
}
}
pub fn block_size_limit(self, size: u16) -> Self {
TftpServerBuilder {
block_size_limit: Some(size),
..self
}
}
pub fn max_send_retries(self, retries: u32) -> Self {
TftpServerBuilder {
max_send_retries: retries,
..self
}
}
pub fn ignore_client_timeout(self) -> Self {
TftpServerBuilder {
ignore_client_timeout: true,
..self
}
}
pub fn ignore_client_block_size(self) -> Self {
TftpServerBuilder {
ignore_client_block_size: true,
..self
}
}
pub async fn build(mut self) -> Result<TftpServer<H>> {
let socket = match self.socket.take() {
Some(socket) => socket,
None => Async::<UdpSocket>::bind(self.addr).map_err(Error::Bind)?,
};
let config = ServerConfig {
timeout: self.timeout,
block_size_limit: self.block_size_limit,
max_send_retries: self.max_send_retries,
ignore_client_timeout: self.ignore_client_timeout,
ignore_client_block_size: self.ignore_client_block_size,
};
let local_ip = socket.as_ref().local_addr()?.ip();
Ok(TftpServer {
socket,
handler: Arc::new(Mutex::new(self.handle)),
reqs_in_progress: Arc::new(Mutex::new(HashSet::new())),
ex: Executor::new(),
config,
local_ip,
})
}
}