use an iced stream to update newer_release_available instead of using a mutex

This commit is contained in:
GyulyVGC
2025-05-09 22:38:50 +02:00
parent 88270ba950
commit b4038e62ec
8 changed files with 54 additions and 60 deletions

2
Cargo.lock generated
View File

@@ -4071,7 +4071,6 @@ dependencies = [
"base64",
"bytes",
"encoding_rs",
"futures-channel",
"futures-core",
"futures-util",
"h2",
@@ -4715,6 +4714,7 @@ dependencies = [
"serde_test",
"serial_test",
"splines",
"tokio",
"toml 0.8.22",
"winres",
]

View File

@@ -55,15 +55,16 @@ phf = "0.11.3"
phf_shared = "0.11.3"
splines = "4.4.2"
clap = { version = "4.5.37", features = ["derive"] }
tokio = "1.44.2"
[target.'cfg(windows)'.dependencies]
gag = "1.0.0"
[target.'cfg(not(target_arch = "powerpc64"))'.dependencies]
reqwest = { version = "0.12.15", default-features = false, features = ["json", "blocking", "rustls-tls"] }
reqwest = { version = "0.12.15", default-features = false, features = ["json", "rustls-tls"] }
[target.'cfg(target_arch = "powerpc64")'.dependencies]
reqwest = { version = "0.12.15", features = ["json", "blocking"] }
reqwest = { version = "0.12.15", features = ["json"] }
#───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

View File

@@ -123,9 +123,6 @@ fn test_restore_default_configs() {
assert_eq!(Configs::load(), Configs::default());
// only needed because it will delete config files via its Drop implementation
Sniffer::new(
&Arc::new(Mutex::new(Configs::default())),
Arc::new(Mutex::new(Some(true))),
);
Sniffer::new(&Arc::new(Mutex::new(Configs::default())));
}
}

View File

@@ -1,7 +1,5 @@
//! GUI bottom footer
use std::sync::Mutex;
use iced::widget::text::LineHeight;
use iced::widget::tooltip::Position;
use iced::widget::{Column, Container, Row, Text, Tooltip, button, rich_text, span};
@@ -29,7 +27,7 @@ pub fn footer<'a>(
color_gradient: GradientType,
font: Font,
font_footer: Font,
newer_release_available: &Mutex<Option<bool>>,
newer_release_available: Option<bool>,
) -> Container<'a, Message, StyleType> {
if thumbnail {
return thumbnail_footer();
@@ -188,7 +186,7 @@ fn get_release_details<'a>(
language: Language,
font: Font,
font_footer: Font,
newer_release_available: &Mutex<Option<bool>>,
newer_release_available: Option<bool>,
) -> Row<'a, Message, StyleType> {
let mut ret_val = Row::new()
.align_y(Alignment::Center)
@@ -199,7 +197,7 @@ fn get_release_details<'a>(
.size(FONT_SIZE_FOOTER)
.font(font_footer),
);
if let Some(boolean_response) = *newer_release_available.lock().unwrap() {
if let Some(boolean_response) = newer_release_available {
if boolean_response {
// a newer release is available on GitHub
let button = button(

View File

@@ -7,12 +7,13 @@
use std::time::Duration;
use iced::Event::{Keyboard, Window};
use iced::futures::Stream;
use iced::keyboard::key::Named;
use iced::keyboard::{Event, Key, Modifiers};
use iced::mouse::Event::ButtonPressed;
use iced::widget::Column;
use iced::window::{Id, Level};
use iced::{Element, Point, Size, Subscription, Task, window};
use iced::{Element, Point, Size, Subscription, Task, stream, window};
use pcap::Device;
use rfd::FileHandle;
@@ -58,6 +59,7 @@
use crate::report::types::report_sort_type::ReportSortType;
use crate::report::types::search_parameters::SearchParameters;
use crate::report::types::sort_type::SortType;
use crate::secondary_threads::check_updates::set_newer_release_status;
use crate::secondary_threads::parse_packets::parse_packets;
use crate::translations::types::language::Language;
use crate::utils::error_logger::{ErrorLogger, Location};
@@ -82,7 +84,7 @@ pub struct Sniffer {
/// Capture data updated by thread parsing packets
pub info_traffic: Arc<Mutex<InfoTraffic>>,
/// Reports if a newer release of the software is available on GitHub
pub newer_release_available: Arc<Mutex<Option<bool>>>,
pub newer_release_available: Option<bool>,
/// Traffic data displayed in GUI
pub runtime_data: RunTimeData,
/// Network adapter to be analyzed
@@ -130,10 +132,7 @@ pub struct Sniffer {
}
impl Sniffer {
pub fn new(
configs: &Arc<Mutex<Configs>>,
newer_release_available: Arc<Mutex<Option<bool>>>,
) -> Self {
pub fn new(configs: &Arc<Mutex<Configs>>) -> Self {
let ConfigSettings {
style,
language,
@@ -146,7 +145,7 @@ pub fn new(
configs: configs.clone(),
current_capture_id: Arc::new(Mutex::new(0)),
info_traffic: Arc::new(Mutex::new(InfoTraffic::new())),
newer_release_available,
newer_release_available: None,
runtime_data: RunTimeData::new(),
device,
filters: Filters::default(),
@@ -254,6 +253,10 @@ fn window_subscription() -> Subscription<Message> {
})
}
fn check_updates_stream() -> impl Stream<Item = Message> {
stream::channel(1, set_newer_release_status)
}
pub fn update(&mut self, message: Message) -> Task<Message> {
match message {
Message::TickRun => return self.refresh_data(),
@@ -536,6 +539,7 @@ pub fn update(&mut self, message: Message) -> Task<Message> {
}
}
Message::WindowId(id) => self.id = id,
Message::SetNewerReleaseStatus(status) => self.newer_release_available = status,
Message::TickInit => {}
}
Task::none()
@@ -570,7 +574,7 @@ pub fn view(&self) -> Element<Message, StyleType> {
color_gradient,
font,
font_headers,
&self.newer_release_available,
self.newer_release_available,
);
let content: Element<Message, StyleType> =
@@ -625,6 +629,7 @@ pub fn subscription(&self) -> Subscription<Message> {
self.mouse_subscription(),
self.time_subscription(),
Sniffer::window_subscription(),
Subscription::run(Sniffer::check_updates_stream),
])
}
@@ -998,15 +1003,12 @@ mod tests {
// tests using this will require the #[parallel] annotation
fn new_sniffer() -> Sniffer {
Sniffer::new(
&Arc::new(Mutex::new(Configs::default())),
Arc::new(Mutex::new(None)),
)
Sniffer::new(&Arc::new(Mutex::new(Configs::default())))
}
// tests using this will require the #[serial] annotation
fn new_sniffer_with_configs(configs: Configs) -> Sniffer {
Sniffer::new(&Arc::new(Mutex::new(configs)), Arc::new(Mutex::new(None)))
Sniffer::new(&Arc::new(Mutex::new(configs)))
}
// helpful to clean up files generated from tests

View File

@@ -126,4 +126,6 @@ pub enum Message {
ScaleFactorShortcut(bool),
/// Set the window ID
WindowId(Option<window::Id>),
/// Set new release status
SetNewerReleaseStatus(Option<bool>),
}

View File

@@ -4,7 +4,7 @@
use std::borrow::Cow;
use std::sync::{Arc, Mutex};
use std::{panic, process, thread};
use std::{panic, process};
use iced::advanced::graphics::image::image_rs::ImageFormat;
#[cfg(target_os = "linux")]
@@ -34,7 +34,6 @@
use crate::configs::types::configs::{CONFIGS, Configs};
use crate::gui::sniffer::FONT_FAMILY_NAME;
use crate::gui::styles::style_constants::{ICONS_BYTES, SARASA_MONO_BOLD_BYTES, SARASA_MONO_BYTES};
use crate::secondary_threads::check_updates::set_newer_release_status;
use crate::utils::error_logger::{ErrorLogger, Location};
mod chart;
@@ -75,9 +74,6 @@ pub fn main() -> iced::Result {
let configs1 = Arc::new(Mutex::new(configs));
let configs2 = configs1.clone();
let newer_release_available1 = Arc::new(Mutex::new(None));
let newer_release_available2 = newer_release_available1.clone();
// kill the main thread as soon as a secondary thread panics
let orig_hook = panic::take_hook();
panic::set_hook(Box::new(move |panic_info| {
@@ -93,13 +89,6 @@ pub fn main() -> iced::Result {
})
.log_err(location!());
let _ = thread::Builder::new()
.name("thread_check_updates".to_string())
.spawn(move || {
set_newer_release_status(&newer_release_available2);
})
.log_err(location!());
print_cli_welcome_message();
let ConfigWindow { size, position, .. } = configs1.lock().unwrap().window;
@@ -138,10 +127,5 @@ pub fn main() -> iced::Result {
.subscription(Sniffer::subscription)
.theme(Sniffer::theme)
.scale_factor(Sniffer::scale_factor)
.run_with(move || {
(
Sniffer::new(&configs1, newer_release_available1),
boot_task_chain,
)
})
.run_with(move || (Sniffer::new(&configs1), boot_task_chain))
}

View File

@@ -1,11 +1,11 @@
use std::sync::Mutex;
use std::thread;
use std::time::Duration;
use serde::Deserialize;
use crate::SNIFFNET_LOWERCASE;
use crate::gui::types::message::Message;
use crate::utils::error_logger::ErrorLogger;
use crate::utils::formatted_strings::APP_VERSION;
use crate::{Location, SNIFFNET_LOWERCASE, location};
use iced::futures::SinkExt;
use iced::futures::channel::mpsc::Sender;
use serde::Deserialize;
use std::time::Duration;
#[derive(Deserialize, Debug)]
struct AppVersion {
@@ -14,23 +14,27 @@ struct AppVersion {
/// Calls a method to check if a newer release of Sniffnet is available on GitHub
/// and updates application status accordingly
pub fn set_newer_release_status(newer_release_available: &Mutex<Option<bool>>) {
let result = is_newer_release_available(6, 30);
*newer_release_available.lock().unwrap() = result;
pub async fn set_newer_release_status(mut sender: Sender<Message>) {
let result = is_newer_release_available(6, 30).await;
let _ = sender
.send(Message::SetNewerReleaseStatus(result))
.await
.log_err(location!());
}
/// Checks if a newer release of Sniffnet is available on GitHub
fn is_newer_release_available(max_retries: u8, seconds_between_retries: u8) -> Option<bool> {
let client = reqwest::blocking::Client::new();
async fn is_newer_release_available(max_retries: u8, seconds_between_retries: u8) -> Option<bool> {
let client = reqwest::Client::new();
let response = client
.get("https://api.github.com/repos/GyulyVGC/sniffnet/releases/latest")
.header("User-agent", format!("{SNIFFNET_LOWERCASE}-{APP_VERSION}"))
.header("Accept", "application/vnd.github+json")
.header("X-GitHub-Api-Version", "2022-11-28")
.send();
.send()
.await;
if let Ok(result) = response {
let result_json = result.json::<AppVersion>();
let result_json = result.json::<AppVersion>().await;
#[cfg(test)]
if result_json.is_err() {
@@ -39,7 +43,8 @@ fn is_newer_release_available(max_retries: u8, seconds_between_retries: u8) -> O
.header("User-agent", format!("{SNIFFNET_LOWERCASE}-{APP_VERSION}"))
.header("Accept", "application/vnd.github+json")
.header("X-GitHub-Api-Version", "2022-11-28")
.send();
.send()
.await;
println!("\nResponse text: {:?}", response2.unwrap());
println!("JSON result: {result_json:?}\n");
}
@@ -52,6 +57,7 @@ fn is_newer_release_available(max_retries: u8, seconds_between_retries: u8) -> O
latest_version = latest_version.trim().to_string();
// release name sample: v1.1.2
// TODO: support versions with numbers of more than 1 digit
let latest_version_as_bytes = latest_version.as_bytes();
if latest_version.len() == 6
&& latest_version.starts_with('v')
@@ -72,8 +78,12 @@ fn is_newer_release_available(max_retries: u8, seconds_between_retries: u8) -> O
let retries_left = max_retries - 1;
if retries_left > 0 {
// sleep seconds_between_retries and retries the request
thread::sleep(Duration::from_secs(u64::from(seconds_between_retries)));
is_newer_release_available(retries_left, seconds_between_retries)
tokio::time::sleep(Duration::from_secs(u64::from(seconds_between_retries))).await;
Box::pin(is_newer_release_available(
retries_left,
seconds_between_retries,
))
.await
} else {
None
}