fix request handling
This commit is contained in:
@@ -1331,9 +1331,9 @@ class LiveStatsTracker:
|
|||||||
self.blocked_paths: Dict[str, List[float]] = {} # Path -> [blocked timestamps]
|
self.blocked_paths: Dict[str, List[float]] = {} # Path -> [blocked timestamps]
|
||||||
self.ip_404s: Dict[str, List[float]] = {} # IP -> [404 timestamps]
|
self.ip_404s: Dict[str, List[float]] = {} # IP -> [404 timestamps]
|
||||||
|
|
||||||
# IP Request Details (für IP-Detail Popup)
|
# IP Request Details (für IP-Detail Popup) - werden NICHT nach window_seconds gelöscht!
|
||||||
self.ip_request_details: Dict[str, List[Dict]] = {} # IP -> [{ts, path, ua}, ...]
|
self.ip_request_details: Dict[str, List[Dict]] = {} # IP -> [{ts, path, ua}, ...]
|
||||||
self.max_request_details = 100 # Max Anzahl Details pro IP
|
self.max_request_details = 500 # Max Anzahl Details pro IP (nicht zeitbasiert)
|
||||||
|
|
||||||
# Human/Bot Counters
|
# Human/Bot Counters
|
||||||
self.human_requests: List[float] = []
|
self.human_requests: List[float] = []
|
||||||
@@ -1357,15 +1357,12 @@ class LiveStatsTracker:
|
|||||||
self.human_requests = [t for t in self.human_requests if t > cutoff]
|
self.human_requests = [t for t in self.human_requests if t > cutoff]
|
||||||
self.bot_requests = [t for t in self.bot_requests if t > cutoff]
|
self.bot_requests = [t for t in self.bot_requests if t > cutoff]
|
||||||
|
|
||||||
# Request Details cleanup
|
# Request Details werden NICHT zeitbasiert gelöscht - nur durch max_request_details limitiert
|
||||||
for ip in list(self.ip_request_details.keys()):
|
# Damit bleiben alle Requests im Speicher für das IP-Detail-Popup
|
||||||
self.ip_request_details[ip] = [r for r in self.ip_request_details[ip] if r['ts'] > cutoff]
|
|
||||||
if not self.ip_request_details[ip]:
|
|
||||||
del self.ip_request_details[ip]
|
|
||||||
|
|
||||||
def record_request(self, ip: str, path: str, is_bot: bool, is_blocked: bool = False, is_404: bool = False, user_agent: str = ''):
|
def record_request(self, ip: str, path: str, is_bot: bool, is_blocked: bool = False, is_404: bool = False, user_agent: str = '', timestamp: float = None):
|
||||||
"""Zeichnet einen Request auf."""
|
"""Zeichnet einen Request auf. timestamp=None nutzt aktuelle Zeit."""
|
||||||
now = time.time()
|
now = timestamp if timestamp is not None else time.time()
|
||||||
|
|
||||||
# IP-Request
|
# IP-Request
|
||||||
if ip not in self.ip_requests:
|
if ip not in self.ip_requests:
|
||||||
@@ -1526,13 +1523,102 @@ _shop_stats_trackers: Dict[str, LiveStatsTracker] = {}
|
|||||||
def get_shop_stats_tracker(shop: str, window_seconds: int = 300) -> LiveStatsTracker:
|
def get_shop_stats_tracker(shop: str, window_seconds: int = 300) -> LiveStatsTracker:
|
||||||
"""Gibt den Stats-Tracker für einen Shop zurück (erstellt falls nötig)."""
|
"""Gibt den Stats-Tracker für einen Shop zurück (erstellt falls nötig)."""
|
||||||
if shop not in _shop_stats_trackers:
|
if shop not in _shop_stats_trackers:
|
||||||
_shop_stats_trackers[shop] = LiveStatsTracker(shop, window_seconds)
|
tracker = LiveStatsTracker(shop, window_seconds)
|
||||||
|
# Initialen Log-Scan durchführen um Request-Details zu laden
|
||||||
|
_load_initial_request_details(tracker, shop)
|
||||||
|
_shop_stats_trackers[shop] = tracker
|
||||||
elif _shop_stats_trackers[shop].window_seconds != window_seconds:
|
elif _shop_stats_trackers[shop].window_seconds != window_seconds:
|
||||||
# Window geändert - neuen Tracker erstellen
|
# Window geändert - neuen Tracker erstellen
|
||||||
_shop_stats_trackers[shop] = LiveStatsTracker(shop, window_seconds)
|
tracker = LiveStatsTracker(shop, window_seconds)
|
||||||
|
_load_initial_request_details(tracker, shop)
|
||||||
|
_shop_stats_trackers[shop] = tracker
|
||||||
return _shop_stats_trackers[shop]
|
return _shop_stats_trackers[shop]
|
||||||
|
|
||||||
|
|
||||||
|
def _load_initial_request_details(tracker: LiveStatsTracker, shop: str, max_lines: int = 5000):
|
||||||
|
"""
|
||||||
|
Lädt initiale Request-Details aus dem Log-File.
|
||||||
|
Wird beim Erstellen eines neuen LiveStatsTracker aufgerufen.
|
||||||
|
"""
|
||||||
|
log_file = os.path.join(VHOSTS_DIR, shop, 'httpdocs', SHOP_LOG_FILE)
|
||||||
|
|
||||||
|
if not os.path.isfile(log_file):
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Letzte N Zeilen des Logs lesen (effizient von hinten)
|
||||||
|
with open(log_file, 'r') as f:
|
||||||
|
# Gehe ans Ende der Datei
|
||||||
|
f.seek(0, 2)
|
||||||
|
file_size = f.tell()
|
||||||
|
|
||||||
|
if file_size == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Lies maximal 500KB von hinten
|
||||||
|
read_size = min(512000, file_size)
|
||||||
|
f.seek(file_size - read_size)
|
||||||
|
|
||||||
|
# Überspringe erste (möglicherweise unvollständige) Zeile
|
||||||
|
if read_size < file_size:
|
||||||
|
f.readline()
|
||||||
|
|
||||||
|
lines = f.readlines()
|
||||||
|
|
||||||
|
# Nur die letzten max_lines Zeilen verarbeiten
|
||||||
|
lines = lines[-max_lines:]
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
try:
|
||||||
|
# IP extrahieren
|
||||||
|
ip = None
|
||||||
|
if 'IP: ' in line:
|
||||||
|
ip = line.split('IP: ')[1].split(' |')[0].strip()
|
||||||
|
|
||||||
|
if not ip:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Zeitstempel extrahieren (Format: [2024-01-09 12:34:56])
|
||||||
|
timestamp = None
|
||||||
|
if line.startswith('[') and ']' in line:
|
||||||
|
try:
|
||||||
|
ts_str = line[1:line.index(']')]
|
||||||
|
ts_dt = datetime.strptime(ts_str, '%Y-%m-%d %H:%M:%S')
|
||||||
|
timestamp = ts_dt.timestamp()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Path extrahieren
|
||||||
|
path = '/'
|
||||||
|
if 'Path: ' in line:
|
||||||
|
path = line.split('Path: ')[1].split(' |')[0].strip()
|
||||||
|
elif 'URI: ' in line:
|
||||||
|
path = line.split('URI: ')[1].split(' |')[0].strip()
|
||||||
|
|
||||||
|
# User-Agent extrahieren
|
||||||
|
user_agent = ''
|
||||||
|
if 'UA: ' in line:
|
||||||
|
user_agent = line.split('UA: ')[1].split(' |')[0].strip()
|
||||||
|
elif 'User-Agent: ' in line:
|
||||||
|
user_agent = line.split('User-Agent: ')[1].split(' |')[0].strip()
|
||||||
|
|
||||||
|
# Bot/Blocked erkennen
|
||||||
|
is_bot = any(x in line for x in ['BOT: ', 'BOT:', 'BLOCKED_BOT:', 'MONITOR_BOT:', 'BANNED_BOT:'])
|
||||||
|
is_blocked = any(x in line for x in ['BANNED', 'BLOCKED'])
|
||||||
|
is_404 = '404' in line
|
||||||
|
|
||||||
|
# Request aufzeichnen (mit originalem Zeitstempel falls vorhanden)
|
||||||
|
tracker.record_request(ip, path, is_bot, is_blocked, is_404, user_agent, timestamp)
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
|
||||||
|
logger.info(f"Initiale Request-Details für {shop} geladen: {len(tracker.ip_request_details)} IPs")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Fehler beim Laden der initialen Request-Details für {shop}: {e}")
|
||||||
|
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# BAN/WHITELIST MANAGEMENT
|
# BAN/WHITELIST MANAGEMENT
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|||||||
Reference in New Issue
Block a user