From 14192169c496bbd090f85a7e308817e6e6027aed Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Wed, 14 Jul 2021 08:13:30 +0200 Subject: [PATCH] Split in modules --- src/config.rs | 33 ++++++++++++++++ src/error.rs | 15 +++++++ src/main.rs | 107 ++++++++++++++++---------------------------------- 3 files changed, 81 insertions(+), 74 deletions(-) create mode 100644 src/config.rs create mode 100644 src/error.rs diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..e3b1309 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,33 @@ +use ron::{ de::from_reader, ser::to_writer }; +use serde::{ Deserialize, Serialize }; +use std::{ fs::File, time }; + +use crate::error::Result; + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct Config { + pub delay_between_check: time::Duration, + pub api_key: String, + pub fqdn: String, + pub domains: Vec, + pub ttl: i32 +} + +impl Config { + pub fn default() -> Self { + Config { delay_between_check: time::Duration::from_secs(120), api_key: String::from(""), fqdn: String::from(""), domains: Vec::new(), ttl: 300 } + } + + pub fn read(file_path: &str) -> Result { + match File::open(file_path) { + Ok(file) => from_reader(file).map_err(|e| e.into()), + // The file doesn't exit -> create it with default values. + Err(_) => { + let file = File::create(file_path)?; + let default_config = Config::default(); + to_writer(file, &default_config)?; + Ok(default_config) + } + } + } +} \ No newline at end of file diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..12221fb --- /dev/null +++ b/src/error.rs @@ -0,0 +1,15 @@ +// A generic result of type 'T'. +pub type Result = std::result::Result>; + +#[derive(Debug)] +pub struct Error { + pub message: String +} + +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Error: {}", &self.message) + } +} + +impl std::error::Error for Error { } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 67c251a..79b2262 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,54 +11,14 @@ #![cfg_attr(debug_assertions, allow(unused_variables, unused_imports, dead_code))] -use std::{ fs::File, net::{ IpAddr, Ipv4Addr }, thread, time }; -use ron::{ de::from_reader, ser::to_writer }; -use serde::{ Deserialize, Serialize }; +use std::{ net::{ IpAddr, Ipv4Addr }, thread, time }; use serde_json::{ Value, json }; -// A generic result of type 'T'. -type Result = std::result::Result>; +mod error; +mod config; -#[derive(Debug)] -struct Error { - message: String -} - -impl std::fmt::Display for Error { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Error: {}", &self.message) - } -} - -impl std::error::Error for Error { } - -#[derive(Debug, Clone, Deserialize, Serialize)] -struct Config { - delay_between_check: time::Duration, - api_key: String, - fqdn: String, - domains: Vec, - ttl: i32 -} - -impl Config { - fn default() -> Self { - Config { delay_between_check: time::Duration::from_secs(120), api_key: String::from(""), fqdn: String::from(""), domains: Vec::new(), ttl: 300 } - } - - fn read(file_path: &str) -> Result { - match File::open(file_path) { - Ok(file) => from_reader(file).map_err(|e| e.into()), - // The file doesn't exit -> create it with default values. - Err(_) => { - let file = File::create(file_path)?; - let default_config = Config::default(); - to_writer(file, &default_config)?; - Ok(default_config) - } - } - } -} +use crate::error::{ Result, Error }; +use crate::config::Config; const FILE_CONF: &str = "config.ron"; @@ -103,7 +63,6 @@ fn check_and_update_dns(api_key: &str, fqdn: &str, domains: &Vec, ttl: i } fn get_real_ip() -> Result { - let url = "https://api.ipify.org"; let client = reqwest::blocking::Client::new(); @@ -111,7 +70,7 @@ fn get_real_ip() -> Result { Ok(resp) => if resp.status().is_success() { let content = resp.text().unwrap(); - match content.parse::() { + match content.parse() { Ok(IpAddr::V4(ip_v4)) => Ok(ip_v4), _ => Err(Box::new(Error { message: String::from("Can't parse IPv4 from ipify") })) } @@ -125,6 +84,33 @@ fn get_real_ip() -> Result { } } +fn get_current_record_ip(api_key: &str, name: &str, fqdn: &str) -> Result { + let json_value = request_livedns_gandi(api_key, &format!("domains/{}/records/{}/A", fqdn, name), Method::Get)?; + + match &json_value["rrset_values"][0] { + Value::String(ip_str) => + Ok(ip_str.parse()?), + _ => + Result::Err(Box::new(Error { message: format!("Unable to extract the IP from the JSON answer: {}", json_value) })) + } +} + +fn update_record_ip(api_key: &str, name: &str, fqdn: &str, ip: Ipv4Addr, ttl: i32) -> Result<()> { + let json_body = + json!( + { + "rrset_values": [ format!("{}", ip) ], + "rrset_ttl": ttl + } + ); + + let json_value = request_livedns_gandi(api_key, &format!("domains/{}/records/{}/A", fqdn, name), Method::Put(json_body.to_string()))?; + + println!("Update response: {}", json_value); + + Ok(()) +} + enum Method { Put(String), Get @@ -152,30 +138,3 @@ fn request_livedns_gandi(api_key: &str, url_fragment: &str, method: Method) -> R Err(Box::new(Error { message: format!("Error during request: {:?}", error) })) } } - -fn get_current_record_ip(api_key: &str, name: &str, fqdn: &str) -> Result { - let json_value = request_livedns_gandi(api_key, &format!("domains/{}/records/{}/A", fqdn, name), Method::Get)?; - - match &json_value["rrset_values"][0] { - Value::String(ip_str) => - Ok(ip_str.parse()?), - _ => - Result::Err(Box::new(Error { message: format!("Unable to extract the IP from the JSON answer: {}", json_value) })) - } -} - -fn update_record_ip(api_key: &str, name: &str, fqdn: &str, ip: Ipv4Addr, ttl: i32) -> Result<()> { - let json_body = - json!( - { - "rrset_values": [ format!("{}", ip) ], - "rrset_ttl": ttl - } - ); - - let json_value = request_livedns_gandi(api_key, &format!("domains/{}/records/{}/A", fqdn, name), Method::Put(json_body.to_string()))?; - - println!("Update response: {}", json_value); - - Ok(()) -} -- 2.45.2