Kraft102's picture
fix: sql.js Docker/Alpine compatibility layer for PatternMemory and FailureMemory
5a81b95
import { useState, useEffect, useCallback } from 'react';
import { useNotifications, NotificationSeverity } from '@/contexts/NotificationContext';
export type MetricType =
| 'threat_count'
| 'cpu_usage'
| 'memory_usage'
| 'network_traffic'
| 'failed_logins'
| 'active_connections'
| 'response_time'
| 'error_rate';
export type Operator = 'gt' | 'lt' | 'eq' | 'gte' | 'lte';
export interface AlertRule {
id: string;
name: string;
description?: string;
enabled: boolean;
metric: MetricType;
operator: Operator;
threshold: number;
severity: NotificationSeverity;
cooldownMinutes: number;
lastTriggered?: number;
triggerCount: number;
createdAt: number;
}
export interface MetricValue {
metric: MetricType;
value: number;
timestamp: number;
}
const RULES_STORAGE_KEY = 'cyber-alert-rules';
export const METRIC_CONFIG: Record<MetricType, { label: string; unit: string; icon: string }> = {
threat_count: { label: 'Antal trusler', unit: '', icon: 'Shield' },
cpu_usage: { label: 'CPU forbrug', unit: '%', icon: 'Cpu' },
memory_usage: { label: 'Memory forbrug', unit: '%', icon: 'HardDrive' },
network_traffic: { label: 'Netværkstrafik', unit: 'MB/s', icon: 'Network' },
failed_logins: { label: 'Fejlede logins', unit: '', icon: 'UserX' },
active_connections: { label: 'Aktive forbindelser', unit: '', icon: 'Users' },
response_time: { label: 'Responstid', unit: 'ms', icon: 'Clock' },
error_rate: { label: 'Fejlrate', unit: '%', icon: 'AlertCircle' },
};
export const OPERATOR_CONFIG: Record<Operator, { label: string; symbol: string }> = {
gt: { label: 'større end', symbol: '>' },
lt: { label: 'mindre end', symbol: '<' },
eq: { label: 'lig med', symbol: '=' },
gte: { label: 'større end eller lig', symbol: '≥' },
lte: { label: 'mindre end eller lig', symbol: '≤' },
};
// Simulated metric values for demo
const generateMetricValue = (metric: MetricType): number => {
switch (metric) {
case 'threat_count': return Math.floor(Math.random() * 150);
case 'cpu_usage': return Math.floor(Math.random() * 100);
case 'memory_usage': return Math.floor(40 + Math.random() * 50);
case 'network_traffic': return Math.floor(Math.random() * 500);
case 'failed_logins': return Math.floor(Math.random() * 20);
case 'active_connections': return Math.floor(50 + Math.random() * 200);
case 'response_time': return Math.floor(50 + Math.random() * 300);
case 'error_rate': return Math.floor(Math.random() * 15);
default: return 0;
}
};
const evaluateCondition = (value: number, operator: Operator, threshold: number): boolean => {
switch (operator) {
case 'gt': return value > threshold;
case 'lt': return value < threshold;
case 'eq': return value === threshold;
case 'gte': return value >= threshold;
case 'lte': return value <= threshold;
default: return false;
}
};
export const useAlertRules = () => {
const [rules, setRules] = useState<AlertRule[]>([]);
const [currentMetrics, setCurrentMetrics] = useState<Record<MetricType, number>>({} as any);
const { addNotification } = useNotifications();
// Load rules from localStorage
useEffect(() => {
const saved = localStorage.getItem(RULES_STORAGE_KEY);
if (saved) {
try {
setRules(JSON.parse(saved));
} catch (e) {
console.error('Failed to load alert rules:', e);
}
}
}, []);
// Save rules to localStorage
const saveRules = useCallback((newRules: AlertRule[]) => {
localStorage.setItem(RULES_STORAGE_KEY, JSON.stringify(newRules));
setRules(newRules);
}, []);
// Create new rule
const createRule = useCallback((rule: Omit<AlertRule, 'id' | 'triggerCount' | 'createdAt'>): AlertRule => {
const newRule: AlertRule = {
...rule,
id: `rule-${Date.now()}`,
triggerCount: 0,
createdAt: Date.now(),
};
saveRules([...rules, newRule]);
return newRule;
}, [rules, saveRules]);
// Update existing rule
const updateRule = useCallback((ruleId: string, updates: Partial<AlertRule>) => {
saveRules(rules.map(r => r.id === ruleId ? { ...r, ...updates } : r));
}, [rules, saveRules]);
// Delete rule
const deleteRule = useCallback((ruleId: string) => {
saveRules(rules.filter(r => r.id !== ruleId));
}, [rules, saveRules]);
// Toggle rule enabled state
const toggleRule = useCallback((ruleId: string) => {
saveRules(rules.map(r => r.id === ruleId ? { ...r, enabled: !r.enabled } : r));
}, [rules, saveRules]);
// Evaluate all rules against current metrics
const evaluateRules = useCallback((metrics: Record<MetricType, number>) => {
const now = Date.now();
const updatedRules = [...rules];
let hasChanges = false;
rules.forEach((rule, index) => {
if (!rule.enabled) return;
const metricValue = metrics[rule.metric];
if (metricValue === undefined) return;
// Check cooldown
if (rule.lastTriggered) {
const cooldownMs = rule.cooldownMinutes * 60 * 1000;
if (now - rule.lastTriggered < cooldownMs) return;
}
// Evaluate condition
if (evaluateCondition(metricValue, rule.operator, rule.threshold)) {
const config = METRIC_CONFIG[rule.metric];
const opConfig = OPERATOR_CONFIG[rule.operator];
addNotification({
title: `Alert: ${rule.name}`,
message: `${config.label} er ${metricValue}${config.unit} (${opConfig.symbol} ${rule.threshold}${config.unit})`,
severity: rule.severity,
source: 'Alert Rules Engine',
});
updatedRules[index] = {
...rule,
lastTriggered: now,
triggerCount: rule.triggerCount + 1,
};
hasChanges = true;
}
});
if (hasChanges) {
saveRules(updatedRules);
}
}, [rules, addNotification, saveRules]);
// Simulate metric updates (for demo purposes)
useEffect(() => {
const updateMetrics = () => {
const newMetrics: Record<MetricType, number> = {
threat_count: generateMetricValue('threat_count'),
cpu_usage: generateMetricValue('cpu_usage'),
memory_usage: generateMetricValue('memory_usage'),
network_traffic: generateMetricValue('network_traffic'),
failed_logins: generateMetricValue('failed_logins'),
active_connections: generateMetricValue('active_connections'),
response_time: generateMetricValue('response_time'),
error_rate: generateMetricValue('error_rate'),
};
setCurrentMetrics(newMetrics);
evaluateRules(newMetrics);
};
// Initial update
updateMetrics();
// Update every 15 seconds
const interval = setInterval(updateMetrics, 15000);
return () => clearInterval(interval);
}, [evaluateRules]);
return {
rules,
currentMetrics,
createRule,
updateRule,
deleteRule,
toggleRule,
};
};