feat(transport): Make Transport result type an actual Result (fixes #405)

This commit is contained in:
Alexis Mousset
2020-05-05 22:03:53 +02:00
parent ed9f38d2c8
commit 6afdb0cf3a
10 changed files with 72 additions and 48 deletions

View File

@@ -45,6 +45,8 @@ pub use crate::transport::smtp::{SmtpTransport, Tls};
pub use crate::transport::stub::StubTransport;
#[cfg(feature = "builder")]
use std::convert::TryFrom;
use std::error::Error as StdError;
use std::fmt;
/// Simple email envelope representation
///
@@ -117,17 +119,18 @@ impl TryFrom<&Headers> for Envelope {
}
/// Transport method for emails
pub trait Transport<'a> {
/// Result type for the transport
type Result;
pub trait Transport {
/// Result types for the transport
type Ok: fmt::Debug;
type Error: StdError;
/// Sends the email
fn send(&self, message: &Message) -> Self::Result {
fn send(&self, message: &Message) -> Result<Self::Ok, Self::Error> {
let raw = message.formatted();
self.send_raw(message.envelope(), &raw)
}
fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Self::Result;
fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error>;
}
#[cfg(test)]

View File

@@ -55,8 +55,3 @@ impl From<&'static str> for Error {
Error::Client(string)
}
}
type Id = String;
/// SMTP result type
pub type FileResult = Result<Id, Error>;

View File

@@ -35,7 +35,7 @@
//! TODO
//! ```
use crate::{transport::file::error::FileResult, Envelope, Transport};
use crate::{transport::file::error::Error, Envelope, Transport};
use std::{
fs::File,
io::prelude::*,
@@ -46,6 +46,8 @@ use uuid::Uuid;
pub mod error;
type Id = String;
/// Writes the content and the envelope information to a file
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -70,10 +72,11 @@ struct SerializableEmail<'a> {
message: Option<&'a str>,
}
impl<'a> Transport<'a> for FileTransport {
type Result = FileResult;
impl Transport for FileTransport {
type Ok = Id;
type Error = Error;
fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Self::Result {
fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
let email_id = Uuid::new_v4();
let mut file = self.path.clone();

View File

@@ -50,6 +50,3 @@ impl From<FromUtf8Error> for Error {
Utf8Parsing(err)
}
}
/// sendmail result type
pub type SendmailResult = Result<(), Error>;

View File

@@ -23,7 +23,7 @@
//! # }
//! ```
use crate::{transport::sendmail::error::SendmailResult, Envelope, Transport};
use crate::{transport::sendmail::error::Error, Envelope, Transport};
use std::{
convert::AsRef,
io::prelude::*,
@@ -55,10 +55,11 @@ impl SendmailTransport {
}
}
impl<'a> Transport<'a> for SendmailTransport {
type Result = SendmailResult;
impl Transport for SendmailTransport {
type Ok = ();
type Error = Error;
fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Self::Result {
fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
// Spawn the sendmail command
let mut process = Command::new(&self.command)
.arg("-i")

View File

@@ -5,7 +5,7 @@ use crate::{
authentication::{Credentials, Mechanism},
client::net::{NetworkStream, TlsParameters},
commands::*,
error::{Error, SmtpResult},
error::Error,
extension::{ClientId, Extension, MailBodyParameter, MailParameter, ServerInfo},
response::Response,
},
@@ -140,7 +140,7 @@ impl SmtpConnection {
Ok(conn)
}
pub fn send(&mut self, envelope: &Envelope, email: &[u8]) -> SmtpResult {
pub fn send(&mut self, envelope: &Envelope, email: &[u8]) -> Result<Response, Error> {
// Mail
let mut mail_options = vec![];
@@ -210,7 +210,7 @@ impl SmtpConnection {
Ok(())
}
pub fn quit(&mut self) -> SmtpResult {
pub fn quit(&mut self) -> Result<Response, Error> {
Ok(try_smtp!(self.command(Quit), self))
}
@@ -244,7 +244,11 @@ impl SmtpConnection {
}
/// Sends an AUTH command with the given mechanism, and handles challenge if needed
pub fn auth(&mut self, mechanisms: &[Mechanism], credentials: &Credentials) -> SmtpResult {
pub fn auth(
&mut self,
mechanisms: &[Mechanism],
credentials: &Credentials,
) -> Result<Response, Error> {
let mechanism = match self.server_info.get_auth_mechanism(mechanisms) {
Some(m) => m,
None => {
@@ -278,7 +282,7 @@ impl SmtpConnection {
}
/// Sends the message content
pub fn message(&mut self, message: &[u8]) -> SmtpResult {
pub fn message(&mut self, message: &[u8]) -> Result<Response, Error> {
let mut out_buf: Vec<u8> = vec![];
let mut codec = ClientCodec::new();
codec.encode(message, &mut out_buf)?;
@@ -288,7 +292,7 @@ impl SmtpConnection {
}
/// Sends an SMTP command
pub fn command<C: Display>(&mut self, command: C) -> SmtpResult {
pub fn command<C: Display>(&mut self, command: C) -> Result<Response, Error> {
self.write(command.to_string().as_bytes())?;
self.read_response()
}
@@ -307,7 +311,7 @@ impl SmtpConnection {
}
/// Gets the SMTP response
pub fn read_response(&mut self) -> SmtpResult {
pub fn read_response(&mut self) -> Result<Response, Error> {
let mut raw_response = String::new();
let mut response = raw_response.parse::<Response>();

View File

@@ -152,6 +152,3 @@ impl From<&'static str> for Error {
Client(string)
}
}
/// SMTP result type
pub type SmtpResult = Result<Response, Error>;

View File

@@ -182,8 +182,9 @@ use crate::{
transport::smtp::{
authentication::{Credentials, Mechanism, DEFAULT_MECHANISMS},
client::SmtpConnection,
error::{Error, SmtpResult},
error::Error,
extension::ClientId,
response::Response,
},
Envelope, Transport,
};
@@ -419,11 +420,12 @@ impl SmtpTransport {
}
}
impl<'a> Transport<'a> for SmtpTransport {
type Result = SmtpResult;
impl Transport for SmtpTransport {
type Ok = Response;
type Error = Error;
/// Sends an email
fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Self::Result {
fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
#[cfg(feature = "r2d2")]
let mut conn: Box<dyn DerefMut<Target = SmtpConnection>> = match self.pool {
Some(ref p) => Box::new(p.get()?),

View File

@@ -17,38 +17,60 @@
//! .body("Be happy!")
//! .unwrap();
//!
//! let mut sender = StubTransport::new_positive();
//! let mut sender = StubTransport::new_ok();
//! let result = sender.send(&email);
//! assert!(result.is_ok());
//! ```
use crate::{Envelope, Transport};
use std::error::Error as StdError;
use std::fmt;
#[derive(Debug, Copy, Clone)]
pub struct Error;
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "stub error")
}
}
impl StdError for Error {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
None
}
}
/// This transport logs the message envelope and returns the given response
#[derive(Debug, Clone, Copy)]
pub struct StubTransport {
response: StubResult,
response: Result<(), Error>,
}
impl StubTransport {
/// Creates a new transport that always returns the given response
pub fn new(response: StubResult) -> StubTransport {
/// Creates aResult new transport that always returns the given response
pub fn new(response: Result<(), Error>) -> StubTransport {
StubTransport { response }
}
/// Creates a new transport that always returns a success response
pub fn new_positive() -> StubTransport {
pub fn new_ok() -> StubTransport {
StubTransport { response: Ok(()) }
}
/// Creates a new transport that always returns an error
pub fn new_error() -> StubTransport {
StubTransport {
response: Err(Error),
}
}
}
/// SMTP result type
pub type StubResult = Result<(), ()>;
impl Transport for StubTransport {
type Ok = ();
type Error = Error;
impl<'a> Transport<'a> for StubTransport {
type Result = StubResult;
fn send_raw(&self, _envelope: &Envelope, _email: &[u8]) -> Self::Result {
fn send_raw(&self, _envelope: &Envelope, _email: &[u8]) -> Result<Self::Ok, Self::Error> {
self.response
}
}

View File

@@ -2,8 +2,8 @@ use lettre::{transport::stub::StubTransport, Message, Transport};
#[test]
fn stub_transport() {
let sender_ok = StubTransport::new_positive();
let sender_ko = StubTransport::new(Err(()));
let sender_ok = StubTransport::new_ok();
let sender_ko = StubTransport::new_error();
let email = Message::builder()
.from("NoBody <nobody@domain.tld>".parse().unwrap())
.reply_to("Yuin <yuin@domain.tld>".parse().unwrap())