2 * API Reference: https://api.gandi.net/docs/livedns/
3 * Some inspiration: https://github.com/rmarchant/gandi-ddns/blob/master/gandi_ddns.py
6 use std
::{ thread
, time
, fs
::File
, net
::{ IpAddr
, Ipv4Addr
} };
7 use ron
::{ de
::from_reader
, ser
::to_writer
};
8 use serde
::{ Deserialize
, Serialize
};
10 type Result
<T
> = std
::result
::Result
<T
, Box
<dyn std
::error
::Error
>>;
13 struct GetRealIpError
;
15 impl std
::fmt
::Display
for GetRealIpError
{
16 fn fmt(&self, f
: &mut std
::fmt
::Formatter
<'_
>) -> std
::fmt
::Result
{
17 write!(f
, "SuperErrorSideKick is here!")
21 impl std
::error
::Error
for GetRealIpError {}
23 #[derive(Debug, Deserialize, Serialize)]
25 delay_between_check
: time
::Duration
,
30 fn default() -> Self {
31 Config
{ delay_between_check
: time
::Duration
::from_secs(60), api_key
: String
::from("") }
34 fn read(file_path
: &str) -> Result
<Config
> {
35 match File
::open(file_path
) {
36 Ok(file
) => from_reader(file
).map_err(|e
| e
.into()),
37 // The file doesn't exit -> create it with default values.
39 let file
= File
::create(file_path
)?
;
40 let default_config
= Config
::default();
41 to_writer(file
, &default_config
)?
;
48 const FILE_CONF
: &str = "config.ron";
50 fn main() -> Result
<()> {
51 println!("GANDI DynDNS");
53 let config
= Config
::read(FILE_CONF
)?
;
55 println!("Configuration: {:?}", config
);
58 let time_beginning_loop
= time
::Instant
::now();
60 check_and_update_dns(&config
.api_key
);
62 let elapsed
= time
::Instant
::now() - time_beginning_loop
;
64 if elapsed
< config
.delay_between_check
{
65 let to_wait
= config
.delay_between_check
- elapsed
;
66 thread
::sleep(to_wait
);
72 fn check_and_update_dns(api_key
: &str) {
74 let url = "https://api.gandi.net/v5/livedns/domains";
75 let client = reqwest::blocking::Client::new();
77 match client.get(url).header("Authorization", format!("Apikey {}", api_key)).send() {
79 if resp.status().is_success() {
80 let content = resp.text().unwrap();
81 println!("Content:\n{:?}", content);
83 println!("Request unsuccessful:\n{:#?}", resp);
86 println!("Error during request: {:?}", error)
92 fn get_real_ip() -> Result
<Ipv4Addr
> {
94 let url
= "https://api.ipify.org";
95 let client
= reqwest
::blocking
::Client
::new();
97 match client
.get(url
).send() {
99 if resp
.status().is_success() {
100 let content
= resp
.text().unwrap();
101 match content
.parse
::<IpAddr
>() {
102 Ok(IpAddr
::V4(ip_v4
)) => Ok(ip_v4
),
103 /*Err(_)*/ _
=> Err(Box
::new(GetRealIpError
))
105 //println!("Content:\n{:?}", content);
107 println!("Request unsuccessful:\n{:#?}", resp
);
108 Err(Box
::new(GetRealIpError
))
112 println!("Error during request: {:?}", error
);
113 Err(Box
::new(GetRealIpError
))
118 fn get_current_record_ip() {
122 fn update_record_ip() {