use std::path::PathBuf;
use std::time::Duration;
pub const DEFAULT_PORT: u16 = 8427;
pub const DEFAULT_DATABASE: &str = "main";
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
pub const FEATURE_CORRELATION_ID: u64 = 1 << 0;
pub const FEATURE_SERVER_PARAMS: u64 = 1 << 1;
pub const FEATURE_SESSION_TXN: u64 = 1 << 2;
pub const ALL_FEATURES: u64 = FEATURE_CORRELATION_ID | FEATURE_SERVER_PARAMS | FEATURE_SESSION_TXN;
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct TlsOptions {
pub ca_file: Option<PathBuf>,
pub server_name: Option<String>,
pub danger_accept_invalid_certs: bool,
pub client_cert_file: Option<PathBuf>,
pub client_key_file: Option<PathBuf>,
}
impl TlsOptions {
pub fn new() -> Self {
Self::default()
}
pub fn ca_file(mut self, path: impl Into<PathBuf>) -> Self {
self.ca_file = Some(path.into());
self
}
pub fn server_name(mut self, name: impl Into<String>) -> Self {
self.server_name = Some(name.into());
self
}
pub fn client_identity(
mut self,
cert_file: impl Into<PathBuf>,
key_file: impl Into<PathBuf>,
) -> Self {
self.client_cert_file = Some(cert_file.into());
self.client_key_file = Some(key_file.into());
self
}
pub fn danger_accept_invalid_certs(mut self, yes: bool) -> Self {
self.danger_accept_invalid_certs = yes;
self
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Options {
pub host: String,
pub port: u16,
pub user: Option<String>,
pub secret: Option<String>,
pub database: String,
pub client_name: String,
pub connect_timeout: Option<Duration>,
pub read_timeout: Option<Duration>,
pub tls: Option<TlsOptions>,
pub features: Option<u64>,
}
impl Default for Options {
fn default() -> Self {
Self {
host: "127.0.0.1".to_string(),
port: DEFAULT_PORT,
user: None,
secret: None,
database: DEFAULT_DATABASE.to_string(),
client_name: concat!("tricoredb-rust/", env!("CARGO_PKG_VERSION")).to_string(),
connect_timeout: None,
read_timeout: None,
tls: None,
features: None,
}
}
}
impl Options {
pub fn new(host: impl Into<String>, port: u16) -> Self {
Self {
host: host.into(),
port,
..Self::default()
}
}
pub fn user(mut self, user: impl Into<String>) -> Self {
self.user = Some(user.into());
self
}
pub fn secret(mut self, secret: impl Into<String>) -> Self {
self.secret = Some(secret.into());
self
}
pub fn database(mut self, database: impl Into<String>) -> Self {
self.database = database.into();
self
}
pub fn client_name(mut self, name: impl Into<String>) -> Self {
self.client_name = name.into();
self
}
pub fn connect_timeout(mut self, timeout: Duration) -> Self {
self.connect_timeout = Some(timeout);
self
}
pub fn read_timeout(mut self, timeout: Duration) -> Self {
self.read_timeout = Some(timeout);
self
}
pub fn tls(mut self, tls: TlsOptions) -> Self {
self.tls = Some(tls);
self
}
pub fn features(mut self, features: u64) -> Self {
self.features = Some(features);
self
}
pub(crate) fn announced_features(&self) -> u64 {
self.features.unwrap_or(ALL_FEATURES)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn defaults_are_the_documented_ones() {
let o = Options::default();
assert_eq!(o.host, "127.0.0.1");
assert_eq!(o.port, 8427);
assert_eq!(o.database, "main");
assert!(o.client_name.starts_with("tricoredb-rust/"));
assert_eq!(o.read_timeout, None);
assert!(o.tls.is_none());
assert_eq!(o.announced_features(), ALL_FEATURES);
}
#[test]
fn announcing_nothing_differs_from_leaving_it_unset() {
assert_eq!(Options::default().features(0).announced_features(), 0);
}
#[test]
fn every_feature_has_its_own_bit() {
assert_eq!(FEATURE_CORRELATION_ID, 1);
assert_eq!(FEATURE_SERVER_PARAMS, 2);
assert_eq!(FEATURE_SESSION_TXN, 4);
assert_eq!(ALL_FEATURES, 7);
}
}