Changed module name: "go_daddy_ddns -> records_handler" and added path and file handlers.
This commit is contained in:
parent
fa814087bd
commit
29bc00e0e8
|
@ -82,6 +82,26 @@ version = "0.8.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "4.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
|
||||
dependencies = [
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_users",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
version = "0.8.30"
|
||||
|
@ -176,6 +196,7 @@ dependencies = [
|
|||
name = "godaddy_ddns"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"dirs",
|
||||
"log",
|
||||
"reqwest",
|
||||
"serde",
|
||||
|
@ -616,6 +637,16 @@ dependencies = [
|
|||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"redox_syscall",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
version = "0.5.3"
|
||||
|
|
10
Cargo.toml
10
Cargo.toml
|
@ -12,4 +12,12 @@ serde = { version = "1.0.132", features = ["derive"]}
|
|||
serde_json = "1.0"
|
||||
log = { version = "0.4", features = ["std", "serde"] }
|
||||
simple_logger = "1.16.0"
|
||||
strfmt = "0.1.6"
|
||||
strfmt = "0.1.6"
|
||||
dirs = "4.0.0"
|
||||
|
||||
[profile.release]
|
||||
opt-level = 3
|
||||
lto = true
|
||||
debug = false
|
||||
codegen-units = 1
|
||||
panic = "abort"
|
|
@ -0,0 +1,80 @@
|
|||
use std::fs::{create_dir, read_to_string, File};
|
||||
use std::io::{Error, ErrorKind, Write};
|
||||
use std::path::Path;
|
||||
|
||||
use crate::file_handler::path_handler::{
|
||||
get_application_folder_path, get_ip_file_path, get_records_file_path,
|
||||
};
|
||||
|
||||
pub mod path_handler;
|
||||
|
||||
/// Sets up the application folder.
|
||||
pub fn application_folder_setup() -> std::io::Result<()> {
|
||||
let app_folder_path = get_application_folder_path();
|
||||
|
||||
if app_folder_path.is_none() {
|
||||
return Err(Error::from(ErrorKind::NotFound));
|
||||
}
|
||||
|
||||
let path = app_folder_path.unwrap();
|
||||
|
||||
if path.exists() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
create_dir(&path)
|
||||
}
|
||||
|
||||
/// Gets the contents of the RECORDS_FILE.
|
||||
pub fn get_records_file() -> String {
|
||||
let path = get_records_file_path().expect("Couldn't get RECORDS_FILE path.");
|
||||
|
||||
read_file(&path).expect(&format!(
|
||||
"{} does not exist. Please create it.",
|
||||
path.display()
|
||||
))
|
||||
}
|
||||
|
||||
/// Gets the contents of the IP_FILE.
|
||||
pub fn get_ip_file() -> Option<String> {
|
||||
let path = get_ip_file_path().expect("Couldn't get IP_FILE path.");
|
||||
|
||||
read_file(&path).ok()
|
||||
}
|
||||
|
||||
/// Stores the current IP value in the FILE_NAME.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `content` - A &[u8] holding the current IP value.
|
||||
pub fn set_ip_file(content: &[u8]) -> () {
|
||||
let path = get_ip_file_path().expect("Couldn't get IP_FILE path.");
|
||||
|
||||
write_file(&path, content)
|
||||
}
|
||||
|
||||
/// Reads a file and returns its contents as String if Ok().
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `path` - A &Path holding the path of the file to be read.
|
||||
fn read_file(path: &Path) -> std::io::Result<String> {
|
||||
read_to_string(path)
|
||||
}
|
||||
|
||||
/// Writes a file.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `path` - A &Path holding the path of the file to be written.
|
||||
///
|
||||
/// * `content` - A &[u8] holding the info that will be written to the file.
|
||||
fn write_file(path: &Path, content: &[u8]) -> () {
|
||||
let display = &path.display();
|
||||
|
||||
let mut file =
|
||||
File::create(path).expect(&format!("Error opening or creating file: {}", display));
|
||||
|
||||
file.write_all(content)
|
||||
.expect(&format!("Error writing file: {}", display))
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
const APP_DIR: &'static str = ".godaddy-ddns";
|
||||
const IP_FILE_NAME: &'static str = "ddns_ip";
|
||||
const RECORDS_FILE_NAME: &'static str = "records.json";
|
||||
|
||||
/// Gets the application folder path and returns it if found.
|
||||
pub fn get_application_folder_path() -> Option<PathBuf> {
|
||||
let home = dirs::home_dir();
|
||||
|
||||
if home.is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(PathBuf::from(format!(
|
||||
"{}/{}",
|
||||
home.unwrap().display(),
|
||||
APP_DIR
|
||||
)))
|
||||
}
|
||||
|
||||
/// Gets the IP_FILE path and returns it if found.
|
||||
pub fn get_ip_file_path() -> Option<PathBuf> {
|
||||
let app_folder = get_application_folder_path();
|
||||
|
||||
if app_folder.is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(PathBuf::from(format!(
|
||||
"{}/{}",
|
||||
app_folder.unwrap().display(),
|
||||
IP_FILE_NAME
|
||||
)))
|
||||
}
|
||||
|
||||
/// Gets the RECORDS_FILE path and returns it if found.
|
||||
pub fn get_records_file_path() -> Option<PathBuf> {
|
||||
let app_folder = get_application_folder_path();
|
||||
|
||||
if app_folder.is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(PathBuf::from(format!(
|
||||
"{}/{}",
|
||||
app_folder.unwrap().display(),
|
||||
RECORDS_FILE_NAME
|
||||
)))
|
||||
}
|
|
@ -1,14 +1,10 @@
|
|||
use std::fs::{File, read_to_string};
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
|
||||
use log::debug;
|
||||
|
||||
use crate::file_handler::{get_ip_file, set_ip_file};
|
||||
use crate::ip_handler::ip::IP;
|
||||
|
||||
mod ip;
|
||||
|
||||
const IP_FILE_NAME: &'static str = "ddns_ip";
|
||||
const WEBSITE_URL: &'static str = "https://httpbin.org/ip";
|
||||
|
||||
/// Returns an Option holding the current IP address if the value has changed, otherwise returns None.
|
||||
|
@ -37,31 +33,12 @@ pub async fn get_ip_to_publish() -> Option<String> {
|
|||
async fn check_current_ip() -> Result<String, Box<dyn std::error::Error>> {
|
||||
let resp = reqwest::get(WEBSITE_URL).await?.json::<IP>().await?;
|
||||
|
||||
record_current_ip(&resp.origin);
|
||||
set_ip_file((&resp.origin).as_ref());
|
||||
|
||||
Ok(resp.origin)
|
||||
}
|
||||
|
||||
/// Stores the current IP value in the FILE_NAME.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `current_ip` - A &str holding the current IP value.
|
||||
fn record_current_ip(current_ip: &str) -> () {
|
||||
let mut file = File::create(IP_FILE_NAME).expect("Error creating file.");
|
||||
file.write_all(current_ip.as_ref())
|
||||
.expect("Error writing file.");
|
||||
}
|
||||
|
||||
/// Reads the current IP value from the FILE_NAME and returns it.
|
||||
fn check_previous_ip() -> Option<String> {
|
||||
let path = Path::new(IP_FILE_NAME);
|
||||
|
||||
if !path.exists() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let contents = read_to_string(path).expect("Error reading file.");
|
||||
|
||||
Some(contents)
|
||||
get_ip_file()
|
||||
}
|
||||
|
|
10
src/main.rs
10
src/main.rs
|
@ -1,13 +1,15 @@
|
|||
use std::env;
|
||||
use std::error::Error;
|
||||
|
||||
use log::LevelFilter;
|
||||
use simple_logger::SimpleLogger;
|
||||
|
||||
mod go_daddy_ddns;
|
||||
mod file_handler;
|
||||
mod records_handler;
|
||||
mod ip_handler;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
async fn main() -> Result<(), Box<dyn Error>> {
|
||||
SimpleLogger::new()
|
||||
.with_colors(true)
|
||||
.with_utc_timestamps()
|
||||
|
@ -15,9 +17,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
.init()
|
||||
.unwrap();
|
||||
|
||||
file_handler::application_folder_setup().expect("Error setting up application folder.");
|
||||
|
||||
let domain = env::var("DOMAIN").expect("You need to set DOMAIN env variable first.");
|
||||
let key = env::var("KEY").expect("You need to set KEY env variable first.");
|
||||
let secret = env::var("SECRET").expect("You need to set SECRET env variable first.");
|
||||
|
||||
go_daddy_ddns::exec(&domain, &key, &secret).await
|
||||
records_handler::update(&domain, &key, &secret).await
|
||||
}
|
||||
|
|
|
@ -1,17 +1,14 @@
|
|||
use std::collections::HashMap;
|
||||
use std::fs::read_to_string;
|
||||
use std::path::Path;
|
||||
|
||||
use log::{debug, info};
|
||||
use strfmt::strfmt;
|
||||
|
||||
use crate::go_daddy_ddns::dns_record::{DNSRecord, DNSRecordsHolder};
|
||||
use crate::file_handler::get_records_file;
|
||||
use crate::records_handler::dns_record::{DNSRecord, DNSRecordsHolder};
|
||||
use crate::ip_handler::get_ip_to_publish;
|
||||
|
||||
mod dns_record;
|
||||
|
||||
const RECORDS_FILE_NAME: &'static str = "records.json";
|
||||
|
||||
/// Updates the DNS records if the IP has changed and returns the result of the execution.
|
||||
///
|
||||
/// # Arguments
|
||||
|
@ -21,7 +18,9 @@ const RECORDS_FILE_NAME: &'static str = "records.json";
|
|||
/// * `key` - A &str holding the GoDaddy developer key.
|
||||
///
|
||||
/// * `secret` - A &str holding the GoDaddy developer secret.
|
||||
pub async fn exec(domain: &str, key: &str, secret: &str) -> Result<(), Box<dyn std::error::Error>> {
|
||||
pub async fn update(domain: &str, key: &str, secret: &str) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let records = get_records();
|
||||
|
||||
info!("Checking if the IP has changed.");
|
||||
let new_ip = get_ip_to_publish().await;
|
||||
|
||||
|
@ -32,7 +31,7 @@ pub async fn exec(domain: &str, key: &str, secret: &str) -> Result<(), Box<dyn s
|
|||
}
|
||||
|
||||
info!("The IP has changed. Let's update the DNS records.");
|
||||
for record in get_records() {
|
||||
for record in records {
|
||||
debug!("{:?}", record);
|
||||
update_record(record, &new_ip.clone().unwrap(), domain, key, secret).await;
|
||||
}
|
||||
|
@ -42,8 +41,7 @@ pub async fn exec(domain: &str, key: &str, secret: &str) -> Result<(), Box<dyn s
|
|||
|
||||
/// Gets a vector of DNSRecord from RECORDS_FILE_NAME and returns it.
|
||||
fn get_records() -> Vec<DNSRecord> {
|
||||
let path = Path::new(RECORDS_FILE_NAME);
|
||||
let content = read_to_string(path).unwrap();
|
||||
let content = get_records_file();
|
||||
|
||||
let base: DNSRecordsHolder =
|
||||
serde_json::from_str(&content).expect("Failed to deserialize JSON");
|
Loading…
Reference in New Issue