Files
Main/shanty-data/src/http.rs
T
Connor Johnstone 6f73bb87ce
CI / check (push) Successful in 1m12s
CI / docker (push) Successful in 2m1s
Added the playlist generator
2026-03-20 18:09:47 -04:00

65 lines
1.8 KiB
Rust

use std::sync::Arc;
use std::time::Duration;
use tokio::sync::Mutex;
use tokio::time::Instant;
/// A simple rate limiter that enforces a minimum interval between requests.
/// Can be cloned (via Arc) to share across multiple clients.
#[derive(Clone)]
pub struct RateLimiter {
last_request: Arc<Mutex<Instant>>,
interval: Duration,
}
impl RateLimiter {
pub fn new(interval: Duration) -> Self {
Self {
last_request: Arc::new(Mutex::new(Instant::now() - interval)),
interval,
}
}
/// Wait if needed so we don't exceed the rate limit.
pub async fn wait(&self) {
let mut last = self.last_request.lock().await;
let elapsed = last.elapsed();
if elapsed < self.interval {
tokio::time::sleep(self.interval - elapsed).await;
}
*last = Instant::now();
}
}
/// Build a reqwest client with a custom user agent and timeout.
pub fn build_client(user_agent: &str, timeout_secs: u64) -> reqwest::Result<reqwest::Client> {
reqwest::Client::builder()
.user_agent(user_agent)
.timeout(Duration::from_secs(timeout_secs))
.build()
}
/// Simple URL-encode for query parameters.
pub fn urlencoded(s: &str) -> String {
s.replace(' ', "+")
.replace('&', "%26")
.replace('=', "%3D")
.replace('#', "%23")
}
/// Escape special characters for MusicBrainz Lucene query syntax.
pub fn escape_lucene(s: &str) -> String {
let special = [
'+', '-', '&', '|', '!', '(', ')', '{', '}', '[', ']', '^', '"', '~', '*', '?', ':', '\\',
'/',
];
let mut result = String::with_capacity(s.len());
for c in s.chars() {
if special.contains(&c) {
result.push('\\');
}
result.push(c);
}
result
}