monovm-whois-rust 1.0.0

Domain WHOIS and RDAP lookups with availability detection, structured record parsing, referral chasing, caching and rate limiting.
Documentation
//! The facade: one object that ties the other layers together.
//!
//! Everything below this module does one job and knows nothing about the others.
//! A [`WhoisClient`] is what turns them into a lookup — resolve the suffix, order
//! the endpoints, ask, interpret, chase a referral, parse. It owns the sequence and
//! delegates every decision inside it.
//!
//! ```no_run
//! # #[cfg(feature = "blocking")] {
//! use monovm_whois::WhoisClient;
//!
//! let client = WhoisClient::new()?;
//! let lookup = client.lookup("example.com")?;
//!
//! println!("{} is {}", lookup.domain, lookup.availability());
//! # }
//! # Ok::<(), monovm_whois::Error>(())
//! ```
//!
//! # Configuring it
//!
//! Every collaborator is replaceable, and the builder is how:
//!
//! ```no_run
//! # #[cfg(feature = "blocking")] {
//! use std::time::Duration;
//! use monovm_whois::client::{Preference, ReferralPolicy};
//! use monovm_whois::WhoisClient;
//!
//! let client = WhoisClient::builder()
//!     .prefer(Preference::Rdap)
//!     .referrals(ReferralPolicy::eager(2))
//!     .memory_cache(Duration::from_secs(600))
//!     .throttle_per_host(Duration::from_millis(500))
//!     .build()?;
//! # }
//! # Ok::<(), monovm_whois::Error>(())
//! ```

#[cfg(any(feature = "blocking", feature = "async"))]
use std::sync::Arc;

#[cfg(any(feature = "blocking", feature = "async"))]
use crate::detect::DetectionEngine;
#[cfg(any(feature = "blocking", feature = "async"))]
use crate::registry::RegistryProvider;

#[cfg(all(feature = "parser", any(feature = "blocking", feature = "async")))]
use crate::parser::CompositeParser;

mod lookup;
mod plan;

// A checker needs a client to drive, so it only exists when one does.
#[cfg(any(feature = "blocking", feature = "async"))]
mod checker;

#[cfg(feature = "async")]
mod asynchronous;
#[cfg(feature = "blocking")]
mod blocking;

pub use lookup::{Explanation, Lookup};
pub use plan::{Plan, Preference, ReferralPolicy};

#[cfg(any(feature = "blocking", feature = "async"))]
pub use checker::{CheckReport, DEFAULT_POPULAR_TLDS};

#[cfg(feature = "async")]
pub use asynchronous::{AsyncWhoisClient, AsyncWhoisClientBuilder, DEFAULT_CONCURRENCY};
#[cfg(feature = "async")]
pub use checker::AsyncChecker;

#[cfg(feature = "blocking")]
pub use blocking::{WhoisClient, WhoisClientBuilder};
#[cfg(feature = "blocking")]
pub use checker::Checker;

/// The runtime-independent collaborators every client shares.
///
/// Kept as one struct so the blocking and asynchronous clients cannot drift apart
/// in what they hold — only in how they wait. Gated with them: with neither runtime
/// compiled in there is no client to hold it.
#[cfg(any(feature = "blocking", feature = "async"))]
#[derive(Debug, Clone)]
pub(crate) struct Parts {
    pub registry: Arc<dyn RegistryProvider>,
    pub engine: Arc<DetectionEngine>,
    #[cfg(feature = "parser")]
    pub parser: Arc<CompositeParser>,
    pub preference: Preference,
    pub referrals: ReferralPolicy,
}

#[cfg(any(feature = "blocking", feature = "async"))]
impl Parts {
    /// Fill in whatever the caller left unset.
    ///
    /// The parser is set separately by [`with_parser`](Parts::with_parser) rather than
    /// taken as a `#[cfg]`-gated parameter: attributes on call arguments are not stable
    /// Rust, so a gated parameter cannot actually be passed.
    pub(crate) fn new(
        registry: Option<Arc<dyn RegistryProvider>>,
        engine: Option<Arc<DetectionEngine>>,
        preference: Preference,
        referrals: ReferralPolicy,
    ) -> Self {
        Parts {
            registry: registry.unwrap_or_else(crate::registry::default_provider),
            engine: engine.unwrap_or_else(|| Arc::new(DetectionEngine::standard())),
            #[cfg(feature = "parser")]
            parser: Arc::new(CompositeParser::standard()),
            preference,
            referrals,
        }
    }

    /// Override the record parser, if the caller supplied one.
    #[cfg(feature = "parser")]
    pub(crate) fn with_parser(mut self, parser: Option<Arc<CompositeParser>>) -> Self {
        if let Some(parser) = parser {
            self.parser = parser;
        }
        self
    }
}