ich geh behindert
This commit is contained in:
194
backend/app.py
194
backend/app.py
@@ -90,7 +90,7 @@ class OptimizedConfig:
|
||||
app.config['EXPLAIN_TEMPLATE_LOADING'] = False
|
||||
app.config['TEMPLATES_AUTO_RELOAD'] = False
|
||||
|
||||
print("🚀 Running in OPTIMIZED mode for Raspberry Pi")
|
||||
print("[START] Running in OPTIMIZED mode for Raspberry Pi")
|
||||
|
||||
def detect_raspberry_pi():
|
||||
"""Erkennt ob das System auf einem Raspberry Pi läuft"""
|
||||
@@ -145,11 +145,11 @@ if os.name == 'nt':
|
||||
try:
|
||||
from utils.windows_fixes import get_windows_thread_manager
|
||||
# apply_all_windows_fixes() wird automatisch beim Import ausgeführt
|
||||
print("✅ Windows-Fixes (sichere Version) geladen")
|
||||
print("[OK] Windows-Fixes (sichere Version) geladen")
|
||||
except ImportError as e:
|
||||
# Fallback falls windows_fixes nicht verfügbar
|
||||
get_windows_thread_manager = None
|
||||
print(f"⚠️ Windows-Fixes nicht verfügbar: {str(e)}")
|
||||
print(f"[WARN] Windows-Fixes nicht verfügbar: {str(e)}")
|
||||
else:
|
||||
get_windows_thread_manager = None
|
||||
|
||||
@@ -158,7 +158,7 @@ from models import init_database, create_initial_admin, User, Printer, Job, Stat
|
||||
from utils.logging_config import setup_logging, get_logger, measure_execution_time, log_startup_info, debug_request, debug_response
|
||||
from utils.job_scheduler import JobScheduler, get_job_scheduler
|
||||
from utils.queue_manager import start_queue_manager, stop_queue_manager, get_queue_manager
|
||||
from config.settings import SECRET_KEY, UPLOAD_FOLDER, ALLOWED_EXTENSIONS, ENVIRONMENT, SESSION_LIFETIME, SCHEDULER_ENABLED, SCHEDULER_INTERVAL, TAPO_USERNAME, TAPO_PASSWORD
|
||||
from utils.settings import SECRET_KEY, UPLOAD_FOLDER, ALLOWED_EXTENSIONS, ENVIRONMENT, SESSION_LIFETIME, SCHEDULER_ENABLED, SCHEDULER_INTERVAL, TAPO_USERNAME, TAPO_PASSWORD
|
||||
from utils.file_manager import file_manager, save_job_file, save_guest_file, save_avatar_file, save_asset_file, save_log_file, save_backup_file, save_temp_file, delete_file as delete_file_safe
|
||||
|
||||
# ===== OFFLINE-MODUS KONFIGURATION =====
|
||||
@@ -291,10 +291,10 @@ try:
|
||||
timeout_context
|
||||
)
|
||||
TIMEOUT_FORCE_QUIT_AVAILABLE = True
|
||||
app_logger.info("✅ Timeout Force-Quit Manager geladen")
|
||||
app_logger.info("[OK] Timeout Force-Quit Manager geladen")
|
||||
except ImportError as e:
|
||||
TIMEOUT_FORCE_QUIT_AVAILABLE = False
|
||||
app_logger.warning(f"⚠️ Timeout Force-Quit Manager nicht verfügbar: {e}")
|
||||
app_logger.warning(f"[WARN] Timeout Force-Quit Manager nicht verfügbar: {e}")
|
||||
|
||||
# ===== PERFORMANCE-OPTIMIERTE CACHES =====
|
||||
# Thread-sichere Caches für häufig abgerufene Daten
|
||||
@@ -328,7 +328,7 @@ def aggressive_shutdown_handler(sig, frame):
|
||||
Aggressiver Signal-Handler für sofortiges Herunterfahren bei Strg+C.
|
||||
Schließt sofort alle Datenbankverbindungen und beendet das Programm um jeden Preis.
|
||||
"""
|
||||
print("\n🚨 STRG+C ERKANNT - SOFORTIGES SHUTDOWN!")
|
||||
print("\n[ALERT] STRG+C ERKANNT - SOFORTIGES SHUTDOWN!")
|
||||
print("🔥 Schließe Datenbank sofort und beende Programm um jeden Preis!")
|
||||
|
||||
try:
|
||||
@@ -343,51 +343,51 @@ def aggressive_shutdown_handler(sig, frame):
|
||||
if _scoped_session:
|
||||
try:
|
||||
_scoped_session.remove()
|
||||
print("✅ Scoped Sessions geschlossen")
|
||||
print("[OK] Scoped Sessions geschlossen")
|
||||
except Exception as e:
|
||||
print(f"⚠️ Fehler beim Schließen der Scoped Sessions: {e}")
|
||||
print(f"[WARN] Fehler beim Schließen der Scoped Sessions: {e}")
|
||||
|
||||
if _engine:
|
||||
try:
|
||||
_engine.dispose()
|
||||
print("✅ Datenbank-Engine geschlossen")
|
||||
print("[OK] Datenbank-Engine geschlossen")
|
||||
except Exception as e:
|
||||
print(f"⚠️ Fehler beim Schließen der Engine: {e}")
|
||||
print(f"[WARN] Fehler beim Schließen der Engine: {e}")
|
||||
except ImportError:
|
||||
print("⚠️ Models nicht verfügbar für Database-Cleanup")
|
||||
print("[WARN] Models nicht verfügbar für Database-Cleanup")
|
||||
|
||||
# 3. Alle offenen DB-Sessions forciert schließen
|
||||
try:
|
||||
import gc
|
||||
# Garbage Collection für nicht geschlossene Sessions
|
||||
gc.collect()
|
||||
print("✅ Garbage Collection ausgeführt")
|
||||
print("[OK] Garbage Collection ausgeführt")
|
||||
except Exception as e:
|
||||
print(f"⚠️ Garbage Collection fehlgeschlagen: {e}")
|
||||
print(f"[WARN] Garbage Collection fehlgeschlagen: {e}")
|
||||
|
||||
# 4. SQLite WAL-Dateien forciert synchronisieren
|
||||
try:
|
||||
import sqlite3
|
||||
from config.settings import DATABASE_PATH
|
||||
from utils.settings import DATABASE_PATH
|
||||
conn = sqlite3.connect(DATABASE_PATH, timeout=1.0)
|
||||
conn.execute("PRAGMA wal_checkpoint(TRUNCATE)")
|
||||
conn.close()
|
||||
print("✅ SQLite WAL-Checkpoint ausgeführt")
|
||||
print("[OK] SQLite WAL-Checkpoint ausgeführt")
|
||||
except Exception as e:
|
||||
print(f"⚠️ WAL-Checkpoint fehlgeschlagen: {e}")
|
||||
print(f"[WARN] WAL-Checkpoint fehlgeschlagen: {e}")
|
||||
|
||||
# 5. Queue Manager stoppen falls verfügbar
|
||||
try:
|
||||
from utils.queue_manager import stop_queue_manager
|
||||
stop_queue_manager()
|
||||
print("✅ Queue Manager gestoppt")
|
||||
print("[OK] Queue Manager gestoppt")
|
||||
except Exception as e:
|
||||
print(f"⚠️ Queue Manager Stop fehlgeschlagen: {e}")
|
||||
print(f"[WARN] Queue Manager Stop fehlgeschlagen: {e}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Fehler beim Database-Cleanup: {e}")
|
||||
print(f"[ERROR] Fehler beim Database-Cleanup: {e}")
|
||||
|
||||
print("🛑 SOFORTIGES PROGRAMM-ENDE - EXIT CODE 0")
|
||||
print("[STOP] SOFORTIGES PROGRAMM-ENDE - EXIT CODE 0")
|
||||
# Sofortiger Exit ohne weitere Cleanup-Routinen
|
||||
os._exit(0)
|
||||
|
||||
@@ -404,22 +404,22 @@ def register_aggressive_shutdown():
|
||||
if os.name == 'nt':
|
||||
try:
|
||||
signal.signal(signal.SIGBREAK, aggressive_shutdown_handler) # Strg+Break
|
||||
print("✅ Windows SIGBREAK Handler registriert")
|
||||
print("[OK] Windows SIGBREAK Handler registriert")
|
||||
except AttributeError:
|
||||
pass # SIGBREAK nicht auf allen Windows-Versionen verfügbar
|
||||
else:
|
||||
# Unix/Linux-spezifische Signale
|
||||
try:
|
||||
signal.signal(signal.SIGHUP, aggressive_shutdown_handler) # Hangup Signal
|
||||
print("✅ Unix SIGHUP Handler registriert")
|
||||
print("[OK] Unix SIGHUP Handler registriert")
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
# Atexit-Handler als Backup registrieren
|
||||
atexit.register(lambda: print("🔄 Atexit-Handler ausgeführt - Programm beendet"))
|
||||
atexit.register(lambda: print("[RESTART] Atexit-Handler ausgeführt - Programm beendet"))
|
||||
|
||||
print("🚨 AGGRESSIVER STRG+C SHUTDOWN-HANDLER AKTIVIERT")
|
||||
print("📋 Bei Strg+C wird die Datenbank sofort geschlossen und das Programm beendet!")
|
||||
print("[ALERT] AGGRESSIVER STRG+C SHUTDOWN-HANDLER AKTIVIERT")
|
||||
print("[LIST] Bei Strg+C wird die Datenbank sofort geschlossen und das Programm beendet!")
|
||||
|
||||
# Aggressive Shutdown-Handler sofort registrieren
|
||||
register_aggressive_shutdown()
|
||||
@@ -435,7 +435,7 @@ app.secret_key = SECRET_KEY
|
||||
USE_OPTIMIZED_CONFIG = should_use_optimized_config()
|
||||
|
||||
if USE_OPTIMIZED_CONFIG:
|
||||
app_logger.info("🚀 Aktiviere optimierte Konfiguration für schwache Hardware/Raspberry Pi")
|
||||
app_logger.info("[START] Aktiviere optimierte Konfiguration für schwache Hardware/Raspberry Pi")
|
||||
|
||||
# Optimierte Flask-Konfiguration anwenden
|
||||
app.config.update({
|
||||
@@ -480,7 +480,7 @@ if USE_OPTIMIZED_CONFIG:
|
||||
response.headers['X-Optimized-Asset'] = 'true'
|
||||
return response
|
||||
|
||||
app_logger.info("✅ Optimierte Konfiguration aktiviert")
|
||||
app_logger.info("[OK] Optimierte Konfiguration aktiviert")
|
||||
|
||||
else:
|
||||
# Standard-Konfiguration
|
||||
@@ -497,7 +497,7 @@ else:
|
||||
'base_template': 'base.html'
|
||||
})
|
||||
|
||||
app_logger.info("📋 Standard-Konfiguration verwendet")
|
||||
app_logger.info("[LIST] Standard-Konfiguration verwendet")
|
||||
|
||||
# Globale db-Variable für Kompatibilität mit init_simple_db.py
|
||||
db = db_engine
|
||||
@@ -2234,20 +2234,20 @@ def check_printer_status(ip_address: str, timeout: int = 7) -> Tuple[str, bool]:
|
||||
else:
|
||||
# Steckdose aus = Drucker ONLINE (bereit zum Drucken)
|
||||
status = "online"
|
||||
printers_logger.info(f"✅ Drucker {ip_address}: ONLINE (Steckdose aus - bereit zum Drucken)")
|
||||
printers_logger.info(f"[OK] Drucker {ip_address}: ONLINE (Steckdose aus - bereit zum Drucken)")
|
||||
|
||||
except Exception as e:
|
||||
printers_logger.error(f"❌ Fehler bei Tapo-Status-Check für {ip_address}: {str(e)}")
|
||||
printers_logger.error(f"[ERROR] Fehler bei Tapo-Status-Check für {ip_address}: {str(e)}")
|
||||
reachable = False
|
||||
status = "error"
|
||||
else:
|
||||
# Steckdose nicht erreichbar = kritischer Fehler
|
||||
printers_logger.warning(f"❌ Drucker {ip_address}: OFFLINE (Steckdose nicht erreichbar)")
|
||||
printers_logger.warning(f"[ERROR] Drucker {ip_address}: OFFLINE (Steckdose nicht erreichbar)")
|
||||
reachable = False
|
||||
status = "offline"
|
||||
|
||||
except Exception as e:
|
||||
printers_logger.error(f"❌ Unerwarteter Fehler bei Status-Check für {ip_address}: {str(e)}")
|
||||
printers_logger.error(f"[ERROR] Unerwarteter Fehler bei Status-Check für {ip_address}: {str(e)}")
|
||||
reachable = False
|
||||
status = "error"
|
||||
|
||||
@@ -2269,10 +2269,10 @@ def check_multiple_printers_status(printers: List[Dict], timeout: int = 7) -> Di
|
||||
|
||||
# Wenn keine Drucker vorhanden sind, gebe leeres Dict zurück
|
||||
if not printers:
|
||||
printers_logger.info("ℹ️ Keine Drucker zum Status-Check gefunden")
|
||||
printers_logger.info("[INFO] Keine Drucker zum Status-Check gefunden")
|
||||
return results
|
||||
|
||||
printers_logger.info(f"🔍 Prüfe Status von {len(printers)} Druckern parallel...")
|
||||
printers_logger.info(f"[SEARCH] Prüfe Status von {len(printers)} Druckern parallel...")
|
||||
|
||||
# Parallel-Ausführung mit ThreadPoolExecutor
|
||||
# Sicherstellen, dass max_workers mindestens 1 ist
|
||||
@@ -2296,7 +2296,7 @@ def check_multiple_printers_status(printers: List[Dict], timeout: int = 7) -> Di
|
||||
printers_logger.error(f"Fehler bei Status-Check für Drucker {printer['name']}: {str(e)}")
|
||||
results[printer['id']] = ("offline", False)
|
||||
|
||||
printers_logger.info(f"✅ Status-Check abgeschlossen für {len(results)} Drucker")
|
||||
printers_logger.info(f"[OK] Status-Check abgeschlossen für {len(results)} Drucker")
|
||||
|
||||
return results
|
||||
|
||||
@@ -4807,7 +4807,7 @@ def check_session_activity():
|
||||
|
||||
# Session-Sicherheit: Überprüfe IP-Adresse und User-Agent (Optional)
|
||||
if 'session_ip' in session and session['session_ip'] != request.remote_addr:
|
||||
auth_logger.warning(f"⚠️ IP-Adresse geändert für Benutzer {current_user.email}: {session['session_ip']} → {request.remote_addr}")
|
||||
auth_logger.warning(f"[WARN] IP-Adresse geändert für Benutzer {current_user.email}: {session['session_ip']} → {request.remote_addr}")
|
||||
# Optional: Benutzer abmelden bei IP-Wechsel (kann bei VPN/Proxy problematisch sein)
|
||||
session['security_warning'] = "IP-Adresse hat sich geändert"
|
||||
|
||||
@@ -5882,7 +5882,7 @@ def admin_advanced_settings():
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
app_logger.error(f"❌ Fehler beim Laden der erweiterten Einstellungen: {str(e)}")
|
||||
app_logger.error(f"[ERROR] Fehler beim Laden der erweiterten Einstellungen: {str(e)}")
|
||||
flash('Fehler beim Laden der erweiterten Einstellungen', 'error')
|
||||
return redirect(url_for('admin_page'))
|
||||
|
||||
@@ -5892,7 +5892,7 @@ def admin_advanced_settings():
|
||||
def admin_performance_optimization():
|
||||
"""Performance-Optimierungs-Verwaltungsseite für Admins"""
|
||||
try:
|
||||
app_logger.info(f"🚀 Performance-Optimierung-Seite aufgerufen von Admin {current_user.username}")
|
||||
app_logger.info(f"[START] Performance-Optimierung-Seite aufgerufen von Admin {current_user.username}")
|
||||
|
||||
# Aktuelle Optimierungseinstellungen sammeln
|
||||
optimization_status = {
|
||||
@@ -5935,7 +5935,7 @@ def admin_performance_optimization():
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
app_logger.error(f"❌ Fehler beim Laden der Performance-Optimierung-Seite: {str(e)}")
|
||||
app_logger.error(f"[ERROR] Fehler beim Laden der Performance-Optimierung-Seite: {str(e)}")
|
||||
flash('Fehler beim Laden der Performance-Optimierung-Seite', 'error')
|
||||
return redirect(url_for('admin_page'))
|
||||
|
||||
@@ -5945,7 +5945,7 @@ def admin_performance_optimization():
|
||||
def api_cleanup_logs():
|
||||
"""Bereinigt alte Log-Dateien"""
|
||||
try:
|
||||
app_logger.info(f"📋 Log-Bereinigung gestartet von Benutzer {current_user.username}")
|
||||
app_logger.info(f"[LIST] Log-Bereinigung gestartet von Benutzer {current_user.username}")
|
||||
|
||||
cleanup_results = {
|
||||
'files_removed': 0,
|
||||
@@ -5998,7 +5998,7 @@ def api_cleanup_logs():
|
||||
|
||||
cleanup_results['space_freed_mb'] = round(cleanup_results['space_freed_mb'], 2)
|
||||
|
||||
app_logger.info(f"✅ Log-Bereinigung abgeschlossen: {cleanup_results['files_removed']} Dateien entfernt, {cleanup_results['space_freed_mb']} MB freigegeben")
|
||||
app_logger.info(f"[OK] Log-Bereinigung abgeschlossen: {cleanup_results['files_removed']} Dateien entfernt, {cleanup_results['space_freed_mb']} MB freigegeben")
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
@@ -6007,7 +6007,7 @@ def api_cleanup_logs():
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
app_logger.error(f"❌ Fehler bei Log-Bereinigung: {str(e)}")
|
||||
app_logger.error(f"[ERROR] Fehler bei Log-Bereinigung: {str(e)}")
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'Fehler bei der Log-Bereinigung: {str(e)}'
|
||||
@@ -6019,7 +6019,7 @@ def api_cleanup_logs():
|
||||
def api_system_check():
|
||||
"""Führt eine System-Integritätsprüfung durch"""
|
||||
try:
|
||||
app_logger.info(f"🔍 System-Integritätsprüfung gestartet von Benutzer {current_user.username}")
|
||||
app_logger.info(f"[SEARCH] System-Integritätsprüfung gestartet von Benutzer {current_user.username}")
|
||||
|
||||
check_results = {
|
||||
'database_integrity': False,
|
||||
@@ -6162,7 +6162,7 @@ def api_system_check():
|
||||
|
||||
check_results['success_rate'] = round(success_rate, 1)
|
||||
|
||||
app_logger.info(f"✅ System-Integritätsprüfung abgeschlossen: {success_rate:.1f}% ({passed_checks}/{total_checks} Tests bestanden)")
|
||||
app_logger.info(f"[OK] System-Integritätsprüfung abgeschlossen: {success_rate:.1f}% ({passed_checks}/{total_checks} Tests bestanden)")
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
@@ -6171,7 +6171,7 @@ def api_system_check():
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
app_logger.error(f"❌ Fehler bei System-Integritätsprüfung: {str(e)}")
|
||||
app_logger.error(f"[ERROR] Fehler bei System-Integritätsprüfung: {str(e)}")
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'Fehler bei der System-Integritätsprüfung: {str(e)}'
|
||||
@@ -6661,7 +6661,7 @@ def export_table_data():
|
||||
query_params = data.get('query', {})
|
||||
|
||||
# Vollständige Export-Logik implementierung
|
||||
app_logger.info(f"📊 Starte Tabellen-Export: {table_type} als {export_format}")
|
||||
app_logger.info(f"[STATS] Starte Tabellen-Export: {table_type} als {export_format}")
|
||||
|
||||
# Tabellen-Konfiguration basierend auf Typ erstellen
|
||||
if table_type == 'jobs':
|
||||
@@ -6745,7 +6745,7 @@ def export_table_data():
|
||||
response.headers['Content-Type'] = 'text/csv; charset=utf-8'
|
||||
response.headers['Content-Disposition'] = f'attachment; filename="{table_type}_export_{datetime.now().strftime("%Y%m%d_%H%M%S")}.csv"'
|
||||
|
||||
app_logger.info(f"✅ CSV-Export erfolgreich: {len(export_data)} Datensätze")
|
||||
app_logger.info(f"[OK] CSV-Export erfolgreich: {len(export_data)} Datensätze")
|
||||
return response
|
||||
|
||||
elif export_format == 'json':
|
||||
@@ -6756,7 +6756,7 @@ def export_table_data():
|
||||
response.headers['Content-Type'] = 'application/json; charset=utf-8'
|
||||
response.headers['Content-Disposition'] = f'attachment; filename="{table_type}_export_{datetime.now().strftime("%Y%m%d_%H%M%S")}.json"'
|
||||
|
||||
app_logger.info(f"✅ JSON-Export erfolgreich: {len(export_data)} Datensätze")
|
||||
app_logger.info(f"[OK] JSON-Export erfolgreich: {len(export_data)} Datensätze")
|
||||
return response
|
||||
|
||||
elif export_format == 'excel':
|
||||
@@ -6780,11 +6780,11 @@ def export_table_data():
|
||||
response.headers['Content-Type'] = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||
response.headers['Content-Disposition'] = f'attachment; filename="{table_type}_export_{datetime.now().strftime("%Y%m%d_%H%M%S")}.xlsx"'
|
||||
|
||||
app_logger.info(f"✅ Excel-Export erfolgreich: {len(export_data)} Datensätze")
|
||||
app_logger.info(f"[OK] Excel-Export erfolgreich: {len(export_data)} Datensätze")
|
||||
return response
|
||||
|
||||
except ImportError:
|
||||
app_logger.warning("⚠️ Excel-Export nicht verfügbar - openpyxl/pandas fehlt")
|
||||
app_logger.warning("[WARN] Excel-Export nicht verfügbar - openpyxl/pandas fehlt")
|
||||
return jsonify({'error': 'Excel-Export nicht verfügbar - erforderliche Bibliotheken fehlen'}), 400
|
||||
|
||||
except Exception as e:
|
||||
@@ -6853,7 +6853,7 @@ def api_clear_cache():
|
||||
import gc
|
||||
gc.collect()
|
||||
|
||||
app_logger.info(f"✅ Cache erfolgreich geleert. {len(myp_temp_files)} temporäre Dateien entfernt")
|
||||
app_logger.info(f"[OK] Cache erfolgreich geleert. {len(myp_temp_files)} temporäre Dateien entfernt")
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
@@ -6865,7 +6865,7 @@ def api_clear_cache():
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
app_logger.error(f"❌ Fehler beim Leeren des Cache: {str(e)}")
|
||||
app_logger.error(f"[ERROR] Fehler beim Leeren des Cache: {str(e)}")
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'Fehler beim Leeren des Cache: {str(e)}'
|
||||
@@ -6930,7 +6930,7 @@ def api_optimize_database():
|
||||
except Exception as e:
|
||||
optimization_results['errors'].append(f"Datei-Bereinigung: {str(e)}")
|
||||
|
||||
app_logger.info(f"✅ Datenbank-Optimierung abgeschlossen: {optimization_results}")
|
||||
app_logger.info(f"[OK] Datenbank-Optimierung abgeschlossen: {optimization_results}")
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
@@ -6940,7 +6940,7 @@ def api_optimize_database():
|
||||
|
||||
except Exception as e:
|
||||
db_session.rollback()
|
||||
app_logger.error(f"❌ Fehler bei Datenbank-Optimierung: {str(e)}")
|
||||
app_logger.error(f"[ERROR] Fehler bei Datenbank-Optimierung: {str(e)}")
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'Fehler bei der Datenbank-Optimierung: {str(e)}'
|
||||
@@ -7032,7 +7032,7 @@ def api_create_backup():
|
||||
except Exception as e:
|
||||
app_logger.warning(f"Fehler beim Bereinigen alter Backups: {str(e)}")
|
||||
|
||||
app_logger.info(f"✅ Backup erfolgreich erstellt: {backup_filename} ({backup_info['size_mb']} MB)")
|
||||
app_logger.info(f"[OK] Backup erfolgreich erstellt: {backup_filename} ({backup_info['size_mb']} MB)")
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
@@ -7041,7 +7041,7 @@ def api_create_backup():
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
app_logger.error(f"❌ Fehler bei Backup-Erstellung: {str(e)}")
|
||||
app_logger.error(f"[ERROR] Fehler bei Backup-Erstellung: {str(e)}")
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'Fehler bei der Backup-Erstellung: {str(e)}'
|
||||
@@ -7346,7 +7346,7 @@ def setup_database_with_migrations():
|
||||
Führt Migrationen für neue Tabellen wie JobOrder durch.
|
||||
"""
|
||||
try:
|
||||
app_logger.info("🔄 Starte Datenbank-Setup und Migrationen...")
|
||||
app_logger.info("[RESTART] Starte Datenbank-Setup und Migrationen...")
|
||||
|
||||
# Standard-Datenbank-Initialisierung
|
||||
init_database()
|
||||
@@ -7363,19 +7363,19 @@ def setup_database_with_migrations():
|
||||
existing_tables = inspector.get_table_names()
|
||||
|
||||
if 'job_orders' in existing_tables:
|
||||
app_logger.info("✅ JobOrder-Tabelle bereits vorhanden")
|
||||
app_logger.info("[OK] JobOrder-Tabelle bereits vorhanden")
|
||||
else:
|
||||
# Tabelle manuell erstellen
|
||||
JobOrder.__table__.create(engine, checkfirst=True)
|
||||
app_logger.info("✅ JobOrder-Tabelle erfolgreich erstellt")
|
||||
app_logger.info("[OK] JobOrder-Tabelle erfolgreich erstellt")
|
||||
|
||||
# Initial-Admin erstellen falls nicht vorhanden
|
||||
create_initial_admin()
|
||||
|
||||
app_logger.info("✅ Datenbank-Setup und Migrationen erfolgreich abgeschlossen")
|
||||
app_logger.info("[OK] Datenbank-Setup und Migrationen erfolgreich abgeschlossen")
|
||||
|
||||
except Exception as e:
|
||||
app_logger.error(f"❌ Fehler bei Datenbank-Setup: {str(e)}")
|
||||
app_logger.error(f"[ERROR] Fehler bei Datenbank-Setup: {str(e)}")
|
||||
raise e
|
||||
|
||||
# ===== LOG-MANAGEMENT API =====
|
||||
@@ -7707,7 +7707,7 @@ def api_admin_logs():
|
||||
level_stats[entry['level']] = level_stats.get(entry['level'], 0) + 1
|
||||
component_stats[entry['component']] = component_stats.get(entry['component'], 0) + 1
|
||||
|
||||
app_logger.debug(f"📋 Log-API: {total_count} Einträge gefunden, {len(paginated_entries)} zurückgegeben")
|
||||
app_logger.debug(f"[LIST] Log-API: {total_count} Einträge gefunden, {len(paginated_entries)} zurückgegeben")
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
@@ -9229,7 +9229,7 @@ def api_admin_plug_schedules_calendar():
|
||||
title = f"🔌 {log.printer.name}: Verbunden"
|
||||
elif log.status == 'disconnected':
|
||||
color = '#ef4444' # Rot
|
||||
title = f"❌ {log.printer.name}: Getrennt"
|
||||
title = f"[ERROR] {log.printer.name}: Getrennt"
|
||||
else:
|
||||
color = '#6b7280' # Grau
|
||||
title = f"❓ {log.printer.name}: {log.status}"
|
||||
@@ -9297,7 +9297,7 @@ def get_status_icon(status):
|
||||
"""
|
||||
icons = {
|
||||
'connected': '🔌',
|
||||
'disconnected': '❌',
|
||||
'disconnected': '[ERROR]',
|
||||
'on': '🟢',
|
||||
'off': '🔴'
|
||||
}
|
||||
@@ -9361,9 +9361,9 @@ if __name__ == "__main__":
|
||||
try:
|
||||
from utils.shutdown_manager import get_shutdown_manager
|
||||
shutdown_manager = get_shutdown_manager(timeout=45) # 45 Sekunden Gesamt-Timeout
|
||||
app_logger.info("✅ Zentraler Shutdown-Manager initialisiert")
|
||||
app_logger.info("[OK] Zentraler Shutdown-Manager initialisiert")
|
||||
except ImportError as e:
|
||||
app_logger.error(f"❌ Shutdown-Manager konnte nicht geladen werden: {e}")
|
||||
app_logger.error(f"[ERROR] Shutdown-Manager konnte nicht geladen werden: {e}")
|
||||
# Fallback auf die alte Methode
|
||||
shutdown_manager = None
|
||||
|
||||
@@ -9374,11 +9374,11 @@ if __name__ == "__main__":
|
||||
|
||||
# Error-Recovery-Monitoring starten
|
||||
start_error_monitoring()
|
||||
app_logger.info("✅ Error-Recovery-Monitoring gestartet")
|
||||
app_logger.info("[OK] Error-Recovery-Monitoring gestartet")
|
||||
|
||||
# System-Control-Manager initialisieren
|
||||
system_control_manager = get_system_control_manager()
|
||||
app_logger.info("✅ System-Control-Manager initialisiert")
|
||||
app_logger.info("[OK] System-Control-Manager initialisiert")
|
||||
|
||||
# Integriere in Shutdown-Manager
|
||||
if shutdown_manager:
|
||||
@@ -9390,24 +9390,24 @@ if __name__ == "__main__":
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
app_logger.error(f"❌ Fehlerresilienz-Systeme konnten nicht initialisiert werden: {e}")
|
||||
app_logger.error(f"[ERROR] Fehlerresilienz-Systeme konnten nicht initialisiert werden: {e}")
|
||||
|
||||
# ===== KIOSK-SERVICE-OPTIMIERUNG =====
|
||||
try:
|
||||
# Stelle sicher, dass der Kiosk-Service korrekt konfiguriert ist
|
||||
kiosk_service_exists = os.path.exists('/etc/systemd/system/myp-kiosk.service')
|
||||
if not kiosk_service_exists:
|
||||
app_logger.warning("⚠️ Kiosk-Service nicht gefunden - Kiosk-Funktionen eventuell eingeschränkt")
|
||||
app_logger.warning("[WARN] Kiosk-Service nicht gefunden - Kiosk-Funktionen eventuell eingeschränkt")
|
||||
else:
|
||||
app_logger.info("✅ Kiosk-Service-Konfiguration gefunden")
|
||||
app_logger.info("[OK] Kiosk-Service-Konfiguration gefunden")
|
||||
|
||||
except Exception as e:
|
||||
app_logger.error(f"❌ Kiosk-Service-Check fehlgeschlagen: {e}")
|
||||
app_logger.error(f"[ERROR] Kiosk-Service-Check fehlgeschlagen: {e}")
|
||||
|
||||
# Windows-spezifisches Signal-Handling als Fallback
|
||||
def fallback_signal_handler(sig, frame):
|
||||
"""Fallback Signal-Handler für ordnungsgemäßes Shutdown."""
|
||||
app_logger.warning(f"🛑 Signal {sig} empfangen - fahre System herunter (Fallback)...")
|
||||
app_logger.warning(f"[STOP] Signal {sig} empfangen - fahre System herunter (Fallback)...")
|
||||
try:
|
||||
# Queue Manager stoppen
|
||||
stop_queue_manager()
|
||||
@@ -9422,10 +9422,10 @@ if __name__ == "__main__":
|
||||
except Exception as e:
|
||||
app_logger.error(f"Fehler beim Stoppen des Schedulers: {str(e)}")
|
||||
|
||||
app_logger.info("✅ Fallback-Shutdown abgeschlossen")
|
||||
app_logger.info("[OK] Fallback-Shutdown abgeschlossen")
|
||||
sys.exit(0)
|
||||
except Exception as e:
|
||||
app_logger.error(f"❌ Fehler beim Fallback-Shutdown: {str(e)}")
|
||||
app_logger.error(f"[ERROR] Fehler beim Fallback-Shutdown: {str(e)}")
|
||||
sys.exit(1)
|
||||
|
||||
# Signal-Handler registrieren (Windows-kompatibel)
|
||||
@@ -9447,8 +9447,8 @@ if __name__ == "__main__":
|
||||
|
||||
# Optimierungsstatus beim Start anzeigen
|
||||
if USE_OPTIMIZED_CONFIG:
|
||||
app_logger.info("🚀 === OPTIMIERTE KONFIGURATION AKTIV ===")
|
||||
app_logger.info(f"📊 Hardware erkannt: Raspberry Pi={detect_raspberry_pi()}")
|
||||
app_logger.info("[START] === OPTIMIERTE KONFIGURATION AKTIV ===")
|
||||
app_logger.info(f"[STATS] Hardware erkannt: Raspberry Pi={detect_raspberry_pi()}")
|
||||
app_logger.info(f"⚙️ Erzwungen: {os.getenv('FORCE_OPTIMIZED_MODE', '').lower() in ['true', '1', 'yes']}")
|
||||
app_logger.info(f"🔧 CLI-Parameter: {'--optimized' in sys.argv}")
|
||||
app_logger.info("🔧 Aktive Optimierungen:")
|
||||
@@ -9457,9 +9457,9 @@ if __name__ == "__main__":
|
||||
app_logger.info(f" - Glassmorphism begrenzt: {app.jinja_env.globals.get('limit_glassmorphism', False)}")
|
||||
app_logger.info(f" - Template-Caching: {not app.config.get('TEMPLATES_AUTO_RELOAD', True)}")
|
||||
app_logger.info(f" - Static Cache: {app.config.get('SEND_FILE_MAX_AGE_DEFAULT', 0) / 3600:.1f}h")
|
||||
app_logger.info("🚀 ========================================")
|
||||
app_logger.info("[START] ========================================")
|
||||
else:
|
||||
app_logger.info("📋 Standard-Konfiguration aktiv (keine Optimierungen)")
|
||||
app_logger.info("[LIST] Standard-Konfiguration aktiv (keine Optimierungen)")
|
||||
|
||||
# Drucker-Monitor Steckdosen-Initialisierung beim Start
|
||||
try:
|
||||
@@ -9469,15 +9469,15 @@ if __name__ == "__main__":
|
||||
if initialization_results:
|
||||
success_count = sum(1 for success in initialization_results.values() if success)
|
||||
total_count = len(initialization_results)
|
||||
app_logger.info(f"✅ Steckdosen-Initialisierung: {success_count}/{total_count} Drucker erfolgreich")
|
||||
app_logger.info(f"[OK] Steckdosen-Initialisierung: {success_count}/{total_count} Drucker erfolgreich")
|
||||
|
||||
if success_count < total_count:
|
||||
app_logger.warning(f"⚠️ {total_count - success_count} Drucker konnten nicht initialisiert werden")
|
||||
app_logger.warning(f"[WARN] {total_count - success_count} Drucker konnten nicht initialisiert werden")
|
||||
else:
|
||||
app_logger.info("ℹ️ Keine Drucker zur Initialisierung gefunden")
|
||||
app_logger.info("[INFO] Keine Drucker zur Initialisierung gefunden")
|
||||
|
||||
except Exception as e:
|
||||
app_logger.error(f"❌ Fehler bei automatischer Steckdosen-Initialisierung: {str(e)}")
|
||||
app_logger.error(f"[ERROR] Fehler bei automatischer Steckdosen-Initialisierung: {str(e)}")
|
||||
|
||||
# ===== SHUTDOWN-MANAGER KONFIGURATION =====
|
||||
if shutdown_manager:
|
||||
@@ -9485,9 +9485,9 @@ if __name__ == "__main__":
|
||||
try:
|
||||
import utils.queue_manager as queue_module
|
||||
shutdown_manager.register_queue_manager(queue_module)
|
||||
app_logger.debug("✅ Queue Manager beim Shutdown-Manager registriert")
|
||||
app_logger.debug("[OK] Queue Manager beim Shutdown-Manager registriert")
|
||||
except Exception as e:
|
||||
app_logger.warning(f"⚠️ Queue Manager Registrierung fehlgeschlagen: {e}")
|
||||
app_logger.warning(f"[WARN] Queue Manager Registrierung fehlgeschlagen: {e}")
|
||||
|
||||
# Scheduler beim Shutdown-Manager registrieren
|
||||
shutdown_manager.register_scheduler(scheduler, SCHEDULER_ENABLED)
|
||||
@@ -9503,12 +9503,12 @@ if __name__ == "__main__":
|
||||
if not debug_mode:
|
||||
try:
|
||||
queue_manager = start_queue_manager()
|
||||
app_logger.info("✅ Printer Queue Manager erfolgreich gestartet")
|
||||
app_logger.info("[OK] Printer Queue Manager erfolgreich gestartet")
|
||||
|
||||
except Exception as e:
|
||||
app_logger.error(f"❌ Fehler beim Starten des Queue-Managers: {str(e)}")
|
||||
app_logger.error(f"[ERROR] Fehler beim Starten des Queue-Managers: {str(e)}")
|
||||
else:
|
||||
app_logger.info("🔄 Debug-Modus: Queue Manager deaktiviert für Entwicklung")
|
||||
app_logger.info("[RESTART] Debug-Modus: Queue Manager deaktiviert für Entwicklung")
|
||||
|
||||
# Scheduler starten (falls aktiviert)
|
||||
if SCHEDULER_ENABLED:
|
||||
@@ -9525,7 +9525,7 @@ if __name__ == "__main__":
|
||||
# Kill hängende Prozesse auf Port 5000 (Windows-Fix)
|
||||
if os.name == 'nt' and use_production_server:
|
||||
try:
|
||||
app_logger.info("🔄 Bereinige hängende Prozesse auf Port 5000...")
|
||||
app_logger.info("[RESTART] Bereinige hängende Prozesse auf Port 5000...")
|
||||
import subprocess
|
||||
result = subprocess.run(["netstat", "-ano"], capture_output=True, text=True, shell=True)
|
||||
hanging_pids = set()
|
||||
@@ -9541,14 +9541,14 @@ if __name__ == "__main__":
|
||||
try:
|
||||
subprocess.run(["taskkill", "/F", "/PID", str(pid)],
|
||||
capture_output=True, shell=True)
|
||||
app_logger.info(f"✅ Prozess {pid} beendet")
|
||||
app_logger.info(f"[OK] Prozess {pid} beendet")
|
||||
except:
|
||||
pass
|
||||
|
||||
if hanging_pids:
|
||||
time.sleep(2) # Kurz warten nach Cleanup
|
||||
except Exception as e:
|
||||
app_logger.warning(f"⚠️ Prozess-Cleanup fehlgeschlagen: {e}")
|
||||
app_logger.warning(f"[WARN] Prozess-Cleanup fehlgeschlagen: {e}")
|
||||
|
||||
if debug_mode and "--production" not in sys.argv:
|
||||
# Debug-Modus: Flask Development Server
|
||||
@@ -9577,10 +9577,10 @@ if __name__ == "__main__":
|
||||
host = "127.0.0.1" # Nur IPv4!
|
||||
port = 5000
|
||||
|
||||
app_logger.info(f"🚀 Starte Production Server (Waitress) auf {host}:{port}")
|
||||
app_logger.info(f"[START] Starte Production Server (Waitress) auf {host}:{port}")
|
||||
app_logger.info("💡 Kiosk-Browser sollte http://127.0.0.1:5000 verwenden")
|
||||
app_logger.info("✅ IPv6-Probleme behoben durch IPv4-only Binding")
|
||||
app_logger.info("✅ Performance optimiert für Kiosk-Betrieb")
|
||||
app_logger.info("[OK] IPv6-Probleme behoben durch IPv4-only Binding")
|
||||
app_logger.info("[OK] Performance optimiert für Kiosk-Betrieb")
|
||||
|
||||
# Waitress-Konfiguration für optimale Performance
|
||||
serve(
|
||||
@@ -9601,7 +9601,7 @@ if __name__ == "__main__":
|
||||
|
||||
except ImportError:
|
||||
# Fallback auf Flask wenn Waitress nicht verfügbar
|
||||
app_logger.warning("⚠️ Waitress nicht installiert - verwende Flask-Server")
|
||||
app_logger.warning("[WARN] Waitress nicht installiert - verwende Flask-Server")
|
||||
app_logger.warning("💡 Installiere mit: pip install waitress")
|
||||
|
||||
ssl_context = get_ssl_context()
|
||||
@@ -9624,7 +9624,7 @@ if __name__ == "__main__":
|
||||
threaded=True
|
||||
)
|
||||
except KeyboardInterrupt:
|
||||
app_logger.info("🔄 Tastatur-Unterbrechung empfangen - beende Anwendung...")
|
||||
app_logger.info("[RESTART] Tastatur-Unterbrechung empfangen - beende Anwendung...")
|
||||
if shutdown_manager:
|
||||
shutdown_manager.shutdown()
|
||||
else:
|
||||
|
Reference in New Issue
Block a user