#![feature(error_generic_member_access)]
mod auth;
mod core;
pub use crate::core::domain::error::ProxmoxResult;
use crate::{
auth::application::service::login_service::LoginService,
core::domain::{
error::{ProxmoxError, ValidationError},
model::proxmox_auth::ProxmoxAuth,
model::proxmox_connection::ProxmoxConnection,
value_object::{
proxmox_csrf_token::ProxmoxCSRFToken, proxmox_host::ProxmoxHost,
proxmox_password::ProxmoxPassword, proxmox_port::ProxmoxPort,
proxmox_realm::ProxmoxRealm, proxmox_ticket::ProxmoxTicket,
proxmox_username::ProxmoxUsername,
},
},
};
use std::backtrace::Backtrace;
pub struct ProxmoxClient {
connection: ProxmoxConnection,
auth: Option<ProxmoxAuth>,
}
#[derive(Debug, Default)]
pub struct ProxmoxClientBuilder {
host: Option<String>,
port: Option<u16>,
username: Option<String>,
password: Option<String>,
realm: Option<String>,
secure: bool,
}
impl ProxmoxClientBuilder {
pub fn host(mut self, host: impl Into<String>) -> ProxmoxResult<Self> {
self.host = Some(host.into());
Ok(self)
}
pub fn port(mut self, port: u16) -> ProxmoxResult<Self> {
self.port = Some(port);
Ok(self)
}
pub fn credentials(
mut self,
username: impl Into<String>,
password: impl Into<String>,
realm: impl Into<String>,
) -> ProxmoxResult<Self> {
self.username = Some(username.into());
self.password = Some(password.into());
self.realm = Some(realm.into());
Ok(self)
}
pub fn secure(mut self, secure: bool) -> Self {
self.secure = secure;
self
}
pub async fn build(self) -> ProxmoxResult<ProxmoxClient> {
let host = ProxmoxHost::new(self.host.ok_or_else(|| ProxmoxError::Validation {
source: ValidationError::Field {
field: "host".to_string(),
message: "Host is required".to_string(),
},
backtrace: Backtrace::capture(),
})?)
.await?;
let port = ProxmoxPort::new(self.port.unwrap_or(8006)).await?;
let username =
ProxmoxUsername::new(self.username.ok_or_else(|| ProxmoxError::Validation {
source: ValidationError::Field {
field: "username".to_string(),
message: "Username is required".to_string(),
},
backtrace: Backtrace::capture(),
})?)
.await?;
let password =
ProxmoxPassword::new(self.password.ok_or_else(|| ProxmoxError::Validation {
source: ValidationError::Field {
field: "password".to_string(),
message: "Password is required".to_string(),
},
backtrace: Backtrace::capture(),
})?)
.await?;
let realm = ProxmoxRealm::new(self.realm.ok_or_else(|| ProxmoxError::Validation {
source: ValidationError::Field {
field: "realm".to_string(),
message: "Realm is required".to_string(),
},
backtrace: Backtrace::capture(),
})?)
.await?;
let connection =
ProxmoxConnection::new(host, port, username, password, realm, self.secure).await?;
Ok(ProxmoxClient {
connection,
auth: None,
})
}
}
impl ProxmoxClient {
pub fn builder() -> ProxmoxClientBuilder {
ProxmoxClientBuilder::default()
}
pub async fn login(&mut self) -> ProxmoxResult<()> {
let service = LoginService::new();
self.auth = Some(service.execute(&self.connection).await?);
Ok(())
}
pub fn is_authenticated(&self) -> bool {
self.auth.is_some()
}
pub fn auth_token(&self) -> Option<&ProxmoxTicket> {
self.auth.as_ref().map(|auth| auth.ticket())
}
pub fn csrf_token(&self) -> Option<&ProxmoxCSRFToken> {
self.auth.as_ref().and_then(|auth| auth.csrf_token())
}
}