@clduab11/gemini-flow
Version:
Revolutionary AI agent swarm coordination platform with Google Services integration, multimedia processing, and production-ready monitoring. Features 8 Google AI services, quantum computing capabilities, and enterprise-grade security.
1,202 lines (1,048 loc) • 33.1 kB
text/typescript
/**
* A2A Rate Limiter and DDoS Protection System
*
* Implements advanced rate limiting and DDoS protection:
* - Token bucket algorithm with burst capacity
* - Sliding window rate limiting
* - Adaptive throttling based on system load
* - Circuit breakers for fault isolation
* - Geofencing and IP reputation scoring
* - Behavioral analysis for anomaly detection
* - Distributed rate limiting across nodes
* - Auto-scaling thresholds and backpressure
*/
import { EventEmitter } from "events";
import { Logger } from "../utils/logger.js";
import { CacheManager } from "./cache-manager.js";
export interface RateLimitRule {
ruleId: string;
name: string;
agentPattern: string | RegExp;
limits: {
requestsPerSecond: number;
requestsPerMinute: number;
requestsPerHour: number;
requestsPerDay: number;
burstCapacity: number;
concurrentRequests: number;
};
priority: number;
enabled: boolean;
exemptions?: string[];
conditions?: {
timeWindows?: string[];
messageTypes?: string[];
capabilities?: string[];
};
}
export interface CircuitBreakerConfig {
failureThreshold: number;
recoveryTimeout: number;
halfOpenMaxRequests: number;
monitoringWindow: number;
autoRecovery: boolean;
}
export interface AdaptiveThrottlingConfig {
enabled: boolean;
cpuThreshold: number;
memoryThreshold: number;
responseTimeThreshold: number;
backpressureMultiplier: number;
recoveryRate: number;
}
export interface DDoSProtectionConfig {
enabled: boolean;
detectionWindow: number;
anomalyThreshold: number;
behaviorAnalysis: boolean;
ipReputation: boolean;
geofencing: {
enabled: boolean;
allowedRegions: string[];
blockedRegions: string[];
};
autoMitigation: {
enabled: boolean;
blockDuration: number;
escalationLevels: number[];
};
}
export interface RateLimitingConfig {
defaultLimits: {
requestsPerSecond: number;
requestsPerMinute: number;
requestsPerHour: number;
requestsPerDay: number;
burstCapacity: number;
concurrentRequests: number;
};
circuitBreaker: CircuitBreakerConfig;
adaptiveThrottling: AdaptiveThrottlingConfig;
ddosProtection: DDoSProtectionConfig;
distributedMode: {
enabled: boolean;
syncInterval: number;
consensusThreshold: number;
};
monitoring: {
metricsWindow: number;
alertThresholds: {
highUsage: number;
rateLimitHit: number;
ddosDetected: number;
};
};
}
export interface RateLimitState {
agentId: string;
tokens: number;
lastRefill: number;
requestCounts: {
perSecond: number[];
perMinute: number[];
perHour: number[];
perDay: number[];
};
concurrentRequests: number;
circuitState: "closed" | "open" | "half-open";
lastCircuitStateChange: number;
reputationScore: number;
behaviorProfile: BehaviorProfile;
}
export interface BehaviorProfile {
requestPatterns: Map<string, number>;
timeDistribution: number[];
messageTypeDistribution: Map<string, number>;
averagePayloadSize: number;
errorRate: number;
suspiciousBehaviorCount: number;
lastAnalysis: number;
}
export interface RateLimitResult {
allowed: boolean;
reason?: string;
retryAfter?: number;
tokensRemaining?: number;
quotaResetTime?: number;
circuitState?: string;
adaptiveMultiplier?: number;
}
export interface SystemMetrics {
cpuUsage: number;
memoryUsage: number;
averageResponseTime: number;
activeConnections: number;
requestRate: number;
errorRate: number;
timestamp: number;
}
export class A2ARateLimiter extends EventEmitter {
private logger: Logger;
private cache: CacheManager;
private config: RateLimitingConfig;
// Rate limiting state
private rateLimitRules: Map<string, RateLimitRule> = new Map();
private agentStates: Map<string, RateLimitState> = new Map();
private globalState: RateLimitState;
// Circuit breakers
private circuitBreakers: Map<string, CircuitBreakerState> = new Map();
// System monitoring
private systemMetrics: SystemMetrics;
private metricsHistory: SystemMetrics[] = [];
// DDoS protection
private suspiciousIPs: Map<string, SuspiciousActivity> = new Map();
private behaviorAnalyzer: BehaviorAnalyzer;
private ipReputationService: IPReputationService;
// Adaptive throttling
private adaptiveMultiplier: number = 1.0;
private lastAdaptiveAdjustment: number = 0;
// Performance metrics
private processingMetrics = {
requestsProcessed: 0,
requestsBlocked: 0,
ddosAttacksDetected: 0,
circuitBreakersTripped: 0,
adaptiveAdjustments: 0,
averageProcessingTime: 0,
};
constructor(config: Partial<RateLimitingConfig> = {}) {
super();
this.logger = new Logger("A2ARateLimiter");
this.cache = new CacheManager();
this.initializeConfig(config);
this.initializeGlobalState();
this.initializeDefaultRules();
this.initializeSystemMonitoring();
this.initializeDDoSProtection();
this.startMaintenanceTasks();
this.logger.info("A2A Rate Limiter initialized", {
adaptiveThrottling: this.config.adaptiveThrottling.enabled,
ddosProtection: this.config.ddosProtection.enabled,
distributedMode: this.config.distributedMode.enabled,
});
}
/**
* Initialize configuration with defaults
*/
private initializeConfig(config: Partial<RateLimitingConfig>): void {
this.config = {
defaultLimits: {
requestsPerSecond: 10,
requestsPerMinute: 100,
requestsPerHour: 1000,
requestsPerDay: 10000,
burstCapacity: 20,
concurrentRequests: 5,
},
circuitBreaker: {
failureThreshold: 5,
recoveryTimeout: 60000,
halfOpenMaxRequests: 3,
monitoringWindow: 30000,
autoRecovery: true,
},
adaptiveThrottling: {
enabled: true,
cpuThreshold: 80,
memoryThreshold: 85,
responseTimeThreshold: 1000,
backpressureMultiplier: 0.5,
recoveryRate: 0.1,
},
ddosProtection: {
enabled: true,
detectionWindow: 60000,
anomalyThreshold: 3,
behaviorAnalysis: true,
ipReputation: true,
geofencing: {
enabled: false,
allowedRegions: [],
blockedRegions: [],
},
autoMitigation: {
enabled: true,
blockDuration: 300000,
escalationLevels: [1, 2, 5, 10],
},
},
distributedMode: {
enabled: false,
syncInterval: 10000,
consensusThreshold: 0.6,
},
monitoring: {
metricsWindow: 300000,
alertThresholds: {
highUsage: 0.8,
rateLimitHit: 0.1,
ddosDetected: 0.05,
},
},
...config,
};
}
/**
* Initialize global rate limiting state
*/
private initializeGlobalState(): void {
this.globalState = {
agentId: "global",
tokens: this.config.defaultLimits.burstCapacity,
lastRefill: Date.now(),
requestCounts: {
perSecond: new Array(60).fill(0),
perMinute: new Array(60).fill(0),
perHour: new Array(24).fill(0),
perDay: new Array(7).fill(0),
},
concurrentRequests: 0,
circuitState: "closed",
lastCircuitStateChange: Date.now(),
reputationScore: 1.0,
behaviorProfile: {
requestPatterns: new Map(),
timeDistribution: new Array(24).fill(0),
messageTypeDistribution: new Map(),
averagePayloadSize: 0,
errorRate: 0,
suspiciousBehaviorCount: 0,
lastAnalysis: Date.now(),
},
};
}
/**
* Initialize default rate limiting rules
*/
private initializeDefaultRules(): void {
const defaultRule: RateLimitRule = {
ruleId: "default",
name: "Default Rate Limit",
agentPattern: ".*",
limits: this.config.defaultLimits,
priority: 0,
enabled: true,
};
this.rateLimitRules.set("default", defaultRule);
// High priority agents get higher limits
const highPriorityRule: RateLimitRule = {
ruleId: "high-priority",
name: "High Priority Agents",
agentPattern: "(coordinator|security|monitor).*",
limits: {
requestsPerSecond: 50,
requestsPerMinute: 500,
requestsPerHour: 5000,
requestsPerDay: 50000,
burstCapacity: 100,
concurrentRequests: 20,
},
priority: 10,
enabled: true,
};
this.rateLimitRules.set("high-priority", highPriorityRule);
// Strict limits for untrusted agents
const untrustedRule: RateLimitRule = {
ruleId: "untrusted",
name: "Untrusted Agents",
agentPattern: "untrusted-.*",
limits: {
requestsPerSecond: 2,
requestsPerMinute: 20,
requestsPerHour: 200,
requestsPerDay: 1000,
burstCapacity: 5,
concurrentRequests: 2,
},
priority: 20,
enabled: true,
};
this.rateLimitRules.set("untrusted", untrustedRule);
}
/**
* Initialize system monitoring
*/
private initializeSystemMonitoring(): void {
this.systemMetrics = {
cpuUsage: 0,
memoryUsage: 0,
averageResponseTime: 0,
activeConnections: 0,
requestRate: 0,
errorRate: 0,
timestamp: Date.now(),
};
// Start system metrics collection
setInterval(() => {
this.collectSystemMetrics();
}, 5000);
}
/**
* Initialize DDoS protection components
*/
private initializeDDoSProtection(): void {
this.behaviorAnalyzer = new BehaviorAnalyzer(this.config.ddosProtection);
this.ipReputationService = new IPReputationService(
this.config.ddosProtection,
);
}
/**
* Check if request is allowed under rate limits
*/
async checkRateLimit(
agentId: string,
messageType: string = "request",
payloadSize: number = 0,
sourceIP?: string,
): Promise<RateLimitResult> {
const startTime = Date.now();
try {
// Get or create agent state
let agentState = this.agentStates.get(agentId);
if (!agentState) {
agentState = this.createAgentState(agentId);
this.agentStates.set(agentId, agentState);
}
// Check circuit breaker state
if (agentState.circuitState === "open") {
const timeSinceOpen = Date.now() - agentState.lastCircuitStateChange;
if (timeSinceOpen < this.config.circuitBreaker.recoveryTimeout) {
this.processingMetrics.requestsBlocked++;
return {
allowed: false,
reason: "Circuit breaker open",
retryAfter:
this.config.circuitBreaker.recoveryTimeout - timeSinceOpen,
circuitState: "open",
};
} else {
// Transition to half-open
agentState.circuitState = "half-open";
agentState.lastCircuitStateChange = Date.now();
}
}
// DDoS protection checks
if (this.config.ddosProtection.enabled && sourceIP) {
const ddosResult = await this.checkDDoSProtection(
agentId,
sourceIP,
messageType,
payloadSize,
);
if (!ddosResult.allowed) {
this.processingMetrics.requestsBlocked++;
return ddosResult;
}
}
// Find applicable rate limit rule
let rule = this.findApplicableRule(agentId);
if (!rule || !rule.enabled) {
// No rule applies, use default limits
rule = this.rateLimitRules.get("default")!;
}
// Apply adaptive throttling
const adaptiveLimits = this.applyAdaptiveThrottling(rule.limits);
// Token bucket algorithm for burst control
const tokenResult = this.checkTokenBucket(
agentState,
rule,
adaptiveLimits,
);
if (!tokenResult.allowed) {
this.processingMetrics.requestsBlocked++;
return tokenResult;
}
// Sliding window rate limiting
const windowResult = this.checkSlidingWindows(
agentState,
rule,
adaptiveLimits,
);
if (!windowResult.allowed) {
this.processingMetrics.requestsBlocked++;
return windowResult;
}
// Concurrent request limiting
const concurrentResult = this.checkConcurrentRequests(
agentState,
adaptiveLimits,
);
if (!concurrentResult.allowed) {
this.processingMetrics.requestsBlocked++;
return concurrentResult;
}
// Update behavior profile
this.updateBehaviorProfile(agentState, messageType, payloadSize);
// Consume token and update counters
agentState.tokens--;
agentState.concurrentRequests++;
this.updateRequestCounters(agentState);
this.processingMetrics.requestsProcessed++;
// Update performance metrics
const processingTime = Date.now() - startTime;
this.processingMetrics.averageProcessingTime =
(this.processingMetrics.averageProcessingTime + processingTime) / 2;
this.logger.debug("Rate limit check passed", {
agentId,
tokensRemaining: agentState.tokens,
processingTime,
});
return {
allowed: true,
tokensRemaining: agentState.tokens,
quotaResetTime: this.calculateQuotaResetTime(agentState),
circuitState: agentState.circuitState,
adaptiveMultiplier: this.adaptiveMultiplier,
};
} catch (error) {
this.logger.error("Rate limit check failed", { agentId, error });
// Fail open for availability
return {
allowed: true,
reason: "Rate limiter error - failing open",
};
}
}
/**
* Release resources when request completes
*/
async releaseRequest(
agentId: string,
success: boolean = true,
): Promise<void> {
const agentState = this.agentStates.get(agentId);
if (!agentState) return;
// Decrement concurrent requests
agentState.concurrentRequests = Math.max(
0,
agentState.concurrentRequests - 1,
);
// Update circuit breaker based on success/failure
if (agentState.circuitState === "half-open") {
if (success) {
agentState.circuitState = "closed";
agentState.lastCircuitStateChange = Date.now();
} else {
agentState.circuitState = "open";
agentState.lastCircuitStateChange = Date.now();
this.processingMetrics.circuitBreakersTripped++;
}
} else if (!success) {
// Track failures for circuit breaker
this.trackFailure(agentState);
}
// Update behavior profile
if (!success) {
agentState.behaviorProfile.errorRate =
agentState.behaviorProfile.errorRate * 0.9 + 1 * 0.1;
}
}
/**
* Check DDoS protection measures
*/
private async checkDDoSProtection(
agentId: string,
sourceIP: string,
messageType: string,
payloadSize: number,
): Promise<RateLimitResult> {
// IP reputation check
if (this.config.ddosProtection.ipReputation) {
const reputation = await this.ipReputationService.getReputation(sourceIP);
if (reputation < 0.5) {
return {
allowed: false,
reason: "Low IP reputation score",
retryAfter: this.config.ddosProtection.autoMitigation.blockDuration,
};
}
}
// Behavior analysis
if (this.config.ddosProtection.behaviorAnalysis) {
const agentState = this.agentStates.get(agentId);
if (agentState) {
const anomalyScore = await this.behaviorAnalyzer.analyzeRequest(
agentState.behaviorProfile,
messageType,
payloadSize,
Date.now(),
);
if (anomalyScore > this.config.ddosProtection.anomalyThreshold) {
this.processingMetrics.ddosAttacksDetected++;
this.emit("ddos_detected", {
agentId,
sourceIP,
anomalyScore,
timestamp: Date.now(),
});
return {
allowed: false,
reason: "Anomalous behavior detected",
retryAfter: this.config.ddosProtection.autoMitigation.blockDuration,
};
}
}
}
// Geofencing check
if (this.config.ddosProtection.geofencing.enabled) {
const region = await this.getIPRegion(sourceIP);
if (
this.config.ddosProtection.geofencing.blockedRegions.includes(region)
) {
return {
allowed: false,
reason: "Geographic region blocked",
retryAfter: this.config.ddosProtection.autoMitigation.blockDuration,
};
}
if (
this.config.ddosProtection.geofencing.allowedRegions.length > 0 &&
!this.config.ddosProtection.geofencing.allowedRegions.includes(region)
) {
return {
allowed: false,
reason: "Geographic region not allowed",
retryAfter: this.config.ddosProtection.autoMitigation.blockDuration,
};
}
}
return { allowed: true };
}
/**
* Token bucket rate limiting check
*/
private checkTokenBucket(
agentState: RateLimitState,
rule: RateLimitRule,
limits: typeof rule.limits,
): RateLimitResult {
const now = Date.now();
const timeSinceLastRefill = now - agentState.lastRefill;
// Refill tokens based on time elapsed
const tokensToAdd = Math.floor(
(timeSinceLastRefill / 1000) * limits.requestsPerSecond,
);
if (tokensToAdd > 0) {
agentState.tokens = Math.min(
limits.burstCapacity,
agentState.tokens + tokensToAdd,
);
agentState.lastRefill = now;
}
// Check if tokens are available
if (agentState.tokens <= 0) {
const refillTime = (1 / limits.requestsPerSecond) * 1000;
return {
allowed: false,
reason: "Rate limit exceeded - no tokens available",
retryAfter: refillTime,
tokensRemaining: 0,
};
}
return { allowed: true };
}
/**
* Sliding window rate limiting check
*/
private checkSlidingWindows(
agentState: RateLimitState,
rule: RateLimitRule,
limits: typeof rule.limits,
): RateLimitResult {
const now = Date.now();
const currentSecond = Math.floor(now / 1000) % 60;
// Check per-second limit
const recentSecondsCount = agentState.requestCounts.perSecond
.slice(Math.max(0, currentSecond - 1), currentSecond + 1)
.reduce((sum, count) => sum + count, 0);
if (recentSecondsCount >= limits.requestsPerSecond) {
return {
allowed: false,
reason: "Per-second rate limit exceeded",
retryAfter: 1000,
};
}
// Check per-minute limit
const recentMinutesCount = agentState.requestCounts.perMinute.reduce(
(sum, count) => sum + count,
0,
);
if (recentMinutesCount >= limits.requestsPerMinute) {
return {
allowed: false,
reason: "Per-minute rate limit exceeded",
retryAfter: 60000,
};
}
// Check per-hour limit
const recentHoursCount = agentState.requestCounts.perHour.reduce(
(sum, count) => sum + count,
0,
);
if (recentHoursCount >= limits.requestsPerHour) {
return {
allowed: false,
reason: "Per-hour rate limit exceeded",
retryAfter: 3600000,
};
}
// Check per-day limit
const recentDaysCount = agentState.requestCounts.perDay.reduce(
(sum, count) => sum + count,
0,
);
if (recentDaysCount >= limits.requestsPerDay) {
return {
allowed: false,
reason: "Per-day rate limit exceeded",
retryAfter: 86400000,
};
}
return { allowed: true };
}
/**
* Concurrent request limiting check
*/
private checkConcurrentRequests(
agentState: RateLimitState,
limits: typeof this.config.defaultLimits,
): RateLimitResult {
if (agentState.concurrentRequests >= limits.concurrentRequests) {
return {
allowed: false,
reason: "Concurrent request limit exceeded",
retryAfter: 1000,
};
}
return { allowed: true };
}
/**
* Apply adaptive throttling based on system metrics
*/
private applyAdaptiveThrottling(
baseLimits: typeof this.config.defaultLimits,
): typeof this.config.defaultLimits {
if (!this.config.adaptiveThrottling.enabled) {
return baseLimits;
}
// Check if adaptive adjustment is needed
const now = Date.now();
if (now - this.lastAdaptiveAdjustment < 10000) {
// Use cached multiplier
return this.multiplyLimits(baseLimits, this.adaptiveMultiplier);
}
let shouldThrottle = false;
// Check CPU usage
if (
this.systemMetrics.cpuUsage > this.config.adaptiveThrottling.cpuThreshold
) {
shouldThrottle = true;
}
// Check memory usage
if (
this.systemMetrics.memoryUsage >
this.config.adaptiveThrottling.memoryThreshold
) {
shouldThrottle = true;
}
// Check response time
if (
this.systemMetrics.averageResponseTime >
this.config.adaptiveThrottling.responseTimeThreshold
) {
shouldThrottle = true;
}
// Adjust multiplier
if (shouldThrottle) {
this.adaptiveMultiplier = Math.max(
0.1,
this.adaptiveMultiplier *
this.config.adaptiveThrottling.backpressureMultiplier,
);
this.processingMetrics.adaptiveAdjustments++;
} else {
// Gradually recover
this.adaptiveMultiplier = Math.min(
1.0,
this.adaptiveMultiplier + this.config.adaptiveThrottling.recoveryRate,
);
}
this.lastAdaptiveAdjustment = now;
return this.multiplyLimits(baseLimits, this.adaptiveMultiplier);
}
/**
* Helper methods
*/
private createAgentState(agentId: string): RateLimitState {
return {
agentId,
tokens: this.config.defaultLimits.burstCapacity,
lastRefill: Date.now(),
requestCounts: {
perSecond: new Array(60).fill(0),
perMinute: new Array(60).fill(0),
perHour: new Array(24).fill(0),
perDay: new Array(7).fill(0),
},
concurrentRequests: 0,
circuitState: "closed",
lastCircuitStateChange: Date.now(),
reputationScore: 1.0,
behaviorProfile: {
requestPatterns: new Map(),
timeDistribution: new Array(24).fill(0),
messageTypeDistribution: new Map(),
averagePayloadSize: 0,
errorRate: 0,
suspiciousBehaviorCount: 0,
lastAnalysis: Date.now(),
},
};
}
private findApplicableRule(agentId: string): RateLimitRule | null {
let bestRule: RateLimitRule | null = null;
let highestPriority = -1;
for (const rule of this.rateLimitRules.values()) {
if (!rule.enabled) continue;
const pattern =
typeof rule.agentPattern === "string"
? new RegExp(rule.agentPattern)
: rule.agentPattern;
if (pattern.test(agentId) && rule.priority > highestPriority) {
bestRule = rule;
highestPriority = rule.priority;
}
}
return bestRule;
}
private multiplyLimits(
limits: typeof this.config.defaultLimits,
multiplier: number,
): typeof this.config.defaultLimits {
return {
requestsPerSecond: Math.floor(limits.requestsPerSecond * multiplier),
requestsPerMinute: Math.floor(limits.requestsPerMinute * multiplier),
requestsPerHour: Math.floor(limits.requestsPerHour * multiplier),
requestsPerDay: Math.floor(limits.requestsPerDay * multiplier),
burstCapacity: Math.floor(limits.burstCapacity * multiplier),
concurrentRequests: Math.floor(limits.concurrentRequests * multiplier),
};
}
private updateRequestCounters(agentState: RateLimitState): void {
const now = Date.now();
const currentSecond = Math.floor(now / 1000) % 60;
const currentMinute = Math.floor(now / 60000) % 60;
const currentHour = Math.floor(now / 3600000) % 24;
const currentDay = Math.floor(now / 86400000) % 7;
agentState.requestCounts.perSecond[currentSecond]++;
agentState.requestCounts.perMinute[currentMinute]++;
agentState.requestCounts.perHour[currentHour]++;
agentState.requestCounts.perDay[currentDay]++;
}
private updateBehaviorProfile(
agentState: RateLimitState,
messageType: string,
payloadSize: number,
): void {
const profile = agentState.behaviorProfile;
const now = Date.now();
const hour = new Date(now).getHours();
// Update message type distribution
const currentCount = profile.messageTypeDistribution.get(messageType) || 0;
profile.messageTypeDistribution.set(messageType, currentCount + 1);
// Update time distribution
profile.timeDistribution[hour]++;
// Update average payload size
profile.averagePayloadSize = (profile.averagePayloadSize + payloadSize) / 2;
// Update last analysis time
profile.lastAnalysis = now;
}
private trackFailure(agentState: RateLimitState): void {
const circuitBreaker = this.getOrCreateCircuitBreaker(agentState.agentId);
circuitBreaker.failures++;
if (
circuitBreaker.failures >= this.config.circuitBreaker.failureThreshold
) {
agentState.circuitState = "open";
agentState.lastCircuitStateChange = Date.now();
circuitBreaker.failures = 0;
this.processingMetrics.circuitBreakersTripped++;
this.emit("circuit_breaker_opened", {
agentId: agentState.agentId,
timestamp: Date.now(),
});
}
}
private getOrCreateCircuitBreaker(agentId: string): CircuitBreakerState {
let circuitBreaker = this.circuitBreakers.get(agentId);
if (!circuitBreaker) {
circuitBreaker = {
failures: 0,
lastFailure: 0,
halfOpenRequests: 0,
};
this.circuitBreakers.set(agentId, circuitBreaker);
}
return circuitBreaker;
}
private calculateQuotaResetTime(_agentState: RateLimitState): number {
// Calculate when the next token will be available
const refillRate = this.config.defaultLimits.requestsPerSecond;
const refillInterval = 1000 / refillRate;
return Date.now() + refillInterval;
}
private async getIPRegion(_ip: string): Promise<string> {
// Placeholder for IP geolocation service
// In production, integrate with MaxMind, IPinfo, or similar service
return "unknown";
}
private collectSystemMetrics(): void {
// Collect system metrics
// In production, integrate with system monitoring tools
this.systemMetrics = {
cpuUsage: Math.random() * 100, // Placeholder
memoryUsage: Math.random() * 100, // Placeholder
averageResponseTime: Math.random() * 1000, // Placeholder
activeConnections: this.agentStates.size,
requestRate: this.processingMetrics.requestsProcessed / 60,
errorRate:
this.processingMetrics.requestsBlocked /
this.processingMetrics.requestsProcessed,
timestamp: Date.now(),
};
// Store metrics history
this.metricsHistory.push(this.systemMetrics);
// Limit history size
if (this.metricsHistory.length > 100) {
this.metricsHistory = this.metricsHistory.slice(-50);
}
this.emit("system_metrics", this.systemMetrics);
}
private startMaintenanceTasks(): void {
// Cleanup old agent states
setInterval(() => {
this.cleanupOldStates();
}, 300000); // 5 minutes
// Reset request counters
setInterval(() => {
this.resetCounters();
}, 60000); // 1 minute
// Sync with distributed nodes
if (this.config.distributedMode.enabled) {
setInterval(() => {
this.syncWithDistributedNodes();
}, this.config.distributedMode.syncInterval);
}
}
private cleanupOldStates(): void {
const now = Date.now();
const maxAge = 24 * 60 * 60 * 1000; // 24 hours
for (const [agentId, state] of this.agentStates) {
if (now - state.lastRefill > maxAge && state.concurrentRequests === 0) {
this.agentStates.delete(agentId);
this.circuitBreakers.delete(agentId);
}
}
this.logger.debug("Cleaned up old agent states", {
remaining: this.agentStates.size,
});
}
private resetCounters(): void {
const now = Date.now();
const currentSecond = Math.floor(now / 1000) % 60;
const currentMinute = Math.floor(now / 60000) % 60;
const currentHour = Math.floor(now / 3600000) % 24;
const currentDay = Math.floor(now / 86400000) % 7;
for (const state of this.agentStates.values()) {
// Reset old time windows
if (Math.floor((now - 60000) / 1000) % 60 !== currentSecond) {
state.requestCounts.perSecond[(currentSecond + 1) % 60] = 0;
}
if (Math.floor((now - 60000) / 60000) % 60 !== currentMinute) {
state.requestCounts.perMinute[(currentMinute + 1) % 60] = 0;
}
if (Math.floor((now - 3600000) / 3600000) % 24 !== currentHour) {
state.requestCounts.perHour[(currentHour + 1) % 24] = 0;
}
if (Math.floor((now - 86400000) / 86400000) % 7 !== currentDay) {
state.requestCounts.perDay[(currentDay + 1) % 7] = 0;
}
}
}
private async syncWithDistributedNodes(): Promise<void> {
// Placeholder for distributed synchronization
// In production, implement consensus mechanism for rate limiting state
this.logger.debug("Syncing with distributed nodes");
}
/**
* Public API methods
*/
addRule(rule: RateLimitRule): void {
this.rateLimitRules.set(rule.ruleId, rule);
this.logger.info("Rate limit rule added", {
ruleId: rule.ruleId,
name: rule.name,
});
}
removeRule(ruleId: string): boolean {
const removed = this.rateLimitRules.delete(ruleId);
if (removed) {
this.logger.info("Rate limit rule removed", { ruleId });
}
return removed;
}
getRules(): RateLimitRule[] {
return Array.from(this.rateLimitRules.values());
}
getAgentState(agentId: string): RateLimitState | null {
return this.agentStates.get(agentId) || null;
}
getSystemMetrics(): SystemMetrics {
return { ...this.systemMetrics };
}
getProcessingMetrics() {
return { ...this.processingMetrics };
}
async blockAgent(agentId: string, duration: number = 300000): Promise<void> {
const agentState = this.agentStates.get(agentId);
if (agentState) {
agentState.circuitState = "open";
agentState.lastCircuitStateChange = Date.now();
// Auto-unblock after duration
setTimeout(() => {
const state = this.agentStates.get(agentId);
if (state && state.circuitState === "open") {
state.circuitState = "closed";
state.lastCircuitStateChange = Date.now();
}
}, duration);
this.logger.warn("Agent blocked", { agentId, duration });
this.emit("agent_blocked", { agentId, duration, timestamp: Date.now() });
}
}
async unblockAgent(agentId: string): Promise<void> {
const agentState = this.agentStates.get(agentId);
if (agentState) {
agentState.circuitState = "closed";
agentState.lastCircuitStateChange = Date.now();
this.logger.info("Agent unblocked", { agentId });
this.emit("agent_unblocked", { agentId, timestamp: Date.now() });
}
}
}
// Supporting interfaces and classes
interface CircuitBreakerState {
failures: number;
lastFailure: number;
halfOpenRequests: number;
}
interface SuspiciousActivity {
ip: string;
detectedAt: number;
severity: number;
patterns: string[];
}
class BehaviorAnalyzer {
constructor(private config: DDoSProtectionConfig) {}
async analyzeRequest(
profile: BehaviorProfile,
messageType: string,
payloadSize: number,
timestamp: number,
): Promise<number> {
let anomalyScore = 0;
// Check message type patterns
const messageTypeCount =
profile.messageTypeDistribution.get(messageType) || 0;
const totalMessages = Array.from(
profile.messageTypeDistribution.values(),
).reduce((sum, count) => sum + count, 0);
if (totalMessages > 0) {
const messageTypeRatio = messageTypeCount / totalMessages;
if (messageTypeRatio > 0.9) {
anomalyScore += 1;
}
}
// Check payload size anomalies
if (payloadSize > profile.averagePayloadSize * 10) {
anomalyScore += 2;
}
// Check time-based patterns
const hour = new Date(timestamp).getHours();
const hourlyRequests = profile.timeDistribution[hour];
const avgHourlyRequests =
profile.timeDistribution.reduce((sum, count) => sum + count, 0) / 24;
if (hourlyRequests > avgHourlyRequests * 5) {
anomalyScore += 1;
}
return anomalyScore;
}
}
class IPReputationService {
constructor(private config: DDoSProtectionConfig) {}
async getReputation(_ip: string): Promise<number> {
// Placeholder for IP reputation service
// In production, integrate with threat intelligence feeds
return Math.random();
}
}