limon-core 0.3.3

limon core library
Documentation
use std::net::IpAddr;
use std::sync::Arc;
use std::time::Duration;

use once_cell::sync::Lazy;
use trust_dns_resolver::TokioAsyncResolver;
use trust_dns_resolver::error::ResolveError;

#[doc(hidden)]
#[macro_export]
macro_rules! measure {
  ($block:block) => {{
    let start = std::time::Instant::now();
    let result = { $block };

    (result, start.elapsed())
  }};
}

static _RESOLVER: Lazy<Arc<TokioAsyncResolver>> =
  Lazy::new(|| Arc::new(TokioAsyncResolver::tokio_from_system_conf().expect("system resolver")));

pub struct Dns;

impl Dns {
  pub async fn measure(host: &String) -> Result<(IpAddr, Duration), ResolveError> {
    let host = host.rsplit_once(':').map(|(h, _port)| h).unwrap_or(host);
    let (lookup_ip, lookup_duration) = measure!({ Arc::clone(&_RESOLVER).lookup_ip(host).await? });

    Ok((
      lookup_ip
        .iter()
        .next()
        .ok_or(ResolveError::from("No records found"))?,
      lookup_duration,
    ))
  }
}

#[cfg(test)]
mod tests {
  use super::*;

  #[tokio::test]
  async fn resolve_localhost() {
    let (ip_addr, lookup_duration) = Dns::measure(&String::from("localhost")).await.unwrap();

    assert!(ip_addr.is_loopback());
    assert!(!lookup_duration.is_zero());
  }

  #[tokio::test]
  async fn resolve_localhost_with_port() {
    let (ip_addr, lookup_duration) = Dns::measure(&String::from("localhost:5555")).await.unwrap();

    assert!(ip_addr.is_loopback());
    assert!(!lookup_duration.is_zero());
  }
}