use std::time::{Duration, Instant};
use uuid::Uuid;
pub fn create_random_string(length: usize) -> String {
use uuid::Uuid;
let mut result = String::new();
while result.len() < length {
let uuid_str = Uuid::new_v4().to_string().replace('-', "");
result.push_str(&uuid_str);
}
result.truncate(length);
result
}
pub fn format_duration(duration_ms: u64) -> String {
if duration_ms < 1000 {
format!("{duration_ms}ms")
} else {
let seconds = duration_ms as f64 / 1000.0;
if seconds.fract() == 0.0 {
format!("{}s", seconds as u64)
} else {
format!("{seconds:.1}s")
}
}
}
pub fn current_time_millis() -> u64 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_millis() as u64
}
pub fn generate_uuid() -> String {
Uuid::new_v4().to_string()
}
pub fn safe_json_parse<T>(data: &str) -> Result<T, Box<dyn std::error::Error + Send + Sync>>
where
T: for<'de> serde::Deserialize<'de>,
{
match serde_json::from_str::<T>(data) {
Ok(parsed) => Ok(parsed),
Err(_) => {
let fixed_json = llm_json::repair_json(data, &Default::default())
.map_err(|e| format!("Failed to fix malformed JSON: {e}"))?;
serde_json::from_str::<T>(&fixed_json)
.map_err(|e| format!("Failed to parse even after JSON fixing: {e}").into())
}
}
}
pub fn parse_ai_response<T>(data: &str) -> Result<T, Box<dyn std::error::Error + Send + Sync>>
where
T: for<'de> serde::Deserialize<'de>,
{
safe_json_parse(data)
}
pub struct Throttle {
last_called: std::sync::Mutex<Option<Instant>>,
limit: Duration,
}
impl Throttle {
pub fn new(limit_ms: u64) -> Self {
Self {
last_called: std::sync::Mutex::new(None),
limit: Duration::from_millis(limit_ms),
}
}
pub fn execute<F, R>(&self, f: F) -> Option<R>
where
F: FnOnce() -> R,
{
let mut last_called = self.last_called.lock().unwrap();
let now = Instant::now();
match *last_called {
Some(last) if now.duration_since(last) < self.limit => None,
_ => {
*last_called = Some(now);
Some(f())
}
}
}
}
pub struct Debounce {
timer: std::sync::Mutex<Option<tokio::task::JoinHandle<()>>>,
delay: Duration,
}
impl Debounce {
pub fn new(delay_ms: u64) -> Self {
Self {
timer: std::sync::Mutex::new(None),
delay: Duration::from_millis(delay_ms),
}
}
pub async fn execute<F, Fut>(&self, f: F)
where
F: FnOnce() -> Fut + Send + 'static,
Fut: std::future::Future<Output = ()> + Send + 'static,
{
let mut timer = self.timer.lock().unwrap();
if let Some(handle) = timer.take() {
handle.abort();
}
let delay = self.delay;
*timer = Some(tokio::spawn(async move {
tokio::time::sleep(delay).await;
f().await;
}));
}
}