use serde_json::Value;
use std::time::Duration;
use tokio::time::sleep;
use crate::error::{Result, SdkError};
use super::client::{Client, ResultResponse};
#[derive(Clone)]
pub struct RetryClient {
client: Client,
max_retries: usize,
retry_delay: Duration,
}
impl RetryClient {
pub fn new(
base_url: impl Into<String>,
max_retries: usize,
retry_delay: Duration,
) -> Self {
Self {
client: Client::new(base_url),
max_retries,
retry_delay,
}
}
pub async fn execute_with_retry(
&self,
method: impl Into<String> + Clone,
params: Value,
) -> Result<ResultResponse> {
let mut last_error = None;
for attempt in 0..=self.max_retries {
match self.client.execute(method.clone(), params.clone()).await {
Ok(response) => return Ok(response),
Err(e) => {
last_error = Some(e);
if attempt < self.max_retries {
sleep(self.retry_delay).await;
}
}
}
}
Err(SdkError::Generic(format!(
"Failed after {} retries: {}",
self.max_retries,
last_error.unwrap()
)))
}
pub async fn execute_encrypted_with_retry(
&self,
method: impl Into<String> + Clone,
key: &str,
salt: i32,
params: Value,
) -> Result<ResultResponse> {
let mut last_error = None;
for attempt in 0..=self.max_retries {
match self.client.execute_encrypted(method.clone(), key, salt, params.clone()).await {
Ok(response) => return Ok(response),
Err(e) => {
last_error = Some(e);
if attempt < self.max_retries {
sleep(self.retry_delay).await;
}
}
}
}
Err(SdkError::Generic(format!(
"Failed after {} retries: {}",
self.max_retries,
last_error.unwrap()
)))
}
pub async fn execute_sync_with_retry(
&self,
method: impl Into<String> + Clone,
params: Value,
_timeout_duration: Duration,
) -> Result<ResultResponse> {
let exec_response = self.execute_with_retry(method, params).await?;
let result = self.client.get_result(&exec_response.task_id).await?;
Ok(result)
}
pub async fn execute_sync_encrypted_with_retry(
&self,
method: impl Into<String> + Clone,
key: &str,
salt: i32,
params: Value,
_timeout_duration: Duration,
) -> Result<ResultResponse> {
let exec_response = self.execute_encrypted_with_retry(method, key, salt, params).await?;
let result = self.client.get_result_encrypted(&exec_response.task_id, key, salt).await?;
Ok(result)
}
pub fn client(&self) -> &Client {
&self.client
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::time::Duration;
#[test]
fn test_retry_client_creation() {
let client = RetryClient::new(
"http://localhost:8080",
3,
Duration::from_millis(500),
);
assert_eq!(client.max_retries, 3);
assert_eq!(client.retry_delay, Duration::from_millis(500));
}
#[test]
fn test_client_access() {
let retry_client = RetryClient::new(
"http://localhost:8080",
3,
Duration::from_millis(500),
);
let _client = retry_client.client();
}
}