use crate::api::RecordType;
use log::{debug, trace};
use serde::Deserialize;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::path::Path;
#[derive(Debug, Deserialize)]
pub struct NameComConfigCore {
#[serde(default = "default_url")]
pub url: String,
pub username: String,
pub key: String,
#[serde(default = "default_interval")]
pub interval: u64,
#[serde(default = "default_timeout")]
pub timeout: u64,
}
fn default_url() -> String {
String::from("https://api.name.com/")
}
fn default_interval() -> u64 {
60
}
fn default_timeout() -> u64 {
30
}
#[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, PartialEq)]
pub enum NameComConfigMethod {
#[serde(rename = "global")]
Global,
#[serde(rename = "local")]
Local,
#[serde(rename = "script")]
Script,
}
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq)]
pub struct NameComConfigRecord {
pub host: String,
pub zone: String,
#[serde(rename = "type")]
pub rec_type: RecordType,
pub ttl: u32,
pub method: NameComConfigMethod,
pub interface: Option<String>,
pub command: Option<Vec<String>>,
}
#[derive(Debug, Deserialize)]
#[allow(clippy::module_name_repetitions)]
pub struct NameComDdnsConfig {
pub core: NameComConfigCore,
pub records: Vec<NameComConfigRecord>,
}
impl NameComDdnsConfig {
pub fn from_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
let mut file = File::open(path)?;
debug!("Opened file {:?}", file);
let mut file_content = String::new();
file.read_to_string(&mut file_content)?;
trace!("Configuration contains {:?}", file_content);
Ok(toml::from_str(&file_content)?)
}
}
#[cfg(test)]
mod test {
use crate::api::RecordType;
use crate::config::{NameComConfigMethod, NameComDdnsConfig};
use std::path::PathBuf;
#[test]
fn test_config_parser() {
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
path.push("examples/namecom_ddns.toml");
let config = NameComDdnsConfig::from_file(&path).expect("Cannot open example file");
let core = config.core;
let record1 = &config.records[0];
let record2 = &config.records[1];
assert_eq!(core.username, "example", "core.username mismatch");
assert_eq!(core.key, "40-char Name.com API key", "core.key mismatch");
assert_eq!(core.url, "https://api.name.com/", "core.url mismatch");
assert_eq!(core.timeout, 30, "core.timeout mismatch");
assert_eq!(core.interval, 60, "core.interval mismatch");
assert_eq!(record1.host, "ddns", "record[0].host mismatch");
assert_eq!(record1.zone, "example.com", "record[0].zone mismatch");
assert_eq!(record1.rec_type, RecordType::A, "record[0].type mismatch");
assert_eq!(record1.ttl, 300, "record[0].ttl mismatch");
assert_eq!(
record1.method,
NameComConfigMethod::Global,
"record[0].method mismatch"
);
assert_eq!(
record1.interface.as_ref().unwrap(),
"en0",
"record[0].interface mismatch"
);
assert_eq!(
record1.command.as_deref().unwrap(),
vec!["/bin/get_an_ip"],
"record[0].command mismatch"
);
assert_eq!(record2.host, "ddns", "record[0].host mismatch");
assert_eq!(record2.zone, "example.com", "record[0].zone mismatch");
assert_eq!(
record2.rec_type,
RecordType::Aaaa,
"record[0].type mismatch"
);
assert_eq!(record2.ttl, 300, "record[0].ttl mismatch");
assert_eq!(
record2.method,
NameComConfigMethod::Local,
"record[0].method mismatch"
);
assert_eq!(
record2.interface.as_ref().unwrap(),
"en0",
"record[0].interface mismatch"
);
}
}