use std::convert::TryFrom; use std::fmt; use anyhow::{format_err, Error}; use proxmox::api::schema::*; use crate::api2::types::*; /// API schema format definition for repository URLs pub const BACKUP_REPO_URL: ApiStringFormat = ApiStringFormat::Pattern(&BACKUP_REPO_URL_REGEX); /// Reference remote backup locations /// #[derive(Debug)] pub struct BackupRepository { /// The user name used for Authentication user: Option, /// The host name or IP address host: Option, /// The port port: Option, /// The name of the datastore store: String, } impl BackupRepository { pub fn new(user: Option, host: Option, port: Option, store: String) -> Self { let host = match host { Some(host) if (IP_V6_REGEX.regex_obj)().is_match(&host) => { Some(format!("[{}]", host)) }, other => other, }; Self { user, host, port, store } } pub fn user(&self) -> &Userid { if let Some(ref user) = self.user { return &user; } Userid::root_userid() } pub fn host(&self) -> &str { if let Some(ref host) = self.host { return host; } "localhost" } pub fn port(&self) -> u16 { if let Some(port) = self.port { return port; } 8007 } pub fn store(&self) -> &str { &self.store } } impl fmt::Display for BackupRepository { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match (&self.user, &self.host, self.port) { (Some(user), _, _) => write!(f, "{}@{}:{}:{}", user, self.host(), self.port(), self.store), (None, Some(host), None) => write!(f, "{}:{}", host, self.store), (None, _, Some(port)) => write!(f, "{}:{}:{}", self.host(), port, self.store), (None, None, None) => write!(f, "{}", self.store), } } } impl std::str::FromStr for BackupRepository { type Err = Error; /// Parse a repository URL. /// /// This parses strings like `user@host:datastore`. The `user` and /// `host` parts are optional, where `host` defaults to the local /// host, and `user` defaults to `root@pam`. fn from_str(url: &str) -> Result { let cap = (BACKUP_REPO_URL_REGEX.regex_obj)().captures(url) .ok_or_else(|| format_err!("unable to parse repository url '{}'", url))?; Ok(Self { user: cap.get(1).map(|m| Userid::try_from(m.as_str().to_owned())).transpose()?, host: cap.get(2).map(|m| m.as_str().to_owned()), port: cap.get(3).map(|m| m.as_str().parse::()).transpose()?, store: cap[4].to_owned(), }) } }