Skip to main content

nym_http_api_client/
registry.rs

1//! Global registry for HTTP client configurations.
2//!
3//! This module provides a compile-time registry system that allows any crate
4//! in the workspace to contribute configuration modifications to HTTP clients.
5
6use crate::ReqwestClientBuilder;
7
8/// A configuration record that modifies a `ReqwestClientBuilder`.
9///
10/// Records are collected at compile-time via the `inventory` crate and
11/// applied in priority order when building HTTP clients.
12pub struct ConfigRecord {
13    /// Lower numbers run earlier.
14    pub priority: i32,
15    /// A function that takes a builder and returns a mutated builder.
16    pub apply: fn(ReqwestClientBuilder) -> ReqwestClientBuilder,
17}
18
19inventory::collect!(ConfigRecord);
20
21/// Returns the default builder with all registered configurations applied.
22pub fn default_builder() -> ReqwestClientBuilder {
23    let mut b = ReqwestClientBuilder::new();
24
25    #[cfg(feature = "debug-inventory")]
26    let mut test_client = ReqwestClientBuilder::new();
27
28    let mut records: Vec<&'static ConfigRecord> =
29        inventory::iter::<ConfigRecord>.into_iter().collect();
30    records.sort_by_key(|r| r.priority); // lower runs first
31
32    #[cfg(feature = "debug-inventory")]
33    {
34        eprintln!(
35            "[HTTP-INVENTORY] Building client with {} registered configurations",
36            records.len()
37        );
38    }
39
40    for r in records {
41        b = (r.apply)(b);
42        #[cfg(feature = "debug-inventory")]
43        {
44            test_client = (r.apply)(test_client);
45        }
46    }
47
48    #[cfg(feature = "debug-inventory")]
49    {
50        eprintln!("[HTTP-INVENTORY] Final builder state (Debug):");
51        eprintln!("{:#?}", b);
52        eprintln!(
53            "[HTTP-INVENTORY] Note: reqwest::ClientBuilder doesn't expose all internal state"
54        );
55        eprintln!("[HTTP-INVENTORY] Building test client to verify configuration...");
56
57        // Try to build a client to see if it works
58        match test_client.build() {
59            Ok(client) => {
60                eprintln!("[HTTP-INVENTORY] ✓ Client built successfully");
61                eprintln!("[HTTP-INVENTORY] Client debug info: {:#?}", client);
62            }
63            Err(e) => {
64                eprintln!("[HTTP-INVENTORY] ✗ Failed to build client: {}", e);
65            }
66        }
67    }
68
69    b
70}
71
72/// Builds a client using the default builder with all registered configurations.
73pub fn build_client() -> reqwest::Result<reqwest::Client> {
74    default_builder().build()
75}
76
77/// Debug function to inspect registered configurations.
78/// Returns a vector of (priority, function_pointer) tuples for debugging.
79pub fn inspect_registered_configs() -> Vec<(i32, usize)> {
80    let mut configs: Vec<(i32, usize)> = inventory::iter::<ConfigRecord>
81        .into_iter()
82        .map(|record| (record.priority, record.apply as usize))
83        .collect();
84    configs.sort_by_key(|(priority, _)| *priority);
85    configs
86}
87
88/// Print all registered configurations to stderr for debugging.
89/// This shows the priority and function pointer address of each registered config.
90pub fn debug_print_inventory() {
91    eprintln!("[HTTP-INVENTORY] Registered configurations:");
92    let configs = inspect_registered_configs();
93    if configs.is_empty() {
94        eprintln!("  (none)");
95    } else {
96        for (i, (priority, ptr)) in configs.iter().enumerate() {
97            eprintln!(
98                "  [{:2}] Priority: {:4}, Function: 0x{:016x}",
99                i, priority, ptr
100            );
101        }
102        eprintln!("  Total: {} configurations", configs.len());
103    }
104}
105
106/// Returns the count of registered configuration records.
107pub fn registered_config_count() -> usize {
108    inventory::iter::<ConfigRecord>.into_iter().count()
109}