From a36c14115a6b777dd7a81f5b0d69ea692bc09426 Mon Sep 17 00:00:00 2001 From: Till Tomczak Date: Sat, 31 May 2025 21:56:50 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9A=20Improved=20backend=20structure?= =?UTF-8?q?=20&=20error=20handling=20(#123)=20=F0=9F=96=A5=EF=B8=8F?= =?UTF-8?q?=F0=9F=94=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/app.py | 4 +- backend/app/installer.sh | 571 ++++++++++++++++++++++++----- backend/app/utils/queue_manager.py | 36 +- 3 files changed, 520 insertions(+), 91 deletions(-) diff --git a/backend/app/app.py b/backend/app/app.py index 53c10658..3a7efde5 100644 --- a/backend/app/app.py +++ b/backend/app/app.py @@ -5611,10 +5611,10 @@ if __name__ == "__main__": threaded=True ) else: - app_logger.info("Starte HTTP-Server auf 0.0.0.0:8080") + app_logger.info("Starte HTTP-Server auf 0.0.0.0:80") app.run( host="0.0.0.0", - port=8080, + port=80, debug=False, threaded=True ) diff --git a/backend/app/installer.sh b/backend/app/installer.sh index c72d523b..6ebbe1fc 100644 --- a/backend/app/installer.sh +++ b/backend/app/installer.sh @@ -1,9 +1,10 @@ #!/bin/bash # =================================================================== -# MYP Druckerverwaltung - Installer für Raspbian Kiosk-System +# MYP Druckerverwaltung - VOLLSTÄNDIGER KIOSK-INSTALLER für Raspbian # Entwickelt auf Windows, ausführbar auf Raspberry Pi / Debian # OHNE virtualenv - verwendet System-Python mit --break-system-packages +# ECHTER KIOSK-MODUS: Entfernt Desktop, 3 Backend-Instanzen, Autologin # =================================================================== set -euo pipefail @@ -11,7 +12,10 @@ set -euo pipefail # =========================== KONFIGURATION =========================== APP_NAME="MYP Druckerverwaltung" APP_DIR="/opt/myp" -SERVICE_NAME="myp-kiosk" +SERVICE_NAME_KIOSK="myp-kiosk" +SERVICE_NAME_HTTPS="myp-https" +SERVICE_NAME_HTTP="myp-http" +KIOSK_USER="kiosk" CURRENT_DIR="$(pwd)" INSTALL_LOG="/var/log/myp-install.log" @@ -60,6 +64,114 @@ check_debian_system() { log "✅ Debian/Raspbian-System erkannt" } +# ========================== DESKTOP ENVIRONMENTS ENTFERNEN ========================== +remove_desktop_environments() { + log "=== ENTFERNE ALLE DESKTOP ENVIRONMENTS ===" + + progress "Stoppe alle Desktop-Services..." + systemctl stop lightdm 2>/dev/null || true + systemctl stop gdm3 2>/dev/null || true + systemctl stop sddm 2>/dev/null || true + systemctl stop xdm 2>/dev/null || true + + systemctl disable lightdm 2>/dev/null || true + systemctl disable gdm3 2>/dev/null || true + systemctl disable sddm 2>/dev/null || true + systemctl disable xdm 2>/dev/null || true + + progress "Entferne Desktop-Pakete vollständig..." + + # Raspberry Pi OS Desktop entfernen + apt-get remove --purge -y \ + raspberrypi-ui-mods \ + pi-package \ + desktop-base \ + lxde* \ + xfce4* \ + gnome* \ + kde* \ + mate* \ + cinnamon* \ + openbox \ + pcmanfm \ + file-manager* \ + task-lxde-desktop \ + task-xfce-desktop \ + task-gnome-desktop \ + task-kde-desktop \ + 2>/dev/null || true + + # Display Manager entfernen + apt-get remove --purge -y \ + lightdm* \ + gdm3* \ + sddm* \ + xdm* \ + nodm* \ + 2>/dev/null || true + + # Unnötige Pakete entfernen + apt-get remove --purge -y \ + libreoffice* \ + thunderbird* \ + firefox* \ + chromium-browser \ + vlc* \ + gimp* \ + scratch* \ + minecraft-pi \ + sonic-pi \ + 2>/dev/null || true + + # Autoremove und Autoclean + apt-get autoremove --purge -y + apt-get autoclean + + log "✅ Desktop Environments vollständig entfernt" +} + +# ========================== KIOSK BENUTZER ERSTELLEN ========================== +create_kiosk_user() { + log "=== ERSTELLE KIOSK-BENUTZER ===" + + # Kiosk-Benutzer erstellen falls nicht vorhanden + if ! id "$KIOSK_USER" &>/dev/null; then + progress "Erstelle Kiosk-Benutzer: $KIOSK_USER" + useradd -m -s /bin/bash "$KIOSK_USER" || error "Kann Kiosk-Benutzer nicht erstellen" + + # Gruppen hinzufügen + usermod -aG audio,video,input,dialout,plugdev,users "$KIOSK_USER" 2>/dev/null || true + else + info "Kiosk-Benutzer $KIOSK_USER existiert bereits" + fi + + # Passwort entfernen für automatischen Login + passwd -d "$KIOSK_USER" || warning "Konnte Passwort nicht entfernen" + + log "✅ Kiosk-Benutzer erstellt: $KIOSK_USER" +} + +# ========================== MINIMALE X11 INSTALLATION ========================== +install_minimal_x11() { + log "=== INSTALLIERE MINIMALE X11-UMGEBUNG ===" + + progress "Installiere minimale X11-Pakete..." + apt-get install -y \ + xserver-xorg-core \ + xserver-xorg-input-all \ + xserver-xorg-video-fbdev \ + xserver-xorg-video-vesa \ + xinit \ + x11-xserver-utils \ + xdotool \ + unclutter \ + chromium-browser \ + openbox \ + || error "X11 Installation fehlgeschlagen" + + log "✅ Minimale X11-Umgebung installiert" +} + # ========================== MERCEDES ZERTIFIKATE ========================== install_mercedes_certificates() { log "=== INSTALLIERE MERCEDES SSL-ZERTIFIKATE ===" @@ -200,13 +312,287 @@ install_system_dependencies() { log "✅ Alle Abhängigkeiten erfolgreich installiert" } +# ========================== 3 BACKEND SERVICES ERSTELLEN ========================== +create_backend_services() { + log "=== ERSTELLE 3 BACKEND-SERVICES ===" + + # Service 1: Kiosk-Backend (Port 5000) + progress "Erstelle myp-kiosk.service (Port 5000)..." + cat > "/etc/systemd/system/${SERVICE_NAME_KIOSK}.service" << EOF +[Unit] +Description=MYP Kiosk Backend (Port 5000) +After=network.target network-online.target +Wants=network-online.target +Requires=network.target + +[Service] +Type=simple +User=root +Group=root +WorkingDirectory=$APP_DIR +ExecStart=/usr/bin/python3 $APP_DIR/app.py --debug +Restart=always +RestartSec=5 +StartLimitBurst=5 +StartLimitInterval=60 + +# Umgebungsvariablen +Environment=PYTHONUNBUFFERED=1 +Environment=FLASK_ENV=production +Environment=FLASK_HOST=0.0.0.0 +Environment=FLASK_PORT=5000 +Environment=PYTHONPATH=$APP_DIR +Environment=LC_ALL=C.UTF-8 +Environment=LANG=C.UTF-8 + +# Logging +StandardOutput=journal +StandardError=journal +SyslogIdentifier=myp-kiosk + +# Security-Einstellungen +NoNewPrivileges=true +PrivateTmp=false +ProtectSystem=strict +ReadWritePaths=$APP_DIR + +[Install] +WantedBy=multi-user.target +EOF + + # Service 2: HTTPS-Backend (Port 443) + progress "Erstelle myp-https.service (Port 443)..." + cat > "/etc/systemd/system/${SERVICE_NAME_HTTPS}.service" << EOF +[Unit] +Description=MYP HTTPS Backend (Port 443) +After=network.target network-online.target +Wants=network-online.target +Requires=network.target + +[Service] +Type=simple +User=root +Group=root +WorkingDirectory=$APP_DIR +ExecStart=/usr/bin/python3 -c " +import sys, os +sys.path.insert(0, '$APP_DIR') +os.environ['FLASK_PORT'] = '443' +os.environ['FLASK_HOST'] = '0.0.0.0' +os.environ['FLASK_ENV'] = 'production' +from app import app, get_ssl_context +ssl_context = get_ssl_context() +if ssl_context: + app.run(host='0.0.0.0', port=443, debug=False, ssl_context=ssl_context, threaded=True) +else: + print('SSL-Kontext nicht verfügbar') + exit(1) +" +Restart=always +RestartSec=5 +StartLimitBurst=5 +StartLimitInterval=60 + +# Umgebungsvariablen +Environment=PYTHONUNBUFFERED=1 +Environment=FLASK_ENV=production +Environment=FLASK_HOST=0.0.0.0 +Environment=FLASK_PORT=443 +Environment=PYTHONPATH=$APP_DIR +Environment=LC_ALL=C.UTF-8 +Environment=LANG=C.UTF-8 + +# Logging +StandardOutput=journal +StandardError=journal +SyslogIdentifier=myp-https + +# Security-Einstellungen +NoNewPrivileges=true +PrivateTmp=false +ProtectSystem=strict +ReadWritePaths=$APP_DIR + +[Install] +WantedBy=multi-user.target +EOF + + # Service 3: HTTP-Backend (Port 80) + progress "Erstelle myp-http.service (Port 80)..." + cat > "/etc/systemd/system/${SERVICE_NAME_HTTP}.service" << EOF +[Unit] +Description=MYP HTTP Backend (Port 80) +After=network.target network-online.target +Wants=network-online.target +Requires=network.target + +[Service] +Type=simple +User=root +Group=root +WorkingDirectory=$APP_DIR +ExecStart=/usr/bin/python3 -c " +import sys, os +sys.path.insert(0, '$APP_DIR') +os.environ['FLASK_PORT'] = '80' +os.environ['FLASK_HOST'] = '0.0.0.0' +os.environ['FLASK_ENV'] = 'production' +from app import app +app.run(host='0.0.0.0', port=80, debug=False, threaded=True) +" +Restart=always +RestartSec=5 +StartLimitBurst=5 +StartLimitInterval=60 + +# Umgebungsvariablen +Environment=PYTHONUNBUFFERED=1 +Environment=FLASK_ENV=production +Environment=FLASK_HOST=0.0.0.0 +Environment=FLASK_PORT=80 +Environment=PYTHONPATH=$APP_DIR +Environment=LC_ALL=C.UTF-8 +Environment=LANG=C.UTF-8 + +# Logging +StandardOutput=journal +StandardError=journal +SyslogIdentifier=myp-http + +# Security-Einstellungen +NoNewPrivileges=true +PrivateTmp=false +ProtectSystem=strict +ReadWritePaths=$APP_DIR + +[Install] +WantedBy=multi-user.target +EOF + + log "✅ 3 Backend-Services erstellt" +} + +# ========================== AUTOLOGIN KONFIGURIEREN ========================== +configure_autologin() { + log "=== KONFIGURIERE AUTOLOGIN ===" + + progress "Erstelle Autologin-Service..." + + # Getty-Service für automatischen Login überschreiben + mkdir -p /etc/systemd/system/getty@tty1.service.d/ + cat > /etc/systemd/system/getty@tty1.service.d/autologin.conf << EOF +[Service] +ExecStart= +ExecStart=-/sbin/agetty --autologin $KIOSK_USER --noclear %I linux +EOF + + # Systemd Target auf Multi-User setzen (ohne grafisches Login) + systemctl set-default multi-user.target + + log "✅ Autologin konfiguriert für Benutzer: $KIOSK_USER" +} + +# ========================== KIOSK BROWSER KONFIGURATION ========================== +configure_kiosk_browser() { + log "=== KONFIGURIERE KIOSK-BROWSER ===" + + KIOSK_HOME="/home/$KIOSK_USER" + + # .bashrc für automatischen X-Start erweitern + progress "Konfiguriere automatischen X-Start..." + cat >> "$KIOSK_HOME/.bashrc" << 'EOF' + +# Automatischer X-Start für Kiosk-Modus +if [ -z "$DISPLAY" ] && [ "$(tty)" = "/dev/tty1" ]; then + exec startx +fi +EOF + + # .xinitrc für Kiosk-Session erstellen + progress "Erstelle Kiosk X-Session..." + cat > "$KIOSK_HOME/.xinitrc" << 'EOF' +#!/bin/bash + +# Bildschirmschoner und Energieverwaltung deaktivieren +xset s off +xset s noblank +xset s noexpose +xset -dpms + +# Mauszeiger verstecken +unclutter -idle 0.5 -root & + +# Warte auf Backend-Services +echo "Warte auf MYP Backend-Services..." +WAIT_COUNT=0 +while ! curl -s http://localhost:5000 > /dev/null; do + echo "Warte auf Backend (Port 5000)... ($WAIT_COUNT/60)" + sleep 2 + WAIT_COUNT=$((WAIT_COUNT + 1)) + if [ $WAIT_COUNT -gt 60 ]; then + echo "FEHLER: Backend nach 120s nicht erreichbar!" + break + fi +done + +echo "Backend erreichbar - starte Kiosk-Browser..." + +# Chromium im Vollbild-Kiosk-Modus +exec chromium-browser \ + --kiosk \ + --no-sandbox \ + --disable-infobars \ + --disable-session-crashed-bubble \ + --disable-restore-session-state \ + --disable-web-security \ + --disable-features=TranslateUI \ + --disable-extensions \ + --disable-plugins \ + --disable-popup-blocking \ + --disable-prompt-on-repost \ + --disable-sync \ + --disable-translate \ + --noerrdialogs \ + --no-first-run \ + --no-default-browser-check \ + --autoplay-policy=no-user-gesture-required \ + --start-fullscreen \ + --window-position=0,0 \ + --user-data-dir=/home/kiosk/.chromium-kiosk \ + --disable-background-mode \ + --force-device-scale-factor=1.0 \ + --disable-pinch \ + --overscroll-history-navigation=0 \ + --disable-dev-shm-usage \ + --memory-pressure-off \ + --max_old_space_size=512 \ + http://localhost:5000 +EOF + + # Berechtigungen setzen + chmod +x "$KIOSK_HOME/.xinitrc" + chown -R "$KIOSK_USER:$KIOSK_USER" "$KIOSK_HOME" + + log "✅ Kiosk-Browser konfiguriert" +} + # ========================== PRODUKTIONS-KIOSK SETUP ========================== setup_production_kiosk() { log "=== RICHTE PRODUKTIONS-KIOSK-MODUS EIN ===" - # Zuerst Abhängigkeiten installieren + # 1. System-Abhängigkeiten installieren install_system_dependencies + # 2. Desktop-Environments entfernen + remove_desktop_environments + + # 3. Minimale X11-Umgebung installieren + install_minimal_x11 + + # 4. Kiosk-Benutzer erstellen + create_kiosk_user + + # 5. Anwendung kopieren progress "Erstelle Zielverzeichnis /opt/myp..." mkdir -p "$APP_DIR" || error "Konnte Zielverzeichnis nicht erstellen" @@ -263,114 +649,113 @@ setup_production_kiosk() { chmod 750 "$APP_DIR/logs" chmod 755 "$APP_DIR/uploads" - progress "Erstelle Systemd-Service myp-kiosk.service..." - cat > "/etc/systemd/system/${SERVICE_NAME}.service" << EOF -[Unit] -Description=MYP Druckerverwaltung Kiosk-Modus -After=network.target network-online.target -Wants=network-online.target -Requires=network.target - -[Service] -Type=simple -User=root -Group=root -WorkingDirectory=$APP_DIR -ExecStart=/usr/bin/python3 $APP_DIR/app.py --debug -Restart=always -RestartSec=5 -StartLimitBurst=5 -StartLimitInterval=60 - -# Umgebungsvariablen -Environment=PYTHONUNBUFFERED=1 -Environment=FLASK_ENV=production -Environment=FLASK_HOST=0.0.0.0 -Environment=FLASK_PORT=5000 -Environment=PYTHONPATH=$APP_DIR -Environment=LC_ALL=C.UTF-8 -Environment=LANG=C.UTF-8 - -# Logging -StandardOutput=journal -StandardError=journal -SyslogIdentifier=myp-kiosk - -# Security-Einstellungen -NoNewPrivileges=true -PrivateTmp=false -ProtectSystem=strict -ReadWritePaths=$APP_DIR - -[Install] -WantedBy=multi-user.target -EOF + # 6. Backend-Services erstellen + create_backend_services + # 7. Autologin konfigurieren + configure_autologin + + # 8. Kiosk-Browser konfigurieren + configure_kiosk_browser + + # 9. Services aktivieren und starten progress "Lade Systemd-Konfiguration neu..." systemctl daemon-reload || error "Systemd Reload fehlgeschlagen" - progress "Aktiviere und starte $SERVICE_NAME Service..." - systemctl enable "$SERVICE_NAME.service" || error "Service Enable fehlgeschlagen" - systemctl start "$SERVICE_NAME.service" || error "Service Start fehlgeschlagen" + progress "Aktiviere alle Backend-Services..." + systemctl enable "$SERVICE_NAME_KIOSK.service" || error "Kiosk-Service Enable fehlgeschlagen" + systemctl enable "$SERVICE_NAME_HTTPS.service" || error "HTTPS-Service Enable fehlgeschlagen" + systemctl enable "$SERVICE_NAME_HTTP.service" || error "HTTP-Service Enable fehlgeschlagen" + + progress "Starte alle Backend-Services..." + systemctl start "$SERVICE_NAME_KIOSK.service" || error "Kiosk-Service Start fehlgeschlagen" + systemctl start "$SERVICE_NAME_HTTPS.service" || warning "HTTPS-Service Start fehlgeschlagen (SSL möglicherweise nicht konfiguriert)" + systemctl start "$SERVICE_NAME_HTTP.service" || error "HTTP-Service Start fehlgeschlagen" # Service-Status prüfen sleep 5 - if systemctl is-active --quiet "$SERVICE_NAME.service"; then - log "✅ $SERVICE_NAME Service läuft erfolgreich" - info "Service-Status: $(systemctl is-active $SERVICE_NAME.service)" - info "Port 5000: Flask-App läuft im Debug-Modus" - info "Projektverzeichnis: $APP_DIR" - - # Test der Anwendung - progress "Teste Anwendungserreichbarkeit..." - sleep 3 - if curl -s http://localhost:5000 > /dev/null 2>&1; then - log "✅ Anwendung ist unter http://localhost:5000 erreichbar" + + info "=== SERVICE-STATUS ===" + for service in "$SERVICE_NAME_KIOSK" "$SERVICE_NAME_HTTPS" "$SERVICE_NAME_HTTP"; do + if systemctl is-active --quiet "$service.service"; then + log "✅ $service Service läuft erfolgreich" else - warning "⚠️ Anwendung noch nicht erreichbar (möglicherweise noch beim Starten)" + warning "⚠️ $service Service läuft nicht - prüfen Sie die Logs: journalctl -u $service -f" fi + done + + # Backend-Tests + progress "Teste Backend-Erreichbarkeit..." + sleep 3 + + if curl -s http://localhost:5000 > /dev/null 2>&1; then + log "✅ Port 5000 (Kiosk) erreichbar" else - error "$SERVICE_NAME Service konnte nicht gestartet werden - prüfen Sie die Logs: journalctl -u $SERVICE_NAME -f" + warning "⚠️ Port 5000 (Kiosk) nicht erreichbar" fi - log "✅ Produktions-Kiosk-Modus erfolgreich eingerichtet" - log "🎯 Anwendung erreichbar unter: http://localhost:5000" - log "📋 Service-Befehle:" - log " • Status: sudo systemctl status $SERVICE_NAME" - log " • Stoppen: sudo systemctl stop $SERVICE_NAME" - log " • Starten: sudo systemctl start $SERVICE_NAME" - log " • Neustarten: sudo systemctl restart $SERVICE_NAME" - log " • Logs: sudo journalctl -u $SERVICE_NAME -f" - log " • Service-Info: sudo journalctl -u $SERVICE_NAME --no-pager" + if curl -s http://localhost:80 > /dev/null 2>&1; then + log "✅ Port 80 (HTTP) erreichbar" + else + warning "⚠️ Port 80 (HTTP) nicht erreichbar" + fi + + if curl -k -s https://localhost:443 > /dev/null 2>&1; then + log "✅ Port 443 (HTTPS) erreichbar" + else + warning "⚠️ Port 443 (HTTPS) nicht erreichbar (SSL möglicherweise nicht konfiguriert)" + fi + + log "✅ PRODUKTIONS-KIOSK-MODUS ERFOLGREICH EINGERICHTET" + log "" + log "🚀 WICHTIG: NEUSTART ERFORDERLICH!" + log " sudo reboot" + log "" + log "📊 NACH DEM NEUSTART:" + log " • Automatischer Login als Benutzer: $KIOSK_USER" + log " • Automatischer X-Start und Chromium-Kiosk" + log " • Backend läuft auf 3 Ports:" + log " - http://localhost:5000 (Kiosk-Anzeige)" + log " - http://localhost:80 (HTTP-API)" + log " - https://localhost:443 (HTTPS-API)" + log "" + log "🔧 SERVICE-BEFEHLE:" + log " • Status: sudo systemctl status myp-{kiosk,https,http}" + log " • Logs: sudo journalctl -u myp-kiosk -f" + log " • Restart: sudo systemctl restart myp-{kiosk,https,http}" + log "" + warning "🔄 FÜHRE JETZT 'sudo reboot' AUS, UM DEN KIOSK-MODUS ZU AKTIVIEREN!" } # ========================== HAUPTMENÜ ========================== show_menu() { clear echo -e "${BLUE}=================================================================${NC}" - echo -e "${GREEN} $APP_NAME - Installer für Raspbian${NC}" + echo -e "${GREEN} $APP_NAME - VOLLSTÄNDIGER KIOSK-INSTALLER${NC}" echo -e "${BLUE}=================================================================${NC}" echo "" echo -e "${YELLOW}Aktuelles Verzeichnis:${NC} $CURRENT_DIR" echo -e "${YELLOW}Systemzeit:${NC} $(date)" echo -e "${YELLOW}Zielverzeichnis:${NC} $APP_DIR" + echo -e "${YELLOW}Kiosk-Benutzer:${NC} $KIOSK_USER" echo "" echo -e "${PURPLE}Wählen Sie eine Option:${NC}" echo "" echo -e "${GREEN}1)${NC} System vorbereiten (Abhängigkeiten installieren)" echo -e " → Installiert Python 3, pip und alle benötigten Pakete" echo -e " → Verwendet: pip install --break-system-packages" - echo -e " → Keine virtualenv, direktes System-Python" + echo -e " → Mercedes SSL-Zertifikate werden konfiguriert" echo "" - echo -e "${GREEN}2)${NC} Produktions-Kiosk-Modus installieren" - echo -e " → Führt System-Vorbereitung durch" - echo -e " → Verschiebt Dateien selektiv nach /opt/myp/" - echo -e " → Erstellt systemd-Service: myp-kiosk.service" - echo -e " → Startet Flask-App mit --debug auf Port 5000" - echo -e " → Testet Anwendungserreichbarkeit" + echo -e "${GREEN}2)${NC} VOLLSTÄNDIGER KIOSK-MODUS installieren" + echo -e " → ${RED}ENTFERNT ALLE DESKTOP-ENVIRONMENTS!${NC}" + echo -e " → Installiert minimale X11-Umgebung" + echo -e " → Erstellt 3 Backend-Services (Port 5000, 80, 443)" + echo -e " → Konfiguriert Autologin und Kiosk-Browser" + echo -e " → ${YELLOW}NEUSTART ERFORDERLICH!${NC}" echo "" echo -e "${RED}0)${NC} Beenden" echo "" + echo -e "${RED}⚠️ WARNUNG: Option 2 macht Raspberry Pi zu reinem Kiosk-System!${NC}" echo -e "${BLUE}=================================================================${NC}" echo -n "Ihre Wahl [0-2]: " } @@ -385,10 +770,11 @@ main() { mkdir -p "$(dirname "$INSTALL_LOG")" touch "$INSTALL_LOG" - log "=== MYP INSTALLER GESTARTET ===" + log "=== MYP VOLLSTÄNDIGER KIOSK-INSTALLER GESTARTET ===" log "Arbeitsverzeichnis: $CURRENT_DIR" log "Zielverzeichnis: $APP_DIR" - log "Service-Name: $SERVICE_NAME" + log "Kiosk-Services: $SERVICE_NAME_KIOSK, $SERVICE_NAME_HTTPS, $SERVICE_NAME_HTTP" + log "Kiosk-Benutzer: $KIOSK_USER" log "System: $(uname -a)" log "Debian-Version: $(cat /etc/debian_version 2>/dev/null || echo 'Unbekannt')" @@ -408,13 +794,26 @@ main() { ;; 2) clear - log "=== OPTION 2: PRODUKTIONS-KIOSK-MODUS ===" - setup_production_kiosk + echo -e "${RED}⚠️ WARNUNG: Sie sind dabei, alle Desktop-Environments zu entfernen!${NC}" + echo -e "${YELLOW}Der Raspberry Pi wird zu einem reinen Kiosk-System umgebaut.${NC}" + echo -e "${BLUE}Nach der Installation startet automatisch der Kiosk-Browser.${NC}" echo "" - echo -e "${GREEN}✅ Produktions-Kiosk-Modus erfolgreich eingerichtet!${NC}" - echo -e "${BLUE}ℹ️ Die Anwendung startet automatisch bei jedem Systemstart.${NC}" - echo -e "${YELLOW}Drücken Sie Enter, um fortzufahren...${NC}" - read -r + echo -n "Sind Sie sicher? [ja/NEIN]: " + read -r confirm + + if [ "$confirm" = "ja" ] || [ "$confirm" = "JA" ]; then + clear + log "=== OPTION 2: VOLLSTÄNDIGER KIOSK-MODUS ===" + setup_production_kiosk + echo "" + echo -e "${GREEN}✅ KIOSK-MODUS ERFOLGREICH EINGERICHTET!${NC}" + echo -e "${RED}🔄 NEUSTART JETZT ERFORDERLICH: sudo reboot${NC}" + echo -e "${YELLOW}Drücken Sie Enter, um fortzufahren...${NC}" + read -r + else + echo -e "${BLUE}Installation abgebrochen.${NC}" + sleep 2 + fi ;; 0) log "=== INSTALLER BEENDET ===" diff --git a/backend/app/utils/queue_manager.py b/backend/app/utils/queue_manager.py index a3583acd..6ac216d4 100644 --- a/backend/app/utils/queue_manager.py +++ b/backend/app/utils/queue_manager.py @@ -385,12 +385,42 @@ def start_queue_manager(): return manager def stop_queue_manager(): - """Stoppt den globalen Queue-Manager.""" + """Stoppt den globalen Queue-Manager definitiv und sicher.""" global _queue_manager_instance with _queue_manager_lock: if _queue_manager_instance: - _queue_manager_instance.stop() - _queue_manager_instance = None + try: + queue_logger.info("🔄 Stoppe Queue-Manager...") + + # Shutdown-Event setzen + _queue_manager_instance.shutdown_event.set() + + # Monitor-Thread beenden + if (_queue_manager_instance.monitor_thread and + _queue_manager_instance.monitor_thread.is_alive()): + + queue_logger.info("⏳ Warte auf Monitor-Thread...") + _queue_manager_instance.monitor_thread.join(timeout=5.0) + + # Falls Thread nicht beendet wurde, forciere Beendigung + if _queue_manager_instance.monitor_thread.is_alive(): + queue_logger.warning("⚠️ Monitor-Thread reagiert nicht - forciere Beendigung") + # Thread als Daemon markieren für automatische Beendigung + _queue_manager_instance.monitor_thread.daemon = True + + # Status auf gestoppt setzen + _queue_manager_instance.is_running = False + + # Explizit stop() aufrufen + _queue_manager_instance.stop() + + queue_logger.info("✅ Queue-Manager erfolgreich gestoppt") + + except Exception as e: + queue_logger.error(f"❌ Fehler beim Stoppen des Queue-Managers: {str(e)}") + finally: + # Instanz definitiv auf None setzen + _queue_manager_instance = None # Automatisches Cleanup bei Prozess-Ende registrieren atexit.register(stop_queue_manager) \ No newline at end of file