import os import zlib import glob import time import sys from core.connection import BuzzerError def get_file_crc32(filepath: str) -> int: """Berechnet die IEEE CRC32-Prüfsumme einer Datei in Chunks.""" crc = 0 with open(filepath, 'rb') as f: while chunk := f.read(4096): crc = zlib.crc32(chunk, crc) return crc & 0xFFFFFFFF def execute(conn, sources: list, target: str): # 1. Globbing auflösen resolved_files = [f for src in sources for f in glob.glob(src) if os.path.isfile(f)] if not resolved_files: print("Keine gültigen Dateien gefunden.") return total_size_all = sum(os.path.getsize(f) for f in resolved_files) sent_all = 0 start_time_all = time.monotonic() is_target_dir = target.endswith('/') for filepath in resolved_files: filename = os.path.basename(filepath) filesize = os.path.getsize(filepath) crc32 = get_file_crc32(filepath) dest_path = f"{target}{filename}" if is_target_dir else target print(f"Sende 📄 {filename} ({filesize/1024:.1f} KB) -> {dest_path}") start_time_file = time.monotonic() sent_file = 0 def progress_handler(chunk_len): nonlocal sent_file, sent_all sent_file += chunk_len sent_all += chunk_len elapsed = time.monotonic() - start_time_file speed = (sent_file / 1024) / elapsed if elapsed > 0 else 0 # Prozentberechnungen perc_file = (sent_file / filesize) * 100 perc_all = (sent_all / total_size_all) * 100 # ETA (Basierend auf Gesamtgeschwindigkeit) elapsed_all = time.monotonic() - start_time_all avg_speed_all = sent_all / elapsed_all if elapsed_all > 0 else 0 eta_sec = (total_size_all - sent_all) / avg_speed_all if avg_speed_all > 0 else 0 eta_str = f"{int(eta_sec // 60):02d}:{int(eta_sec % 60):02d}" # Ausgabezeile (\r überschreibt die aktuelle Zeile) sys.stdout.write( f"\r \033[90mProg: {perc_file:3.0f}% | Gesamt: {perc_all:3.0f}% | " f"{speed:6.1f} KB/s | ETA: {eta_str}\033[0m" ) sys.stdout.flush() try: cmd = f"put {dest_path};{filesize};{crc32}\n" conn.serial.write(cmd.encode('utf-8')) conn.serial.flush() # Binärtransfer mit unserem Handler conn.send_binary(filepath, progress_callback=progress_handler) # Zeile nach Erfolg abschließen print(f"\r \033[32mFertig: {filename} übertragen. \033[0m") except Exception as e: print(f"\n ❌ \033[31mFehler: {e}\033[0m") total_duration = time.monotonic() - start_time_all print(f"\nAlle {len(resolved_files)} Dateien in {total_duration:.1f}s übertragen.")