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    // reqwest builds its TLS config from the process-wide default provider
24    #[cfg(not(target_arch = "wasm32"))]
25    crate::tls::install_default_crypto_provider();
26
27    let mut b = ReqwestClientBuilder::new();
28
29    #[cfg(feature = "debug-inventory")]
30    let mut test_client = ReqwestClientBuilder::new();
31
32    let mut records: Vec<&'static ConfigRecord> =
33        inventory::iter::<ConfigRecord>.into_iter().collect();
34    records.sort_by_key(|r| r.priority); // lower runs first
35
36    #[cfg(feature = "debug-inventory")]
37    {
38        eprintln!(
39            "[HTTP-INVENTORY] Building client with {} registered configurations",
40            records.len()
41        );
42    }
43
44    for r in records {
45        b = (r.apply)(b);
46        #[cfg(feature = "debug-inventory")]
47        {
48            test_client = (r.apply)(test_client);
49        }
50    }
51
52    #[cfg(feature = "debug-inventory")]
53    {
54        eprintln!("[HTTP-INVENTORY] Final builder state (Debug):");
55        eprintln!("{:#?}", b);
56        eprintln!(
57            "[HTTP-INVENTORY] Note: reqwest::ClientBuilder doesn't expose all internal state"
58        );
59        eprintln!("[HTTP-INVENTORY] Building test client to verify configuration...");
60
61        // Try to build a client to see if it works
62        match test_client.build() {
63            Ok(client) => {
64                eprintln!("[HTTP-INVENTORY] ✓ Client built successfully");
65                eprintln!("[HTTP-INVENTORY] Client debug info: {:#?}", client);
66            }
67            Err(e) => {
68                eprintln!("[HTTP-INVENTORY] ✗ Failed to build client: {}", e);
69            }
70        }
71    }
72
73    b
74}
75
76/// Builds a client using the default builder with all registered configurations.
77pub fn build_client() -> reqwest::Result<reqwest::Client> {
78    default_builder().build()
79}
80
81/// Debug function to inspect registered configurations.
82/// Returns a vector of (priority, function_pointer) tuples for debugging.
83pub fn inspect_registered_configs() -> Vec<(i32, usize)> {
84    let mut configs: Vec<(i32, usize)> = inventory::iter::<ConfigRecord>
85        .into_iter()
86        .map(|record| (record.priority, record.apply as usize))
87        .collect();
88    configs.sort_by_key(|(priority, _)| *priority);
89    configs
90}
91
92/// Print all registered configurations to stderr for debugging.
93/// This shows the priority and function pointer address of each registered config.
94pub fn debug_print_inventory() {
95    eprintln!("[HTTP-INVENTORY] Registered configurations:");
96    let configs = inspect_registered_configs();
97    if configs.is_empty() {
98        eprintln!("  (none)");
99    } else {
100        for (i, (priority, ptr)) in configs.iter().enumerate() {
101            eprintln!(
102                "  [{:2}] Priority: {:4}, Function: 0x{:016x}",
103                i, priority, ptr
104            );
105        }
106        eprintln!("  Total: {} configurations", configs.len());
107    }
108}
109
110/// Returns the count of registered configuration records.
111pub fn registered_config_count() -> usize {
112    inventory::iter::<ConfigRecord>.into_iter().count()
113}