mirror of
https://github.com/rommapp/romm.git
synced 2026-06-28 06:46:00 +00:00
feat: Use X-Accel-Redirect to improve file download speed
Instead of making FastAPI handle file download, which has serious performance issues on big files [1], this change uses nginx's `X-Accel` feature to delegate single-file downloads to nginx. Partial fix for #1079, as it solves the CPU usage issue for single-file downloads. [1] https://github.com/fastapi/fastapi/discussions/6050
This commit is contained in:
@@ -13,7 +13,8 @@ GUNICORN_WORKERS: Final = int(os.environ.get("GUNICORN_WORKERS", 2))
|
||||
|
||||
# PATHS
|
||||
ROMM_BASE_PATH: Final = os.environ.get("ROMM_BASE_PATH", "/romm")
|
||||
LIBRARY_BASE_PATH: Final = f"{ROMM_BASE_PATH}/library"
|
||||
LIBRARY_PATH_SUFFIX: Final = "/library"
|
||||
LIBRARY_BASE_PATH: Final = f"{ROMM_BASE_PATH}{LIBRARY_PATH_SUFFIX}"
|
||||
RESOURCES_BASE_PATH: Final = f"{ROMM_BASE_PATH}/resources"
|
||||
ASSETS_BASE_PATH: Final = f"{ROMM_BASE_PATH}/assets"
|
||||
FRONTEND_RESOURCES_PATH: Final = "/assets/romm/resources"
|
||||
|
||||
@@ -9,6 +9,7 @@ from anyio import Path, open_file
|
||||
from config import (
|
||||
DISABLE_DOWNLOAD_ENDPOINT_AUTH,
|
||||
LIBRARY_BASE_PATH,
|
||||
LIBRARY_PATH_SUFFIX,
|
||||
RESOURCES_BASE_PATH,
|
||||
)
|
||||
from decorators.auth import protected_route
|
||||
@@ -22,7 +23,7 @@ from endpoints.responses.rom import (
|
||||
)
|
||||
from exceptions.endpoint_exceptions import RomNotFoundInDatabaseException
|
||||
from exceptions.fs_exceptions import RomAlreadyExistsException
|
||||
from fastapi import File, HTTPException, Query, Request, UploadFile, status
|
||||
from fastapi import File, HTTPException, Query, Request, Response, UploadFile, status
|
||||
from fastapi.responses import FileResponse
|
||||
from handler.database import db_platform_handler, db_rom_handler
|
||||
from handler.filesystem import fs_resource_handler, fs_rom_handler
|
||||
@@ -210,17 +211,28 @@ async def get_rom_content(
|
||||
if not rom:
|
||||
raise RomNotFoundInDatabaseException(id)
|
||||
|
||||
rom_path = f"{LIBRARY_BASE_PATH}/{rom.full_path}"
|
||||
files_to_download = files or [r["filename"] for r in rom.files]
|
||||
|
||||
if not rom.multi:
|
||||
return FileResponse(path=rom_path, filename=rom.file_name)
|
||||
return Response(
|
||||
headers={
|
||||
"Content-Disposition": f'attachment; filename="{quote(rom.file_name)}"',
|
||||
"Content-Type": "application/octet-stream",
|
||||
"X-Accel-Redirect": f"{LIBRARY_PATH_SUFFIX}/{rom.full_path}",
|
||||
},
|
||||
)
|
||||
|
||||
if len(files_to_download) == 1:
|
||||
return FileResponse(
|
||||
path=f"{rom_path}/{files_to_download[0]}", filename=files_to_download[0]
|
||||
return Response(
|
||||
headers={
|
||||
"Content-Disposition": f'attachment; filename="{quote(files_to_download[0])}"',
|
||||
"Content-Type": "application/octet-stream",
|
||||
"X-Accel-Redirect": f"{LIBRARY_PATH_SUFFIX}/{rom.full_path}/{files_to_download[0]}",
|
||||
},
|
||||
)
|
||||
|
||||
rom_path = f"{LIBRARY_BASE_PATH}/{rom.full_path}"
|
||||
|
||||
# Builds a generator of tuples for each member file
|
||||
async def local_files() -> AsyncIterator[AsyncMemberFile]:
|
||||
async def contents(filename: str) -> AsyncIterator[bytes]:
|
||||
|
||||
@@ -87,5 +87,11 @@ http {
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}
|
||||
|
||||
# Library files
|
||||
location /library {
|
||||
internal;
|
||||
alias /romm/library;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user