Send an email in case of error
[stakingWatchdog.git] / src / main.rs
index fadc30d..0b7c9c4 100644 (file)
@@ -12,6 +12,10 @@ use std::{
 };
 
 use anyhow::{Context, Result};
+use lettre::{
+    message::header::ContentType, transport::smtp::authentication::Credentials, Message,
+    SmtpTransport, Transport,
+};
 use reqwest::StatusCode;
 use serde::Deserialize;
 use serde_json::{json, Value};
@@ -22,8 +26,8 @@ mod config;
 // mod error;
 
 const FILE_CONF: &str = "config.ron";
-const CHECK_PERIOD: Duration = Duration::from_secs(5); // 5s.
-const EMAIL_RESEND_PERIOD: Duration = Duration::from_secs(12 * 60 * 60); // 12h.
+const CHECK_PERIOD: Duration = Duration::from_secs(10); // 10s.
+const EMAIL_RESEND_PERIOD: Duration = Duration::from_secs(6 * 60 * 60); // 6h.
 const BASE_URI: &str = "http://localhost:5052/eth/v1/";
 
 fn main() -> Result<()> {
@@ -43,8 +47,18 @@ fn main() -> Result<()> {
             if time::Instant::now() - time_last_email_send >= EMAIL_RESEND_PERIOD {
                 // Send e-mail.
                 println!("Sending email...");
-
-                time_last_email_send = time::Instant::now();
+                match send_email(
+                    "Staking ERROR",
+                    &format!("Error: {:?}", error),
+                    &config.smtp_login,
+                    &config.smtp_password,
+                ) {
+                    Err(email_error) => println!("Error sending email: {:?}", email_error),
+                    _ => {
+                        println!("Email successfully sent");
+                        time_last_email_send = time::Instant::now();
+                    }
+                }
             }
         }
 
@@ -100,7 +114,7 @@ fn check_validators(pub_keys: &[String]) -> std::result::Result<(), CheckError>
         .header("accept", "application/json");
     match request_health.send() {
         Ok(resp) => {
-            println!("{resp:?}");
+            // println!("{resp:?}"); // For debug.
             match resp.status().as_u16() {
                 200 => (),
                 206 => return Err(CheckError::NotSync),
@@ -115,19 +129,16 @@ fn check_validators(pub_keys: &[String]) -> std::result::Result<(), CheckError>
         }
     }
 
-    return Err(CheckError::NotSync);
-
     for pub_key in pub_keys {
         let request = client
             .get(format!("{url}beacon/states/head/validators/0x{pub_key}"))
             .header("accept", "application/json");
         match request.send() {
             Ok(resp) => {
-                println!("{resp:?}");
+                // println!("{resp:?}"); // For debug.
                 match resp.status().as_u16() {
                     200 => {
                         let json: JsonValidatorState = resp.json()?;
-                        // println!("JSON:\n{:?}", json); // For Debug.
                         if json.data.status != "active_ongoing" {
                             return Err(CheckError::ValidatorStatusError {
                                 pub_key: pub_key.clone(),
@@ -137,7 +148,6 @@ fn check_validators(pub_keys: &[String]) -> std::result::Result<(), CheckError>
                     }
                     code => {
                         let json: JsonError = resp.json()?;
-                        // println!("JSON:\n{:?}", json); // For Debug.
                         return Err(CheckError::ValidatorError {
                             pub_key: pub_key.clone(),
                             message: format!(
@@ -149,7 +159,6 @@ fn check_validators(pub_keys: &[String]) -> std::result::Result<(), CheckError>
                 }
             }
             Err(error) => {
-                println!("{error:?}");
                 return Err(CheckError::ValidatorError {
                     pub_key: pub_key.clone(),
                     message: error.to_string(),
@@ -158,28 +167,29 @@ fn check_validators(pub_keys: &[String]) -> std::result::Result<(), CheckError>
         }
     }
 
-    // match request_builder
-    //     .header("Authorization", format!("Apikey {}", api_key))
-    //     .send()
-    // {
-    //     Ok(resp) => {
-    //         if resp.status().is_success() {
-    //             let content = resp.text().unwrap();
-    //             Ok(serde_json::from_str(&content).unwrap())
-    //         } else {
-    //             Err(Box::new(Error {
-    //                 message: format!("Request unsuccessful to {}: {:#?}", &url, resp),
-    //             }))
-    //         }
-    //     }
-    //     Err(error) => Err(Box::new(Error {
-    //         message: format!("Error during request to {}: {:?}", &url, error),
-    //     })),
-    // }
-
-    // 1) Check health.
-
-    // 2) Check each validators.
+    Ok(())
+}
+
+fn send_email(title: &str, body: &str, login: &str, pass: &str) -> Result<()> {
+    let email = Message::builder()
+        .message_id(None)
+        .from("Staking Watchdog <redmine@d-lan.net>".parse()?)
+        .to("Greg Burri <greg.burri@gmail.com>".parse()?)
+        .subject(title)
+        .header(ContentType::TEXT_PLAIN)
+        .body(body.to_string())?;
+
+    let creds = Credentials::new(login.to_string(), pass.to_string());
+
+    // Open a remote connection to gmail
+    let mailer = SmtpTransport::relay("mail.gandi.net")?
+        .credentials(creds)
+        .build();
+
+    // Send the email
+    let response = mailer.send(&email)?;
+
+    println!("{:?}", response);
 
     Ok(())
 }