use std::collections::VecDeque; use xdp_firewall_common::{FirewallEvent, RuleKey, RuleValue, Stats}; #[derive(Clone, Copy, PartialEq, Eq)] pub enum Pane { Rules, Blocklist, Logs, } pub struct App { pub iface: String, pub quit: bool, pub pane: Pane, pub global_stats: Stats, pub prev_global_stats: Stats, pub rules: Vec<(RuleKey, RuleValue, Stats)>, pub blocklist: Vec<(u32, u64)>, pub logs: VecDeque, pub max_logs: usize, pub pps: u64, pub bps: u64, pub dialog: Dialog, pub rules_selected: usize, pub blocklist_selected: usize, } #[derive(Clone, Default, PartialEq, Eq)] pub enum Dialog { #[default] None, BlockIp { input: String }, AddRule { src_ip: String, dst_ip: String, proto: String, src_port: String, dst_port: String, action: String }, ConfirmDelete, } impl App { pub fn new(iface: String) -> Self { Self { iface, quit: false, pane: Pane::Rules, global_stats: Stats::default(), prev_global_stats: Stats::default(), rules: Vec::new(), blocklist: Vec::new(), logs: VecDeque::new(), max_logs: 100, pps: 0, bps: 0, dialog: Dialog::None, rules_selected: 0, blocklist_selected: 0, } } pub fn on_tick(&mut self, global: Stats, rules: Vec<(RuleKey, RuleValue, Stats)>, blocklist: Vec<(u32, u64)>) { let elapsed = 0.1; let pkts = global.packets.saturating_sub(self.prev_global_stats.packets); let bytes = global.bytes.saturating_sub(self.prev_global_stats.bytes); self.pps = (pkts as f64 / elapsed) as u64; self.bps = (bytes as f64 / elapsed) as u64; self.prev_global_stats = self.global_stats; self.global_stats = global; self.rules = rules; self.blocklist = blocklist; } pub fn add_log(&mut self, ev: FirewallEvent) { if self.logs.len() >= self.max_logs { self.logs.pop_back(); } self.logs.push_front(ev); } pub fn selected_rule_id(&self) -> Option { self.rules.get(self.rules_selected).map(|(_, v, _)| v.rule_id) } pub fn selected_block_ip(&self) -> Option { self.blocklist.get(self.blocklist_selected).map(|(ip, _)| *ip) } }