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}