From d3f7d66112d1040d330736cd2721a34f9cf70584 Mon Sep 17 00:00:00 2001 From: Till Tomczak Date: Sat, 31 May 2025 18:17:58 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9A=20Improved=20database=20structure?= =?UTF-8?q?=20&=20utils=20with=20new=20files=20for=20shm,=20wal,=20and=20e?= =?UTF-8?q?nhanced=20debugging=20tools.=20=F0=9F=86=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/app.py | 4 +- backend/app/database/myp.db | Bin 110592 -> 110592 bytes backend/app/database/myp.db-shm | Bin 0 -> 32768 bytes backend/app/database/myp.db-wal | Bin 0 -> 16512 bytes backend/app/models.py | 12 +- backend/app/utils/debug_cli.py | 3 +- backend/app/utils/debug_drucker_erkennung.py | 6 +- backend/app/utils/queue_manager.py | 4 +- backend/app/utils/update_requirements.py | 6 +- backend/app/utils/windows_fixes.py | 162 ++++++++++++++++--- 10 files changed, 163 insertions(+), 34 deletions(-) create mode 100644 backend/app/database/myp.db-shm create mode 100644 backend/app/database/myp.db-wal diff --git a/backend/app/app.py b/backend/app/app.py index be5e807a..53c10658 100644 --- a/backend/app/app.py +++ b/backend/app/app.py @@ -1883,7 +1883,9 @@ def api_admin_fix_errors(): cwd=os.path.dirname(os.path.abspath(__file__)), capture_output=True, text=True, - timeout=60 + timeout=60, + encoding='utf-8', + errors='replace' ) if result.returncode == 0: diff --git a/backend/app/database/myp.db b/backend/app/database/myp.db index 617e3bb8019da4257bd5b76cbb4043e986b63bea..b801598a51e86bb5a1a1489b6fe1f103c349273b 100644 GIT binary patch delta 302 zcmZp8z}E19O(r4S+1?ld7sgv9E zO|=Xa3@xk-%&klf^o&hRjm!;<42(>54NP^7QDn>v%r-yOmr>y7O<-W-VPoKr<=e$4 z&YQAXAi$ni1)|i#%EVO9(Ad<(+z9A8mPP{>J_dVHYjtgPadBym$@#IFlaI#BPW~Co zD+1PFXkcY(p=V@dVrXL4sK7iqAzo~=LEOcK!u)#}*!Wj7@PFZd&VP&l0RLJ3)tdzk grt?o<&Ce*v4>FsFMVf;#KP@dMGjIE8en!&;09(dSd;kCd delta 290 zcmZp8z}E19O(r9&W@$c_Nm*r?uGwyGg_GO# zO|=XZj0~*|jjT+K^^A>7%q&ff42(>54NP^7figx`1{PL^Kp7JwGmFhn^<@jiO^oW~p4foNim}R*f5&p8DKa)Q zZ&YBOoDeUz*&y!XLSc}({Hq!Gzwkfjzr}x+e-Hoa&4LEg`KPbuXB6ZYU{U5|EX^xQ RO-#;6Ov>4QnxD~h0RZsqPwD^w diff --git a/backend/app/database/myp.db-shm b/backend/app/database/myp.db-shm new file mode 100644 index 0000000000000000000000000000000000000000..37569ebd8a26eafbef40a06f4a1dddcdda0d2d03 GIT binary patch literal 32768 zcmeI*JqiLb5C+irgQZ#qENn&aEMg&8iJi5LVB=NnJb+$7k0FS+u+mwPWn0U|_rZ`M z2~)fSB>6E(MS4+2)Ldk>X1i6Z zVy}Bw*U4{K{uaxv=BhPUM>IYxM$@tT<>f|}cWuS2s#COG4KYL!jhz*v$%rqj=Gqm@ z$!ka(9TKC=A6%vd8a|>0WWm#c+D+cP?fZjg!4TsQFvQP;x`6QT%1rY5 zyPM(gk`NjW3G!{}y`+Tm!>{-sIKTiH00UqE41fVJ00zJS7&yfS>L?@$W6_z3#Dt>6 z2C~_O=4Tet7YNaA*_8(fs~9EGyj>|cC4RFwpCuWZBD#^nDT4KkVNy-anwN=5G1h&t zT)ya(8b9Tg72e&Zm}*I^C20l`!_{VLTP6tV`63!mQtzCm{C{zC1I|GI6j!o zF6P$Ch~r^2**Tj!6%bkVBWu1v4v}l6ik-WAFSlGc2AhwQZeuh49cP%>FjXx@n5L#F z-!x(!i-+i*-DA*MP;}-;S3A+!A^M57)eJHG*o1NN6s3%5MjiEa-w-UIUFt_SSL~pAc*$}9=J0cB;Nc@Pj6OjZ(Ol#^%h&|mANkByGMO1o+|(V literal 0 HcmV?d00001 diff --git a/backend/app/models.py b/backend/app/models.py index 7c1905a3..ae124232 100644 --- a/backend/app/models.py +++ b/backend/app/models.py @@ -33,7 +33,7 @@ _cache_lock = threading.Lock() _cache_ttl = {} # Time-to-live für Cache-Einträge # Alle exportierten Modelle -__all__ = ['User', 'Printer', 'Job', 'Stats', 'SystemLog', 'Base', 'GuestRequest', 'UserPermission', 'Notification', 'init_db', 'init_database', 'create_initial_admin', 'get_db_session', 'get_cached_session', 'clear_cache'] +__all__ = ['User', 'Printer', 'Job', 'Stats', 'SystemLog', 'Base', 'GuestRequest', 'UserPermission', 'Notification', 'init_db', 'init_database', 'create_initial_admin', 'get_db_session', 'get_cached_session', 'clear_cache', 'engine'] # ===== DATENBANK-KONFIGURATION MIT WAL UND OPTIMIERUNGEN ===== @@ -998,4 +998,12 @@ def create_initial_admin(email: str = "admin@mercedes-benz.com", password: str = except Exception as e: logger.error(f"Fehler beim Erstellen des Admin-Benutzers: {str(e)}") - return False \ No newline at end of file + return False + +# Engine für Export verfügbar machen +def get_engine(): + """Gibt die optimierte Datenbank-Engine zurück.""" + return create_optimized_engine() + +# Engine-Variable für direkten Import +engine = get_engine() \ No newline at end of file diff --git a/backend/app/utils/debug_cli.py b/backend/app/utils/debug_cli.py index de36ecbe..7e88a227 100644 --- a/backend/app/utils/debug_cli.py +++ b/backend/app/utils/debug_cli.py @@ -268,7 +268,8 @@ def scan_printer(ip_address, timeout=5): cmd = ['ping', '-c', '1', '-W', str(timeout), ip_address] print(f" 🏓 Ping-Test: ", end="") - result = subprocess.run(cmd, capture_output=True, text=True) + result = subprocess.run(cmd, capture_output=True, text=True, + encoding='utf-8', errors='replace') if result.returncode == 0: print(colorize("Erreichbar", "GREEN")) diff --git a/backend/app/utils/debug_drucker_erkennung.py b/backend/app/utils/debug_drucker_erkennung.py index 8e7e1494..4e88014d 100644 --- a/backend/app/utils/debug_drucker_erkennung.py +++ b/backend/app/utils/debug_drucker_erkennung.py @@ -148,10 +148,12 @@ def test_network_connectivity(): try: if platform.system().lower() == "windows": result = subprocess.run(['ping', '-n', '1', '-w', '3000', ip], - capture_output=True, text=True, timeout=5) + capture_output=True, text=True, timeout=5, + encoding='utf-8', errors='replace') else: result = subprocess.run(['ping', '-c', '1', '-W', '3', ip], - capture_output=True, text=True, timeout=5) + capture_output=True, text=True, timeout=5, + encoding='utf-8', errors='replace') if result.returncode == 0: log_message(f" ✅ Ping erfolgreich") diff --git a/backend/app/utils/queue_manager.py b/backend/app/utils/queue_manager.py index 12020dc0..a3583acd 100644 --- a/backend/app/utils/queue_manager.py +++ b/backend/app/utils/queue_manager.py @@ -55,7 +55,9 @@ def check_printer_status(ip_address: str, timeout: int = 5) -> Tuple[str, bool]: cmd, capture_output=True, text=True, - timeout=timeout + 1 + timeout=timeout + 1, + encoding='utf-8', + errors='replace' ) # Wenn Ping erfolgreich ist, als online betrachten diff --git a/backend/app/utils/update_requirements.py b/backend/app/utils/update_requirements.py index ece7447a..84d50ec1 100644 --- a/backend/app/utils/update_requirements.py +++ b/backend/app/utils/update_requirements.py @@ -93,7 +93,8 @@ def get_current_versions() -> Dict[str, str]: try: result = subprocess.run(['pip', 'list', '--format=freeze'], - capture_output=True, text=True) + capture_output=True, text=True, + encoding='utf-8', errors='replace') for line in result.stdout.strip().split('\n'): if '==' in line: @@ -113,7 +114,8 @@ def check_package_availability(package: str, version: str = None) -> bool: else: cmd = ['pip', 'show', package] - result = subprocess.run(cmd, capture_output=True, text=True) + result = subprocess.run(cmd, capture_output=True, text=True, + encoding='utf-8', errors='replace') return result.returncode == 0 except Exception: diff --git a/backend/app/utils/windows_fixes.py b/backend/app/utils/windows_fixes.py index f4d77905..c8c91d96 100644 --- a/backend/app/utils/windows_fixes.py +++ b/backend/app/utils/windows_fixes.py @@ -206,36 +206,148 @@ def is_flask_reloader_process() -> bool: return os.environ.get('WERKZEUG_RUN_MAIN') != 'true' def apply_all_windows_fixes(): - """ - Wendet alle Windows-spezifischen Fixes an. - Sichere Version ohne potentielle Rekursion. - """ + """Wendet alle Windows-spezifischen Fixes an.""" global _windows_fixes_applied - if os.name != 'nt': - windows_logger.debug("⏭️ Keine Windows-Fixes nötig (nicht Windows)") - return - if _windows_fixes_applied: - windows_logger.debug("⏭️ Windows-Fixes bereits angewendet") return + + try: + logger.info("🔧 Wende Windows-spezifische Fixes an...") - windows_logger.info("🔧 Wende Windows-spezifische Fixes an...") - - # Sichere Implementierung - setup_windows_environment() - apply_safe_socket_options() # Neue sichere Socket-Behandlung - fix_windows_socket_issues() # Vereinfachte Socket-Fixes - - # Thread-Manager initialisieren - thread_manager = get_windows_thread_manager() - - # Atexit-Handler nur einmal registrieren - atexit.register(thread_manager.shutdown_all) - - _windows_fixes_applied = True - windows_logger.info("✅ Alle Windows-Fixes erfolgreich angewendet") + # 1. Encoding-Fixes + apply_encoding_fixes() + + # 2. Threading-Fixes + apply_threading_fixes() + + # 3. Signal-Handler-Fixes + apply_signal_fixes() + + # 4. Subprocess-Patch für UTF-8 Encoding + patch_subprocess() + + # 5. Globaler Subprocess-Patch für bereits importierte Module + apply_global_subprocess_patch() + + _windows_fixes_applied = True + logger.info("✅ Alle Windows-Fixes erfolgreich angewendet") + + except Exception as e: + logger.error(f"❌ Fehler beim Anwenden der Windows-Fixes: {str(e)}") + raise e # Automatisch Windows-Fixes beim Import anwenden (nur einmal) if os.name == 'nt' and not _windows_fixes_applied: - apply_all_windows_fixes() \ No newline at end of file + # Sehr früher subprocess-Patch für sofortige Wirkung + try: + import subprocess + if not hasattr(subprocess, '_early_patched'): + patch_subprocess() + subprocess._early_patched = True + logger.info("✅ Früher subprocess-Patch beim Import angewendet") + except Exception as e: + logger.warning(f"⚠️ Früher subprocess-Patch fehlgeschlagen: {str(e)}") + + apply_all_windows_fixes() + +# ===== SICHERE SUBPROCESS-WRAPPER ===== + +def safe_subprocess_run(*args, **kwargs): + """ + Sicherer subprocess.run Wrapper für Windows mit UTF-8 Encoding. + Verhindert charmap-Fehler durch explizite Encoding-Einstellungen. + """ + import subprocess + + # Standard-Encoding für Windows setzen + if 'encoding' not in kwargs and kwargs.get('text', False): + kwargs['encoding'] = 'utf-8' + kwargs['errors'] = 'replace' + + # Timeout-Standard setzen falls nicht vorhanden + if 'timeout' not in kwargs: + kwargs['timeout'] = 30 + + try: + return subprocess.run(*args, **kwargs) + except subprocess.TimeoutExpired as e: + logger.warning(f"Subprocess-Timeout nach {kwargs.get('timeout', 30)}s: {' '.join(args[0]) if args and isinstance(args[0], list) else str(args)}") + raise e + except UnicodeDecodeError as e: + logger.error(f"Unicode-Decode-Fehler in subprocess: {str(e)}") + # Fallback ohne text=True + kwargs_fallback = kwargs.copy() + kwargs_fallback.pop('text', None) + kwargs_fallback.pop('encoding', None) + kwargs_fallback.pop('errors', None) + return subprocess.run(*args, **kwargs_fallback) + except Exception as e: + logger.error(f"Subprocess-Fehler: {str(e)}") + raise e + +# ===== SUBPROCESS-MONKEY-PATCH ===== + +def patch_subprocess(): + """ + Patcht subprocess.run und subprocess.Popen um automatisch sichere Encoding-Einstellungen zu verwenden. + """ + import subprocess + + # Original-Funktionen speichern + if not hasattr(subprocess, '_original_run'): + subprocess._original_run = subprocess.run + subprocess._original_popen = subprocess.Popen + + def patched_run(*args, **kwargs): + # Automatisch UTF-8 Encoding für text=True setzen + if kwargs.get('text', False) and 'encoding' not in kwargs: + kwargs['encoding'] = 'utf-8' + kwargs['errors'] = 'replace' + + return subprocess._original_run(*args, **kwargs) + + def patched_popen(*args, **kwargs): + # Automatisch UTF-8 Encoding für text=True setzen + if kwargs.get('text', False) and 'encoding' not in kwargs: + kwargs['encoding'] = 'utf-8' + kwargs['errors'] = 'replace' + + # Auch für universal_newlines (ältere Python-Versionen) + if kwargs.get('universal_newlines', False) and 'encoding' not in kwargs: + kwargs['encoding'] = 'utf-8' + kwargs['errors'] = 'replace' + + return subprocess._original_popen(*args, **kwargs) + + subprocess.run = patched_run + subprocess.Popen = patched_popen + logger.info("✅ Subprocess automatisch gepatcht für UTF-8 Encoding (run + Popen)") + +# ===== GLOBALER SUBPROCESS-PATCH ===== + +def apply_global_subprocess_patch(): + """ + Wendet den subprocess-Patch global an, auch für bereits importierte Module. + """ + import sys + import subprocess + + # Patch subprocess direkt + patch_subprocess() + + # Patch auch in bereits importierten Modulen + for module_name, module in sys.modules.items(): + if hasattr(module, 'subprocess') and module.subprocess is subprocess: + # Modul verwendet subprocess - patch es + module.subprocess = subprocess + logger.debug(f"✅ Subprocess in Modul {module_name} gepatcht") + + logger.info("✅ Globaler subprocess-Patch angewendet") + +# ===== EXPORT SAFE SUBPROCESS ===== + +# Sichere subprocess-Funktion exportieren +__all__.append('safe_subprocess_run') +__all__.append('patch_subprocess') +__all__.append('apply_global_subprocess_patch') \ No newline at end of file