vonage 0.1.1

Unified Rust SDK for Vonage APIs
Documentation
//! Main Vonage client implementation

use vonage_core::{Result, HttpConfig, Auth};
use vonage_sms::{SmsClient, SmsRequest, SmsResponse};
use crate::builder::VonageBuilder;

/// Main Vonage client providing access to all Vonage services
pub struct Vonage {
    auth: Box<dyn Auth + Send + Sync>,
    sms_client: SmsClient,
}

impl std::fmt::Debug for Vonage {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("Vonage")
            .field("sms_client", &self.sms_client)
            .finish()
    }
}

impl Vonage {
    /// Create a new Vonage client with default configuration
    /// 
    /// # Arguments
    /// 
    /// * `auth` - Authentication credentials
    /// 
    /// # Examples
    /// 
    /// ```rust
    /// use vonage::{Vonage, BasicAuth};
    /// 
    /// # fn example() -> Result<(), Box<dyn std::error::Error>> {
    /// let vonage = Vonage::new(BasicAuth::new("api_key", "api_secret"))?;
    /// # Ok(())
    /// # }
    /// ```
    pub fn new<A: Auth + Clone + Send + Sync + 'static>(auth: A) -> Result<Self> {
        Self::with_config(auth, HttpConfig::default())
    }
    
    /// Create a new Vonage client with custom configuration
    /// 
    /// # Arguments
    /// 
    /// * `auth` - Authentication credentials
    /// * `config` - HTTP client configuration
    pub fn with_config<A: Auth + Clone + Send + Sync + 'static>(
        auth: A, 
        config: HttpConfig
    ) -> Result<Self> {
        let sms_client = SmsClient::with_config(config.clone())?;
        
        Ok(Self {
            auth: Box::new(auth),
            sms_client,
        })
    }
    
    /// Create a builder for configuring the client
    /// 
    /// # Examples
    /// 
    /// ```rust
    /// use vonage::{Vonage, BasicAuth, Region};
    /// use std::time::Duration;
    /// 
    /// # fn example() -> Result<(), Box<dyn std::error::Error>> {
    /// let vonage = Vonage::builder()
    ///     .region(Region::EuWest)
    ///     .timeout(Duration::from_secs(60))
    ///     .build(BasicAuth::new("api_key", "api_secret"))?;
    /// # Ok(())
    /// # }
    /// ```
    pub fn builder() -> VonageBuilder {
        VonageBuilder::new()
    }
    
    /// Get access to SMS functionality
    /// 
    /// # Examples
    /// 
    /// ```rust
    /// use vonage::{Vonage, BasicAuth};
    /// use vonage::sms::SmsRequest;
    /// 
    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
    /// let vonage = Vonage::new(BasicAuth::new("api_key", "api_secret"))?;
    /// let request = SmsRequest::text("Vonage", "15551234567", "Hello!");
    /// let response = vonage.sms().send(&request).await?;
    /// # Ok(())
    /// # }
    /// ```
    pub fn sms(&self) -> SmsService<'_> {
        SmsService {
            client: &self.sms_client,
            auth: self.auth.as_ref(),
        }
    }
}

/// SMS service wrapper that includes authentication
pub struct SmsService<'a> {
    client: &'a SmsClient,
    auth: &'a dyn Auth,
}

impl<'a> std::fmt::Debug for SmsService<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("SmsService")
            .field("client", &self.client)
            .finish()
    }
}

impl<'a> SmsService<'a> {
    /// Send an SMS message
    /// 
    /// # Arguments
    /// 
    /// * `request` - SMS request parameters
    /// 
    /// # Returns
    /// 
    /// Returns an `SmsResponse` containing details about sent messages
    /// 
    /// # Examples
    /// 
    /// ```rust
    /// use vonage::{Vonage, BasicAuth};
    /// use vonage::sms::SmsRequest;
    /// 
    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
    /// let vonage = Vonage::new(BasicAuth::new("api_key", "api_secret"))?;
    /// let request = SmsRequest::text("Vonage", "15551234567", "Hello World!");
    /// 
    /// let response = vonage.sms().send(&request).await?;
    /// println!("Message sent with {} parts", response.message_count);
    /// 
    /// if !response.all_successful() {
    ///     for failed in response.failed_messages() {
    ///         let to = failed.to.as_deref().unwrap_or("unknown");
    ///         println!("Failed to send to {}: {}", 
    ///             to, 
    ///             failed.status.description()
    ///         );
    ///     }
    /// }
    /// # Ok(())
    /// # }
    /// ```
    pub async fn send(&self, request: &SmsRequest) -> Result<SmsResponse> {
        self.client.send(self.auth, request).await
    }
    
    /// Send a simple text message (convenience method)
    /// 
    /// # Arguments
    /// 
    /// * `from` - Sender ID or phone number
    /// * `to` - Recipient phone number  
    /// * `text` - Message text
    /// 
    /// # Examples
    /// 
    /// ```rust
    /// use vonage::{Vonage, BasicAuth};
    /// 
    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
    /// let vonage = Vonage::new(BasicAuth::new("api_key", "api_secret"))?;
    /// 
    /// let response = vonage.sms().send_text("Vonage", "15551234567", "Hello!").await?;
    /// if let Some(message_id) = &response.messages[0].message_id {
    ///     println!("Sent message with ID: {}", message_id);
    /// }
    /// # Ok(())
    /// # }
    /// ```
    pub async fn send_text(
        &self,
        from: impl Into<String>,
        to: impl Into<String>,
        text: impl Into<String>,
    ) -> Result<SmsResponse> {
        let request = SmsRequest::text(from, to, text);
        self.send(&request).await
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use vonage_core::BasicAuth;
    
    #[test]
    fn test_vonage_client_creation() {
        let auth = BasicAuth::new("test_key", "test_secret");
        let vonage = Vonage::new(auth);
        assert!(vonage.is_ok());
    }
    
    #[test]
    fn test_vonage_builder() {
        use vonage_core::Region;
        use std::time::Duration;
        
        let auth = BasicAuth::new("test_key", "test_secret");
        let vonage = Vonage::builder()
            .region(Region::EuWest)
            .timeout(Duration::from_secs(60))
            .build(auth);
        
        assert!(vonage.is_ok());
    }
    
    #[test]
    fn test_sms_service_access() {
        let auth = BasicAuth::new("test_key", "test_secret");
        let vonage = Vonage::new(auth).unwrap();
        
        // Test that we can access the SMS service
        let _sms_service = vonage.sms();
    }
}