From 59480217aa86019532064d7b26ecb691b5d97b8e Mon Sep 17 00:00:00 2001 From: SashegDev Date: Fri, 8 May 2026 18:51:15 +0000 Subject: [PATCH] Server: generate meta.json for builds/ on startup for incremental updates --- server/main.py | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/server/main.py b/server/main.py index 8477b01..cfb8d60 100644 --- a/server/main.py +++ b/server/main.py @@ -151,6 +151,10 @@ async def lifespan(app: FastAPI): # Scan launcher versions and generate meta logger.info("Scanning launcher versions...") + # Generate meta.json in builds/ directory + logger.info("Generating launcher meta...") + generate_launcher_builds_meta() + # Extract new format ZIPs to versions directory logger.info("Extracting new format versions...") extract_new_format_versions() @@ -829,8 +833,79 @@ def calculate_file_hash(file_path: Path) -> str: return hash_sha.hexdigest() +def generate_launcher_builds_meta(): + """Generate meta.json in builds/ directory for incremental updates""" + import hashlib + + version = get_current_launcher_version() + if not version: + return + + meta_path = BUILDS_DIR / "meta.json" + + # Check if meta exists and is fresh + if meta_path.exists(): + try: + with open(meta_path, 'r', encoding='utf-8') as f: + existing = json.load(f) + if existing.get("version") == version: + logger.debug("Launcher meta.json already exists and is current") + return + except Exception: + pass + + # Generate new meta + files = [] + try: + for file_path in BUILDS_DIR.rglob("*"): + if file_path.is_file() and file_path.name not in ["meta.json"]: + rel_path = str(file_path.relative_to(BUILDS_DIR)) + stat = file_path.stat() + + # Calculate hash + sha256_hash = hashlib.sha256() + with open(file_path, "rb") as f: + for chunk in iter(lambda: f.read(8192), b""): + sha256_hash.update(chunk) + + files.append({ + "path": rel_path, + "size": stat.st_size, + "hash": f"sha256:{sha256_hash.hexdigest()}" + }) + except Exception as e: + logger.warning(f"Failed to generate launcher meta: {e}") + return + + meta = { + "version": version, + "type": "builds", + "release_date": datetime.utcnow().isoformat(), + "files": files + } + + try: + with open(meta_path, 'w', encoding='utf-8') as f: + json.dump(meta, f, indent=2) + logger.info(f"Generated launcher meta.json with {len(files)} files") + except Exception as e: + logger.warning(f"Failed to save meta.json: {e}") + + def scan_launcher_version(version: str) -> Optional[dict]: """Scan a launcher version directory and return meta""" + # First check if meta exists in builds/ directly (for new format) + meta_path = BUILDS_DIR / "meta.json" + if meta_path.exists(): + try: + with open(meta_path, 'r', encoding='utf-8') as f: + meta = json.load(f) + if meta.get("version") == version: + return meta + except Exception: + pass + + # Fallback: check versions directory version_path = VERSIONS_DIR / version if not version_path.exists() or not version_path.is_dir():