1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
//! This module provides a type alias and constructor function for an simple context impl.
//!
//! It used the `FsResourceLoader` and `CpuPool` with a `CompositeContext`.
//!
//! Note this module is only available if the `default_impl_cpupool` feature
//! is enabled.
//!
//! # Example
//!
//! ```
//! # extern crate mail_core as mail;
//! # extern crate mail_headers as headers;
//! # use headers::header_components::Domain;
//! # // It's re-exported in the facade under `default_impl`.
//! # use std::str::FromStr;
//! use mail::default_impl::simple_context;
//!
//! # fn main() {
//! //TODO[FEAT]: use parse once the `Domain` component implements `FromStr`.
//! //let domain = "example.com".parse().unwrap();
//! let domain = Domain::from_unchecked("example.com".to_owned());
//! // This normally should be world unique for any usage with the same domain.
//! // This is necessary to generate `Content-Id` and `Message-Id` correctly.
//! let ascii_unique_part = "xm3r2u".parse().unwrap();
//! let ctx = simple_context::new(domain, ascii_unique_part).unwrap();
//! # }
//! ```
//!
use std::io;

use soft_ascii_string::SoftAsciiString;
use futures_cpupool::{Builder, CpuPool};

use internals::error::EncodingError;
use headers::header_components::Domain;

use ::context::CompositeContext;
use ::default_impl::{FsResourceLoader, HashedIdGen};

/// Error returned when creating a "simple_context" fails.
#[derive(Debug, Fail)]
pub enum ContextSetupError {
    /// Reading the env variables failed.
    ///
    /// (Mainly getting the current working dir failed).
    #[fail(display="{}", _0)]
    ReadingEnv(io::Error),

    /// Punny encoding a non us-ascii domain failed.
    #[fail(display="{}", _0)]
    PunyCodingDomain(EncodingError)
}

/// Type Alias for a the type returned by `simple_context::new`.
pub type Context = CompositeContext<FsResourceLoader, CpuPool, HashedIdGen>;

/// create a new CompositeContext<FsResourceLoader, CpuPool, HashedIdGen>
///
/// It uses the current working directory as root for the `FsResourceLoader`,
/// and the default settings for the `CpuPool`, both the `domain` and
/// `unique_part` are passed to the `HashedIdGen::new` constructor.
///
/// Note that the combination of `unique_part` and `domain` should be world
/// unique. This is needed to generate `Content-Id` and `Message-Id` reliably
/// correctly. This means if you run multiple instances of softer using a context
/// or you create multiple contexts they should _not_ use the same `unique_part`
/// under any circumstances (expect if they use different domains, but then you
/// also should only use domain you actually own).
pub fn new(domain: Domain, unique_part: SoftAsciiString) -> Result<Context, ContextSetupError> {
    let resource_loader = FsResourceLoader
        ::with_cwd_root()
        .map_err(|err| ContextSetupError::ReadingEnv(err))?;

    let cpu_pool = Builder::new().create();

    let id_gen = HashedIdGen
        ::new(domain, unique_part)
        .map_err(|err| ContextSetupError::PunyCodingDomain(err))?;

    Ok(CompositeContext::new(
        resource_loader,
        cpu_pool,
        id_gen,
    ))
}