1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

use crate::table::{Table, TableTemplate};

use std::sync::Arc;

use tokio::sync::RwLock;
use tokio::time::{sleep, Duration};

use tokio_postgres::{connect, NoTls};
use tokio_postgres::Client;

pub(crate) type SharedClient = Arc<RwLock<Client>>;

#[derive(Debug, Clone)]
pub struct Database {
	client: SharedClient
}

impl Database {

	pub async fn new(name: &str, user: &str, password: &str) -> Self {
		Self::with_host("localhost", name, user, password).await
	}

	pub async fn with_host(
		host: &str,
		name: &str,
		user: &str,
		password: &str
	) -> Self {
		// let client = Client::with_uri_str("mongodb://localhost:27017")
		//	.expect("Failed to initilize mongo client.");
		let config = format!(
			"host={} dbname={} user={} password={}",
			host,name, user, password
		);

		let (client, connection) = connect(&config, NoTls).await
			.expect("Failed to initialize postgres client");

		let client = Arc::new(RwLock::new(client));

		let bg_client = client.clone();
		tokio::spawn(async move {
			let mut connection = Some(connection);

			loop {
				if let Some(con) = connection.take() {
					if let Err(e) = con.await {
						eprintln!("connection closed error: {}", e);
					}
				}

				sleep(Duration::from_secs(5)).await;

				let (client, con) = match connect(&config, NoTls).await {
					Ok(o) => o,
					Err(e) => {
						eprintln!("connection error: {}", e);
						continue
					}
				};

				// yeah, we got a new connection
				// let's replace the old one
				connection = Some(con);
				*bg_client.write().await = client;
			}
		});

		Self { client }
	}

	pub fn table<T>(&self, name: &'static str) -> Table<T>
	where T: TableTemplate {
		Table::new(self.client.clone(), name)
	}

}