Skip to content

Commit

Permalink
Merge pull request #664 from zurdi15/3.0-rc-6
Browse files Browse the repository at this point in the history
Hotfixes for RC6
  • Loading branch information
zurdi15 committed Feb 26, 2024
2 parents 3701c97 + 9bc6fb4 commit 4cb4dd3
Show file tree
Hide file tree
Showing 15 changed files with 235 additions and 184 deletions.
135 changes: 79 additions & 56 deletions backend/config/config_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from pathlib import Path
from typing import Final
from urllib.parse import quote_plus

import pydash
import yaml
from config import (
Expand Down Expand Up @@ -69,7 +68,7 @@ def __init__(self, config_file: str = ROMM_USER_CONFIG_FILE):
with open(config_file, "w") as file:
file.write("")
try:
self.read_config()
self.get_config()
except ConfigNotReadableException as e:
log.critical(e.message)
sys.exit(5)
Expand All @@ -96,9 +95,7 @@ def get_db_engine() -> str:

# DEPRECATED
if ROMM_DB_DRIVER == "sqlite":
log.critical(
"Sqlite is not supported anymore, migrate to mariaDB"
)
log.critical("Sqlite is not supported anymore, migrate to mariaDB")
sys.exit(6)
# DEPRECATED

Expand Down Expand Up @@ -200,7 +197,7 @@ def _validate_config(self):
)
sys.exit(3)

def read_config(self) -> None:
def get_config(self) -> None:
try:
with open(self.config_file) as config_file:
self._raw_config = yaml.load(config_file, Loader=SafeLoader) or {}
Expand All @@ -209,10 +206,37 @@ def read_config(self) -> None:
except PermissionError:
self._raw_config = {}
raise ConfigNotReadableException

self._parse_config()
self._validate_config()

def update_config(self) -> None:
return self.config

def update_config_file(self) -> None:
self._raw_config = {
"exclude": {
"platforms": self.config.EXCLUDED_PLATFORMS,
"roms": {
"single_file": {
"extensions": self.config.EXCLUDED_SINGLE_EXT,
"names": self.config.EXCLUDED_SINGLE_FILES,
},
"multi_file": {
"names": self.config.EXCLUDED_MULTI_FILES,
"parts": {
"extensions": self.config.EXCLUDED_MULTI_PARTS_EXT,
"names": self.config.EXCLUDED_MULTI_PARTS_FILES,
},
},
},
},
"filesystem": {"roms_folder": self.config.ROMS_FOLDER_NAME},
"system": {
"platforms": self.config.PLATFORMS_BINDING,
"versions": self.config.PLATFORMS_VERSIONS,
},
}

try:
with open(self.config_file, "w") as config_file:
yaml.dump(self._raw_config, config_file)
Expand All @@ -221,66 +245,65 @@ def update_config(self) -> None:
except PermissionError:
self._raw_config = {}
raise ConfigNotWritableException
finally:
self._parse_config()

def add_binding(self, fs_slug: str, slug: str) -> None:
try:
_ = self._raw_config["system"]
except KeyError:
self._raw_config = {"system": {"platforms": {}}}
try:
_ = self._raw_config["system"]["platforms"]
except KeyError:
self._raw_config["system"]["platforms"] = {}
self._raw_config["system"]["platforms"][fs_slug] = slug
self.update_config()
def add_platform_binding(self, fs_slug: str, slug: str) -> None:
platform_bindings = self.config.PLATFORMS_BINDING
if fs_slug in platform_bindings:
log.warn(f"Binding for {fs_slug} already exists")
return

platform_bindings[fs_slug] = slug
self.config.PLATFORMS_BINDING = platform_bindings
self.update_config_file()

def remove_platform_binding(self, fs_slug: str) -> None:
platform_bindings = self.config.PLATFORMS_BINDING

def remove_binding(self, fs_slug: str) -> None:
try:
del self._raw_config["system"]["platforms"][fs_slug]
del platform_bindings[fs_slug]
except KeyError:
pass
self.update_config()

def add_version(self, fs_slug: str, slug: str) -> None:
try:
_ = self._raw_config["system"]
except KeyError:
self._raw_config = {"system": {"versions": {}}}
self.config.PLATFORMS_BINDING = platform_bindings
self.update_config_file()

def add_platform_version(self, fs_slug: str, slug: str) -> None:
platform_versions = self.config.PLATFORMS_VERSIONS
if fs_slug in platform_versions:
log.warn(f"Version for {fs_slug} already exists")
return

platform_versions[fs_slug] = slug
self.config.PLATFORMS_VERSIONS = platform_versions
self.update_config_file()

def remove_platform_version(self, fs_slug: str) -> None:
platform_versions = self.config.PLATFORMS_VERSIONS

try:
_ = self._raw_config["system"]["versions"]
del platform_versions[fs_slug]
except KeyError:
self._raw_config["system"]["versions"] = {}
self._raw_config["system"]["versions"][fs_slug] = slug
self.update_config()
pass

self.config.PLATFORMS_VERSIONS = platform_versions
self.update_config_file()

def add_exclusion(self, config_key: str, exclusion: str):
config_item = self.config.__getattribute__(config_key)
config_item.append(exclusion)
self.config.__setattr__(config_key, config_item)
self.update_config_file()

def remove_exclusion(self, config_key: str, exclusion: str):
config_item = self.config.__getattribute__(config_key)

def remove_version(self, fs_slug: str) -> None:
try:
del self._raw_config["system"]["versions"][fs_slug]
except KeyError:
config_item.remove(exclusion)
except ValueError:
pass
self.update_config()

# def _get_exclude_path(self, exclude):
# exclude_base = self._raw_config["exclude"]
# exclusions = {
# "platforms": exclude_base["platforms"],
# "single_ext": exclude_base["roms"]["single_file"]["extensions"],
# "single_file": exclude_base["roms"]["single_file"]["names"],
# "multi_file": exclude_base["roms"]["multi_file"]["names"],
# "multi_part_ext": exclude_base["roms"]["multi_file"]["parts"]["extensions"],
# "multi_part_file": exclude_base["roms"]["multi_file"]["parts"]["names"],
# }
# return exclusions[exclude]

# def add_exclusion(self, exclude: str, exclusion: str):
# config = self._get_exclude_path(exclude)
# config.append(exclusion)

# def remove_exclusion(self, exclude: str, exclusion: str):
# config = self._get_exclude_path(exclude)
# config.remove(exclusion)

self.config.__setattr__(config_key, config_item)
self.update_config_file()


config_manager = ConfigManager()
12 changes: 5 additions & 7 deletions backend/endpoints/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,13 @@ def get_config() -> ConfigResponse:
"""

try:
cm.read_config()
return cm.get_config().__dict__
except ConfigNotReadableException as e:
log.critical(e.message)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=e.message
)

return cm.config.__dict__


@protected_route(router.post, "/config/system/platforms", ["platforms.write"])
async def add_platform_binding(request: Request) -> MessageResponse:
Expand All @@ -40,7 +38,7 @@ async def add_platform_binding(request: Request) -> MessageResponse:
slug = data["slug"]

try:
cm.add_binding(fs_slug, slug)
cm.add_platform_binding(fs_slug, slug)
except ConfigNotWritableException as e:
log.critical(e.message)
raise HTTPException(
Expand All @@ -57,7 +55,7 @@ async def delete_platform_binding(request: Request, fs_slug: str) -> MessageResp
"""Delete platform binding from the configuration"""

try:
cm.remove_binding(fs_slug)
cm.remove_platform_binding(fs_slug)
except ConfigNotWritableException as e:
log.critical(e.message)
raise HTTPException(
Expand All @@ -76,7 +74,7 @@ async def add_platform_version(request: Request) -> MessageResponse:
slug = data["slug"]

try:
cm.add_version(fs_slug, slug)
cm.add_platform_version(fs_slug, slug)
except ConfigNotWritableException as e:
log.critical(e.message)
raise HTTPException(
Expand All @@ -93,7 +91,7 @@ async def delete_platform_version(request: Request, fs_slug: str) -> MessageResp
"""Delete platform version from the configuration"""

try:
cm.remove_version(fs_slug)
cm.remove_platform_version(fs_slug)
except ConfigNotWritableException as e:
log.critical(e.message)
raise HTTPException(
Expand Down
44 changes: 28 additions & 16 deletions backend/endpoints/rom.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
from datetime import datetime
from stat import S_IFREG
from typing import Annotated, Optional
Expand All @@ -24,7 +25,7 @@
)
from handler.fs_handler import CoverSize
from logger.logger import log
from stream_zip import ZIP_64, stream_zip # type: ignore[import]
from stream_zip import ZIP_AUTO, stream_zip # type: ignore[import]

router = APIRouter()

Expand Down Expand Up @@ -130,13 +131,14 @@ def get_rom(request: Request, id: int) -> RomSchema:
return RomSchema.from_orm_with_request(db_rom_handler.get_roms(id), request)


@protected_route(router.head, "/roms/{id}/content", ["roms.read"])
def head_rom_content(request: Request, id: int):
@protected_route(router.head, "/roms/{id}/content/{file_name}", ["roms.read"])
def head_rom_content(request: Request, id: int, file_name: str):
"""Head rom content endpoint
Args:
request (Request): Fastapi Request object
id (int): Rom internal id
file_name (str): Required due to a bug in emulatorjs
Returns:
FileResponse: Returns the response with headers
Expand All @@ -147,7 +149,7 @@ def head_rom_content(request: Request, id: int):

return FileResponse(
path=rom_path if not rom.multi else f"{rom_path}/{rom.files[0]}",
filename=rom.file_name,
filename=file_name,
headers={
"Content-Disposition": f"attachment; filename={rom.name}.zip",
"Content-Type": "application/zip",
Expand All @@ -156,9 +158,12 @@ def head_rom_content(request: Request, id: int):
)


@protected_route(router.get, "/roms/{id}/content", ["roms.read"])
@protected_route(router.get, "/roms/{id}/content/{file_name}", ["roms.read"])
def get_rom_content(
request: Request, id: int, files: Annotated[list[str] | None, Query()] = None
request: Request,
id: int,
file_name: str,
files: Annotated[list[str] | None, Query()] = None,
):
"""Download rom endpoint (one single file or multiple zipped files for multi-part roms)
Expand All @@ -178,28 +183,35 @@ def get_rom_content(
rom_path = f"{LIBRARY_BASE_PATH}/{rom.full_path}"

if not rom.multi:
return FileResponse(path=rom_path, filename=rom.file_name)
return FileResponse(path=rom_path, filename=file_name)

# Builds a generator of tuples for each member file
def local_files():
def contents(file_name):
def contents(f):
try:
with open(f"{rom_path}/{file_name}", "rb") as f:
with open(f"{rom_path}/{f}", "rb") as f:
while chunk := f.read(65536):
yield chunk
except FileNotFoundError:
log.error(f"File {rom_path}/{file_name} not found!")
log.error(f"File {rom_path}/{f} not found!")

m3u_file = [str.encode(f"{rom.files[i]}\n") for i in range(len(rom.files))]
return [
(file_name, datetime.now(), S_IFREG | 0o600, ZIP_64, contents(file_name))
for file_name in rom.files
(
f,
datetime.now(),
S_IFREG | 0o600,
ZIP_AUTO(os.path.getsize(f"{rom_path}/{f}")),
contents(f),
)
for f in rom.files
] + [
(
f"{rom.file_name}.m3u",
f"{file_name}.m3u",
datetime.now(),
S_IFREG | 0o600,
ZIP_64,
[str.encode(f"{rom.files[i]}\n") for i in range(len(rom.files))],
ZIP_AUTO(sum([len(f) for f in m3u_file])),
m3u_file,
)
]

Expand All @@ -209,7 +221,7 @@ def contents(file_name):
return CustomStreamingResponse(
zipped_chunks,
media_type="application/zip",
headers={"Content-Disposition": f"attachment; filename={rom.file_name}.zip"},
headers={"Content-Disposition": f"attachment; filename={file_name}.zip"},
emit_body={"id": rom.id},
)

Expand Down
Loading

0 comments on commit 4cb4dd3

Please sign in to comment.