use crate::client::ClientRequest;
use crate::errors::{SDKError, ValidationError};
use crate::response::ClientResponse;
use crate::traits::Client;
use std::future::Future;
use std::time::Duration;
#[derive(Clone)]
pub struct ClientBuilder {
base_url: Option<String>,
timeout: Duration,
auth_token: Option<String>,
}
impl std::fmt::Debug for ClientBuilder {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ClientBuilder")
.field("base_url", &self.base_url)
.field("timeout", &self.timeout)
.field(
"auth_token",
&self.auth_token.as_ref().map(|_| "***REDACTED***"),
)
.finish()
}
}
impl Default for ClientBuilder {
fn default() -> Self {
Self {
base_url: None,
timeout: Duration::from_secs(30),
auth_token: None,
}
}
}
impl ClientBuilder {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn base_url(mut self, base_url: impl Into<String>) -> Self {
self.base_url = Some(base_url.into());
self
}
#[must_use]
pub fn timeout(mut self, timeout: Duration) -> Self {
self.timeout = timeout;
self
}
#[must_use]
pub fn auth_token(mut self, auth_token: impl Into<String>) -> Self {
self.auth_token = Some(auth_token.into());
self
}
pub fn build(self) -> Result<BuiltClient, SDKError> {
let base_url = self
.base_url
.ok_or_else(|| SDKError::Validation(ValidationError::new("base_url is required")))?;
let auth_token = self
.auth_token
.ok_or_else(|| SDKError::Validation(ValidationError::new("auth_token is required")))?;
Ok(BuiltClient {
base_url,
timeout: self.timeout,
auth_token,
})
}
}
#[derive(Clone)]
pub struct BuiltClient {
base_url: String,
timeout: Duration,
auth_token: String,
}
impl std::fmt::Debug for BuiltClient {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("BuiltClient")
.field("base_url", &self.base_url)
.field("timeout", &self.timeout)
.field("auth_token", &"***REDACTED***")
.finish()
}
}
impl BuiltClient {
#[must_use]
pub fn base_url(&self) -> &str {
&self.base_url
}
#[must_use]
pub fn timeout(&self) -> Duration {
self.timeout
}
#[must_use]
pub fn auth_token(&self) -> &str {
&self.auth_token
}
}
impl Client for BuiltClient {
#[allow(clippy::manual_async_fn)]
fn send_request(
&self,
request: ClientRequest,
) -> impl Future<Output = Result<ClientResponse, SDKError>> + Send {
async move {
let _ = request;
Err(SDKError::Validation(ValidationError::new(
"Not implemented",
)))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_client_builder_defaults() {
let builder = ClientBuilder::new();
assert_eq!(builder.timeout, Duration::from_secs(30));
assert!(builder.base_url.is_none());
assert!(builder.auth_token.is_none());
}
#[test]
fn test_client_builder_validation_error_url() {
let builder = ClientBuilder::new().auth_token("secret");
let result = builder.build();
assert!(result.is_err());
if let Err(SDKError::Validation(e)) = result {
assert_eq!(e.message, "base_url is required");
} else {
panic!("Expected validation error");
}
}
#[test]
fn test_client_builder_validation_error_auth() {
let builder = ClientBuilder::new().base_url("https://api.example.com");
let result = builder.build();
assert!(result.is_err());
if let Err(SDKError::Validation(e)) = result {
assert_eq!(e.message, "auth_token is required");
} else {
panic!("Expected validation error");
}
}
#[test]
fn test_client_builder_success() {
let builder = ClientBuilder::new()
.base_url("https://api.example.com")
.auth_token("secret")
.timeout(Duration::from_secs(10));
let client = builder.build().unwrap();
assert_eq!(client.base_url, "https://api.example.com");
assert_eq!(client.auth_token, "secret");
assert_eq!(client.timeout, Duration::from_secs(10));
}
#[tokio::test]
async fn test_built_client_send_request() {
let builder = ClientBuilder::new()
.base_url("https://api.example.com")
.auth_token("secret");
let client = builder.build().unwrap();
let request = ClientRequest::default();
let result = client.send_request(request).await;
assert!(result.is_err());
if let Err(SDKError::Validation(e)) = result {
assert_eq!(e.message, "Not implemented");
} else {
panic!("Expected validation error with message 'Not implemented'");
}
}
}
pub mod request;
pub use request::RequestBuilder;
pub mod conversation;
pub use conversation::ConversationBuilder;
pub mod message;
pub use message::MessageBuilder;