use crate::apis::configuration::{AWSv4Key, Configuration};
use home::home_dir;
use secrecy::SecretString;
use serde::Deserialize;
use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::fs::File;
use std::io::BufReader;
use std::path::PathBuf;
#[derive(Deserialize, Debug)]
pub struct ConfigurationFile(pub HashMap<String, Profile>);
#[derive(Deserialize, Debug, Clone)]
pub struct Profile {
pub access_key: Option<String>,
pub secret_key: Option<String>,
pub x509_client_cert: Option<String>,
pub x509_client_key: Option<String>,
pub protocol: Option<String>,
pub method: Option<String>,
pub region: Option<String>,
pub endpoints: Option<Endpoint>,
}
#[derive(Deserialize, Debug, Clone)]
pub struct Endpoint {
pub api: Option<String>,
pub fcu: Option<String>,
pub lbu: Option<String>,
pub eim: Option<String>,
pub icu: Option<String>,
pub oos: Option<String>,
}
#[derive(Debug, Clone)]
pub enum ConfigurationFileError {
CannotGetDefaultPath,
ProfileNotFound,
}
impl fmt::Display for ConfigurationFileError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ConfigurationFileError::CannotGetDefaultPath => {
write!(f, "cannot find default configuration file path")
}
ConfigurationFileError::ProfileNotFound => write!(f, "profile not found"),
}
}
}
impl Error for ConfigurationFileError {}
impl ConfigurationFile {
pub fn default_path() -> Result<PathBuf, ConfigurationFileError> {
let mut path = match home_dir() {
Some(p) => p,
None => return Err(ConfigurationFileError::CannotGetDefaultPath),
};
path.push(".osc");
path.push("config.json");
return Ok(path);
}
pub fn load_default() -> Result<ConfigurationFile, Box<dyn Error>> {
let path = ConfigurationFile::default_path()?;
ConfigurationFile::load(&path)
}
pub fn load(path: &PathBuf) -> Result<ConfigurationFile, Box<dyn Error>> {
let file = File::open(path)?;
let reader = BufReader::new(file);
let configuration_file = serde_json::from_reader(reader)?;
Ok(configuration_file)
}
pub fn configuration<S: Into<String>>(
&self,
profile_name: S,
) -> Result<Configuration, Box<dyn Error>> {
let profile_name = profile_name.into();
let profile = match self.0.get(&profile_name) {
Some(profile) => profile.clone(),
None => return Err(Box::new(ConfigurationFileError::ProfileNotFound)),
};
let mut config = Configuration::default();
if let Some(ref region) = profile.region {
config.base_path = format!("https://api.{}.outscale.com/api/v1", region);
}
match profile.endpoints {
Some(endpoints) => match endpoints.api {
Some(api_endpoint) => match profile.protocol {
Some(protocol) => {
config.base_path = format!("{}://{}", protocol, api_endpoint);
}
None => {
config.base_path = format!("https://{}", api_endpoint);
}
},
None => {}
},
None => {}
};
if let Some(access_key) = profile.access_key {
if let Some(secret_key) = profile.secret_key {
let region = match profile.region {
Some(r) => r.clone(),
None => "eu-west-2".to_string(),
};
config.aws_v4_key = Some(AWSv4Key {
access_key: access_key,
secret_key: SecretString::new(secret_key),
region: region,
service: "oapi".to_string(),
});
}
}
Ok(config)
}
}