ich geh behindert

This commit is contained in:
2025-06-05 01:34:10 +02:00
parent 0ae23e5272
commit 375c48d72f
478 changed files with 11113 additions and 231267 deletions

View File

@@ -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: