Use of now() to have a precise period of time
[rtx3080.git] / src / main.rs
index 9eca649..4854e1e 100644 (file)
@@ -14,35 +14,46 @@ use lettre::{
     }
 };
 use lettre_email::Email;
-use native_tls::{Protocol, TlsConnector};
+use native_tls::{ Protocol, TlsConnector };
 use ron::{ de::from_reader, ser::to_writer };
 use serde::{ Deserialize, Serialize };
 
+type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
+
 #[derive(Debug, Deserialize, Serialize)]
 struct Config {
     smtp_login: String,
-    smtp_password: String
+    smtp_password: String,
+}
+
+impl Config {
+    fn default() -> Self {
+        Config { smtp_login: "login".to_string(), smtp_password: "password".to_string() }
+    }
+
+    fn read(file_path: &str) -> Result<Config> {
+        match File::open(file_path) {
+            Ok(file) => from_reader(file).map_err(|e| e.into()),
+            Err(_) => {
+                let file = File::create(file_path)?;
+                let default_config = Config::default();
+                to_writer(file, &default_config)?;
+                Ok(default_config)
+            }
+        }
+    }
 }
 
-fn get_default_config() -> Config { Config { smtp_login: "login".to_string(), smtp_password: "password".to_string() } }
 const FILE_CONF: &str = "config.ron";
+const PULL_PERIOD: time::Duration = time::Duration::from_secs(60); // 1 min.
 
-fn main() -> Result<(), Box<dyn std::error::Error>> {
+fn main() -> Result<()> {
     println!("I need a RTX 3080 right now :)");
 
     let to_find = "RTX 3080";
     let to_match = "3080";
 
-    let config: Config =
-        match File::open(FILE_CONF) {
-            Ok(file) => match from_reader(file) { Ok(c) => c, Err(e) => panic!("Failed to load config: {}", e)},
-            Err(_) => {
-                let file = File::create(FILE_CONF)?;
-                let default_config = get_default_config();
-                to_writer(file, &default_config)?;
-                default_config
-            }
-        };
+    let config = Config::read(FILE_CONF)?;
 
     let selector = Selector::parse("div.productGridElement > h2 > a:nth-child(1)").unwrap();
     let url = format!("https://www.steg-electronics.ch/fr/search?suche={}", to_find);
@@ -50,39 +61,49 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
     let client = reqwest::blocking::Client::new();
 
     loop {
+        let time_beginning_loop = time::Instant::now();
         println!("Request: {}", url);
-        let resp = client.get(&url).send()?;
-
-        if resp.status().is_success() {
-            let html = resp.text()?;
-            let document = Html::parse_document(&html);
-
-            // A vector of (<title>, <url>), empty if nothing matches.
-            let match_items: Vec<(String, String)> =
-                document.select(&selector).filter_map(
-                    |element| {
-                        if let (Some(title), Some(url_to_item)) = (element.value().attr("title"), element.value().attr("href")) {
-                            if title.find(to_match).is_some() {
-                                return Some((String::from(title), String::from(url_to_item)))
+
+        match client.get(&url).send() {
+            Ok(resp) =>
+                if resp.status().is_success() {
+                    let html = resp.text()?;
+                    let document = Html::parse_document(&html);
+
+                    // A vector of (<title>, <url>), empty if nothing matches.
+                    let match_items: Vec<(String, String)> =
+                        document.select(&selector).filter_map(
+                            |element| {
+                                if let (Some(title), Some(url_to_item)) = (element.value().attr("title"), element.value().attr("href")) {
+                                    if title.find(to_match).is_some() {
+                                        return Some((String::from(title), String::from(url_to_item)))
+                                    }
+                                }
+                                None
                             }
-                        }
-                        None
+                        ).collect();
+
+                    if match_items.is_empty() {
+                        println!("No matches ðŸ˜¿");
+                    } else if send_email(&match_items[..], &config.smtp_login, &config.smtp_password) {
+                        println!("Some matches has been found ðŸ˜º! An e-mail has been sent!");
+                        return Ok(())
+                    } else {
+                        println!("Unable to send e-mail");
                     }
-                ).collect();
-
-            if match_items.is_empty() {
-                println!("No matches...");
-            } else if send_email(&match_items[..], &config.smtp_login, &config.smtp_password) {
-                println!("Some matches has been found! An e-mail has been sent!");
-                return Ok(())
-            } else {
-                println!("Unable to send e-mail");
-            }
-        } else {
-            println!("Request unsuccessful:\n{:#?}", resp);
+                } else {
+                    println!("Request unsuccessful:\n{:#?}", resp);
+                },
+            Err(error) =>
+                println!("Error during request: {:?}", error)
         }
 
-        thread::sleep(time::Duration::from_secs(60)); // 1 min.
+        let elapsed = time::Instant::now() - time_beginning_loop;
+
+        if elapsed < PULL_PERIOD {
+            let to_wait = PULL_PERIOD - elapsed;
+            thread::sleep(to_wait);
+        }
     }
 }