Skip to content

Commit

Permalink
refactor!: change config
Browse files Browse the repository at this point in the history
structure
  • Loading branch information
Zel9278 committed Sep 28, 2024
1 parent 8478c91 commit 51f1bf6
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 63 deletions.
42 changes: 42 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ edition = "2021"

[dependencies]
reqwest = { version = "0.12.7", features = ["rustls-tls", "json", "charset", "http2", "macos-system-configuration"], default-features = false }
schemars = "0.8.21"
serde = { version = "1.0.210", features = ["derive"] }
serde_json = "1.0.128"
tokio = { version = "1.40.0", features = ["full"] }
Expand Down
45 changes: 45 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use schemars::{schema_for, JsonSchema};
use serde::{Deserialize, Serialize};
use toml;

#[derive(Serialize, Deserialize, Debug, JsonSchema, PartialEq)]
pub enum DnsType {
A,
AAAA,
}

impl DnsType {
pub fn as_str(&self) -> &str {
match self {
DnsType::A => "A",
DnsType::AAAA => "AAAA",
}
}
}

#[derive(Deserialize, Debug)]
pub(crate) struct Config {
pub(crate) account: AccountConfig,
pub(crate) dns: DnsConfig,
}

#[derive(Deserialize, Debug)]
pub(crate) struct AccountConfig {
pub(crate) auth_key: String,
pub(crate) zone_id: String,
}

#[derive(Deserialize, Debug)]
pub(crate) struct DnsConfig {
pub(crate) record: String,
pub(crate) r#type: DnsType,
pub(crate) proxied: bool,
}

impl Config {
pub fn new() -> Self {
let config: Config =
toml::from_str(&std::fs::read_to_string("config.toml").unwrap()).unwrap();
config
}
}
84 changes: 21 additions & 63 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
mod config;

use reqwest::Client;
use serde::{Deserialize, Serialize};
use std::error::Error;
use std::fmt;
use std::fs::read_to_string;
use config::{Config, DnsType};

#[derive(Serialize, Deserialize, Debug)]
struct Data {
Expand All @@ -13,45 +14,6 @@ struct Data {
proxied: bool,
}

#[derive(Deserialize, Debug)]
struct Config {
zone_id: String,
dns_record: String,
auth_key: String,
dns_type: String,
dns_proxy: bool,
}

#[derive(Debug)]
struct InvalidConfigError(String);

impl fmt::Display for InvalidConfigError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}

impl Error for InvalidConfigError {}

impl Config {
fn validate(&self) -> Result<(), InvalidConfigError> {
match self.dns_type.as_str() {
"A" | "AAAA" => Ok(()),
_ => Err(InvalidConfigError(format!(
"Invalid DNS type: {}. Must be 'A' or 'AAAA'.",
self.dns_type
))),
}
}
}

fn read_config(path: &str) -> Result<Config, Box<dyn Error>> {
let content = read_to_string(path)?;
let config: Config = toml::from_str(&content)?;
config.validate()?;
Ok(config)
}

async fn fetch_ip(client: &Client, url: &str) -> Result<String, Box<dyn Error>> {
match client.get(url).send().await {
Ok(result) => {
Expand All @@ -73,33 +35,27 @@ async fn fetch_ip(client: &Client, url: &str) -> Result<String, Box<dyn Error>>
async fn main() {
let client = Client::new();

let mut config: Config = match read_config("config.toml") {
Ok(cfg) => cfg,
Err(e) => {
eprintln!("Failed to load configuration: {}", e);
return;
}
};
let mut config: Config = Config::new();

println!("Loaded Configuration: {:#?}", config);

let mut ip = String::new();

if config.dns_type == "AAAA" {
if config.dns.r#type == DnsType::AAAA {
match fetch_ip(&client, "https://api6.ipify.org").await {
Ok(ipv6) => ip = ipv6,
Err(_) => {
eprintln!("Failed to retrieve IPv6 address. Falling back to IPv4.");
if let Ok(ipv4) = fetch_ip(&client, "https://api.ipify.org").await {
ip = ipv4;
config.dns_type = "A".to_string();
config.dns.r#type = DnsType::A;
} else {
eprintln!("Failed to retrieve both IPv6 and IPv4 addresses.");
return;
}
}
}
} else if config.dns_type == "A" {
} else if config.dns.r#type == DnsType::A {
match fetch_ip(&client, "https://api.ipify.org").await {
Ok(ipv4) => ip = ipv4,
Err(_) => {
Expand All @@ -113,12 +69,14 @@ async fn main() {

let get_url = format!(
"https://api.cloudflare.com/client/v4/zones/{}/dns_records?name={}&type={}",
config.zone_id, config.dns_record, config.dns_type
config.account.zone_id,
config.dns.record,
config.dns.r#type.as_str()
);

let cloudflare_response = client
.get(&get_url)
.header("Authorization", "Bearer ".to_owned() + &config.auth_key)
.header("Authorization", "Bearer ".to_owned() + &config.account.auth_key)
.send()
.await;

Expand All @@ -130,21 +88,21 @@ async fn main() {
if let Some(record_id) = record["id"].as_str() {
println!("Get RecordID: {}", record_id);
let data = Data {
r#type: config.dns_type.clone(),
name: config.dns_record.clone(),
r#type: config.dns.r#type.as_str().to_string(),
name: config.dns.record.clone(),
content: ip.trim().to_string(),
ttl: json["result"][0]["ttl"].as_i64().unwrap() as i32,
proxied: config.dns_proxy,
proxied: config.dns.proxied,
};

let put_url = format!(
"https://api.cloudflare.com/client/v4/zones/{}/dns_records/{}",
config.zone_id, record_id
config.account.zone_id, record_id
);

match client
.put(&put_url)
.header("Authorization", "Bearer ".to_owned() + &config.auth_key)
.header("Authorization", "Bearer ".to_owned() + &config.account.auth_key)
.json(&data)
.send()
.await
Expand All @@ -167,21 +125,21 @@ async fn main() {
println!("No DNS records found. Creating a new record...");

let data = Data {
r#type: config.dns_type.clone(),
name: config.dns_record.clone(),
r#type: config.dns.r#type.as_str().to_string(),
name: config.dns.record.clone(),
content: ip.trim().to_string(),
ttl: 120,
proxied: config.dns_proxy,
proxied: config.dns.proxied,
};

let post_url = format!(
"https://api.cloudflare.com/client/v4/zones/{}/dns_records",
config.zone_id
config.account.zone_id
);

match client
.post(&post_url)
.header("Authorization", "Bearer ".to_owned() + &config.auth_key)
.header("Authorization", "Bearer ".to_owned() + &config.account.auth_key)
.json(&data)
.send()
.await
Expand Down

0 comments on commit 51f1bf6

Please sign in to comment.