'use client';
import React, { useState, useEffect, useRef, useMemo } from 'react';
const VIEW_WIDTH = 1000;
const VIEW_HEIGHT = 600;
// ============================================================================
// 1. FIREWALL VISUALIZATION (High Fidelity Replica)
// ============================================================================
// --- Constants & Types ---
interface PacketData {
id: number;
x: number;
y: number;
ip: string;
port: number;
type: 'normal' | 'malicious';
status: 'moving_in' | 'scanning' | 'moving_out' | 'blocked' | 'destroyed';
opacity: number;
}
// --- Sub-Components ---
const PacketNode = ({ data }: { data: PacketData }) => {
let color = '#3b82f6'; // Default Blue
let glowColor = 'rgba(59, 130, 246, 0.5)';
if (data.status === 'scanning') {
color = '#ffffff'; // Bright white/blue during scan
glowColor = 'rgba(255, 255, 255, 0.8)';
} else if (data.status === 'moving_out') {
color = '#4ade80'; // Green (Allowed)
glowColor = 'rgba(74, 222, 128, 0.6)';
} else if (data.status === 'blocked') {
color = '#ef4444'; // Red (Blocked)
glowColor = 'rgba(239, 68, 68, 0.6)';
}
return (
{/* IP Label */}
{data.ip}
{/* Packet Body (Rounded Square) */}
{/* Outer Glow */}
{/* Main Chip */}
{/* Inner Dots (2x2 Grid) */}
{/* Port Label */}
:{data.port}
);
};
const StatCard = ({ icon, label, value, color, subtext }: any) => (
{/* Icon Box */}
{icon}
{/* Text */}
{label}
{value}
{subtext && {subtext}}
);
// --- Main View ---
export const FirewallView = () => {
const [packets, setPackets] = useState([]);
const [stats, setStats] = useState({ total: 0, allowed: 0, blocked: 0, throughput: 0 });
// Animation refs
const requestRef = useRef(0);
const lastTimeRef = useRef(0);
const packetIdRef = useRef(0);
const throughputTimerRef = useRef(0);
// Config
const CENTER_X = VIEW_WIDTH / 2;
const CENTER_Y = 260;
const SCAN_DURATION = 600; // ms
// Spawn Logic
useEffect(() => {
const spawnInterval = setInterval(() => {
const isMalicious = Math.random() > 0.7;
const ports = [443, 80, 8080, 53, 22, 3306];
const ips = [
'192.168.20.16', '192.168.215.213', '10.0.0.55',
'172.16.0.1', '192.168.0.666', '10.10.10.10'
];
const newPacket: PacketData = {
id: packetIdRef.current++,
x: -50,
y: CENTER_Y,
ip: ips[Math.floor(Math.random() * ips.length)],
port: ports[Math.floor(Math.random() * ports.length)],
type: isMalicious ? 'malicious' : 'normal',
status: 'moving_in',
opacity: 1
};
setPackets(prev => [...prev, newPacket]);
setStats(s => ({ ...s, total: s.total + 1 }));
}, 2000); // Spawn rate
return () => clearInterval(spawnInterval);
}, []);
// Throughput Calculation
useEffect(() => {
const tInterval = setInterval(() => {
setStats(s => ({ ...s, throughput: Math.floor(Math.random() * 5) }));
}, 1000);
return () => clearInterval(tInterval);
}, []);
// Animation Loop
const animate = (time: number) => {
if (!lastTimeRef.current) lastTimeRef.current = time;
const dt = time - lastTimeRef.current;
lastTimeRef.current = time;
setPackets(prev => prev.map(p => {
let next = { ...p };
const SPEED = 2;
if (p.status === 'moving_in') {
// Move towards center
next.x += SPEED;
if (next.x >= CENTER_X) {
next.x = CENTER_X;
next.status = 'scanning';
}
}
else if (p.status === 'scanning') {
// Simulate scan delay
if (Math.random() < 0.05) { // ~5% chance per frame to finish scan
if (p.type === 'malicious') {
next.status = 'blocked';
setStats(s => ({ ...s, blocked: s.blocked + 1 }));
} else {
next.status = 'moving_out';
setStats(s => ({ ...s, allowed: s.allowed + 1 }));
}
}
}
else if (p.status === 'moving_out') {
next.x += SPEED;
if (next.x > VIEW_WIDTH + 50) next.status = 'destroyed';
}
else if (p.status === 'blocked') {
// Fade out and drift up
next.y -= 1;
next.opacity -= 0.02;
if (next.opacity <= 0) next.status = 'destroyed';
}
return next;
}).filter(p => p.status !== 'destroyed'));
requestRef.current = requestAnimationFrame(animate);
};
useEffect(() => {
requestRef.current = requestAnimationFrame(animate);
return () => cancelAnimationFrame(requestRef.current);
}, []);
return (
);
};