From 7b905baf6a3f6044a2f11e38e47f4b3f7ff1ef96 Mon Sep 17 00:00:00 2001 From: GyulyVGC Date: Wed, 11 Mar 2026 19:41:05 +0100 Subject: [PATCH] unify overview page reports and create favorite enums to include services and programs (WIP) --- src/gui/pages/notifications_page.rs | 41 +- src/gui/pages/overview_page.rs | 441 +++++++----------- src/gui/pages/thumbnail_page.rs | 18 +- src/gui/sniffer.rs | 62 ++- src/gui/types/favorite.rs | 273 +++++++++++ src/gui/types/message.rs | 7 +- src/gui/types/mod.rs | 1 + src/networking/parse_packets.rs | 20 +- src/networking/types/data_info_fav.rs | 17 + src/networking/types/data_info_host.rs | 10 +- src/networking/types/info_traffic.rs | 5 +- src/networking/types/mod.rs | 1 + src/networking/types/program_lookup.rs | 21 +- src/notifications/notify_and_log.rs | 19 +- .../types/logged_notification.rs | 10 +- src/report/get_report_entries.rs | 74 +-- 16 files changed, 600 insertions(+), 420 deletions(-) create mode 100644 src/gui/types/favorite.rs create mode 100644 src/networking/types/data_info_fav.rs diff --git a/src/gui/pages/notifications_page.rs b/src/gui/pages/notifications_page.rs index 73a0e33b..64c3e2bf 100644 --- a/src/gui/pages/notifications_page.rs +++ b/src/gui/pages/notifications_page.rs @@ -1,9 +1,9 @@ -use crate::countries::country_utils::get_computer_tooltip; +use crate::countries::country_utils::{get_computer_tooltip, get_flag_tooltip}; use crate::countries::flags_pictures::FLAGS_HEIGHT_BIG; use crate::gui::components::header::get_button_settings; use crate::gui::components::tab::get_pages_tabs; use crate::gui::components::types::my_modal::MyModal; -use crate::gui::pages::overview_page::{get_bars, host_bar, simple_bar}; +use crate::gui::pages::overview_page::{get_bars, item_bar}; use crate::gui::pages::types::settings_page::SettingsPage; use crate::gui::styles::container::ContainerType; use crate::gui::styles::rule::RuleType; @@ -198,13 +198,15 @@ fn favorite_notification_log<'a>( data_repr: DataRepr, language: Language, ) -> Container<'a, Message, StyleType> { - let host_bar = host_bar( - logged_notification.host.to_entry_string(), - logged_notification.host.country, - &logged_notification.data_info_host, + let host = &logged_notification.host; + let data_info_host = logged_notification.data_info_host; + let icon = get_flag_tooltip(host.country, &data_info_host, language, false); + let host_bar = item_bar( + icon, + host.to_entry_string(), + &data_info_host.data_info_fav.data_info, data_repr, first_entry_data_info, - language, ); let content = Row::new() @@ -242,15 +244,15 @@ fn blacklisted_notification_log<'a>( data_repr: DataRepr, language: Language, ) -> Container<'a, Message, StyleType> { - let blacklisted_bar = host_bar( - logged_notification - .host - .to_blacklist_string(logged_notification.ip), - logged_notification.host.country, - &logged_notification.data_info_host, + let host = &logged_notification.host; + let data_info_host = logged_notification.data_info_host; + let icon = get_flag_tooltip(host.country, &data_info_host, language, false); + let blacklisted_bar = item_bar( + icon, + host.to_blacklist_string(logged_notification.ip), + &data_info_host.data_info_fav.data_info, data_repr, first_entry_data_info, - language, ); let content = Row::new() @@ -427,15 +429,16 @@ fn data_notification_extra<'a>( .first() .unwrap_or(&(Host::default(), DataInfoHost::default())) .1 + .data_info_fav .data_info; for (host, data_info_host) in &logged_notification.hosts { - let host_bar = host_bar( + let icon = get_flag_tooltip(host.country, &data_info_host, language, false); + let host_bar = item_bar( + icon, host.to_entry_string(), - host.country, - data_info_host, + &data_info_host.data_info_fav.data_info, logged_notification.data_repr, first_data_info, - language, ); hosts_col = hosts_col.push(host_bar); } @@ -447,7 +450,7 @@ fn data_notification_extra<'a>( .unwrap_or(&(Service::default(), DataInfo::default())) .1; for (service, data_info) in &logged_notification.services { - let service_bar = simple_bar( + let service_bar = item_bar( None::>, service.to_string(), data_info, diff --git a/src/gui/pages/overview_page.rs b/src/gui/pages/overview_page.rs index 16f7d034..b20d3e7a 100644 --- a/src/gui/pages/overview_page.rs +++ b/src/gui/pages/overview_page.rs @@ -4,8 +4,6 @@ //! and overall statistics about the traffic. use crate::chart::types::donut_chart::donut_chart; -use crate::countries::country_utils::get_flag_tooltip; -use crate::countries::types::country::Country; use crate::gui::components::ellipsized_text::EllipsizedText; use crate::gui::components::tab::get_pages_tabs; use crate::gui::pages::initial_page::get_addresses_row; @@ -16,32 +14,21 @@ use crate::gui::styles::rule::RuleType; use crate::gui::styles::scrollbar::ScrollbarType; use crate::gui::styles::style_constants::{FONT_SIZE_FOOTER, FONT_SIZE_TITLE, TOOLTIP_DELAY}; use crate::gui::styles::text::TextType; -use crate::gui::types::conf::Conf; +use crate::gui::types::favorite::Favorite; use crate::gui::types::filters::Filters; use crate::gui::types::message::Message; use crate::gui::types::settings::Settings; use crate::networking::types::capture_context::CaptureSource; use crate::networking::types::data_info::DataInfo; -use crate::networking::types::data_info_host::DataInfoHost; use crate::networking::types::data_representation::DataRepr; -use crate::networking::types::host::Host; -use crate::networking::types::program_lookup::ProgramLookup; -use crate::report::get_report_entries::{ - get_host_entries, get_program_entries, get_service_entries, -}; -use crate::report::types::search_parameters::SearchParameters; use crate::report::types::sort_type::SortType; use crate::translations::translations::{ active_filters_translation, incoming_translation, none_translation, outgoing_translation, traffic_rate_translation, }; use crate::translations::translations_2::{ - data_representation_translation, dropped_translation, host_translation, - only_top_30_items_translation, + data_representation_translation, dropped_translation, only_top_30_items_translation, }; -use crate::translations::translations_3::service_translation; -use crate::translations::translations_5::program_translation; -use crate::utils::types::icon::Icon; use crate::{Language, RunningPage, StyleType}; use iced::Length::Fill; use iced::alignment::{Horizontal, Vertical}; @@ -89,64 +76,55 @@ pub fn overview_page(sniffer: &Sniffer) -> Container<'_, Message, StyleType> { Container::new(Column::new().push(tab_and_body.push(body))).height(Length::Fill) } -fn row_report<'a>(sniffer: &Sniffer) -> Row<'a, Message, StyleType> { - let col_host = col_host(sniffer); - let col_service = col_service(sniffer); - let container_program = sniffer.program_lookup.as_ref().map(|program_lookup| { - Container::new(col_program(&sniffer.conf, program_lookup)) - .width(Length::FillPortion(1)) - .height(Length::Fill) - .padding(Padding::new(10.0).top(0).bottom(5)) - .class(ContainerType::BorderedRound) - }); +fn row_report(sniffer: &Sniffer) -> Row { + let col_host = col_favorite_item(sniffer, Favorite::Host); + let col_service = col_favorite_item(sniffer, Favorite::Service); + let col_program = col_favorite_item(sniffer, Favorite::Program); Row::new() .spacing(10) - .push( - Container::new(col_host) - .width(Length::FillPortion(2)) - .height(Length::Fill) - .padding(Padding::new(10.0).top(0).bottom(5)) - .class(ContainerType::BorderedRound), - ) - .push( - Container::new(col_service) - .width(Length::FillPortion(1)) - .height(Length::Fill) - .padding(Padding::new(10.0).top(0).bottom(5)) - .class(ContainerType::BorderedRound), - ) - .push(container_program) + .push(col_host) + .push(col_service) + .push(col_program) } -fn col_host<'a>(sniffer: &Sniffer) -> Column<'a, Message, StyleType> { +fn col_favorite_item( + sniffer: &Sniffer, + favorite: Favorite, +) -> impl Into> { let Settings { language, .. } = sniffer.conf.settings; let data_repr = sniffer.conf.data_repr; + let program_lookup = sniffer.program_lookup.as_ref(); - let mut scroll_host = Column::new() + if program_lookup.is_none() && favorite == Favorite::Program { + return None::>; + } + + let mut scroll_item = Column::new() .padding(Padding::ZERO.right(11.0)) .align_x(Alignment::Center); - let entries = get_host_entries( + let entries = favorite.get_entries( &sniffer.info_traffic, + program_lookup, data_repr, sniffer.conf.host_sort_type, ); let first_entry_data_info = entries .iter() - .map(|(_, d)| d.data_info) + .map(|fi| fi.data_info()) .max_by(|d1, d2| d1.compare(d2, SortType::Ascending, data_repr)) .unwrap_or_default(); - for (host, data_info_host) in &entries { - let star_button = get_star_button(data_info_host.is_favorite, host.clone()); + for fi in &entries { + let star_button = fi.star_button(); - let host_bar = host_bar( - host.to_entry_string(), - host.country, - data_info_host, + let icon = fi.icon(language, false, program_lookup); + let host_bar = item_bar( + icon, + fi.to_entry_string(), + &fi.data_info(), data_repr, first_entry_data_info, - language, ); let content = Row::new() @@ -155,213 +133,184 @@ fn col_host<'a>(sniffer: &Sniffer) -> Column<'a, Message, StyleType> { .push(star_button) .push(host_bar); - scroll_host = scroll_host.push( + scroll_item = scroll_item.push( button(content) .padding(Padding::new(5.0).right(10)) - .on_press(Message::Search(SearchParameters::new_host_search(host))) + .on_press(Message::Search(fi.new_entry_search())) .class(ButtonType::Neutral), ); } if entries.len() >= 30 { - scroll_host = scroll_host + scroll_item = scroll_item .push(Space::new().height(25)) .push(Text::new(only_top_30_items_translation(language)).align_x(Alignment::Center)); } - Column::new() + let col = Column::new() .push( Row::new() .height(45) .align_y(Alignment::Center) .push( - Text::new(host_translation(language)) + Text::new(favorite.title(language)) .class(TextType::Title) .size(FONT_SIZE_TITLE), ) .push(Space::new().width(Length::Fill)) - .push(sort_arrows( - sniffer.conf.host_sort_type, - Message::HostSortSelection, - )), + .push(favorite.sort_arrows(&sniffer.conf)), ) .push( Scrollable::with_direction( - scroll_host, + scroll_item, Direction::Vertical(ScrollbarType::properties()), ) .width(Length::Fill), - ) -} - -fn col_service<'a>(sniffer: &Sniffer) -> Column<'a, Message, StyleType> { - let Settings { language, .. } = sniffer.conf.settings; - let data_repr = sniffer.conf.data_repr; - - let mut scroll_service = Column::new() - .padding(Padding::ZERO.right(11.0)) - .align_x(Alignment::Center); - let entries = get_service_entries( - &sniffer.info_traffic, - data_repr, - sniffer.conf.service_sort_type, - ); - let first_entry_data_info = entries - .iter() - .map(|&(_, d)| d) - .max_by(|d1, d2| d1.compare(d2, SortType::Ascending, data_repr)) - .unwrap_or_default(); - - for (service, data_info) in &entries { - let content = simple_bar( - None::>, - service.to_string(), - data_info, - data_repr, - first_entry_data_info, ); - scroll_service = scroll_service.push( - button(content) - .padding(Padding::new(5.0).right(15).left(10)) - .on_press(Message::Search(SearchParameters::new_service_search( - service, - ))) - .class(ButtonType::Neutral), - ); - } - - if entries.len() >= 30 { - scroll_service = scroll_service - .push(Space::new().height(25)) - .push(Text::new(only_top_30_items_translation(language)).align_x(Alignment::Center)); - } - - Column::new() - .push( - Row::new() - .height(45) - .align_y(Alignment::Center) - .push( - Text::new(service_translation(language)) - .class(TextType::Title) - .size(FONT_SIZE_TITLE), - ) - .push(Space::new().width(Length::Fill)) - .push(sort_arrows( - sniffer.conf.service_sort_type, - Message::ServiceSortSelection, - )), - ) - .push( - Scrollable::with_direction( - scroll_service, - Direction::Vertical(ScrollbarType::properties()), - ) - .width(Length::Fill), - ) + Some( + Container::new(col) + .width(favorite.fill_portion()) + .height(Length::Fill) + .padding(Padding::new(10.0).top(0).bottom(5)) + .class(ContainerType::BorderedRound) + .into(), + ) } -fn col_program<'a>(conf: &Conf, program_lookup: &ProgramLookup) -> Column<'a, Message, StyleType> { - let Settings { language, .. } = conf.settings; - let data_repr = conf.data_repr; +// fn col_service<'a>(sniffer: &Sniffer) -> Column<'a, Message, StyleType> { +// let Settings { language, .. } = sniffer.conf.settings; +// let data_repr = sniffer.conf.data_repr; +// +// let mut scroll_service = Column::new() +// .padding(Padding::ZERO.right(11.0)) +// .align_x(Alignment::Center); +// let entries = get_service_entries( +// &sniffer.info_traffic, +// data_repr, +// sniffer.conf.service_sort_type, +// ); +// let first_entry_data_info = entries +// .iter() +// .map(|&(_, d)| d) +// .max_by(|d1, d2| d1.compare(d2, SortType::Ascending, data_repr)) +// .unwrap_or_default(); +// +// for (service, data_info) in &entries { +// let content = item_bar( +// None::>, +// service.to_string(), +// data_info, +// data_repr, +// first_entry_data_info, +// ); +// +// scroll_service = scroll_service.push( +// button(content) +// .padding(Padding::new(5.0).right(15).left(10)) +// .on_press(Message::Search(SearchParameters::new_service_search( +// service, +// ))) +// .class(ButtonType::Neutral), +// ); +// } +// +// if entries.len() >= 30 { +// scroll_service = scroll_service +// .push(Space::new().height(25)) +// .push(Text::new(only_top_30_items_translation(language)).align_x(Alignment::Center)); +// } +// +// Column::new() +// .push( +// Row::new() +// .height(45) +// .align_y(Alignment::Center) +// .push( +// Text::new(service_translation(language)) +// .class(TextType::Title) +// .size(FONT_SIZE_TITLE), +// ) +// .push(Space::new().width(Length::Fill)) +// .push(sort_arrows( +// sniffer.conf.service_sort_type, +// Message::ServiceSortSelection, +// )), +// ) +// .push( +// Scrollable::with_direction( +// scroll_service, +// Direction::Vertical(ScrollbarType::properties()), +// ) +// .width(Length::Fill), +// ) +// } - let mut scroll_program = Column::new() - .padding(Padding::ZERO.right(11.0)) - .align_x(Alignment::Center); - let entries = get_program_entries(program_lookup, data_repr, conf.program_sort_type); - let first_entry_data_info = entries - .iter() - .map(|&(_, d)| d) - .max_by(|d1, d2| d1.compare(d2, SortType::Ascending, data_repr)) - .unwrap_or_default(); +// fn col_program<'a>(conf: &Conf, program_lookup: &ProgramLookup) -> Column<'a, Message, StyleType> { +// let Settings { language, .. } = conf.settings; +// let data_repr = conf.data_repr; +// +// let mut scroll_program = Column::new() +// .padding(Padding::ZERO.right(11.0)) +// .align_x(Alignment::Center); +// let entries = get_program_entries(program_lookup, data_repr, conf.program_sort_type); +// let first_entry_data_info = entries +// .iter() +// .map(|&(_, d)| d) +// .max_by(|d1, d2| d1.compare(d2, SortType::Ascending, data_repr)) +// .unwrap_or_default(); +// +// for (program, data_info) in &entries { +// let content = item_bar( +// program_lookup.picon_tooltip(program.icon_key(), program.path()), +// program.to_string(), +// data_info, +// data_repr, +// first_entry_data_info, +// ); +// +// scroll_program = scroll_program.push( +// button(content) +// .padding(Padding::new(5.0).right(15).left(10)) +// .on_press(Message::Search(SearchParameters::new_program_search( +// program, +// ))) +// .class(ButtonType::Neutral), +// ); +// } +// +// if entries.len() >= 30 { +// scroll_program = scroll_program +// .push(Space::new().height(25)) +// .push(Text::new(only_top_30_items_translation(language)).align_x(Alignment::Center)); +// } +// +// Column::new() +// .push( +// Row::new() +// .height(45) +// .align_y(Alignment::Center) +// .push( +// Text::new(program_translation(language)) +// .class(TextType::Title) +// .size(FONT_SIZE_TITLE), +// ) +// .push(Space::new().width(Length::Fill)) +// .push(sort_arrows( +// conf.program_sort_type, +// Message::ProgramSortSelection, +// )), +// ) +// .push( +// Scrollable::with_direction( +// scroll_program, +// Direction::Vertical(ScrollbarType::properties()), +// ) +// .width(Length::Fill), +// ) +// } - for (program, data_info) in &entries { - let content = simple_bar( - program_lookup.picon_tooltip(program.icon_key(), program.path()), - program.to_string(), - data_info, - data_repr, - first_entry_data_info, - ); - - scroll_program = scroll_program.push( - button(content) - .padding(Padding::new(5.0).right(15).left(10)) - .on_press(Message::Search(SearchParameters::new_program_search( - program, - ))) - .class(ButtonType::Neutral), - ); - } - - if entries.len() >= 30 { - scroll_program = scroll_program - .push(Space::new().height(25)) - .push(Text::new(only_top_30_items_translation(language)).align_x(Alignment::Center)); - } - - Column::new() - .push( - Row::new() - .height(45) - .align_y(Alignment::Center) - .push( - Text::new(program_translation(language)) - .class(TextType::Title) - .size(FONT_SIZE_TITLE), - ) - .push(Space::new().width(Length::Fill)) - .push(sort_arrows( - conf.program_sort_type, - Message::ProgramSortSelection, - )), - ) - .push( - Scrollable::with_direction( - scroll_program, - Direction::Vertical(ScrollbarType::properties()), - ) - .width(Length::Fill), - ) -} - -pub fn host_bar<'a>( - item: String, - country: Country, - data_info_host: &DataInfoHost, - data_repr: DataRepr, - first_entry_data_info: DataInfo, - language: Language, -) -> Row<'a, Message, StyleType> { - Row::new() - .height(32) - .align_y(Alignment::Center) - .spacing(5) - .push(get_flag_tooltip(country, data_info_host, language, false)) - .push( - Column::new() - .spacing(2) - .push( - Row::new() - .push( - EllipsizedText::new(item) - .wrapping(Wrapping::Glyph) - .width(Length::Fill), - ) - .push(Text::new(data_repr.formatted_string( - data_info_host.data_info.tot_data(data_repr), - ))), - ) - .push(get_bars( - data_repr, - &first_entry_data_info, - &data_info_host.data_info, - )), - ) -} - -pub fn simple_bar<'a>( +pub fn item_bar<'a>( icon: impl Into>, item: String, data_info: &DataInfo, @@ -387,7 +336,7 @@ pub fn simple_bar<'a>( data_repr.formatted_string(data_info.tot_data(data_repr)), )), ) - .push(get_bars(data_repr, &first_entry_data_info, data_info)), + .push(get_bars(data_repr, &first_entry_data_info, &data_info)), ) } @@ -693,26 +642,6 @@ pub fn get_bars<'a>( }) } -fn get_star_button<'a>(is_favorite: bool, host: Host) -> Button<'a, Message, StyleType> { - let (icon, class) = if is_favorite { - (Icon::StarFull, ButtonType::Starred) - } else { - (Icon::StarEmpty, ButtonType::NotStarred) - }; - - button( - icon.to_text() - .size(16) - .align_x(Alignment::Center) - .align_y(Alignment::Center), - ) - .padding(0) - .height(25) - .width(25) - .class(class) - .on_press(Message::AddOrRemoveFavorite(host, !is_favorite)) -} - fn get_info_tooltip(tooltip_content: Element) -> Tooltip { Tooltip::new( Container::new( @@ -732,24 +661,6 @@ fn get_info_tooltip(tooltip_content: Element) -> Tooltip( - active_sort_type: SortType, - message: fn(SortType) -> Message, -) -> Container<'a, Message, StyleType> { - Container::new( - button( - active_sort_type - .icon() - .align_x(Alignment::Center) - .align_y(Alignment::Center), - ) - .class(active_sort_type.button_type()) - .on_press(message(active_sort_type.next_sort())), - ) - .width(50.0) - .align_x(Alignment::Center) -} - #[cfg(test)] mod tests { use crate::gui::pages::overview_page::{MIN_BARS_LENGTH, get_bars_length}; diff --git a/src/gui/pages/thumbnail_page.rs b/src/gui/pages/thumbnail_page.rs index 3ff28859..e1c4ebf9 100644 --- a/src/gui/pages/thumbnail_page.rs +++ b/src/gui/pages/thumbnail_page.rs @@ -9,11 +9,11 @@ use crate::gui::sniffer::Sniffer; use crate::gui::styles::rule::RuleType; use crate::gui::styles::style_constants::FONT_SIZE_FOOTER; use crate::gui::styles::types::style_type::StyleType; +use crate::gui::types::favorite::{Favorite, FavoriteItem}; use crate::gui::types::message::Message; use crate::networking::types::data_representation::DataRepr; use crate::networking::types::host::ThumbnailHost; use crate::networking::types::info_traffic::InfoTraffic; -use crate::report::get_report_entries::{get_host_entries, get_service_entries}; use crate::report::types::sort_type::SortType; use crate::translations::types::language::Language; use crate::utils::formatted_strings::clip_text; @@ -92,10 +92,14 @@ fn host_col<'a>( .padding([0, 5]) .spacing(3) .width(Length::FillPortion(2)); - let hosts = get_host_entries(info_traffic, data_repr, sort_type); + let hosts = Favorite::Host.get_entries(info_traffic, None, data_repr, sort_type); let mut thumbnail_hosts = Vec::new(); - for (host, data_info_host) in &hosts { + for fi in &hosts { + let FavoriteItem::Host((host, data_info_host)) = fi else { + continue; + }; + let thumbnail_host = ThumbnailHost::from_host(host, MAX_CHARS_HOST); let country = thumbnail_host.country; let text = thumbnail_host.text.clone(); @@ -128,9 +132,13 @@ fn service_col<'a>( sort_type: SortType, ) -> Column<'a, Message, StyleType> { let mut service_col = Column::new().padding([0, 5]).spacing(3).width(Length::Fill); - let services = get_service_entries(info_traffic, data_repr, sort_type); + let services = Favorite::Service.get_entries(info_traffic, None, data_repr, sort_type); let n_entry = min(services.len(), MAX_ENTRIES); - for (service, _) in services.get(..n_entry).unwrap_or_default() { + for fi in services.get(..n_entry).unwrap_or_default() { + let FavoriteItem::Service((service, _)) = fi else { + continue; + }; + service_col = service_col.push( Text::new(clip_text(&service.to_string(), MAX_CHARS_SERVICE)).size(FONT_SIZE_FOOTER), ); diff --git a/src/gui/sniffer.rs b/src/gui/sniffer.rs index 2ad9d88f..9f9b675a 100644 --- a/src/gui/sniffer.rs +++ b/src/gui/sniffer.rs @@ -22,6 +22,7 @@ use crate::gui::styles::types::custom_palette::CustomPalette; use crate::gui::styles::types::gradient_type::GradientType; use crate::gui::styles::types::palette::Palette; use crate::gui::types::conf::Conf; +use crate::gui::types::favorite::FavoriteKey; use crate::gui::types::message::Message; use crate::gui::types::settings::Settings; use crate::gui::types::timing_events::TimingEvents; @@ -96,8 +97,8 @@ pub struct Sniffer { pub info_traffic: InfoTraffic, /// Map of the resolved addresses with their full rDNS value and the corresponding host pub addresses_resolved: HashMap, - /// Collection of the favorite hosts - pub favorite_hosts: HashSet, + /// Collection of the favorite hosts, services and programs + pub favorites: HashSet, /// Log of the displayed notifications, with the total number of notifications for this capture pub logged_notifications: LoggedNotifications, /// Reports if a newer release of the software is available on GitHub @@ -167,7 +168,7 @@ impl Sniffer { preview_captures_rx: None, info_traffic: InfoTraffic::default(), addresses_resolved: HashMap::new(), - favorite_hosts: HashSet::new(), + favorites: HashSet::new(), logged_notifications: LoggedNotifications::default(), newer_release_available: None, capture_source, @@ -302,7 +303,7 @@ impl Sniffer { Message::Reset => return self.reset(), Message::Style(style) => self.style(style), Message::LoadStyle(path) => self.load_style(path), - Message::AddOrRemoveFavorite(host, add) => self.add_or_remove_favorite(&host, add), + Message::AddOrRemoveFavorite(fav, add) => self.add_or_remove_favorite(&fav, add), Message::ShowModal(modal) => self.show_modal(modal), Message::HideModal => self.hide_modal(), Message::OpenSettings(settings_page) => self.open_settings(settings_page), @@ -905,7 +906,7 @@ impl Sniffer { &mut self.logged_notifications, &self.conf.settings.notifications, &msg, - &self.favorite_hosts, + &self.favorites, &self.capture_source, &self.addresses_resolved, ); @@ -1050,7 +1051,7 @@ impl Sniffer { self.current_capture_rx = (self.current_capture_rx.0 + 1, None); self.info_traffic = InfoTraffic::default(); self.addresses_resolved = HashMap::new(); - self.favorite_hosts = HashSet::new(); + self.favorites = HashSet::new(); self.logged_notifications = LoggedNotifications::default(); self.pcap_error = None; self.traffic_chart = TrafficChart::new(style, language, self.conf.data_repr); @@ -1101,16 +1102,31 @@ impl Sniffer { } } - fn add_or_remove_favorite(&mut self, host: &Host, add: bool) { - let info_traffic = &mut self.info_traffic; + fn add_or_remove_favorite(&mut self, fav: &FavoriteKey, add: bool) { if add { - self.favorite_hosts.insert(host.clone()); + self.favorites.insert(fav.clone()); } else { - self.favorite_hosts.remove(host); - } - if let Some(host_info) = info_traffic.hosts.get_mut(host) { - host_info.is_favorite = add; + self.favorites.remove(fav); } + + match fav { + FavoriteKey::Host(host) => { + if let Some(host_info) = self.info_traffic.hosts.get_mut(host) { + host_info.data_info_fav.is_favorite = add; + } + } + FavoriteKey::Service(service) => { + if let Some(service_info) = self.info_traffic.services.get_mut(service) { + service_info.is_favorite = add; + } + } + FavoriteKey::Program(program) => { + let Some(program_lookup) = &mut self.program_lookup else { + return; + }; + program_lookup.edit_fav(program, add); + } + }; } fn close_settings(&mut self) { @@ -1618,7 +1634,7 @@ mod tests { }, false, )); - assert_eq!(sniffer.favorite_hosts, HashSet::new()); + assert_eq!(sniffer.favorites, HashSet::new()); // remove 2 sniffer.update(Message::AddOrRemoveFavorite( Host { @@ -1628,7 +1644,7 @@ mod tests { }, false, )); - assert_eq!(sniffer.favorite_hosts, HashSet::new()); + assert_eq!(sniffer.favorites, HashSet::new()); // add 2 sniffer.update(Message::AddOrRemoveFavorite( Host { @@ -1639,7 +1655,7 @@ mod tests { true, )); assert_eq!( - sniffer.favorite_hosts, + sniffer.favorites, HashSet::from([Host { domain: "2.2".to_string(), asn: Default::default(), @@ -1656,7 +1672,7 @@ mod tests { false, )); assert_eq!( - sniffer.favorite_hosts, + sniffer.favorites, HashSet::from([Host { domain: "2.2".to_string(), asn: Default::default(), @@ -1673,7 +1689,7 @@ mod tests { true, )); assert_eq!( - sniffer.favorite_hosts, + sniffer.favorites, HashSet::from([Host { domain: "2.2".to_string(), asn: Default::default(), @@ -1690,7 +1706,7 @@ mod tests { true, )); assert_eq!( - sniffer.favorite_hosts, + sniffer.favorites, HashSet::from([ Host { domain: "1.1".to_string(), @@ -1714,7 +1730,7 @@ mod tests { true, )); assert_eq!( - sniffer.favorite_hosts, + sniffer.favorites, HashSet::from([ Host { domain: "1.1".to_string(), @@ -1743,7 +1759,7 @@ mod tests { false, )); assert_eq!( - sniffer.favorite_hosts, + sniffer.favorites, HashSet::from([ Host { domain: "1.1".to_string(), @@ -1767,7 +1783,7 @@ mod tests { false, )); assert_eq!( - sniffer.favorite_hosts, + sniffer.favorites, HashSet::from([Host { domain: "1.1".to_string(), asn: Default::default(), @@ -1783,7 +1799,7 @@ mod tests { }, false, )); - assert_eq!(sniffer.favorite_hosts, HashSet::new()); + assert_eq!(sniffer.favorites, HashSet::new()); } #[test] diff --git a/src/gui/types/favorite.rs b/src/gui/types/favorite.rs new file mode 100644 index 00000000..2b3ca679 --- /dev/null +++ b/src/gui/types/favorite.rs @@ -0,0 +1,273 @@ +use crate::countries::country_utils::get_flag_tooltip; +use crate::gui::styles::button::ButtonType; +use crate::gui::styles::types::style_type::StyleType; +use crate::gui::types::conf::Conf; +use crate::gui::types::message::Message; +use crate::networking::types::data_info::DataInfo; +use crate::networking::types::data_info_fav::DataInfoFav; +use crate::networking::types::data_info_host::DataInfoHost; +use crate::networking::types::data_representation::DataRepr; +use crate::networking::types::host::Host; +use crate::networking::types::info_traffic::InfoTraffic; +use crate::networking::types::program::Program; +use crate::networking::types::program_lookup::ProgramLookup; +use crate::networking::types::service::Service; +use crate::report::types::search_parameters::SearchParameters; +use crate::report::types::sort_type::SortType; +use crate::translations::translations_2::host_translation; +use crate::translations::translations_3::service_translation; +use crate::translations::translations_5::program_translation; +use crate::translations::types::language::Language; +use crate::utils::types::icon::Icon; +use iced::widget::{Button, Container, Tooltip, button}; +use iced::{Alignment, Element}; +use std::cmp::min; + +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub enum Favorite { + Host, + Service, + Program, +} + +impl Favorite { + pub fn get_entries( + self, + info_traffic: &InfoTraffic, + program_lookup: Option<&ProgramLookup>, + data_repr: DataRepr, + sort_type: SortType, + ) -> Vec { + match self { + Favorite::Host => get_host_entries(info_traffic, data_repr, sort_type), + Favorite::Service => get_service_entries(info_traffic, data_repr, sort_type), + Favorite::Program => get_program_entries(program_lookup, data_repr, sort_type), + } + } + + pub fn fill_portion(self) -> iced::Length { + match self { + Favorite::Host => iced::Length::FillPortion(2), + Favorite::Service | Favorite::Program => iced::Length::FillPortion(1), + } + } + + pub fn title(self, language: Language) -> &'static str { + match self { + Favorite::Host => host_translation(language), + Favorite::Service => service_translation(language), + Favorite::Program => program_translation(language), + } + } + + pub fn sort_arrows<'a>(self, conf: &Conf) -> Container<'a, Message, StyleType> { + let active_sort_type = match self { + Favorite::Host => conf.host_sort_type, + Favorite::Service => conf.service_sort_type, + Favorite::Program => conf.program_sort_type, + }; + + let message = match self { + Favorite::Host => Message::HostSortSelection, + Favorite::Service => Message::ServiceSortSelection, + Favorite::Program => Message::ProgramSortSelection, + }; + + Container::new( + button( + active_sort_type + .icon() + .align_x(Alignment::Center) + .align_y(Alignment::Center), + ) + .class(active_sort_type.button_type()) + .on_press(message(active_sort_type.next_sort())), + ) + .width(50.0) + .align_x(Alignment::Center) + } +} + +#[derive(Clone)] +pub enum FavoriteItem { + Host((Host, DataInfoHost)), + Service((Service, DataInfoFav)), + Program((Program, DataInfoFav)), +} + +impl FavoriteItem { + pub fn data_info(&self) -> DataInfo { + match self { + FavoriteItem::Host((_, data_info_host)) => data_info_host.data_info_fav.data_info, + FavoriteItem::Service((_, data_info_fav)) => data_info_fav.data_info, + FavoriteItem::Program((_, data_info_fav)) => data_info_fav.data_info, + } + } + + fn is_favorite(&self) -> bool { + match self { + FavoriteItem::Host((_, data_info_host)) => data_info_host.data_info_fav.is_favorite, + FavoriteItem::Service((_, data_info_fav)) => data_info_fav.is_favorite, + FavoriteItem::Program((_, data_info_fav)) => data_info_fav.is_favorite, + } + } + + pub fn star_button<'a>(&self) -> Button<'a, Message, StyleType> { + let is_favorite = self.is_favorite(); + + let (icon, class) = if is_favorite { + (Icon::StarFull, ButtonType::Starred) + } else { + (Icon::StarEmpty, ButtonType::NotStarred) + }; + + button( + icon.to_text() + .size(16) + .align_x(Alignment::Center) + .align_y(Alignment::Center), + ) + .padding(0) + .height(25) + .width(25) + .class(class) + .on_press(Message::AddOrRemoveFavorite( + self.clone().into(), + !is_favorite, + )) + } + + pub fn icon<'a>( + &self, + language: Language, + thumbnail: bool, + program_lookup: Option<&'a ProgramLookup>, + ) -> impl Into> { + match self { + FavoriteItem::Host((host, data_info_host)) => Some(get_flag_tooltip( + host.country, + data_info_host, + language, + thumbnail, + )), + FavoriteItem::Service(_) => None::>, + FavoriteItem::Program((program, _)) => { + let Some(program_lookup) = program_lookup else { + return None::>; + }; + Some(program_lookup.picon_tooltip(program.icon_key(), program.path())) + } + } + } + + pub fn to_entry_string(&self) -> String { + match self { + FavoriteItem::Host((host, _)) => host.to_entry_string(), + FavoriteItem::Service((service, _)) => service.to_string(), + FavoriteItem::Program((program, _)) => program.to_string(), + } + } + + pub fn new_entry_search(&self) -> SearchParameters { + match self { + FavoriteItem::Host((host, _)) => SearchParameters::new_host_search(host), + FavoriteItem::Service((service, _)) => SearchParameters::new_service_search(service), + FavoriteItem::Program((program, _)) => SearchParameters::new_program_search(program), + } + } +} + +#[derive(Clone, Hash, Eq, PartialEq, Debug)] +pub enum FavoriteKey { + Host(Host), + Service(Service), + Program(Program), +} + +impl From for FavoriteKey { + fn from(item: FavoriteItem) -> Self { + match item { + FavoriteItem::Host((h, _)) => FavoriteKey::Host(h), + FavoriteItem::Service((s, _)) => FavoriteKey::Service(s), + FavoriteItem::Program((p, _)) => FavoriteKey::Program(p), + } + } +} + +// get entries helpers ----------------------------------------------------------------------------- + +fn get_host_entries( + info_traffic: &InfoTraffic, + data_repr: DataRepr, + sort_type: SortType, +) -> Vec { + let mut sorted_vec: Vec<(&Host, &DataInfoHost)> = info_traffic.hosts.iter().collect(); + + sorted_vec.sort_by(|&(_, a), &(_, b)| { + a.data_info_fav + .data_info + .compare(&b.data_info_fav.data_info, sort_type, data_repr) + }); + + let n_entry = min(sorted_vec.len(), 30); + sorted_vec[0..n_entry] + .iter() + .map(|&(host, data_info_host)| { + FavoriteItem::Host((host.to_owned(), data_info_host.to_owned())) + }) + .collect() +} + +fn get_service_entries( + info_traffic: &InfoTraffic, + data_repr: DataRepr, + sort_type: SortType, +) -> Vec { + let mut sorted_vec: Vec<(&Service, &DataInfoFav)> = info_traffic + .services + .iter() + .filter(|(service, _)| service != &&Service::NotApplicable) + .collect(); + + sorted_vec.sort_by(|&(_, a), &(_, b)| a.data_info.compare(&b.data_info, sort_type, data_repr)); + + let n_entry = min(sorted_vec.len(), 30); + sorted_vec[0..n_entry] + .iter() + .map(|&(service, data_info_fav)| FavoriteItem::Service((*service, *data_info_fav))) + .collect() +} + +fn get_program_entries( + program_lookup: Option<&ProgramLookup>, + data_repr: DataRepr, + sort_type: SortType, +) -> Vec { + let Some(program_lookup) = program_lookup else { + return Vec::new(); + }; + + let mut sorted_vec: Vec<(&Program, &DataInfoFav)> = program_lookup + .programs() + .iter() + // Unknown may be inserted, and then all of its data could be reassigned to known programs + .filter(|(_, d)| d.data_info.tot_data(DataRepr::Packets) > 0) + .collect(); + + sorted_vec.sort_by(|&(p1, a), &(p2, b)| { + if sort_type == SortType::Neutral && a.data_info.is_within_same_second(&b.data_info) { + if p1.is_unknown() { + return std::cmp::Ordering::Greater; + } else if p2.is_unknown() { + return std::cmp::Ordering::Less; + } + } + a.data_info.compare(&b.data_info, sort_type, data_repr) + }); + + let n_entry = min(sorted_vec.len(), 30); + sorted_vec[0..n_entry] + .iter() + .map(|&(program, data_info)| FavoriteItem::Program((program.to_owned(), *data_info))) + .collect() +} diff --git a/src/gui/types/message.rs b/src/gui/types/message.rs index ce3efa59..70496d4c 100644 --- a/src/gui/types/message.rs +++ b/src/gui/types/message.rs @@ -2,10 +2,11 @@ use crate::gui::components::types::my_modal::MyModal; use crate::gui::pages::types::running_page::RunningPage; use crate::gui::pages::types::settings_page::SettingsPage; use crate::gui::styles::types::gradient_type::GradientType; +use crate::gui::types::favorite::FavoriteKey; use crate::networking::traffic_preview::TrafficPreview; use crate::networking::types::capture_context::CaptureSourcePicklist; use crate::networking::types::data_representation::DataRepr; -use crate::networking::types::host::{Host, HostMessage}; +use crate::networking::types::host::HostMessage; use crate::networking::types::info_traffic::InfoTraffic; use crate::networking::types::ip_blacklist::IpBlacklist; use crate::notifications::types::notifications::Notification; @@ -44,8 +45,8 @@ pub enum Message { ServiceSortSelection(SortType), /// Select program sort type to be displayed (overview page) ProgramSortSelection(SortType), - /// Adds or removes the given host into/from the favorites - AddOrRemoveFavorite(Host, bool), + /// Adds or removes the given item into/from the favorites + AddOrRemoveFavorite(FavoriteKey, bool), /// Open the supplied web page OpenWebPage(WebPage), /// Start sniffing packets diff --git a/src/gui/types/mod.rs b/src/gui/types/mod.rs index f96fc44b..743e119d 100644 --- a/src/gui/types/mod.rs +++ b/src/gui/types/mod.rs @@ -1,6 +1,7 @@ pub mod conf; pub mod config_window; pub mod export_pcap; +pub mod favorite; pub mod filters; pub mod message; pub mod settings; diff --git a/src/networking/parse_packets.rs b/src/networking/parse_packets.rs index 15901f2a..f10a407a 100644 --- a/src/networking/parse_packets.rs +++ b/src/networking/parse_packets.rs @@ -14,6 +14,7 @@ use crate::networking::types::arp_type::ArpType; use crate::networking::types::bogon::is_bogon; use crate::networking::types::capture_context::{CaptureContext, CaptureSource, CaptureType}; use crate::networking::types::data_info::DataInfo; +use crate::networking::types::data_info_fav::DataInfoFav; use crate::networking::types::data_info_host::DataInfoHost; use crate::networking::types::host::{Host, HostMessage}; use crate::networking::types::icmp_type::IcmpType; @@ -243,6 +244,7 @@ pub fn parse_packets( .entry(host) .and_modify(|data_info_host| { data_info_host + .data_info_fav .data_info .add_packet(exchanged_bytes, traffic_direction); }) @@ -260,11 +262,11 @@ pub fn parse_packets( ); let is_bogon = is_bogon(&address_to_lookup); DataInfoHost { - data_info: DataInfo::new_with_first_packet( + data_info_fav: DataInfo::new_with_first_packet( exchanged_bytes, traffic_direction, - ), - is_favorite: false, + ) + .into(), is_loopback, is_local, is_bogon, @@ -278,11 +280,14 @@ pub fn parse_packets( info_traffic_msg .services .entry(service) - .and_modify(|data_info| { - data_info.add_packet(exchanged_bytes, traffic_direction); + .and_modify(|data_info_fav| { + data_info_fav + .data_info + .add_packet(exchanged_bytes, traffic_direction); }) .or_insert_with(|| { DataInfo::new_with_first_packet(exchanged_bytes, traffic_direction) + .into() }); // update dropped packets number @@ -399,8 +404,7 @@ fn reverse_dns_lookups( }; let data_info_host = DataInfoHost { - data_info: DataInfo::default(), - is_favorite: false, + data_info_fav: DataInfoFav::default(), is_local, is_bogon, is_loopback, @@ -455,7 +459,7 @@ impl AddressesResolutionState { .remove(&address_to_lookup) .unwrap_or_default(); // overwrite the host message with the collected data - host_msg.data_info_host.data_info = other_data; + host_msg.data_info_host.data_info_fav.data_info = other_data; // insert the newly resolved host in the collection of resolved addresses self.addresses_resolved .insert(address_to_lookup, host_msg.host.clone()); diff --git a/src/networking/types/data_info_fav.rs b/src/networking/types/data_info_fav.rs new file mode 100644 index 00000000..64dd468c --- /dev/null +++ b/src/networking/types/data_info_fav.rs @@ -0,0 +1,17 @@ +use crate::networking::types::data_info::DataInfo; + +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Default)] +pub struct DataInfoFav { + pub data_info: DataInfo, + /// Determine if this item is one of the favorites + pub is_favorite: bool, +} + +impl From for DataInfoFav { + fn from(data_info: DataInfo) -> Self { + Self { + data_info, + is_favorite: false, + } + } +} diff --git a/src/networking/types/data_info_host.rs b/src/networking/types/data_info_host.rs index 4b63d8f9..d04001ae 100644 --- a/src/networking/types/data_info_host.rs +++ b/src/networking/types/data_info_host.rs @@ -1,15 +1,13 @@ //! Module defining the `DataInfoHost` struct related to hosts. -use crate::networking::types::data_info::DataInfo; +use crate::networking::types::data_info_fav::DataInfoFav; use crate::networking::types::traffic_type::TrafficType; /// Host-related information. #[derive(Clone, Copy, Default, Debug, Eq, PartialEq, Hash)] pub struct DataInfoHost { /// Incoming and outgoing packets and bytes - pub data_info: DataInfo, - /// Determine if this host is one of the favorites - pub is_favorite: bool, + pub data_info_fav: DataInfoFav, /// Determine if the connection is loopback (the "remote" is loopback) pub is_loopback: bool, /// Determine if the connection with this host is local @@ -22,7 +20,9 @@ pub struct DataInfoHost { impl DataInfoHost { pub fn refresh(&mut self, other: &Self) { - self.data_info.refresh(other.data_info); + self.data_info_fav + .data_info + .refresh(other.data_info_fav.data_info); self.is_loopback = other.is_loopback; self.is_local = other.is_local; self.is_bogon = other.is_bogon; diff --git a/src/networking/types/info_traffic.rs b/src/networking/types/info_traffic.rs index bcd4e490..ec3c88cb 100644 --- a/src/networking/types/info_traffic.rs +++ b/src/networking/types/info_traffic.rs @@ -2,6 +2,7 @@ use crate::Service; use crate::networking::manage_packets::get_local_port; use crate::networking::types::address_port_pair::AddressPortPair; use crate::networking::types::data_info::DataInfo; +use crate::networking::types::data_info_fav::DataInfoFav; use crate::networking::types::data_info_host::DataInfoHost; use crate::networking::types::data_representation::DataRepr; use crate::networking::types::host::Host; @@ -23,7 +24,7 @@ pub struct InfoTraffic { /// Map of the traffic pub map: HashMap, /// Map of the upper layer services with their data info - pub services: HashMap, + pub services: HashMap, /// Map of the hosts with their data info pub hosts: HashMap, } @@ -72,7 +73,7 @@ impl InfoTraffic { for (key, value) in &msg.services { self.services .entry(*key) - .and_modify(|x| x.refresh(*value)) + .and_modify(|x| x.data_info.refresh(value.data_info)) .or_insert(*value); } diff --git a/src/networking/types/mod.rs b/src/networking/types/mod.rs index 0a7b1b42..55fc43f3 100644 --- a/src/networking/types/mod.rs +++ b/src/networking/types/mod.rs @@ -6,6 +6,7 @@ pub mod capture_context; pub mod combobox_data_states; pub mod config_device; pub mod data_info; +pub mod data_info_fav; pub mod data_info_host; pub mod data_representation; pub mod host; diff --git a/src/networking/types/program_lookup.rs b/src/networking/types/program_lookup.rs index c0e032ee..ff061a29 100644 --- a/src/networking/types/program_lookup.rs +++ b/src/networking/types/program_lookup.rs @@ -5,6 +5,7 @@ use crate::gui::types::message::Message; use crate::networking::manage_packets::get_local_port; use crate::networking::types::address_port_pair::AddressPortPair; use crate::networking::types::data_info::DataInfo; +use crate::networking::types::data_info_fav::DataInfoFav; use crate::networking::types::data_representation::DataRepr; use crate::networking::types::info_address_port_pair::InfoAddressPortPair; use crate::networking::types::program::Program; @@ -26,7 +27,7 @@ pub struct ProgramLookup { icon_key_tx: Sender, picon_rx: Receiver<(String, IconHandle)>, state: HashMap<(u16, Protocol), LookedUpProgram>, - programs: HashMap, + programs: HashMap, picons: HashMap, } @@ -59,8 +60,8 @@ impl ProgramLookup { let res = Program::from_proc(proc.as_ref()); self.programs .entry(res.clone()) - .and_modify(|d| d.refresh(new_data)) - .or_insert(new_data); + .and_modify(|d| d.data_info.refresh(new_data)) + .or_insert(new_data.into()); res } @@ -159,8 +160,8 @@ impl ProgramLookup { // assign to known self.programs .entry(program) - .and_modify(|d| d.refresh(reassigned_data)) - .or_insert(reassigned_data); + .and_modify(|d| d.data_info.refresh(reassigned_data)) + .or_insert(reassigned_data.into()); // remove from Unknown // NOTE: subtracting reassigned_data from Unknown wouldn't correctly reassign final_instant, // so let's just reiterate through all the Unknown connections @@ -174,7 +175,7 @@ impl ProgramLookup { // or_insert not needed: Unknown is already in the map since reassigned data came from it self.programs .entry(Program::Unknown) - .and_modify(|d| *d = unknown_data); + .and_modify(|d| d.data_info = unknown_data); } } @@ -191,10 +192,16 @@ impl ProgramLookup { } } - pub fn programs(&self) -> &HashMap { + pub fn programs(&self) -> &HashMap { &self.programs } + pub fn edit_fav(&mut self, program: &Program, add: bool) { + if let Some(info) = self.programs.get_mut(program) { + info.is_favorite = add; + } + } + pub fn picon_tooltip<'a>( &self, icon_key: &str, diff --git a/src/notifications/notify_and_log.rs b/src/notifications/notify_and_log.rs index 0378b752..333e44b8 100644 --- a/src/notifications/notify_and_log.rs +++ b/src/notifications/notify_and_log.rs @@ -1,3 +1,4 @@ +use crate::gui::types::favorite::FavoriteKey; use crate::networking::manage_packets::get_address_to_lookup; use crate::networking::types::capture_context::CaptureSource; use crate::networking::types::data_info::DataInfo; @@ -27,7 +28,7 @@ pub fn notify_and_log( logged_notifications: &mut LoggedNotifications, notifications: &Notifications, info_traffic_msg: &InfoTraffic, - favorites: &HashSet, + favorites: &HashSet, cs: &CaptureSource, addresses_resolved: &HashMap, ) -> usize { @@ -114,13 +115,14 @@ pub fn notify_and_log( .get(&host) .copied() .unwrap_or_default(); - data_info_host.data_info = v.data_info(); + data_info_host.data_info_fav.data_info = v.data_info(); blacklisted_last_interval .entry(*address_to_lookup) .and_modify(|(_, existing_data_info_host)| { existing_data_info_host + .data_info_fav .data_info - .refresh(data_info_host.data_info); + .refresh(data_info_host.data_info_fav.data_info); }) .or_insert((host, data_info_host)); } @@ -164,8 +166,11 @@ fn hosts_list(info_traffic_msg: &InfoTraffic, data_repr: DataRepr) -> Vec<(Host, .map(|(h, data)| (h.clone(), *data)) .collect(); hosts.sort_by(|(_, a), (_, b)| { - a.data_info - .compare(&b.data_info, SortType::Descending, data_repr) + a.data_info_fav.data_info.compare( + &b.data_info_fav.data_info, + SortType::Descending, + data_repr, + ) }); let n_entry = min(hosts.len(), 4); hosts @@ -181,9 +186,9 @@ fn services_list(info_traffic_msg: &InfoTraffic, data_repr: DataRepr) -> Vec<(Se .services .iter() .filter(|(service, _)| service != &&Service::NotApplicable) - .map(|(s, data)| (*s, *data)) + .map(|(s, data_info_fav)| (*s, data_info_fav.data_info)) .collect(); - services.sort_by(|(_, a), (_, b)| a.compare(b, SortType::Descending, data_repr)); + services.sort_by(|(_, a), (_, b)| a.compare(&b, SortType::Descending, data_repr)); let n_entry = min(services.len(), 4); services .get(..n_entry) diff --git a/src/notifications/types/logged_notification.rs b/src/notifications/types/logged_notification.rs index 56561808..ecc9cb61 100644 --- a/src/notifications/types/logged_notification.rs +++ b/src/notifications/types/logged_notification.rs @@ -80,8 +80,10 @@ impl LoggedNotification { pub fn data_info(&self) -> DataInfo { match self { LoggedNotification::DataThresholdExceeded(d) => d.data_info, - LoggedNotification::FavoriteTransmitted(f) => f.data_info_host.data_info, - LoggedNotification::BlacklistedTransmitted(b) => b.data_info_host.data_info, + LoggedNotification::FavoriteTransmitted(f) => f.data_info_host.data_info_fav.data_info, + LoggedNotification::BlacklistedTransmitted(b) => { + b.data_info_host.data_info_fav.data_info + } } } @@ -144,7 +146,7 @@ impl FavoriteTransmitted { "domain": self.host.domain, "asn": self.host.asn.name, }, - "data": DataRepr::Bytes.formatted_string(self.data_info_host.data_info.tot_data(DataRepr::Bytes)), + "data": DataRepr::Bytes.formatted_string(self.data_info_host.data_info_fav.data_info.tot_data(DataRepr::Bytes)), }) .to_string() } @@ -170,7 +172,7 @@ impl BlacklistedTransmitted { "domain": self.host.domain, "asn": self.host.asn.name, }, - "data": DataRepr::Bytes.formatted_string(self.data_info_host.data_info.tot_data(DataRepr::Bytes)), + "data": DataRepr::Bytes.formatted_string(self.data_info_host.data_info_fav.data_info.tot_data(DataRepr::Bytes)), }) .to_string() } diff --git a/src/report/get_report_entries.rs b/src/report/get_report_entries.rs index 624d0840..7f2226d4 100644 --- a/src/report/get_report_entries.rs +++ b/src/report/get_report_entries.rs @@ -1,16 +1,11 @@ use std::cmp::min; +use crate::Sniffer; use crate::networking::manage_packets::get_address_to_lookup; use crate::networking::types::address_port_pair::AddressPortPair; use crate::networking::types::data_info::DataInfo; use crate::networking::types::data_info_host::DataInfoHost; -use crate::networking::types::data_representation::DataRepr; -use crate::networking::types::host::Host; use crate::networking::types::info_address_port_pair::InfoAddressPortPair; -use crate::networking::types::program::Program; -use crate::networking::types::program_lookup::ProgramLookup; -use crate::report::types::sort_type::SortType; -use crate::{InfoTraffic, Service, Sniffer}; /// Return the elements that satisfy the search constraints and belong to the given page, /// and the total number of elements which satisfy the search constraints, @@ -31,6 +26,7 @@ pub fn get_searched_entries( .hosts .get(&e.1) .unwrap_or(&DataInfoHost::default()) + .data_info_fav .is_favorite } else { false @@ -62,69 +58,3 @@ pub fn get_searched_entries( agglomerate, ) } - -pub fn get_host_entries( - info_traffic: &InfoTraffic, - data_repr: DataRepr, - sort_type: SortType, -) -> Vec<(Host, DataInfoHost)> { - let mut sorted_vec: Vec<(&Host, &DataInfoHost)> = info_traffic.hosts.iter().collect(); - - sorted_vec.sort_by(|&(_, a), &(_, b)| a.data_info.compare(&b.data_info, sort_type, data_repr)); - - let n_entry = min(sorted_vec.len(), 30); - sorted_vec[0..n_entry] - .iter() - .map(|&(host, data_info_host)| (host.to_owned(), data_info_host.to_owned())) - .collect() -} - -pub fn get_service_entries( - info_traffic: &InfoTraffic, - data_repr: DataRepr, - sort_type: SortType, -) -> Vec<(Service, DataInfo)> { - let mut sorted_vec: Vec<(&Service, &DataInfo)> = info_traffic - .services - .iter() - .filter(|(service, _)| service != &&Service::NotApplicable) - .collect(); - - sorted_vec.sort_by(|&(_, a), &(_, b)| a.compare(b, sort_type, data_repr)); - - let n_entry = min(sorted_vec.len(), 30); - sorted_vec[0..n_entry] - .iter() - .map(|&(service, data_info)| (*service, *data_info)) - .collect() -} - -pub fn get_program_entries( - program_lookup: &ProgramLookup, - data_repr: DataRepr, - sort_type: SortType, -) -> Vec<(Program, DataInfo)> { - let mut sorted_vec: Vec<(&Program, &DataInfo)> = program_lookup - .programs() - .iter() - // Unknown may be inserted, and then all of its data could be reassigned to known programs - .filter(|(_, d)| d.tot_data(DataRepr::Packets) > 0) - .collect(); - - sorted_vec.sort_by(|&(p1, a), &(p2, b)| { - if sort_type == SortType::Neutral && a.is_within_same_second(b) { - if p1.is_unknown() { - return std::cmp::Ordering::Greater; - } else if p2.is_unknown() { - return std::cmp::Ordering::Less; - } - } - a.compare(b, sort_type, data_repr) - }); - - let n_entry = min(sorted_vec.len(), 30); - sorted_vec[0..n_entry] - .iter() - .map(|&(program, data_info)| (program.to_owned(), *data_info)) - .collect() -}