use std::fmt; use log::{debug, error, info, log_enabled, Level}; use netlink_packet_core::{NetlinkMessage, NetlinkPayload}; use netlink_packet_route::RouteNetlinkMessage as RtnlMessage; use crate::CloudflareClient; pub struct MessageHandler<'a> { cloudflare: &'a mut CloudflareClient, errs_counter: usize, errs_max: usize, } impl<'a> MessageHandler<'a> { pub fn new(cloudflare: &'a mut CloudflareClient, errs_max: usize) -> Self { Self { cloudflare, errs_counter: 0, errs_max, } } pub async fn handle_message(&mut self, message: NetlinkMessage) -> Option<()> { match message.payload { NetlinkPayload::InnerMessage(RtnlMessage::NewAddress(msg)) => { self.log_and_check("New IPv4 address", &msg).await } NetlinkPayload::InnerMessage(RtnlMessage::DelAddress(msg)) => { self.log_info("Deleted IPv4 address", &msg).await } NetlinkPayload::InnerMessage(RtnlMessage::NewLink(link)) => { self.log_and_check("New link (interface connected)", &link) .await } NetlinkPayload::InnerMessage(RtnlMessage::DelLink(link)) => { self.log_info("Deleted link (interface disconnected)", &link) .await } _ => { if log_enabled!(Level::Debug) { debug!("Unhandled message payload: {:?}", message.payload); } Some(()) } } } async fn log_and_check(&mut self, log_msg: &D, msg: &M) -> Option<()> where D: fmt::Display + ?Sized, M: fmt::Debug, { if log_enabled!(Level::Debug) { debug!("{}: {:?}", log_msg, msg); } else { info!("{}", log_msg); if let Err(e) = self.cloudflare.check().await { self.errs_counter += 1; error!( "Failed to check cloudflare ({}/{}): {:?}", self.errs_counter, self.errs_max, &e ); if self.errs_counter >= self.errs_max { return None; } } } Some(()) } async fn log_info(&self, log_msg: &str, msg: &M) -> Option<()> { if log_enabled!(Level::Debug) { debug!("{:?} message: {:?}", log_msg, msg); } else { info!("{}", log_msg); } Some(()) } }