rs-smtp 0.1.0

An ESMTP server library written in Rust.
Documentation
use std::pin::Pin;

use anyhow::Result;

use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt};
use tokio::net::TcpStream;
use tokio_rustls::{server::TlsStream, TlsAcceptor};

pub struct MyStream {
    pub unsafe_stream: Option<TcpStream>,
    pub safe_stream: Option<TlsStream<TcpStream>>,
}

impl MyStream {
    pub fn new(unsafe_stream: TcpStream) -> Self {
        Self {
            unsafe_stream: Some(unsafe_stream),
            safe_stream: None,
        }
    }

    pub fn is_tls(&self) -> bool {
        self.safe_stream.is_some()
    }

    pub async fn starttls(&mut self, acceptor: TlsAcceptor) -> Result<()> {
        let stream = self.unsafe_stream.take().unwrap();
        let stream = acceptor.accept(stream).await?;
        self.safe_stream = Some(stream);
        Ok(())
    }

    pub async fn close(&mut self) -> Result<()> {
        if self.unsafe_stream.is_some() {
            self.unsafe_stream.take().unwrap().shutdown().await?;
        }
        if self.safe_stream.is_some() {
            self.safe_stream.take().unwrap().shutdown().await?;
        }
        Ok(())
    }
}

impl AsyncRead for MyStream {
    fn poll_read(
        self: std::pin::Pin<&mut Self>,
        cx: &mut std::task::Context<'_>,
        buf: &mut tokio::io::ReadBuf<'_>,
    ) -> std::task::Poll<std::io::Result<()>> {
        if self.unsafe_stream.is_some() {
            return AsyncRead::poll_read(Pin::new(self.get_mut().unsafe_stream.as_mut().unwrap()), cx, buf);
        }
        if self.safe_stream.is_some() {
            return AsyncRead::poll_read(Pin::new(self.get_mut().safe_stream.as_mut().unwrap()), cx, buf);
        }
        panic!("Stream is not initialized");
    }
}

impl AsyncWrite for MyStream {
    fn poll_write(
        self: std::pin::Pin<&mut Self>,
        cx: &mut std::task::Context<'_>,
        buf: &[u8],
    ) -> std::task::Poll<std::io::Result<usize>> {
        if self.unsafe_stream.is_some() {
            return AsyncWrite::poll_write(Pin::new(self.get_mut().unsafe_stream.as_mut().unwrap()), cx, buf);
        }
        if self.safe_stream.is_some() {
            return AsyncWrite::poll_write(Pin::new(self.get_mut().safe_stream.as_mut().unwrap()), cx, buf);
        }
        panic!("Stream is not initialized");
    }

    fn poll_flush(
        self: std::pin::Pin<&mut Self>,
        cx: &mut std::task::Context<'_>,
    ) -> std::task::Poll<std::io::Result<()>> {
        if self.unsafe_stream.is_some() {
            return AsyncWrite::poll_flush(Pin::new(self.get_mut().unsafe_stream.as_mut().unwrap()), cx);
        }
        if self.safe_stream.is_some() {
            return AsyncWrite::poll_flush(Pin::new(self.get_mut().safe_stream.as_mut().unwrap()), cx);
        }
        panic!("Stream is not initialized");
    }

    fn poll_shutdown(
        self: std::pin::Pin<&mut Self>,
        cx: &mut std::task::Context<'_>,
    ) -> std::task::Poll<std::io::Result<()>> {
        if self.unsafe_stream.is_some() {
            return AsyncWrite::poll_shutdown(Pin::new(self.get_mut().unsafe_stream.as_mut().unwrap()), cx);
        }
        if self.safe_stream.is_some() {
            return AsyncWrite::poll_shutdown(Pin::new(self.get_mut().safe_stream.as_mut().unwrap()), cx);
        }
        panic!("Stream is not initialized");
    }
}