1use crate::smtp::{SmtpClient, SmtpSecurity};
4use avila_error::{Error, ErrorKind, Result};
5use avila_molecule::NetworkAddress;
6use std::collections::VecDeque;
7
8pub 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 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 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 pub async fn acquire(&mut self) -> Result<SmtpClient> {
45 if let Some(client) = self.available.pop_front() {
47 self.in_use += 1;
48 return Ok(client);
49 }
50
51 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 Err(Error::new(
63 ErrorKind::Network,
64 "Connection pool exhausted",
65 ))
66 }
67
68 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 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}