new-home-application 0.1.3

New Home iot application framework. Meant to build application for the New Home Core
Documentation
use std::io::{BufReader, BufWriter, Error};
use std::net::TcpListener;

use crate::application::application::ApplicationConfig;
use crate::net::tcp_reader::{TcpReader, TcpReaderImpl};
use crate::net::tcp_writer::{TcpWriter, TcpWriterImpl};

/// Contains all the required logic to read and get data from connected Tcp Clients
pub struct TcpServerImpl {
    /// Contains the port where the TcpListener is bound to
    port: i16,

    /// Contains the ip where the TcpListener is bound to
    ip: String,

    /// Contains the TcpListener after the `ApplicationServer::bind` method is called
    listener: Option<TcpListener>,
}

/// The interface which wraps around the `std::net::TcpListener` and adapts the `TcpReader` and
/// `TcpWriter` object to the `std::net::*` objects to simplify the usage of networking in unit tests
pub trait TcpServer {
    /// Binds the TcpListener to the given ip and port.
    fn bind(&mut self) -> ();

    /// Accepts a client connections.
    /// Returns a `TcpWriter` and a `TcpReader` connected to the `std::net::TcpStream` of the connected client
    fn get_tcp_stream(&self) -> Result<(Box<dyn TcpWriter>, Box<dyn TcpReader>), Error>;
}

impl TcpServerImpl {
    /// Creates the application server from an application
    /// the Application is a struct that contains information about the application's author etc. and contains its configuration
    pub fn from_application(app: ApplicationConfig) -> Self {
        Self::new(app.port, Option::from(app.ip))
    }

    /// Creates a new application server instance
    /// IP can be a valid IPv4 (X.X.X.X) or an IPv6 in brackets ([X:X:X::X])
    /// The IP is optional, the default value is  [::] and with that its listening on all IPv6
    /// interfaces (dependent on the system configuration [::] includes all IPv4 interfaces as well)
    pub fn new(port: i16, ip: Option<String>) -> Self {
        Self {
            port,
            ip: ip.unwrap_or(String::from("[::]")),
            listener: None,
        }
    }
}

impl TcpServer for TcpServerImpl {
    fn bind(&mut self) -> () {
        self.listener = Option::from(TcpListener::bind(format!("{}:{}", self.ip, self.port)).unwrap());
    }

    fn get_tcp_stream(&self) -> Result<(Box<dyn TcpWriter>, Box<dyn TcpReader>), Error> {
        let listener = self.listener.as_ref().unwrap();
        let client = listener.accept()?;
        let tcp_stream = client.0;
        let stream_copy = tcp_stream.try_clone().expect("Could not copy TcpStream for Reader");
        let buf_reader = BufReader::new(stream_copy);
        let buf_writer = BufWriter::new(tcp_stream);

        Ok((
            Box::new(TcpWriterImpl::new(buf_writer)),
            Box::new(TcpReaderImpl::new(buf_reader))
        ))
    }
}