}
};
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);
+
+ let client = reqwest::blocking::Client::new();
loop {
- let url = format!("https://www.steg-electronics.ch/fr/search?suche={}", to_find);
+ let time_beginning_loop = time::Instant::now();
println!("Request: {}", url);
- let resp = reqwest::blocking::get(&url)?;
-
- 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);
+ }
}
}