First commit
[stakingWatchdogWatchdog.git] / src / main.rs
1 use std::{
2 net::UdpSocket,
3 thread,
4 time::{self, Duration},
5 };
6
7 use anyhow::Result;
8 use lettre::{
9 message::header::ContentType, transport::smtp::authentication::Credentials, Message,
10 SmtpTransport, Transport,
11 };
12 use rand::{rngs::ThreadRng, Rng};
13
14 use crate::config::Config;
15
16 mod config;
17
18 const FILE_CONF: &str = "config.ron";
19 const PING_PERIOD: Duration = Duration::from_secs(5); // 5 s.
20 const EMAIL_RESEND_PERIOD: Duration = Duration::from_secs(2 * 60 * 60); // 2 h.
21 const STATE_PRINT_PERIOD: Duration = Duration::from_secs(15 * 60); // 15 min.
22
23 fn main() -> Result<()> {
24 println!("Staking Watchdog Watchdog");
25
26 let config = Config::read(FILE_CONF)?;
27
28 println!(
29 "Configuration: {:?}",
30 Config {
31 smtp_password: "*****".to_string(),
32 ..config.clone()
33 }
34 );
35
36 let mut time_last_email_send = time::Instant::now() - EMAIL_RESEND_PERIOD;
37 let mut time_last_state_printed = time::Instant::now() - STATE_PRINT_PERIOD;
38 let mut error_state = false;
39
40 let mut rng = rand::thread_rng();
41
42 let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
43 socket.connect("192.168.2.102:8739").unwrap();
44 socket
45 .set_read_timeout(Some(Duration::from_secs(5)))
46 .unwrap();
47 socket
48 .set_write_timeout(Some(Duration::from_secs(5)))
49 .unwrap();
50
51 loop {
52 let time_beginning_loop = time::Instant::now();
53
54 if let Err(error) = ping(&socket, &mut rng) {
55 error_state = true;
56 println!("Error: {:?}", error);
57 if time::Instant::now() - time_last_email_send >= EMAIL_RESEND_PERIOD {
58 // Send e-mail.
59 println!("Sending email...");
60 match send_email(
61 "Watchdog ERROR",
62 &format!("Error: {:?}", error),
63 &config.smtp_login,
64 &config.smtp_password,
65 ) {
66 Err(email_error) => println!("Error sending email: {:?}", email_error),
67 _ => {
68 println!("Email successfully sent");
69 time_last_email_send = time::Instant::now();
70 }
71 }
72 }
73 } else {
74 if error_state {
75 error_state = false;
76 println!("End of erroneous state");
77 }
78
79 if time::Instant::now() - time_last_state_printed >= STATE_PRINT_PERIOD {
80 println!("No error detected");
81 time_last_state_printed = time::Instant::now();
82 }
83 }
84
85 let elapsed = time::Instant::now() - time_beginning_loop;
86
87 if elapsed < PING_PERIOD {
88 let to_wait = PING_PERIOD - elapsed;
89 thread::sleep(to_wait);
90 }
91 }
92 }
93
94 #[derive(Debug)]
95 enum PingError {
96 SocketError(std::io::Error),
97 WrongMessageReceived(String),
98 }
99
100 fn ping(socket: &UdpSocket, rng: &mut ThreadRng) -> std::result::Result<(), PingError> {
101 let number: u64 = rng.gen();
102 let mut buffer = number.to_le_bytes();
103
104 match socket.send(&buffer) {
105 Ok(_size_sent) => {
106 buffer.fill(0);
107 match socket.recv(&mut buffer) {
108 Ok(size_received) => {
109 if size_received == 8 {
110 let number_received = u64::from_le_bytes(buffer);
111 if number_received != number {
112 return Err(PingError::WrongMessageReceived(format!(
113 "Message number receceived ({}) is not equal to the one sent ({})",
114 number_received, number
115 )));
116 }
117 } else {
118 return Err(PingError::WrongMessageReceived(format!(
119 "Size of packet must be 8, received size: {}",
120 size_received
121 )));
122 }
123 }
124 Err(error) => return Err(PingError::SocketError(error)),
125 }
126 }
127 Err(error) => return Err(PingError::SocketError(error)),
128 }
129
130 Ok(())
131 }
132
133 fn send_email(title: &str, body: &str, login: &str, pass: &str) -> Result<()> {
134 let email = Message::builder()
135 .message_id(None)
136 .from("Staking Watchdog <redmine@d-lan.net>".parse()?)
137 .to("Greg Burri <greg.burri@gmail.com>".parse()?)
138 .subject(title)
139 .header(ContentType::TEXT_PLAIN)
140 .body(body.to_string())?;
141
142 let creds = Credentials::new(login.to_string(), pass.to_string());
143
144 // Open a remote connection to gmail
145 let mailer = SmtpTransport::relay("mail.gandi.net")?
146 .credentials(creds)
147 .build();
148
149 // Send the email
150 let response = mailer.send(&email)?;
151
152 println!("{:?}", response);
153
154 Ok(())
155 }