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