Serenity Operating System
at master 144 lines 7.6 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * Copyright (c) 2022, the SerenityOS developers. 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include "NetworkStatisticsWidget.h" 9#include <LibGUI/BoxLayout.h> 10#include <LibGUI/GroupBox.h> 11#include <LibGUI/JsonArrayModel.h> 12#include <LibGUI/Menu.h> 13#include <LibGUI/Process.h> 14#include <LibGUI/SortingProxyModel.h> 15#include <LibGUI/TableView.h> 16#include <LibGfx/Painter.h> 17 18REGISTER_WIDGET(SystemMonitor, NetworkStatisticsWidget) 19 20namespace SystemMonitor { 21 22NetworkStatisticsWidget::NetworkStatisticsWidget() 23{ 24 on_first_show = [this](auto&) { 25 set_layout<GUI::VerticalBoxLayout>(4); 26 set_fill_with_background_color(true); 27 28 m_network_connected_bitmap = Gfx::Bitmap::load_from_file("/res/icons/16x16/network-connected.png"sv).release_value_but_fixme_should_propagate_errors(); 29 m_network_disconnected_bitmap = Gfx::Bitmap::load_from_file("/res/icons/16x16/network-disconnected.png"sv).release_value_but_fixme_should_propagate_errors(); 30 31 m_network_link_down_bitmap = Gfx::Bitmap::create(m_network_connected_bitmap->format(), m_network_connected_bitmap->size()).release_value_but_fixme_should_propagate_errors(); 32 { 33 Gfx::Painter painter(*m_network_link_down_bitmap); 34 painter.blit_filtered(Gfx::IntPoint {}, *m_network_connected_bitmap, m_network_connected_bitmap->rect(), [](Color color) { 35 return color.to_grayscale(); 36 }); 37 } 38 39 auto& adapters_group_box = add<GUI::GroupBox>("Adapters"sv); 40 adapters_group_box.set_layout<GUI::VerticalBoxLayout>(6); 41 adapters_group_box.set_fixed_height(120); 42 43 m_adapter_table_view = adapters_group_box.add<GUI::TableView>(); 44 45 Vector<GUI::JsonArrayModel::FieldSpec> net_adapters_fields; 46 net_adapters_fields.empend("", Gfx::TextAlignment::CenterLeft, 47 [this](JsonObject const& object) -> GUI::Variant { 48 if (!object.get_bool("link_up"sv).value_or(false)) 49 return *m_network_link_down_bitmap; 50 else 51 return object.get_deprecated_string("ipv4_address"sv).value_or("").is_empty() ? *m_network_disconnected_bitmap : *m_network_connected_bitmap; 52 }); 53 net_adapters_fields.empend("name", "Name", Gfx::TextAlignment::CenterLeft); 54 net_adapters_fields.empend("class_name", "Class", Gfx::TextAlignment::CenterLeft); 55 net_adapters_fields.empend("mac_address", "MAC", Gfx::TextAlignment::CenterLeft); 56 net_adapters_fields.empend("Link status", Gfx::TextAlignment::CenterLeft, 57 [](JsonObject const& object) -> DeprecatedString { 58 if (!object.get_bool("link_up"sv).value_or(false)) 59 return "Down"; 60 61 return DeprecatedString::formatted("{} Mb/s {}-duplex", object.get_i32("link_speed"sv).value_or(0), 62 object.get_bool("link_full_duplex"sv).value_or(false) ? "full"sv : "half"sv); 63 }); 64 net_adapters_fields.empend("IPv4", Gfx::TextAlignment::CenterLeft, 65 [](JsonObject const& object) -> DeprecatedString { 66 return object.get_deprecated_string("ipv4_address"sv).value_or(""sv); 67 }); 68 net_adapters_fields.empend("packets_in", "Pkt In", Gfx::TextAlignment::CenterRight); 69 net_adapters_fields.empend("packets_out", "Pkt Out", Gfx::TextAlignment::CenterRight); 70 net_adapters_fields.empend("bytes_in", "Bytes In", Gfx::TextAlignment::CenterRight); 71 net_adapters_fields.empend("bytes_out", "Bytes Out", Gfx::TextAlignment::CenterRight); 72 m_adapter_model = GUI::JsonArrayModel::create("/sys/kernel/net/adapters", move(net_adapters_fields)); 73 m_adapter_table_view->set_model(MUST(GUI::SortingProxyModel::create(*m_adapter_model))); 74 m_adapter_context_menu = MUST(GUI::Menu::try_create()); 75 m_adapter_context_menu->add_action(GUI::Action::create( 76 "Open in Network Settings...", MUST(Gfx::Bitmap::load_from_file("/res/icons/16x16/network.png"sv)), [this](GUI::Action&) { 77 m_adapter_table_view->selection().for_each_index([this](GUI::ModelIndex const& index) { 78 auto adapter_name = index.sibling_at_column(1).data().as_string(); 79 GUI::Process::spawn_or_show_error(window(), "/bin/Escalator"sv, Array { "/bin/NetworkSettings", adapter_name.characters() }); 80 }); 81 }, 82 this)); 83 m_adapter_table_view->on_context_menu_request = [this](GUI::ModelIndex const& index, GUI::ContextMenuEvent const& event) { 84 if (!index.is_valid()) { 85 return; 86 } 87 auto adapter_name = index.sibling_at_column(1).data().as_string(); 88 if (adapter_name == "loop") { 89 return; 90 } 91 m_adapter_context_menu->popup(event.screen_position()); 92 }; 93 94 auto& tcp_sockets_group_box = add<GUI::GroupBox>("TCP Sockets"sv); 95 tcp_sockets_group_box.set_layout<GUI::VerticalBoxLayout>(6); 96 97 m_tcp_socket_table_view = tcp_sockets_group_box.add<GUI::TableView>(); 98 99 Vector<GUI::JsonArrayModel::FieldSpec> net_tcp_fields; 100 net_tcp_fields.empend("peer_address", "Peer", Gfx::TextAlignment::CenterLeft); 101 net_tcp_fields.empend("peer_port", "Port", Gfx::TextAlignment::CenterRight); 102 net_tcp_fields.empend("local_address", "Local", Gfx::TextAlignment::CenterLeft); 103 net_tcp_fields.empend("local_port", "Port", Gfx::TextAlignment::CenterRight); 104 net_tcp_fields.empend("state", "State", Gfx::TextAlignment::CenterLeft); 105 net_tcp_fields.empend("ack_number", "Ack#", Gfx::TextAlignment::CenterRight); 106 net_tcp_fields.empend("sequence_number", "Seq#", Gfx::TextAlignment::CenterRight); 107 net_tcp_fields.empend("packets_in", "Pkt In", Gfx::TextAlignment::CenterRight); 108 net_tcp_fields.empend("packets_out", "Pkt Out", Gfx::TextAlignment::CenterRight); 109 net_tcp_fields.empend("bytes_in", "Bytes In", Gfx::TextAlignment::CenterRight); 110 net_tcp_fields.empend("bytes_out", "Bytes Out", Gfx::TextAlignment::CenterRight); 111 m_tcp_socket_model = GUI::JsonArrayModel::create("/sys/kernel/net/tcp", move(net_tcp_fields)); 112 m_tcp_socket_table_view->set_model(MUST(GUI::SortingProxyModel::create(*m_tcp_socket_model))); 113 114 auto& udp_sockets_group_box = add<GUI::GroupBox>("UDP Sockets"sv); 115 udp_sockets_group_box.set_layout<GUI::VerticalBoxLayout>(6); 116 117 m_udp_socket_table_view = udp_sockets_group_box.add<GUI::TableView>(); 118 119 Vector<GUI::JsonArrayModel::FieldSpec> net_udp_fields; 120 net_udp_fields.empend("peer_address", "Peer", Gfx::TextAlignment::CenterLeft); 121 net_udp_fields.empend("peer_port", "Port", Gfx::TextAlignment::CenterRight); 122 net_udp_fields.empend("local_address", "Local", Gfx::TextAlignment::CenterLeft); 123 net_udp_fields.empend("local_port", "Port", Gfx::TextAlignment::CenterRight); 124 m_udp_socket_model = GUI::JsonArrayModel::create("/sys/kernel/net/udp", move(net_udp_fields)); 125 m_udp_socket_table_view->set_model(MUST(GUI::SortingProxyModel::create(*m_udp_socket_model))); 126 127 m_update_timer = add<Core::Timer>( 128 1000, [this] { 129 update_models(); 130 }); 131 m_update_timer->start(); 132 133 update_models(); 134 }; 135} 136 137void NetworkStatisticsWidget::update_models() 138{ 139 m_adapter_model->update(); 140 m_tcp_socket_model->update(); 141 m_udp_socket_model->update(); 142} 143 144}