netrain 0.2.8

Matrix-style network packet monitor with IP tracking, threat detection and real-time visualization
Documentation
// Protocol activity tracking for time-series visualization

use std::collections::VecDeque;
use crate::Protocol;

const HISTORY_SIZE: usize = 60; // Keep 60 time slices

#[derive(Debug, Clone)]
pub struct ProtocolSnapshot {
    pub tcp: u64,
    pub udp: u64,
    pub http: u64,
    pub https: u64,
    pub dns: u64,
    pub ssh: u64,
    pub unknown: u64,
    pub total: u64,
}

impl ProtocolSnapshot {
    fn new() -> Self {
        Self {
            tcp: 0,
            udp: 0,
            http: 0,
            https: 0,
            dns: 0,
            ssh: 0,
            unknown: 0,
            total: 0,
        }
    }
}

pub struct ProtocolActivityTracker {
    history: VecDeque<ProtocolSnapshot>,
    current: ProtocolSnapshot,
}

impl ProtocolActivityTracker {
    pub fn new() -> Self {
        Self {
            history: VecDeque::with_capacity(HISTORY_SIZE),
            current: ProtocolSnapshot::new(),
        }
    }
    
    pub fn record_packet(&mut self, protocol: Protocol) {
        match protocol {
            Protocol::TCP => self.current.tcp += 1,
            Protocol::UDP => self.current.udp += 1,
            Protocol::HTTP => self.current.http += 1,
            Protocol::HTTPS => self.current.https += 1,
            Protocol::DNS => self.current.dns += 1,
            Protocol::SSH => self.current.ssh += 1,
            Protocol::Unknown => self.current.unknown += 1,
        }
        self.current.total += 1;
    }
    
    pub fn tick(&mut self) {
        // Push current snapshot to history and reset
        self.history.push_back(self.current.clone());
        if self.history.len() > HISTORY_SIZE {
            self.history.pop_front();
        }
        self.current = ProtocolSnapshot::new();
    }
    
    pub fn get_history(&self) -> &VecDeque<ProtocolSnapshot> {
        &self.history
    }
    
    pub fn get_sparkline_data(&self, protocol: Protocol) -> Vec<u64> {
        // Include current snapshot for real-time display
        let mut data: Vec<u64> = self.history.iter().map(|snapshot| {
            match protocol {
                Protocol::TCP => snapshot.tcp,
                Protocol::UDP => snapshot.udp,
                Protocol::HTTP => snapshot.http,
                Protocol::HTTPS => snapshot.https,
                Protocol::DNS => snapshot.dns,
                Protocol::SSH => snapshot.ssh,
                Protocol::Unknown => snapshot.unknown,
            }
        }).collect();
        
        // Add current snapshot value for immediate feedback
        data.push(match protocol {
            Protocol::TCP => self.current.tcp,
            Protocol::UDP => self.current.udp,
            Protocol::HTTP => self.current.http,
            Protocol::HTTPS => self.current.https,
            Protocol::DNS => self.current.dns,
            Protocol::SSH => self.current.ssh,
            Protocol::Unknown => self.current.unknown,
        });
        
        // Pad with zeros at the beginning if we don't have enough history
        while data.len() < 20 {
            data.insert(0, 0);
        }
        
        // Return last 20 values for display
        if data.len() > 20 {
            data.split_off(data.len() - 20)
        } else {
            data
        }
    }
    
    pub fn get_max_value(&self) -> u64 {
        let history_max = self.history.iter()
            .map(|s| s.total)
            .max()
            .unwrap_or(0);
        
        // Include current snapshot in max calculation
        history_max.max(self.current.total).max(1)
    }
}