1use serde::{Deserialize, Serialize};
2use std::net::SocketAddr;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
5pub enum NetMode {
7 Ipv4Only,
9 Ipv6Only,
11 #[default]
12 DualStack,
14}
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct TorrentInfo {
19 pub info_hash: String,
21 pub magnet_link: String,
23 pub name: String,
25 pub total_size: u64,
27 pub files: Vec<FileInfo>,
29 pub piece_length: u64,
31 pub peers: Vec<String>,
33 pub timestamp: u64,
35}
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
39pub enum MetadataFetchCompletionStatus {
40 Accepted,
42 FetchFailed,
44 DeliveryRejected,
46}
47
48#[derive(Debug, Clone, PartialEq, Eq)]
50pub struct MetadataFetchCompletion {
51 pub info_hash: String,
53 pub status: MetadataFetchCompletionStatus,
55 pub attempts: usize,
57}
58
59impl MetadataFetchCompletion {
60 pub fn is_success(&self) -> bool {
62 self.status == MetadataFetchCompletionStatus::Accepted
63 }
64}
65
66#[derive(Debug, Clone, Serialize, Deserialize)]
67pub struct FileInfo {
69 pub path: String,
71 pub size: u64,
73}
74
75#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
76pub struct NodeTuple {
78 pub id: [u8; 20],
80 pub addr: SocketAddr,
82}
83
84impl TorrentInfo {
85 pub fn format_size(&self) -> String {
87 format_bytes(self.total_size)
88 }
89}
90
91impl FileInfo {
92 pub fn format_size(&self) -> String {
94 format_bytes(self.size)
95 }
96}
97
98fn format_bytes(bytes: u64) -> String {
99 const UNITS: &[&str] = &["B", "KB", "MB", "GB", "TB"];
100 let mut size = bytes as f64;
101 let mut unit_index = 0;
102 while size >= 1024.0 && unit_index < UNITS.len() - 1 {
103 size /= 1024.0;
104 unit_index += 1;
105 }
106 format!("{size:.2} {}", UNITS[unit_index])
107}
108
109#[derive(Debug, Clone)]
110pub struct DHTOptions {
112 pub port: u16,
114 pub netmode: NetMode,
116 pub hash_queue_capacity: usize,
118 pub metadata: MetadataOptions,
120 pub peer_lookup: PeerLookupOptions,
122 pub crawl: CrawlOptions,
124}
125
126#[derive(Debug, Clone)]
127pub struct MetadataOptions {
129 pub timeout_secs: u64,
131 pub max_queue_size: usize,
133 pub max_worker_count: usize,
135 pub peer_failure_cache_capacity: usize,
137 pub peer_failure_ttl_secs: u64,
139}
140
141#[derive(Debug, Clone)]
142pub struct PeerLookupOptions {
144 pub max_lookups_per_second: u32,
146 pub burst: u32,
148 pub max_active_lookups: usize,
150}
151
152#[derive(Debug, Clone, Default)]
153pub struct CrawlOptions {
155 pub pool: PoolOptions,
157 pub rate_limit: RateLimitOptions,
159 pub bootstrap: BootstrapOptions,
161 pub target: TargetOptions,
163 pub scheduler: SchedulerOptions,
165}
166
167#[derive(Debug, Clone)]
168pub struct RateLimitOptions {
170 pub max_find_node_rate_per_sec: u32,
172 pub burst: u32,
174 pub max_in_flight: usize,
176 pub request_timeout_secs: u64,
178 pub max_new_destinations_per_minute: u32,
180 pub max_response_rate_per_sec: u32,
182 pub max_response_bytes_per_sec: u64,
184 pub max_response_rate_per_source: u32,
186 pub metadata_pressure_floor_percent: u8,
188 pub max_replacements_per_minute: u32,
190 pub max_in_flight_per_subnet: usize,
192}
193
194#[derive(Debug, Clone)]
195pub struct PoolOptions {
197 pub capacity: usize,
199 pub recent_probe_ttl_secs: u64,
201 pub responsive_capacity: usize,
203 pub responsive_ttl_secs: u64,
205 pub low_watermark: usize,
207}
208
209#[derive(Debug, Clone)]
210pub struct BootstrapOptions {
212 pub nodes: Vec<String>,
214 pub interval_secs: u64,
216 pub max_nodes_per_round: usize,
218 pub source_backoff_base_secs: u64,
220 pub source_backoff_max_secs: u64,
222}
223
224#[derive(Debug, Clone)]
225pub struct TargetOptions {
227 pub random_walk_percent: u8,
229 pub sparse_bucket_percent: u8,
231 pub neighbor_sender_id: bool,
233}
234
235#[derive(Debug, Clone)]
236pub struct SchedulerOptions {
238 pub priority_event_channel_capacity: usize,
240 pub discovery_event_channel_capacity: usize,
242 pub event_batch_limit: usize,
244 pub node_batch_limit: usize,
246 pub routing_snapshot_size: usize,
248 pub snapshot_refresh_millis: u64,
250}
251
252impl Default for DHTOptions {
253 fn default() -> Self {
254 Self {
255 port: 6881,
256 netmode: NetMode::Ipv4Only,
257 hash_queue_capacity: 10_000,
258 metadata: MetadataOptions::default(),
259 peer_lookup: PeerLookupOptions::default(),
260 crawl: CrawlOptions::default(),
261 }
262 }
263}
264
265impl Default for MetadataOptions {
266 fn default() -> Self {
267 Self {
268 timeout_secs: 4,
269 max_queue_size: 10_000,
270 max_worker_count: 256,
271 peer_failure_cache_capacity: 200_000,
272 peer_failure_ttl_secs: 60,
273 }
274 }
275}
276
277impl Default for PeerLookupOptions {
278 fn default() -> Self {
279 Self {
280 max_lookups_per_second: 32,
281 burst: 32,
282 max_active_lookups: 64,
283 }
284 }
285}
286
287impl Default for RateLimitOptions {
288 fn default() -> Self {
289 Self {
290 max_find_node_rate_per_sec: 200,
291 burst: 40,
292 max_in_flight: 512,
293 request_timeout_secs: 2,
294 max_new_destinations_per_minute: 10_000,
295 max_response_rate_per_sec: 500,
296 max_response_bytes_per_sec: 1024 * 1024,
297 max_response_rate_per_source: 40,
298 metadata_pressure_floor_percent: 25,
299 max_replacements_per_minute: 25_000,
300 max_in_flight_per_subnet: 8,
301 }
302 }
303}
304
305impl Default for PoolOptions {
306 fn default() -> Self {
307 Self {
308 capacity: 100_000,
309 recent_probe_ttl_secs: 600,
310 responsive_capacity: 16_384,
311 responsive_ttl_secs: 900,
312 low_watermark: 10_000,
313 }
314 }
315}
316
317impl Default for BootstrapOptions {
318 fn default() -> Self {
319 Self {
320 nodes: vec![
321 "router.bittorrent.com:6881".to_string(),
322 "dht.transmissionbt.com:6881".to_string(),
323 "router.utorrent.com:6881".to_string(),
324 "dht.aelitis.com:6881".to_string(),
325 ],
326 interval_secs: 300,
327 max_nodes_per_round: 3,
328 source_backoff_base_secs: 300,
329 source_backoff_max_secs: 3_600,
330 }
331 }
332}
333
334impl Default for TargetOptions {
335 fn default() -> Self {
336 Self {
337 random_walk_percent: 70,
338 sparse_bucket_percent: 30,
339 neighbor_sender_id: true,
340 }
341 }
342}
343
344impl Default for SchedulerOptions {
345 fn default() -> Self {
346 Self {
347 priority_event_channel_capacity: 8_192,
348 discovery_event_channel_capacity: 16_384,
349 event_batch_limit: 256,
350 node_batch_limit: 4_096,
351 routing_snapshot_size: 4_096,
352 snapshot_refresh_millis: 1_000,
353 }
354 }
355}