feat: add mod editing, revision merges and secure game storage
Add immutable revisions, PGVN editor, asset replacement, merge and rebase workflows, authenticated media delivery and reachability GC. Harden the script interpreter, pin unrpyc and remove tracked build metadata. Include current compatibility checks, Naninovel import and regression tests.
This commit is contained in:
1 parent
06ff19ac4a
commit
c8d83b3fe7
65 files changed
+3825
-68
No files matched your search
+17
-2
@@ -10,6 +10,7 @@ from sqlalchemy import select, update
|
||||
from app.blobs import read_bytes
|
||||
from app.config import get_settings
|
||||
from app.converter.pipeline import convert_archive
|
||||
from app.converter.compatibility import CompatibilityError
|
||||
from app.db import SessionLocal
|
||||
from app.models import Game, GameVersion
|
||||
from app.routers.games import make_cover
|
||||
@@ -36,7 +37,7 @@ async def claim() -> GameVersion | None:
|
||||
return None
|
||||
v = await db.get(GameVersion, version_id)
|
||||
v.status = "converting"
|
||||
v.progress = "Начало конвертации"
|
||||
v.progress = "Проверка совместимости игры"
|
||||
await db.commit()
|
||||
return v
|
||||
|
||||
@@ -48,6 +49,18 @@ async def process(v: GameVersion) -> None:
|
||||
|
||||
|
||||
async def convert(version_id: int, source: Path, filename: str) -> bool:
|
||||
from app.maintenance import storage_access
|
||||
async with storage_access():
|
||||
task = asyncio.create_task(_convert(version_id, source, filename))
|
||||
try:
|
||||
return await asyncio.shield(task)
|
||||
except asyncio.CancelledError:
|
||||
# Conversion threads cannot be cancelled. Keep the lease until commit.
|
||||
await task
|
||||
raise
|
||||
|
||||
|
||||
async def _convert(version_id: int, source: Path, filename: str) -> bool:
|
||||
"""Run the converter for a version and store the outcome. Returns success."""
|
||||
loop = asyncio.get_running_loop()
|
||||
work = get_settings().work_dir / str(version_id)
|
||||
@@ -65,7 +78,7 @@ async def convert(version_id: int, source: Path, filename: str) -> bool:
|
||||
if version:
|
||||
version.status = "failed"
|
||||
version.progress = f"Ошибка: {e}"[:255]
|
||||
version.report = {"error": str(e)}
|
||||
version.report = e.report() if isinstance(e, CompatibilityError) else {"error": str(e)}
|
||||
await db.commit()
|
||||
return False
|
||||
finally:
|
||||
@@ -81,6 +94,8 @@ async def convert(version_id: int, source: Path, filename: str) -> bool:
|
||||
version.report = result.report
|
||||
version.size_bytes = result.size
|
||||
game = await db.get(Game, version.game_id)
|
||||
if game:
|
||||
game.engine = result.report.get("engine", "renpy")
|
||||
if game and not game.cover_hash and result.cover_source:
|
||||
try:
|
||||
game.cover_hash = await asyncio.to_thread(make_cover,
|
||||
|
||||
Reference in new issue
Block a user