autoconfig 0.4.0

A simple implementation of Mozilla Thunderbird's autoconfig
Documentation
use regex::Regex;
use surf::Url;

use crate::{config::Config, dns::Dns, error::Result, http::Http, parse};

pub struct Client {
    http: Http,
    dns: Dns,
}

impl Client {
    pub async fn new() -> Result<Self> {
        let http = Http::new()?;
        let dns = Dns::new().await?;
        let client = Self { http, dns };

        Ok(client)
    }

    pub async fn get_config<U: AsRef<str>>(&self, url: U) -> Result<Config> {
        let bytes = self.http.get(url).await?;

        let config = parse::from_bytes(bytes)?;

        Ok(config)
    }

    const TXT_RECORD_REGEX: &str = r"^mailconf=(https?://\S+)$";

    pub async fn get_url_from_txt<N: AsRef<str>>(&self, name: N) -> Result<Vec<String>> {
        let records = self.dns.get_txt(name).await?;

        let re = Regex::new(Self::TXT_RECORD_REGEX).unwrap();

        let mut urls = Vec::new();

        for record in records {
            if let Some(record_str) = std::str::from_utf8(&record).ok() {
                if let Some(captured) = re.captures(record_str) {
                    if let Some(r#match) = captured.get(1) {
                        let url = r#match.as_str();

                        if let Some(url_parsed) = Url::parse(url).ok() {
                            if url_parsed.scheme() == "https" {
                                urls.push(url.to_string())
                            }
                        }
                    }
                }
            }
        }

        Ok(urls)
    }
}