mirror of
https://github.com/GyulyVGC/sniffnet.git
synced 2026-08-27 03:49:31 +00:00
unify overview page reports and create favorite enums to include services and programs (WIP)
This commit is contained in:
parent
ca5f349e39
commit
7b905baf6a
16 changed files with 600 additions and 420 deletions
|
|
@ -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::<Element<Message, StyleType>>,
|
||||
service.to_string(),
|
||||
data_info,
|
||||
|
|
|
|||
|
|
@ -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<Message, StyleType> {
|
||||
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<Element<Message, StyleType>> {
|
||||
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::<Element<Message, StyleType>>;
|
||||
}
|
||||
|
||||
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::<Element<Message, StyleType>>,
|
||||
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::<Element<Message, StyleType>>,
|
||||
// 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<Element<'a, Message, StyleType>>,
|
||||
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<Message, StyleType>) -> Tooltip<Message, StyleType> {
|
||||
Tooltip::new(
|
||||
Container::new(
|
||||
|
|
@ -732,24 +661,6 @@ fn get_info_tooltip(tooltip_content: Element<Message, StyleType>) -> Tooltip<Mes
|
|||
.delay(TOOLTIP_DELAY)
|
||||
}
|
||||
|
||||
fn sort_arrows<'a>(
|
||||
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};
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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<IpAddr, (String, Host)>,
|
||||
/// Collection of the favorite hosts
|
||||
pub favorite_hosts: HashSet<Host>,
|
||||
/// Collection of the favorite hosts, services and programs
|
||||
pub favorites: HashSet<FavoriteKey>,
|
||||
/// 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]
|
||||
|
|
|
|||
273
src/gui/types/favorite.rs
Normal file
273
src/gui/types/favorite.rs
Normal file
|
|
@ -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<FavoriteItem> {
|
||||
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<Element<'a, Message, StyleType>> {
|
||||
match self {
|
||||
FavoriteItem::Host((host, data_info_host)) => Some(get_flag_tooltip(
|
||||
host.country,
|
||||
data_info_host,
|
||||
language,
|
||||
thumbnail,
|
||||
)),
|
||||
FavoriteItem::Service(_) => None::<Tooltip<Message, StyleType>>,
|
||||
FavoriteItem::Program((program, _)) => {
|
||||
let Some(program_lookup) = program_lookup else {
|
||||
return None::<Tooltip<Message, StyleType>>;
|
||||
};
|
||||
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<FavoriteItem> 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<FavoriteItem> {
|
||||
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<FavoriteItem> {
|
||||
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<FavoriteItem> {
|
||||
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()
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
17
src/networking/types/data_info_fav.rs
Normal file
17
src/networking/types/data_info_fav.rs
Normal file
|
|
@ -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<DataInfo> for DataInfoFav {
|
||||
fn from(data_info: DataInfo) -> Self {
|
||||
Self {
|
||||
data_info,
|
||||
is_favorite: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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<AddressPortPair, InfoAddressPortPair>,
|
||||
/// Map of the upper layer services with their data info
|
||||
pub services: HashMap<Service, DataInfo>,
|
||||
pub services: HashMap<Service, DataInfoFav>,
|
||||
/// Map of the hosts with their data info
|
||||
pub hosts: HashMap<Host, DataInfoHost>,
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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<String>,
|
||||
picon_rx: Receiver<(String, IconHandle)>,
|
||||
state: HashMap<(u16, Protocol), LookedUpProgram>,
|
||||
programs: HashMap<Program, DataInfo>,
|
||||
programs: HashMap<Program, DataInfoFav>,
|
||||
picons: HashMap<String, IconHandle>,
|
||||
}
|
||||
|
||||
|
|
@ -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<Program, DataInfo> {
|
||||
pub fn programs(&self) -> &HashMap<Program, DataInfoFav> {
|
||||
&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,
|
||||
|
|
|
|||
|
|
@ -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<Host>,
|
||||
favorites: &HashSet<FavoriteKey>,
|
||||
cs: &CaptureSource,
|
||||
addresses_resolved: &HashMap<IpAddr, (String, Host)>,
|
||||
) -> 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)
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue