494737e2dfafa2ee372bfff18774921dea1ad256
5 time
::{self, Duration
},
10 message
::header
::ContentType
, transport
::smtp
::authentication
::Credentials
, Message
,
11 SmtpTransport
, Transport
,
13 use rand
::{rngs
::ThreadRng
, Rng
};
15 use crate::config
::Config
;
19 const FILE_CONF
: &str = "config.ron";
20 const PING_PERIOD
: Duration
= Duration
::from_secs(5); // 5 s.
21 const EMAIL_RESEND_PERIOD
: Duration
= Duration
::from_secs(2 * 60 * 60); // 2 h.
22 const STATE_PRINT_PERIOD
: Duration
= Duration
::from_secs(15 * 60); // 15 min.
23 const SOCKET_TIMEOUT
: Duration
= Duration
::from_secs(7);
25 fn main() -> Result
<()> {
26 println!("Staking Watchdog Watchdog");
28 let config
= Config
::read(FILE_CONF
)?
;
31 "Configuration: {:?}",
33 smtp_password
: "*****".to_string(),
38 let mut time_last_email_send
= time
::Instant
::now() - EMAIL_RESEND_PERIOD
;
39 let mut time_last_state_printed
= time
::Instant
::now() - STATE_PRINT_PERIOD
;
40 let mut error_state
= false;
42 let mut rng
= rand
::thread_rng();
44 let mut number_of_pings
= 0;
45 let mut total_ping_duration
= Duration
::default();
47 let socket
= UdpSocket
::bind("0.0.0.0:0").unwrap();
48 socket
.connect("192.168.2.102:8739").unwrap();
49 socket
.set_nonblocking(false).unwrap();
50 socket
.set_read_timeout(Some(SOCKET_TIMEOUT
)).unwrap();
51 socket
.set_write_timeout(Some(SOCKET_TIMEOUT
)).unwrap();
54 let time_beginning_loop
= time
::Instant
::now();
56 match ping(&socket
, &mut rng
) {
58 total_ping_duration
+= t
;
63 println!("End of erroneous state");
66 if time
::Instant
::now() - time_last_state_printed
>= STATE_PRINT_PERIOD
{
68 "No error detected. Mean of ping time: {} μs",
69 total_ping_duration
.as_micros() / number_of_pings
71 total_ping_duration
= Duration
::default();
73 time_last_state_printed
= time
::Instant
::now();
78 println!("Error: {:?}", error
);
79 if time
::Instant
::now() - time_last_email_send
>= EMAIL_RESEND_PERIOD
{
81 println!("Sending email...");
83 "Watchdog Watchdog: Check alive error",
84 &format!("Error: {}", error
),
86 &config
.smtp_password
,
88 Err(email_error
) => println!("Error sending email: {:?}", email_error
),
90 println!("Email successfully sent");
91 time_last_email_send
= time
::Instant
::now();
98 let elapsed
= time
::Instant
::now() - time_beginning_loop
;
100 if elapsed
< PING_PERIOD
{
101 let to_wait
= PING_PERIOD
- elapsed
;
102 thread
::sleep(to_wait
);
109 SocketReceiveError(std
::io
::Error
),
110 SocketSendError(std
::io
::Error
),
111 WrongMessageReceived(String
),
114 impl fmt
::Display
for PingError
{
115 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
117 PingError
::SocketReceiveError(error
) => {
118 write!(f
, "Didn't receive any response from watchdog: {}", error
)
120 PingError
::SocketSendError(error
) => {
121 write!(f
, "Unable to send the message: {}", error
)
123 PingError
::WrongMessageReceived(message
) => {
124 write!(f
, "Watchdog replay with a wrong message: {}", message
)
130 fn ping(socket
: &UdpSocket
, rng
: &mut ThreadRng
) -> std
::result
::Result
<Duration
, PingError
> {
132 let number
: u64 = rng
.gen();
133 let mut buffer
= number
.to_le_bytes();
134 let now
= time
::Instant
::now();
135 match socket
.send(&buffer
) {
138 match socket
.recv(&mut buffer
) {
139 Ok(size_received
) => {
140 if size_received
== 8 {
141 let number_received
= u64::from_le_bytes(buffer
);
142 if number_received
== number
{
143 return Ok(time
::Instant
::now() - now
);
145 return Err(PingError
::WrongMessageReceived(format!(
146 "Message number receceived ({}) is not equal to the one sent ({})",
147 number_received
, number
151 return Err(PingError
::WrongMessageReceived(format!(
152 "Size of packet must be 8, received size: {}",
158 // Test the kind because sometime 'recv' returns
159 // '(Os { code: 11, kind: WouldBlock, message: "Resource temporarily unavailable" }'.
160 // Try again in this case.
161 Err(error
) if error
.kind() == std
::io
::ErrorKind
::WouldBlock
=> {
162 println!("WouldBlock error: {}", error
)
164 Err(error
) => return Err(PingError
::SocketReceiveError(error
)),
167 Err(error
) => return Err(PingError
::SocketSendError(error
)),
172 fn send_email(title
: &str, body
: &str, login
: &str, pass
: &str) -> Result
<()> {
173 let email
= Message
::builder()
175 .from("Staking Watchdog Watchdog <redmine@d-lan.net>".parse()?
)
176 .to("Greg Burri <greg.burri@gmail.com>".parse()?
)
178 .header(ContentType
::TEXT_PLAIN
)
179 .body(body
.to_string())?
;
181 let creds
= Credentials
::new(login
.to_string(), pass
.to_string());
183 // Open a remote connection to gmail
184 let mailer
= SmtpTransport
::relay("mail.infomaniak.com")?
189 let response
= mailer
.send(&email
)?
;
191 println!("{:?}", response
);