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
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
extern crate postgres;
extern crate ini;

use ini::Ini;
use ini::ini::Properties;

pub struct ServiceBuilder
{
	pg_builder : postgres::params::Builder,
	maybe_host : Option<postgres::params::Host>,
}

impl ServiceBuilder
{
	pub fn user(mut self, user : &str) -> ServiceBuilder
	{
		self.pg_builder.user(user, None);
		self
	}
}

impl postgres::params::IntoConnectParams for ServiceBuilder
{
	fn into_connect_params(mut self)
	-> Result<postgres::params::ConnectParams, Box<std::error::Error + Sync + Send>>
	{
		let host = self.maybe_host.unwrap_or(
			postgres::params::Host::Unix(
				std::path::PathBuf::from("/var/run/postgresql")
			)
		);

		Ok(self.pg_builder.build(host))
	}
}


fn build_from_section(section : &Properties)
-> ServiceBuilder
{
	let mut host : Option<postgres::params::Host> = None;
	let mut username : Option<String> = None;
	let mut password : Option<String> = None;

	let mut builder = postgres::params::Builder::new();


	for (k,v) in section
	{
		match k.as_str()
		{
			"host" =>
				host = Some(
					if v.len()>0 && v.starts_with('/')
						{ postgres::params::Host::Unix(std::path::PathBuf::from(v)) }
					else
						{ postgres::params::Host::Tcp(v.clone()) }
				),
			"hostaddr" => 
				host = Some(postgres::params::Host::Tcp(v.clone())),
			"port" =>
				{ builder.port(v.parse().unwrap()); },
			"dbname" =>
				{ builder.database(v); },
			"user" =>
				username = Some(v.clone()),
			"password" =>
				password = Some(v.clone()),
			_ =>
				{ builder.option(k, v); },
		}
	}

	if let Some(username) = username
		{ builder.user(&username, password.as_ref().map(|x| x.as_ref())); }

	ServiceBuilder
	{
		pg_builder : builder,
		maybe_host : host,
	}

}

pub fn load_connect_params(
	service_name : &str
) -> Option<ServiceBuilder>
{
	if let Ok(home) = std::env::var("HOME")
	{
		if let Ok(ini) = Ini::load_from_file(home + "/" + ".pg_service.conf")
		{
			if let Some(section) = ini.section(Some(service_name.clone()))
			{
				return Some(build_from_section(section));
			}
		}
	}

	let confdir = std::env::var("PGSYSCONFDIR").unwrap_or("/etc/postgresql-common".into());

	if let Ok(ini) = Ini::load_from_file(confdir + "/" + "pg_service.conf")
	{
		if let Some(section) = ini.section(Some(service_name))
		{
			return Some(build_from_section(section));
		}
	}

	None
}