@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
JavaScript
"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