UNPKG

@casoon/auditmysite

Version:

A comprehensive command-line tool for automated accessibility, security, performance, and SEO testing using Playwright and pa11y, based on sitemap URLs

268 lines 9.62 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.NetworkThrottler = void 0; const events_1 = require("events"); class NetworkThrottler extends events_1.EventEmitter { constructor(config = {}) { super(); this.requestQueue = []; this.activeRequests = new Map(); this.requestHistory = []; this.isThrottling = false; this.lastRequestTime = 0; this.burstCount = 0; this.burstStartTime = Date.now(); this.backoffDelay = 0; this.config = { requestsPerSecond: 10, requestsPerMinute: 600, concurrentRequests: 5, delayBetweenRequests: 100, burstLimit: 20, burstWindow: 1000, enableBackoff: true, backoffMultiplier: 2, maxBackoffDelay: 5000, ...config }; this.stats = { totalRequests: 0, successfulRequests: 0, throttledRequests: 0, failedRequests: 0, averageResponseTime: 0, currentConcurrentRequests: 0, requestsInLastSecond: 0, requestsInLastMinute: 0, isThrottling: false }; // Cleanup alte Request-Historie setInterval(() => this.cleanupHistory(), 60000); // Jede Minute } async throttleRequest(requestFn, url, method = 'GET', priority = 5, maxRetries = 3) { const requestId = `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; const request = { id: requestId, url, method, timestamp: new Date(), priority, retryCount: 0, maxRetries }; // Request zur Queue hinzufügen this.addToQueue(request); // Warten bis Request ausgeführt werden kann await this.waitForSlot(request); try { // Request ausführen const startTime = Date.now(); const result = await this.executeRequest(request, requestFn); const responseTime = Date.now() - startTime; // Statistiken aktualisieren this.updateStats(true, responseTime); this.recordRequestSuccess(responseTime); this.emit('request:success', { request, responseTime, timestamp: new Date() }); return result; } catch (error) { // Retry-Logic if (request.retryCount < request.maxRetries) { request.retryCount++; console.warn(`🔄 Retrying request ${request.id} (attempt ${request.retryCount}/${request.maxRetries})`); // Backoff-Delay if (this.config.enableBackoff) { this.backoffDelay = Math.min(this.backoffDelay * this.config.backoffMultiplier, this.config.maxBackoffDelay); await this.delay(this.backoffDelay); } // Request erneut zur Queue hinzufügen this.addToQueue(request); return this.throttleRequest(requestFn, url, method, priority, maxRetries); } // Max Retries erreicht this.updateStats(false, 0); this.recordRequestFailure(); this.emit('request:failed', { request, error: String(error), timestamp: new Date() }); throw error; } finally { // Request aus aktiven Requests entfernen this.activeRequests.delete(requestId); this.stats.currentConcurrentRequests = this.activeRequests.size; } } addToQueue(request) { this.requestQueue.push(request); // Nach Priorität sortieren (höchste zuerst) this.requestQueue.sort((a, b) => b.priority - a.priority); this.emit('request:queued', { request, timestamp: new Date() }); } async waitForSlot(request) { return new Promise((resolve) => { const checkSlot = () => { if (this.canExecuteRequest()) { resolve(); } else { // Kurz warten und erneut prüfen setTimeout(checkSlot, 50); } }; checkSlot(); }); } canExecuteRequest() { // Concurrent Requests Limit if (this.activeRequests.size >= this.config.concurrentRequests) { return false; } // Rate Limiting const now = Date.now(); // Requests pro Sekunde const requestsInLastSecond = this.requestHistory.filter(req => now - req.timestamp.getTime() < 1000).length; if (requestsInLastSecond >= this.config.requestsPerSecond) { return false; } // Requests pro Minute const requestsInLastMinute = this.requestHistory.filter(req => now - req.timestamp.getTime() < 60000).length; if (requestsInLastMinute >= this.config.requestsPerMinute) { return false; } // Burst Limiting if (this.burstCount >= this.config.burstLimit) { const burstAge = now - this.burstStartTime; if (burstAge < this.config.burstWindow) { return false; } else { // Burst Window reset this.burstCount = 0; this.burstStartTime = now; } } // Delay zwischen Requests if (now - this.lastRequestTime < this.config.delayBetweenRequests) { return false; } return true; } async executeRequest(request, requestFn) { // Request als aktiv markieren this.activeRequests.set(request.id, request); this.stats.currentConcurrentRequests = this.activeRequests.size; // Burst Counter erhöhen this.burstCount++; this.lastRequestTime = Date.now(); // Request ausführen const result = await requestFn(); // Backoff zurücksetzen bei Erfolg if (this.config.enableBackoff) { this.backoffDelay = 0; } return result; } updateStats(success, responseTime) { this.stats.totalRequests++; if (success) { this.stats.successfulRequests++; } else { this.stats.failedRequests++; } // Durchschnittliche Response-Zeit aktualisieren if (responseTime > 0) { const totalResponseTime = this.stats.averageResponseTime * (this.stats.successfulRequests - 1) + responseTime; this.stats.averageResponseTime = totalResponseTime / this.stats.successfulRequests; } // Aktuelle Request-Raten aktualisieren this.updateCurrentRates(); } updateCurrentRates() { const now = Date.now(); this.stats.requestsInLastSecond = this.requestHistory.filter(req => now - req.timestamp.getTime() < 1000).length; this.stats.requestsInLastMinute = this.requestHistory.filter(req => now - req.timestamp.getTime() < 60000).length; } recordRequestSuccess(responseTime) { this.requestHistory.push({ timestamp: new Date(), success: true, responseTime }); } recordRequestFailure() { this.requestHistory.push({ timestamp: new Date(), success: false, responseTime: 0 }); } cleanupHistory() { const cutoffTime = Date.now() - 60000; // Nur letzte Minute behalten this.requestHistory = this.requestHistory.filter(req => req.timestamp.getTime() > cutoffTime); } delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // Public Methods getStats() { return { ...this.stats }; } getQueueSize() { return this.requestQueue.length; } getActiveRequests() { return this.activeRequests.size; } getThrottlingStatus() { return this.isThrottling; } // Konfiguration ändern updateConfig(newConfig) { this.config = { ...this.config, ...newConfig }; this.emit('config:updated', { config: this.config, timestamp: new Date() }); } // Queue Management clearQueue() { this.requestQueue = []; this.emit('queue:cleared', { timestamp: new Date() }); } pauseThrottling() { this.isThrottling = true; this.stats.isThrottling = true; this.emit('throttling:paused', { timestamp: new Date() }); } resumeThrottling() { this.isThrottling = false; this.stats.isThrottling = false; this.emit('throttling:resumed', { timestamp: new Date() }); } // Utility Methods getConfig() { return { ...this.config }; } resetStats() { this.stats = { totalRequests: 0, successfulRequests: 0, throttledRequests: 0, failedRequests: 0, averageResponseTime: 0, currentConcurrentRequests: 0, requestsInLastSecond: 0, requestsInLastMinute: 0, isThrottling: false }; this.requestHistory = []; this.emit('stats:reset', { timestamp: new Date() }); } // Cleanup async cleanup() { this.clearQueue(); this.activeRequests.clear(); this.requestHistory = []; this.resetStats(); this.emit('throttler:cleanup', { timestamp: new Date() }); } } exports.NetworkThrottler = NetworkThrottler; //# sourceMappingURL=network-throttler.js.map