diff --git a/src/exit_listener.rs b/src/exit_listener.rs new file mode 100644 index 0000000..4875d9c --- /dev/null +++ b/src/exit_listener.rs @@ -0,0 +1,43 @@ +use std::sync::{ + atomic::{AtomicBool, Ordering}, + Arc, +}; + +use tokio::{ + self, signal, + sync::{futures::Notified, Notify}, +}; + +pub struct ExitListener { + should_exit: Arc, + notify: Arc, +} + +impl ExitListener { + pub fn new() -> Self { + let this = Self { + should_exit: Arc::new(AtomicBool::new(false)), + notify: Arc::new(Notify::new()), + }; + + let should_exit = this.should_exit.clone(); + let notify = this.notify.clone(); + + tokio::spawn(async move { + signal::ctrl_c() + .await + .expect("Failed to install CTRL+C signal handler"); + should_exit.store(true, Ordering::SeqCst); + notify.notify_one(); + }); + this + } + + pub fn notified(&self) -> Notified<'_> { + self.notify.notified() + } + + pub fn should_exit(&self) -> bool { + self.should_exit.load(Ordering::SeqCst) + } +} diff --git a/src/lib.rs b/src/lib.rs index 244b6d7..868e773 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ mod cloudflare; mod config; +mod exit_listener; mod logging; mod message_handler; mod public_ip; @@ -10,6 +11,7 @@ pub mod utils; pub use cloudflare::CloudflareClient; pub use config::{get_config_path, read_config, Config}; +pub use exit_listener::ExitListener; pub use logging::init_logger; pub use message_handler::MessageHandler; pub use public_ip::get_current_public_ipv4; diff --git a/src/main.rs b/src/main.rs index 3cb43f9..4f3d106 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,6 @@ // SPDX: BSD-2-Clause use futures::future::{self, Either}; -use std::sync::{ - atomic::{AtomicBool, Ordering}, - Arc, -}; - use futures::stream::StreamExt; use log::{error, info}; use netlink_sys::{AsyncSocket, SocketAddr}; @@ -13,10 +8,10 @@ use rtnetlink::new_connection; use dynip_cloudflare::{ utils::{self, duration_to_string}, - CloudflareClient, MessageHandler, MAX_ERORS_IN_ROW_DEFAULT, + CloudflareClient, ExitListener, MessageHandler, MAX_ERORS_IN_ROW_DEFAULT, }; use scopeguard::defer; -use tokio::{signal, sync::Notify, time}; +use tokio::time; const RTNLGRP_LINK: u32 = 1; const RTNLGRP_IPV4_IFADDR: u32 = 5; @@ -38,19 +33,7 @@ async fn main() { defer! { log::logger().flush(); } - let should_exit = Arc::new(AtomicBool::new(false)); - let notify = Arc::new(Notify::new()); - - let should_exit_clone = should_exit.clone(); - let notify_clone = notify.clone(); - - tokio::spawn(async move { - signal::ctrl_c() - .await - .expect("Failed to install CTRL+C signal handler"); - should_exit_clone.store(true, Ordering::SeqCst); - notify_clone.notify_one(); - }); + let exit_listener = ExitListener::new(); let config = if let Some(aux) = utils::get_config().await { aux @@ -91,14 +74,14 @@ async fn main() { interval }); - while !should_exit.load(Ordering::SeqCst) { + while !exit_listener.should_exit() { let tick_future = match interval.as_mut() { Some(interval) => Either::Left(interval.tick()), None => Either::Right(future::pending::()), }; tokio::select! { - _ = notify.notified() => break, + _ = exit_listener.notified() => break, _ = tick_future => { if let Some(duration) = config.max_duration.as_ref() { let duration_string = duration_to_string(duration);