1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
45use error::RestmailClientError;
6use error_support::{info, warn};
7use serde_json::Value as EmailJson;
8use url::Url;
9use viaduct::Request;
1011mod error;
1213type Result<T> = std::result::Result<T, RestmailClientError>;
1415/// For a given restmail email, find the first email that satisfies the given predicate.
16/// If no email is found, this function sleeps for a few seconds then tries again, up
17/// to `max_tries` times.
18pub fn find_email<F>(email: &str, predicate: F, max_tries: u8) -> Result<EmailJson>
19where
20F: Fn(&EmailJson) -> bool,
21{
22let mail_url = url_for_email(email)?;
23info!("Checking {} up to {} times.", email, max_tries);
24for i in 0..max_tries {
25let resp: Vec<serde_json::Value> = Request::get(mail_url.clone()).send()?.json()?;
26let mut matching_emails: Vec<serde_json::Value> =
27 resp.into_iter().filter(|email| predicate(email)).collect();
2829if matching_emails.is_empty() {
30info!(
31"Failed to find matching email. Waiting {} seconds and retrying.",
32 i + 1
33);
34 std::thread::sleep(std::time::Duration::from_secs((i + 1).into()));
35continue;
36 }
3738if matching_emails.len() > 1 {
39info!(
40"Found {} emails that applies (taking latest)",
41 matching_emails.len()
42 );
43 matching_emails.sort_by(|a, b| {
44let a_time = a["receivedAt"].as_u64();
45let b_time = b["receivedAt"].as_u64();
46match (a_time, b_time) {
47 (Some(a_time), Some(b_time)) => b_time.cmp(&a_time),
48_ => {
49warn!("Could not de-serialize receivedAt for at least one of the emails.");
50 std::cmp::Ordering::Equal
51 }
52 }
53 })
54 }
55return Ok(matching_emails[0].clone());
56 }
57info!("Error: Failed to find email after {} tries!", max_tries);
58Err(RestmailClientError::HitRetryMax)
59}
6061pub fn clear_mailbox(email: &str) -> Result<()> {
62let mail_url = url_for_email(email)?;
63info!("Clearing restmail for {}.", email);
64 Request::delete(mail_url).send()?;
65Ok(())
66}
6768fn username_from_email(email: &str) -> Result<String> {
69let user = email.replace("@restmail.net", "");
70if user.len() == email.len() {
71return Err(RestmailClientError::NotARestmailEmail);
72 }
73Ok(user)
74}
7576fn url_for_email(email: &str) -> Result<Url> {
77let restmail_user = username_from_email(email)?;
78let path = format!("/mail/{}", restmail_user);
79Ok(Url::parse("https://restmail.net")?.join(&path)?)
80}