gov-uk-sdk-core 0.1.0

Shared HTTP client, auth, errors, and content negotiation for GOV.UK / Companies House SDK crates.
Documentation
use std::collections::VecDeque;
use std::sync::Mutex;
use std::time::{Duration, Instant};

/// Client-side throttle aligned with Companies House guidance: **600 requests per 5 minutes**
/// per application (optional; enabled by default on [`crate::SdkClientBuilder`]).
pub(crate) struct WindowRateLimiter {
    window: Duration,
    max_requests: usize,
    stamps: Mutex<VecDeque<Instant>>,
}

impl WindowRateLimiter {
    /// **600** requests per **5** minutes sliding window (Companies House public API guidance).
    pub fn companies_house_default() -> Self {
        Self {
            window: Duration::from_secs(5 * 60),
            max_requests: 600,
            stamps: Mutex::new(VecDeque::new()),
        }
    }

    /// Wait until a slot is available, then record this request.
    pub async fn acquire(&self) {
        loop {
            let wait = {
                let mut stamps = self.stamps.lock().unwrap_or_else(|p| p.into_inner());
                let now = Instant::now();
                while stamps
                    .front()
                    .is_some_and(|t| now.duration_since(*t) > self.window)
                {
                    stamps.pop_front();
                }
                if stamps.len() < self.max_requests {
                    stamps.push_back(now);
                    return;
                }
                let oldest = *stamps.front().expect("non-empty when at capacity");
                self.window.saturating_sub(now.duration_since(oldest))
            };
            if wait.is_zero() {
                tokio::time::sleep(Duration::from_millis(1)).await;
            } else {
                tokio::time::sleep(wait).await;
            }
        }
    }
}