Skip to main content

avila_cell/
pool.rs

1//! Connection pooling for SMTP clients
2
3use crate::smtp::{SmtpClient, SmtpSecurity};
4use avila_error::{Error, ErrorKind, Result};
5use avila_molecule::NetworkAddress;
6use std::collections::VecDeque;
7
8/// Connection pool for SMTP clients
9pub struct SmtpPool {
10    host: String,
11    port: u16,
12    security: SmtpSecurity,
13    max_connections: usize,
14    available: VecDeque<SmtpClient>,
15    in_use: usize,
16}
17
18impl SmtpPool {
19    /// Creates a new connection pool
20    pub fn new(host: String, port: u16, max_connections: usize) -> Self {
21        Self {
22            host,
23            port,
24            security: SmtpSecurity::None,
25            max_connections,
26            available: VecDeque::new(),
27            in_use: 0,
28        }
29    }
30
31    /// Creates pool with security
32    pub fn with_security(host: String, port: u16, security: SmtpSecurity, max_connections: usize) -> Self {
33        Self {
34            host,
35            port,
36            security,
37            max_connections,
38            available: VecDeque::new(),
39            in_use: 0,
40        }
41    }
42
43    /// Acquires a connection from the pool
44    pub async fn acquire(&mut self) -> Result<SmtpClient> {
45        // Try to get an available connection
46        if let Some(client) = self.available.pop_front() {
47            self.in_use += 1;
48            return Ok(client);
49        }
50
51        // Create a new connection if under max
52        if self.in_use < self.max_connections {
53            let mut client = SmtpClient::connect_with_security(
54                NetworkAddress::new(&self.host, self.port),
55                self.security.clone()
56            ).await?;
57            self.in_use += 1;
58            return Ok(client);
59        }
60
61        // Pool exhausted
62        Err(Error::new(
63            ErrorKind::Network,
64            "Connection pool exhausted",
65        ))
66    }
67
68    /// Returns a connection to the pool
69    pub fn release(&mut self, client: SmtpClient) {
70        self.available.push_back(client);
71        if self.in_use > 0 {
72            self.in_use -= 1;
73        }
74    }
75
76    /// Gets pool statistics
77    pub fn stats(&self) -> PoolStats {
78        PoolStats {
79            available: self.available.len(),
80            in_use: self.in_use,
81            total: self.available.len() + self.in_use,
82            max: self.max_connections,
83        }
84    }
85}
86
87#[derive(Debug, Clone)]
88pub struct PoolStats {
89    pub available: usize,
90    pub in_use: usize,
91    pub total: usize,
92    pub max: usize,
93}
94
95#[cfg(test)]
96mod tests {
97    use super::*;
98
99    #[test]
100    fn test_pool_creation() {
101        let pool = SmtpPool::new("smtp.test.com".to_string(), 587, 10);
102        let stats = pool.stats();
103        
104        assert_eq!(stats.max, 10);
105        assert_eq!(stats.available, 0);
106        assert_eq!(stats.in_use, 0);
107    }
108}