DevBlog №4 | массовый фикс JFX и фиксы связанные с самим лаунчером, добавление админ меню

This commit is contained in:
SashegDev
2026-07-01 19:36:52 +00:00
parent e49e630afe
commit 0d61ad1107
12 changed files with 1915 additions and 99 deletions
+63 -25
View File
@@ -43,6 +43,7 @@ manifest_cache = TTLCache(maxsize=100, ttl=300)
BUILDS_DIR = Path("builds")
VERSIONS_DIR = BUILDS_DIR / "versions"
WHITELIST_DIR = Path(__file__).parent / "whitelist"
# Mirror configuration
LAUNCHER_MIRRORS = {
@@ -1256,36 +1257,42 @@ def generate_launcher_builds_meta():
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
# Always regenerate to pick up file changes (new JS, CSS, etc.)
# The version check alone is insufficient — same version can have different files
# 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()}"
})
if not file_path.is_file():
continue
rel_path = str(file_path.relative_to(BUILDS_DIR))
# Only include runtime files needed for launcher updates
# Skip: JRE, JavaFX, old ZIPs, extracted versions, docs, root JARs
if rel_path.startswith(("jre21/", "lib/", "lib-javafx/", "versions/", "libs/")):
continue
if rel_path.endswith(".zip") or rel_path in ("README.txt", "build.version"):
continue
if file_path.name in ("meta.json",):
continue
# Skip root-level JARs — only bin/*.jar is needed at runtime
if rel_path in ("zernmclauncher.jar", "zernmc-bootstrap.jar"):
continue
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
@@ -1905,6 +1912,37 @@ async def get_news(news_id: str):
}
# ====================== WHITELIST MODS ======================
WHITELIST_MODS_FILE = WHITELIST_DIR / "mods.txt"
@app.get("/whitelist/mods")
async def list_whitelist_mods(current_user: dict = Depends(get_current_user)):
"""Return whitelist mods list as name :: size :: hash lines"""
if not WHITELIST_MODS_FILE.exists():
return Response(content="", media_type="text/plain")
content = WHITELIST_MODS_FILE.read_text(encoding="utf-8").strip()
if not content:
return Response(content="", media_type="text/plain")
return Response(content=content, media_type="text/plain")
@app.get("/whitelist/mods/{mod_hash}/{filename:path}")
async def download_whitelist_mod(mod_hash: str, filename: str, request: Request, current_user: dict = Depends(get_current_user)):
"""Download whitelist mod file by hash"""
if ".." in mod_hash or ".." in filename:
raise HTTPException(400, "Invalid path")
mod_path = WHITELIST_DIR / mod_hash
if not mod_path.exists() or not mod_path.is_file():
raise HTTPException(404, "Mod not found")
return await send_file_async(mod_path, request, cache=True)
# ====================== ПРОКСИ ЭНДПОИНТЫ ======================
# Эти эндпоинты позволяют клиентам с сетевыми проблемами
# скачивать файлы через сервер Zern