Skip to main content

pg/
config.rs

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}