1- use clap:: Parser ;
1+ use clap:: { CommandFactory , Parser } ;
22use log;
33use reqwest:: Client ;
44use 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 ) ]
2422struct 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+
3072fn 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-
5184async 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