16#include <glibmm/i18n.h>
52 gtk_widget_queue_draw(widget);
53 return G_SOURCE_CONTINUE;
75 const gint64 now = g_get_monotonic_time();
76 const double t = (now - data->start_us) / 1000000.0;
78 const double cx = width * 0.5;
79 const double cy = height * 0.5;
82 std::clamp(5.0 + std::log2(
static_cast<double>(std::max(1, data->hits)) + 1.0) * 1.8,
86 const double pulse01 = (std::sin(t * 2.8) + 1.0) * 0.5;
87 const double ring_r = base_r + 4.0 + pulse01 * 10.0;
88 const double ring_alpha = 0.10 + (1.0 - pulse01) * 0.22;
89 const double glow_r = base_r + 7.0 + pulse01 * 4.0;
90 const double glow_alpha = 0.12 + pulse01 * 0.10;
94 cairo_pattern_t* glow =
95 cairo_pattern_create_radial(cx, cy, base_r * 0.3, cx, cy, glow_r);
96 cairo_pattern_add_color_stop_rgba(glow, 0.0, 1.0, 0.42, 0.28, glow_alpha);
97 cairo_pattern_add_color_stop_rgba(glow, 1.0, 1.0, 0.42, 0.28, 0.0);
98 cairo_set_source(cr, glow);
99 cairo_arc(cr, cx, cy, glow_r, 0.0, 2.0 * M_PI);
101 cairo_pattern_destroy(glow);
103 cairo_set_source_rgba(cr, 1.0, 0.53, 0.30, ring_alpha);
104 cairo_set_line_width(cr, 2.0);
105 cairo_arc(cr, cx, cy, ring_r, 0.0, 2.0 * M_PI);
108 cairo_set_source_rgba(cr, 1.0, 0.36, 0.26, 0.98);
109 cairo_arc(cr, cx, cy, base_r, 0.0, 2.0 * M_PI);
112 cairo_set_source_rgba(cr, 1.0, 0.95, 0.92, 0.95);
113 cairo_set_line_width(cr, 1.5);
114 cairo_arc(cr, cx, cy, base_r, 0.0, 2.0 * M_PI);
117 cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.30);
121 std::max(1.5, base_r * 0.33),
131 auto* area = gtk_drawing_area_new();
133 const int size = std::clamp(
134 32 +
static_cast<int>(std::log2(
static_cast<double>(std::max(1, hits)) + 1.0) * 8.0),
140 data->start_us = g_get_monotonic_time();
143 gtk_widget_set_size_request(area, size, size);
144 gtk_drawing_area_set_content_width(GTK_DRAWING_AREA(area), size);
145 gtk_drawing_area_set_content_height(GTK_DRAWING_AREA(area), size);
146 gtk_drawing_area_set_draw_func(
147 GTK_DRAWING_AREA(area),
154 gtk_widget_set_halign(area, GTK_ALIGN_CENTER);
155 gtk_widget_set_valign(area, GTK_ALIGN_CENTER);
178: Gtk::Box(Gtk::Orientation::VERTICAL, 0)
180 get_style_context()->add_class(
"bsc-page");
181 get_style_context()->add_class(
"bsc-network-page");
208 m_pulseTimerId = g_timeout_add(66, +[](gpointer data) -> gboolean {
210 self->m_pulseFrame = (self->m_pulseFrame + 1) % 10000;
211 self->triggerFxRedraw();
212 return G_SOURCE_CONTINUE;
240 set_margin_start(12);
243 set_margin_bottom(12);
245 auto header = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL, 8);
246 header->get_style_context()->add_class(
"bsc-page-header");
248 m_headerLabel.set_markup(
"<b>" + Glib::ustring(
_(
"Monitor di rete")) +
"</b>");
250 m_headerLabel.get_style_context()->add_class(
"bsc-page-title");
255 m_summaryLabel.get_style_context()->add_class(
"bsc-page-subtitle");
260 m_clearBtn.get_style_context()->add_class(
"bsc-toolbar-button");
271 m_mapHost.get_style_context()->add_class(
"bsc-map");
280 m_treeView.get_style_context()->add_class(
"bsc-treeview");
281 m_treeView.get_style_context()->add_class(
"bsc-network-treeview");
291 for (guint i = 0; i <
m_treeView.get_n_columns(); ++i) {
293 c->set_resizable(
true);
294 c->set_reorderable(
false);
299 m_scroll.set_policy(Gtk::PolicyType::AUTOMATIC, Gtk::PolicyType::AUTOMATIC);
302 m_scroll.get_style_context()->add_class(
"bsc-scrolled");
310 auto* frame = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8);
311 gtk_widget_add_css_class(frame,
"bsc-network-popover");
312 gtk_widget_set_size_request(frame, 320, -1);
313 gtk_widget_set_halign(frame, GTK_ALIGN_START);
314 gtk_widget_set_valign(frame, GTK_ALIGN_START);
315 gtk_widget_set_margin_start(frame, 28);
316 gtk_widget_set_margin_top(frame, 28);
317 gtk_widget_set_visible(frame, FALSE);
318 gtk_widget_set_can_target(frame, FALSE);
337 const std::string& country_name,
338 const std::string& city,
339 const std::string& ip,
340 const std::string& host,
341 const std::string& app_name,
342 const std::string& isp,
353 if (!country_code.empty() && !country_name.empty()) {
354 title = country_code +
" " + country_name;
355 }
else if (!country_name.empty()) {
356 title = country_name;
358 title =
"Connessione";
361 std::ostringstream body;
362 if (!city.empty()) body << city <<
"\n";
363 body <<
"IP: " << ip;
364 if (!host.empty()) body <<
"\nHost: " << host;
365 if (!app_name.empty()) body <<
"\nApp: " << app_name;
366 if (!isp.empty()) body <<
"\nISP/AS: " << isp;
367 body <<
"\nHit: " << hits;
384 static_cast<guint
>(kHoverHideDelay.count()),
385 +[](gpointer data) -> gboolean {
386 auto* self = static_cast<NetworkPage*>(data);
387 self->m_hoverHideSource = 0;
388 if (self->m_hoverCard) {
389 gtk_widget_set_visible(self->m_hoverCard, FALSE);
391 return G_SOURCE_REMOVE;
401 m_simpleMap = GTK_WIDGET(shumate_simple_map_new());
405 auto* registry = shumate_map_source_registry_new();
406 if (registry !=
nullptr) {
407 shumate_map_source_registry_populate_defaults(registry);
410 SHUMATE_MAP_SOURCE(g_list_model_get_object(G_LIST_MODEL(registry), 0));
411 if (source !=
nullptr) {
412 shumate_simple_map_set_map_source(SHUMATE_SIMPLE_MAP(
m_simpleMap), source);
413 g_object_unref(source);
415 g_object_unref(registry);
418 shumate_simple_map_set_show_zoom_buttons(SHUMATE_SIMPLE_MAP(
m_simpleMap), TRUE);
419 shumate_simple_map_add_overlay_layer(
423 shumate_viewport_set_min_zoom_level(
m_viewport, kMinZoom);
424 shumate_viewport_set_max_zoom_level(
m_viewport, kMaxZoom);
425 shumate_location_set_location(SHUMATE_LOCATION(
m_viewport), kDefaultLat, kDefaultLon);
426 shumate_viewport_set_zoom_level(
m_viewport, kDefaultZoom);
431 gtk_widget_set_size_request(
m_simpleMap, 720, 475);
432 gtk_widget_add_css_class(
m_simpleMap,
"bsc-map-widget");
439 auto* zoom_scroll = gtk_event_controller_scroll_new(
440 static_cast<GtkEventControllerScrollFlags
>(
441 GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE));
442 gtk_event_controller_set_propagation_phase(
443 GTK_EVENT_CONTROLLER(zoom_scroll), GTK_PHASE_CAPTURE);
447 G_CALLBACK(+[](GtkEventControllerScroll*,
double dx,
double dy, gpointer data) -> gboolean {
449 if (!self->m_viewport)
return GDK_EVENT_PROPAGATE;
450 const double delta = (std::abs(dy) >= std::abs(dx)) ? dy : dx;
451 if (delta == 0.0)
return GDK_EVENT_PROPAGATE;
453 self->noteUserViewportInteraction();
455 double zoom = shumate_viewport_get_zoom_level(self->m_viewport);
456 const double step = std::abs(delta) < 1.0 ? 0.25 : 0.45;
457 zoom += (delta < 0.0) ? step : -step;
458 zoom = std::clamp(zoom, kMinZoom, kMaxZoom);
459 shumate_viewport_set_zoom_level(self->m_viewport, zoom);
460 self->triggerFxRedraw();
461 return GDK_EVENT_STOP;
465 gtk_widget_add_controller(
m_mapOverlay, GTK_EVENT_CONTROLLER(zoom_scroll));
472 gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(
m_mapFxArea),
473 map_fx_draw,
this,
nullptr);
489 auto* marker = shumate_marker_new();
508 auto* overlay = gtk_overlay_new();
509 auto* dot = create_animated_dot_widget(pin.
hits);
510 gtk_widget_set_halign(dot, GTK_ALIGN_CENTER);
511 gtk_widget_set_valign(dot, GTK_ALIGN_CENTER);
512 gtk_overlay_set_child(GTK_OVERLAY(overlay), dot);
516 gtk_widget_add_css_class(badge,
"caption");
517 gtk_widget_add_css_class(badge,
"numeric");
518 gtk_widget_add_css_class(badge,
"bsc-network-marker-badge");
519 gtk_widget_set_opacity(badge, 0.94);
527 gtk_widget_set_halign(badge, GTK_ALIGN_CENTER);
528 gtk_widget_set_valign(badge, GTK_ALIGN_START);
529 gtk_widget_set_margin_top(badge, -18);
530 gtk_overlay_add_overlay(GTK_OVERLAY(overlay), badge);
533 auto* payload =
new HoverPayload{};
534 payload->self =
this;
535 payload->ip = pin.
ip;
536 payload->host = pin.
host;
540 payload->city = pin.
city;
541 payload->isp = pin.
isp;
542 payload->hits = pin.
hits;
544 auto* motion = gtk_event_controller_motion_new();
546 g_signal_connect_data(
549 G_CALLBACK(+[](GtkEventControllerMotion*,
double,
double, gpointer data) {
550 auto* payload =
static_cast<HoverPayload*
>(data);
551 payload->self->showHoverCard(
552 payload->country_code,
553 payload->country_name,
563 hover_payload_destroy,
570 G_CALLBACK(+[](GtkEventControllerMotion*, gpointer data) {
576 gtk_widget_add_controller(overlay, GTK_EVENT_CONTROLLER(motion));
578 shumate_marker_set_child(marker, overlay);
583 gtk_widget_set_halign(GTK_WIDGET(marker), GTK_ALIGN_CENTER);
584 gtk_widget_set_valign(GTK_WIDGET(marker), GTK_ALIGN_CENTER);
585 shumate_marker_set_selectable(marker, FALSE);
586 shumate_location_set_location(SHUMATE_LOCATION(marker), pin.
lat, pin.
lon);
588 return GTK_WIDGET(marker);
601 struct LL {
double lat, lon; };
603 all.reserve(pins.size() + 1);
605 for (
const auto& p : pins) {
606 if (p.geo_resolved && !(p.lat == 0.0 && p.lon == 0.0)) {
607 all.push_back({p.lat, p.lon});
615 shumate_location_set_location(
620 shumate_viewport_set_zoom_level(
m_viewport, kDefaultZoom);
624 double min_lat = all.front().lat;
625 double max_lat = all.front().lat;
626 double min_lon = all.front().lon;
627 double max_lon = all.front().lon;
629 for (
const auto& q : all) {
630 min_lat = std::min(min_lat, q.lat);
631 max_lat = std::max(max_lat, q.lat);
632 min_lon = std::min(min_lon, q.lon);
633 max_lon = std::max(max_lon, q.lon);
636 const double center_lat = (min_lat + max_lat) * 0.5;
637 const double center_lon = (min_lon + max_lon) * 0.5;
638 const double span = std::max(max_lat - min_lat, max_lon - min_lon);
649 if (span < 0.5) zoom = 9.0;
650 else if (span < 2.0) zoom = 7.0;
651 else if (span < 5.0) zoom = 6.0;
652 else if (span < 12.0) zoom = 5.0;
653 else if (span < 25.0) zoom = 4.2;
654 else if (span < 50.0) zoom = 3.6;
655 else if (span < 100.0) zoom = 3.0;
656 else zoom = kDefaultZoom;
658 zoom = std::clamp(zoom, kMinZoom, kMaxZoom);
660 shumate_location_set_location(
665 shumate_viewport_set_zoom_level(
m_viewport, zoom);
674 std::vector<Pin> pins_copy;
676 std::lock_guard lk(
m_mu);
677 pins_copy.reserve(
m_pins.size());
678 for (
const auto& [
_, p] :
m_pins) pins_copy.push_back(p);
684 [](
const Pin& a,
const Pin& b) { return a.hits < b.hits; }
690 for (
const auto& p : pins_copy) {
691 if (!p.geo_resolved || (p.lat == 0.0 && p.lon == 0.0))
continue;
694 shumate_marker_layer_add_marker(
696 SHUMATE_MARKER(marker_widget)
706 shumate_marker_layer_add_marker(
726 const std::string& ip = info.
dest_ip;
727 if (ip.empty())
return;
729 bool need_geo =
false;
731 std::lock_guard lk(
m_mu);
739 p.host = info.
dest_host.empty() && safe_local
740 ? std::string{
"Connessione locale sicura"}
742 p.app_name = conn_app_name;
744 p.country_name =
"Locale sicuro";
746 p.isp =
"Sistema locale";
747 p.geo_resolved =
false;
753 if (!conn_app_name.empty() && p.app_name.find(conn_app_name) == std::string::npos) {
754 p.app_name = p.app_name.empty()
756 : conn_app_name +
", " + p.app_name;
758 if (p.host.empty() && !info.
dest_host.empty())
763 p.last_seen = std::chrono::steady_clock::now();
764 p.last_seen_epoch =
static_cast<int64_t
>(std::time(
nullptr));
769 std::lock_guard lk(
m_mu);
770 auto it =
m_pins.find(ip);
772 it->second.country_code = geo->country_code;
773 it->second.country_name = geo->country_name;
774 it->second.city = geo->city;
775 it->second.isp = geo->isp.empty() ? geo->asn : geo->isp;
776 it->second.lat = geo->lat;
777 it->second.lon = geo->lon;
778 it->second.geo_resolved =
true;
784 std::lock_guard lk(
m_mu);
785 auto it =
m_pins.find(ip);
797 static thread_local int save_counter = 0;
798 if (++save_counter >= 20) {
806 std::vector<std::pair<std::string, bsc::ui_util::GeoEntry>> pending;
812 bool self_updated =
false;
814 std::lock_guard lk(
m_mu);
815 for (
const auto& [ip, geo] : pending) {
817 if (ip ==
"__self__") {
825 auto it =
m_pins.find(ip);
826 if (it ==
m_pins.end())
continue;
828 it->second.country_code = geo.country_code;
829 it->second.country_name = geo.country_name;
830 it->second.city = geo.city;
831 it->second.isp = geo.isp.empty() ? geo.asn : geo.isp;
832 it->second.lat = geo.lat;
833 it->second.lon = geo.lon;
834 it->second.geo_resolved =
true;
851 Glib::ustring country_cell;
862 auto row = *(it->second);
888 std::size_t total_ips = 0;
889 std::size_t total_hits = 0;
890 std::size_t countries = 0;
891 std::unordered_map<std::string, int> seen_countries;
894 std::lock_guard lk(
m_mu);
895 total_ips =
m_pins.size();
897 for (
const auto& [
_, p] :
m_pins) {
898 total_hits += p.hits;
899 if (!p.country_code.empty() && !seen_countries.count(p.country_code)) {
900 seen_countries[p.country_code] = 1;
904 countries = seen_countries.size();
907 std::ostringstream oss;
908 oss << total_ips <<
" IP · " << total_hits <<
" conn. · "
909 << countries <<
" paesi";
942 auto* marker = shumate_marker_new();
943 auto* area = gtk_drawing_area_new();
948 gtk_widget_set_size_request(area, 32, 32);
950 gtk_drawing_area_set_draw_func(
951 GTK_DRAWING_AREA(area),
952 +[](GtkDrawingArea*, cairo_t* cr,
int w,
int h, gpointer) {
953 const double cx = w * 0.5;
954 const double cy = h * 0.5;
957 const gint64 us = g_get_monotonic_time();
958 const double t = (us % 2000000) / 2000000.0;
959 const double pulse = 0.5 * (1.0 - std::cos(t * 2.0 * M_PI));
962 const double ring_r = 10.0 + pulse * 6.0;
963 const double ring_a = 0.45 * (1.0 - pulse);
964 cairo_set_source_rgba(cr, 0.20, 0.60, 1.0, ring_a);
965 cairo_arc(cr, cx, cy, ring_r, 0.0, 2.0 * M_PI);
970 cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.35);
971 cairo_arc(cr, cx, cy + 1.0, 9.0, 0.0, 2.0 * M_PI);
975 cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
976 cairo_arc(cr, cx, cy, 9.0, 0.0, 2.0 * M_PI);
980 cairo_set_source_rgba(cr, 0.15, 0.50, 1.0, 1.0);
981 cairo_arc(cr, cx, cy, 7.0, 0.0, 2.0 * M_PI);
985 cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.55);
986 cairo_arc(cr, cx - 2.0, cy - 2.0, 2.2, 0.0, 2.0 * M_PI);
991 shumate_marker_set_child(SHUMATE_MARKER(marker), area);
992 shumate_location_set_location(SHUMATE_LOCATION(marker),
994 return GTK_WIDGET(marker);
1000 if (width <= 0 || height <= 0)
return;
1005 double sx = 0.0, sy = 0.0;
1006 shumate_viewport_location_to_widget_coords(
1014 const bool self_visible =
1015 sx >= 0 && sx <= width && sy >= 0 && sy <= height;
1020 struct Arc {
double tx, ty;
bool visible; uint32_t hits; };
1021 std::vector<Arc> arcs;
1023 std::lock_guard lk(
m_mu);
1024 arcs.reserve(
m_pins.size());
1025 for (
const auto& [ip, p] :
m_pins) {
1026 if (!p.geo_resolved)
continue;
1028 if (p.lat == 0.0 && p.lon == 0.0)
continue;
1029 double tx = 0.0, ty = 0.0;
1030 shumate_viewport_location_to_widget_coords(
1035 const bool visible =
1036 tx >= 0 && tx <= width &&
1037 ty >= 0 && ty <= height;
1038 arcs.push_back({tx, ty, visible, p.hits});
1044 const gint64 us = g_get_monotonic_time();
1045 const double t = (us % 1400000) / 1400000.0;
1046 const double pulse = 0.5 * (1.0 - std::cos(t * 2.0 * M_PI));
1053 for (
const auto& a : arcs) {
1054 if (!a.visible || !self_visible)
continue;
1060 const double dx_ = a.tx - sx;
1061 const double dy_ = a.ty - sy;
1062 const double dist = std::sqrt(dx_ * dx_ + dy_ * dy_);
1063 if (dist < 8.0)
continue;
1068 const double mx = (sx + a.tx) * 0.5;
1069 const double my = (sy + a.ty) * 0.5;
1071 const double nx = -dy_ / dist;
1072 const double ny = dx_ / dist;
1073 const double curve = std::min(60.0, dist * 0.18);
1074 const double cx = mx + nx * curve;
1075 const double cy = my + ny * curve;
1078 const double alpha = std::clamp(0.35 + 0.05 * std::log1p(a.hits), 0.35, 0.80);
1079 cairo_set_source_rgba(cr, 1.0, 0.60, 0.22, alpha);
1080 cairo_set_line_width(cr, 1.5);
1081 cairo_move_to(cr, sx, sy);
1082 cairo_curve_to(cr, cx, cy, cx, cy, a.tx, a.ty);
1086 const double ring_r = 5.0 + pulse * 5.0;
1087 const double ring_a = 0.55 * (1.0 - pulse);
1088 cairo_set_source_rgba(cr, 1.0, 0.60, 0.22, ring_a);
1089 cairo_arc(cr, a.tx, a.ty, ring_r, 0.0, 2.0 * M_PI);
1092 cairo_set_source_rgba(cr, 1.0, 0.70, 0.30, 1.0);
1093 cairo_arc(cr, a.tx, a.ty, 3.5, 0.0, 2.0 * M_PI);
1108 std::lock_guard lk(
m_mu);
1119 std::filesystem::remove(
logPath(), ec);
1131 return "/tmp/bastionguard-sc-network-" +
1132 std::to_string(::getuid()) +
".jsonl";
1141 out.reserve(s.size());
1142 for (
unsigned char c : s) {
1144 case '"': out +=
"\\\"";
break;
1145 case '\\': out +=
"\\\\";
break;
1146 case '\n': out +=
"\\n";
break;
1147 case '\r': out +=
"\\r";
break;
1148 case '\t': out +=
"\\t";
break;
1152 std::snprintf(b,
sizeof(b),
"\\u%04x", c);
1155 out +=
static_cast<char>(c);
1166 const std::string& key) {
1167 const std::string needle =
"\"" + key +
"\":\"";
1168 auto pos = line.find(needle);
1169 if (pos == std::string::npos)
return {};
1170 pos += needle.size();
1171 auto end = line.find(
'"', pos);
1172 return end == std::string::npos ? std::string{}
1173 : line.substr(pos, end - pos);
1177 const std::string& key) {
1178 const std::string needle =
"\"" + key +
"\":";
1179 auto pos = line.find(needle);
1180 if (pos == std::string::npos)
return 0.0;
1181 pos += needle.size();
1182 return std::strtod(line.c_str() + pos,
nullptr);
1186 const std::string& key) {
1187 const std::string needle =
"\"" + key +
"\":";
1188 auto pos = line.find(needle);
1189 if (pos == std::string::npos)
return 0;
1190 pos += needle.size();
1191 return std::strtoll(line.c_str() + pos,
nullptr, 10);
1197 std::ofstream f(
logPath(), std::ios::trunc);
1198 if (!f.is_open())
return;
1202 std::vector<Pin> snapshot;
1204 std::lock_guard lk(
m_mu);
1205 snapshot.reserve(
m_pins.size());
1206 for (
const auto& [ip, p] :
m_pins) snapshot.push_back(p);
1209 for (
const auto& p : snapshot) {
1214 if (!p.geo_resolved)
continue;
1216 f <<
"{\"ip\":\"" << net_json_escape(p.ip) <<
"\""
1217 <<
",\"host\":\"" << net_json_escape(p.host) <<
"\""
1218 <<
",\"app\":\"" << net_json_escape(p.app_name) <<
"\""
1219 <<
",\"cc\":\"" << net_json_escape(p.country_code) <<
"\""
1220 <<
",\"country\":\"" << net_json_escape(p.country_name) <<
"\""
1221 <<
",\"city\":\"" << net_json_escape(p.city) <<
"\""
1222 <<
",\"isp\":\"" << net_json_escape(p.isp) <<
"\""
1223 <<
",\"lat\":" << p.lat
1224 <<
",\"lon\":" << p.lon
1225 <<
",\"hits\":" << p.hits
1226 <<
",\"last_ts\":" << p.last_seen_epoch
1234 if (!f.is_open())
return;
1236 const int64_t now_epoch =
static_cast<int64_t
>(std::time(
nullptr));
1238 int loaded = 0, dropped = 0;
1241 while (std::getline(f, line)) {
1242 if (line.empty() || line[0] !=
'{')
continue;
1244 const int64_t ts = net_json_field_i64(line,
"last_ts");
1246 if (ts > 0 && ts < cutoff) { ++dropped;
continue; }
1249 p.
ip = net_json_field_str(line,
"ip");
1250 if (p.
ip.empty())
continue;
1251 p.
host = net_json_field_str(line,
"host");
1252 p.
app_name = net_json_field_str(line,
"app");
1255 p.
city = net_json_field_str(line,
"city");
1256 p.
isp = net_json_field_str(line,
"isp");
1257 p.
lat = net_json_field_double(line,
"lat");
1258 p.
lon = net_json_field_double(line,
"lon");
1259 p.
hits =
static_cast<uint32_t
>(net_json_field_i64(line,
"hits"));
1264 p.
last_seen = std::chrono::steady_clock::now();
1267 std::lock_guard lk(
m_mu);
1276 g_message(
"NetworkPage: caricati %d pin, scartati %d per retention 7gg",
void noteConnection(const ConnectionInfo &info)
bool shouldHoldUserViewport() const
static constexpr int64_t kRetentionSeconds
Glib::RefPtr< Gtk::ListStore > m_store
std::unordered_map< std::string, Gtk::TreeModel::iterator > m_rows
GtkWidget * m_hoverCardTitle
std::vector< std::pair< std::string, bsc::ui_util::GeoEntry > > m_pendingGeo
GtkWidget * createSelfMarkerWidget()
void drawConnectionArcs(cairo_t *cr, int width, int height)
std::chrono::steady_clock::time_point m_lastUserViewportInteraction
Gtk::Label m_summaryLabel
Glib::Dispatcher m_geoDispatcher
void updateRow(const Pin &pin)
void showHoverCard(const std::string &country_code, const std::string &country_name, const std::string &city, const std::string &ip, const std::string &host, const std::string &app_name, const std::string &isp, uint32_t hits)
GtkWidget * createHoverCard()
void requestSelfLocation()
void noteUserViewportInteraction()
ShumateViewport * m_viewport
ShumateMarkerLayer * m_markerLayer
GtkWidget * createMarkerWidget(const Pin &pin)
Gtk::ScrolledWindow m_scroll
void maybeRecenterMap(const std::vector< Pin > &pins)
std::unordered_map< std::string, Pin > m_pins
static std::string logPath()
GtkWidget * m_hoverCardBody
static GeoResolver & instance()
void on_resolved(ResolvedCallback cb)
static void animated_marker_data_destroy(gpointer data)
static void map_fx_draw(GtkDrawingArea *, cairo_t *cr, int width, int height, gpointer user_data)
int64_t net_json_field_i64(const std::string &line, const std::string &key)
constexpr double kMinZoom
constexpr auto kUserViewportHold
static gboolean animated_marker_tick(GtkWidget *widget, GdkFrameClock *, gpointer)
constexpr auto kHoverHideDelay
constexpr double kMaxZoom
constexpr double kDefaultLat
constexpr double kDefaultZoom
std::string net_json_field_str(const std::string &line, const std::string &key)
constexpr double kFocusedZoom
constexpr double kDefaultLon
std::string net_json_escape(const std::string &s)
static void animated_marker_draw(GtkDrawingArea *, cairo_t *cr, int width, int height, gpointer user_data)
static void hover_payload_destroy(gpointer data, GClosure *)
double net_json_field_double(const std::string &line, const std::string &key)
static GtkWidget * create_animated_dot_widget(int hits)
std::string best_connection_display_name(const std::string &app_comm, const std::string &app_path, const std::vector< std::string > &app_args, const std::string &dst_ip, const std::string &src_ip)
bool is_safe_local_connection(const std::string &dst_ip, const std::string &src_ip)
std::vector< std::string > app_args
Gtk::TreeModelColumn< Glib::ustring > col_country
Gtk::TreeModelColumn< Glib::ustring > col_app
Gtk::TreeModelColumn< uint32_t > col_hits
Gtk::TreeModelColumn< Glib::ustring > col_isp
Gtk::TreeModelColumn< Glib::ustring > col_host
Gtk::TreeModelColumn< Glib::ustring > col_city
Gtk::TreeModelColumn< Glib::ustring > col_ip
std::chrono::steady_clock::time_point last_seen