domain_check_lib/
types.rs

1//! Core data types for domain availability checking.
2//!
3//! This module defines all the main data structures used throughout the library,
4//! including domain results, configuration options, and output formatting.
5
6use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8use std::time::Duration;
9
10/// Result of a domain availability check.
11///
12/// Contains all information about a domain's availability status,
13/// registration details, and metadata about the check itself.
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct DomainResult {
16    /// The domain name that was checked (e.g., "example.com")
17    pub domain: String,
18
19    /// Whether the domain is available for registration.
20    /// - `Some(true)`: Domain is available
21    /// - `Some(false)`: Domain is taken/registered  
22    /// - `None`: Status could not be determined
23    pub available: Option<bool>,
24
25    /// Detailed registration information (only available for taken domains)
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pub info: Option<DomainInfo>,
28
29    /// How long the domain check took to complete
30    #[serde(skip_serializing_if = "Option::is_none")]
31    pub check_duration: Option<Duration>,
32
33    /// Which method was used to check the domain
34    pub method_used: CheckMethod,
35
36    /// Any error message if the check failed
37    #[serde(skip_serializing_if = "Option::is_none")]
38    pub error_message: Option<String>,
39}
40
41/// Detailed information about a registered domain.
42///
43/// This information is typically extracted from RDAP responses
44/// and provides insights into the domain's registration details.
45#[derive(Debug, Clone, Serialize, Deserialize, Default)]
46pub struct DomainInfo {
47    /// The registrar that manages this domain
48    #[serde(skip_serializing_if = "Option::is_none")]
49    pub registrar: Option<String>,
50
51    /// When the domain was first registered
52    #[serde(skip_serializing_if = "Option::is_none")]
53    pub creation_date: Option<String>,
54
55    /// When the domain registration expires
56    #[serde(skip_serializing_if = "Option::is_none")]
57    pub expiration_date: Option<String>,
58
59    /// Domain status codes (e.g., "clientTransferProhibited")
60    pub status: Vec<String>,
61
62    /// Last update date of the domain record
63    #[serde(skip_serializing_if = "Option::is_none")]
64    pub updated_date: Option<String>,
65
66    /// Nameservers associated with the domain
67    pub nameservers: Vec<String>,
68}
69
70/// Configuration options for domain checking operations.
71///
72/// This struct allows fine-tuning of the domain checking behavior,
73/// including performance, timeout, and protocol preferences.
74#[derive(Debug, Clone, Serialize, Deserialize)]
75pub struct CheckConfig {
76    /// Maximum number of concurrent domain checks
77    /// Default: 10, Range: 1-100
78    pub concurrency: usize,
79
80    /// Timeout for each individual domain check
81    /// Default: 5 seconds
82    #[serde(skip)] // Don't serialize Duration directly
83    pub timeout: Duration,
84
85    /// Whether to automatically fall back to WHOIS when RDAP fails
86    /// Default: true
87    pub enable_whois_fallback: bool,
88
89    /// Whether to use IANA bootstrap registry for unknown TLDs
90    /// Default: false (uses built-in registry only)
91    pub enable_bootstrap: bool,
92
93    /// Whether to extract detailed domain information for taken domains
94    /// Default: false (just availability status)
95    pub detailed_info: bool,
96
97    /// List of TLDs to check for base domain names
98    /// If None, defaults to ["com"]
99    pub tlds: Option<Vec<String>>,
100
101    /// Custom timeout for RDAP requests (separate from overall timeout)
102    /// Default: 3 seconds
103    #[serde(skip)] // Don't serialize Duration directly
104    pub rdap_timeout: Duration,
105
106    /// Custom timeout for WHOIS requests
107    /// Default: 5 seconds  
108    #[serde(skip)] // Don't serialize Duration directly
109    pub whois_timeout: Duration,
110
111    /// Custom user-defined TLD presets from config files
112    /// Default: empty
113    #[serde(skip)] // Handled separately in config merging
114    pub custom_presets: HashMap<String, Vec<String>>,
115}
116
117/// Method used to check domain availability.
118///
119/// This helps users understand which protocol was used
120/// and can be useful for debugging or performance analysis.
121#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
122pub enum CheckMethod {
123    /// Domain checked via RDAP protocol
124    #[serde(rename = "rdap")]
125    Rdap,
126
127    /// Domain checked via WHOIS protocol
128    #[serde(rename = "whois")]
129    Whois,
130
131    /// RDAP endpoint discovered via IANA bootstrap registry
132    #[serde(rename = "bootstrap")]
133    Bootstrap,
134
135    /// Check failed or method unknown
136    #[serde(rename = "unknown")]
137    Unknown,
138}
139
140/// Output mode for displaying results.
141///
142/// This controls how and when results are presented to the user,
143/// affecting both performance perception and data formatting.
144#[derive(Debug, Clone, PartialEq)]
145pub enum OutputMode {
146    /// Stream results as they become available (good for interactive use)
147    Streaming,
148
149    /// Collect all results before displaying (good for formatting/sorting)
150    Collected,
151
152    /// Automatically choose based on context (terminal vs pipe, etc.)
153    Auto,
154}
155
156impl Default for CheckConfig {
157    /// Create a sensible default configuration.
158    ///
159    /// These defaults are chosen to work well for most use cases
160    /// while being conservative about resource usage.
161    fn default() -> Self {
162        Self {
163            concurrency: 20,
164            timeout: Duration::from_secs(5),
165            enable_whois_fallback: true,
166            enable_bootstrap: false,
167            detailed_info: false,
168            tlds: None, // Will default to ["com"] when needed
169            rdap_timeout: Duration::from_secs(3),
170            whois_timeout: Duration::from_secs(5),
171            custom_presets: HashMap::new(),
172        }
173    }
174}
175
176impl CheckConfig {
177    /// Create a new configuration with custom concurrency.
178    ///
179    /// Automatically caps concurrency at 100 to prevent resource exhaustion.
180    pub fn with_concurrency(mut self, concurrency: usize) -> Self {
181        self.concurrency = concurrency.clamp(1, 100);
182        self
183    }
184
185    /// Set custom timeout for domain checks.
186    pub fn with_timeout(mut self, timeout: Duration) -> Self {
187        self.timeout = timeout;
188        self
189    }
190
191    /// Enable or disable WHOIS fallback.
192    pub fn with_whois_fallback(mut self, enabled: bool) -> Self {
193        self.enable_whois_fallback = enabled;
194        self
195    }
196
197    /// Enable or disable IANA bootstrap registry.
198    pub fn with_bootstrap(mut self, enabled: bool) -> Self {
199        self.enable_bootstrap = enabled;
200        self
201    }
202
203    /// Enable detailed domain information extraction.
204    pub fn with_detailed_info(mut self, enabled: bool) -> Self {
205        self.detailed_info = enabled;
206        self
207    }
208
209    /// Set TLDs to check for base domain names.
210    pub fn with_tlds(mut self, tlds: Vec<String>) -> Self {
211        self.tlds = Some(tlds);
212        self
213    }
214}
215
216impl std::fmt::Display for CheckMethod {
217    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
218        match self {
219            CheckMethod::Rdap => write!(f, "RDAP"),
220            CheckMethod::Whois => write!(f, "WHOIS"),
221            CheckMethod::Bootstrap => write!(f, "Bootstrap"),
222            CheckMethod::Unknown => write!(f, "Unknown"),
223        }
224    }
225}
226
227impl std::fmt::Display for OutputMode {
228    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
229        match self {
230            OutputMode::Streaming => write!(f, "Streaming"),
231            OutputMode::Collected => write!(f, "Collected"),
232            OutputMode::Auto => write!(f, "Auto"),
233        }
234    }
235}