Skip to content

Commit ecf23ff

Browse files
committed
add CLI; it will accept --config_file argument, if that can not be found then the default and if that can not be found will try with arguments then otherwise throw up --help; all cli arguments have priority over config file, so you can save your api_token to file but give the params for updating via cli
1 parent d86446e commit ecf23ff

File tree

1 file changed

+72
-18
lines changed

1 file changed

+72
-18
lines changed

src/main.rs

Lines changed: 72 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use clap::Parser;
1+
use clap::{CommandFactory, Parser};
22
use log;
33
use reqwest::Client;
44
use serde::Deserialize;
@@ -14,19 +14,61 @@ struct CloudflareConfig {
1414
cloudflare_zone_api_token: String,
1515
dns_record: String, // Comma-separated DNS records
1616
ttl: u32,
17-
proxied: bool,
1817
what_ip: String,
1918
}
2019

21-
/// Command-line options
2220
#[derive(Parser, Debug)]
23-
#[command(author, version, about, long_about = None)]
21+
#[command(version, about, long_about = None)]
2422
struct Args {
25-
/// Enable verbose output
26-
#[arg(short, long)]
23+
#[arg(long)]
24+
zoneid: Option<String>,
25+
26+
#[arg(long)]
27+
api_token: Option<String>,
28+
29+
#[arg(long)]
30+
dns_record: Option<String>, // Comma-separated DNS records
31+
32+
#[arg(long)]
33+
ttl: Option<u32>,
34+
35+
#[arg(long)]
36+
what_ip: Option<String>,
37+
38+
#[arg(long)]
39+
config_file: Option<String>,
40+
41+
#[arg(long, default_value = "false")]
2742
verbose: bool,
2843
}
2944

45+
fn read_config_from_file(config_file: String) -> Result<CloudflareConfig, Box<dyn error::Error>> {
46+
let settings = Config::builder()
47+
.add_source(config::File::with_name(&*config_file))
48+
.build()?;
49+
let config: CloudflareConfig = settings.try_deserialize()?;
50+
Ok(config)
51+
}
52+
53+
fn merge_config(cli_args: Args, file_config: Option<CloudflareConfig>) -> CloudflareConfig {
54+
let default_config = file_config.unwrap_or_else(|| CloudflareConfig {
55+
zoneid: "".to_string(),
56+
cloudflare_zone_api_token: "".to_string(),
57+
dns_record: "".to_string(),
58+
ttl: 1,
59+
what_ip: "external".to_string(),
60+
});
61+
62+
CloudflareConfig {
63+
zoneid: cli_args.zoneid.unwrap_or(default_config.zoneid),
64+
cloudflare_zone_api_token: cli_args.api_token.unwrap_or(default_config.cloudflare_zone_api_token),
65+
dns_record: cli_args.dns_record.unwrap_or(default_config.dns_record),
66+
ttl: cli_args.ttl.unwrap_or(default_config.ttl),
67+
what_ip: cli_args.what_ip.unwrap_or(default_config.what_ip),
68+
}
69+
}
70+
71+
3072
fn init_logger(verbose: bool) {
3173
let log_level = if verbose {
3274
log::LevelFilter::Debug
@@ -39,15 +81,6 @@ fn init_logger(verbose: bool) {
3981
.init();
4082
}
4183

42-
fn read_config(config_file: &str) -> Result<CloudflareConfig, Box<dyn error::Error>> {
43-
let settings = Config::builder()
44-
.add_source(config::File::with_name(config_file))
45-
.build()?;
46-
47-
let config: CloudflareConfig = settings.try_deserialize()?;
48-
Ok(config)
49-
}
50-
5184
async fn get_external_ip() -> Result<IpAddr, Box<dyn error::Error>> {
5285
let client = Client::new();
5386
let resp = client.get("https://checkip.amazonaws.com").send().await?;
@@ -124,7 +157,6 @@ async fn update_cloudflare_dns(config: CloudflareConfig, ip: IpAddr) -> Result<(
124157
"name": record,
125158
"content": ip.to_string(),
126159
"ttl": config.ttl,
127-
"proxied": config.proxied
128160
});
129161

130162
// Update the DNS record
@@ -155,9 +187,31 @@ async fn main() -> Result<(), Box<dyn error::Error>> {
155187
let args = Args::parse();
156188
init_logger(args.verbose);
157189

158-
log::info!("Starting Cloudflare DNS updater...");
190+
// Default config path
191+
let default_config_path = "CloudFlareDDNS.ini";
159192

160-
let config = read_config("cloudflareddns.ini")?;
193+
// Determine whether to use config file or CLI arguments
194+
let config_file = args.config_file.clone().unwrap_or(default_config_path.to_string());
195+
196+
// Try reading the config file if it exists, otherwise proceed with CLI args
197+
let file_config = if std::path::Path::new(&config_file).exists() {
198+
Some(read_config_from_file(config_file)?)
199+
} else {
200+
None
201+
};
202+
203+
// Merge CLI arguments and config file values
204+
let config = merge_config(args, file_config);
205+
206+
// Check if all required fields are filled, otherwise display help
207+
if config.zoneid.is_empty() || config.cloudflare_zone_api_token.is_empty() || config.dns_record.is_empty() {
208+
println!("Missing required arguments: zoneid, api_token, or dns_record");
209+
Args::command().print_help()?;
210+
return Ok(());
211+
}
212+
213+
// now start the actual work
214+
log::info!("Starting Cloudflare DNS updater...");
161215

162216
let ip = match config.what_ip.as_str() {
163217
"external" => get_external_ip().await?,

0 commit comments

Comments
 (0)