1use std::sync::atomic::AtomicBool;
2
3use tokio::sync::Semaphore;
4
5use crate::{PgError, error::Result as PgResult};
6
7#[derive(Debug, Clone)]
8pub struct ConnectParams {
9 pub host: String,
10 pub port: u16,
11 pub dbname: Option<String>,
12 pub user: String,
13 pub password: Option<String>,
14 pub connect_timeout: std::time::Duration,
15}
16
17impl ConnectParams {
18 pub fn parse(conn_string: &str) -> PgResult<Self> {
19 let mut host = String::from("localhost");
20 let mut port: u16 = 5432;
21 let mut dbname = None;
22 let mut user = String::new();
23 let mut password = None;
24 let mut connect_timeout = std::time::Duration::from_secs(10);
25
26 for part in conn_string.split_whitespace() {
27 let (key, value) = match part.split_once('=') {
28 Some(kv) => kv,
29 None => continue,
30 };
31 match key {
32 "host" => host = value.to_string(),
33 "port" => port = value.parse().unwrap_or(5432),
34 "dbname" => dbname = Some(value.to_string()),
35 "user" => user = value.to_string(),
36 "password" => password = Some(value.to_string()),
37 "connect_timeout" => {
38 let secs: u64 = value.parse().unwrap_or(10);
39 connect_timeout = std::time::Duration::from_secs(secs);
40 }
41 _ => {}
42 }
43 }
44
45 if user.is_empty() {
46 return Err(PgError::Config("user is required".into()));
47 }
48
49 Ok(ConnectParams {
50 host,
51 port,
52 dbname,
53 user,
54 password,
55 connect_timeout,
56 })
57 }
58}
59
60#[derive(Debug, Clone)]
61pub struct PoolConfig {
62 pub min_connections: u32,
63 pub max_connections: u32,
64 pub idle_timeout: std::time::Duration,
65 pub max_lifetime: std::time::Duration,
66 pub connect_timeout: std::time::Duration,
67}
68
69impl Default for PoolConfig {
70 fn default() -> Self {
71 PoolConfig {
72 min_connections: 0,
73 max_connections: 10,
74 idle_timeout: std::time::Duration::from_secs(600),
75 max_lifetime: std::time::Duration::from_secs(1800),
76 connect_timeout: std::time::Duration::from_secs(10),
77 }
78 }
79}
80
81pub(crate) struct IdleConn {
82 pub(crate) conn: super::connection::Connection,
83 pub(crate) since: std::time::Instant,
84 pub(crate) created: std::time::Instant,
85 pub(crate) _permit: tokio::sync::OwnedSemaphorePermit,
86}
87
88pub(crate) struct PoolInner {
89 pub(crate) params: ConnectParams,
90 pub(crate) config: PoolConfig,
91 pub(crate) idle: tokio::sync::Mutex<Vec<IdleConn>>,
92 pub(crate) semaphore: std::sync::Arc<Semaphore>,
93 pub(crate) closed: AtomicBool,
94 pub(crate) closed_notify: tokio::sync::Notify,
95}
96
97impl PoolInner {
98 pub(crate) fn new(params: ConnectParams, config: PoolConfig) -> std::sync::Arc<Self> {
99 std::sync::Arc::new(PoolInner {
100 semaphore: std::sync::Arc::new(Semaphore::new(config.max_connections as usize)),
101 idle: tokio::sync::Mutex::new(Vec::new()),
102 params,
103 config,
104 closed: AtomicBool::new(false),
105 closed_notify: tokio::sync::Notify::new(),
106 })
107 }
108}