Skip to content

Commit ff8d4d0

Browse files
authored
Merge pull request #3986 from rommapp/fix/launchbox-cloud-empty-store
fix(launchbox): stop the cloud provider from silently matching nothing
2 parents 49f2b48 + 57f4fd2 commit ff8d4d0

14 files changed

Lines changed: 457 additions & 111 deletions

File tree

backend/endpoints/tasks.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
ENABLE_RESCAN_ON_FILESYSTEM_CHANGE,
1212
RESCAN_ON_FILESYSTEM_CHANGE_DELAY,
1313
TASK_RESULT_TTL,
14-
TASK_TIMEOUT,
1514
)
1615
from decorators.auth import protected_route
1716
from endpoints.responses import (
@@ -145,7 +144,7 @@ def _build_task_info(name: str, task: Task) -> TaskInfo:
145144
title=task.title,
146145
description=task.description,
147146
enabled=task.enabled,
148-
manual_run=task.manual_run,
147+
manual_run=task.can_run_manually,
149148
cron_string=task.cron_string or "",
150149
)
151150

@@ -385,7 +384,7 @@ async def run_single_task(
385384
)
386385

387386
task_instance = all_tasks[task_name]
388-
if not task_instance.enabled or not task_instance.manual_run:
387+
if not task_instance.can_run_manually:
389388
raise HTTPException(
390389
status_code=400,
391390
detail=f"Task '{task_name}' cannot be run",
@@ -394,7 +393,7 @@ async def run_single_task(
394393
job = low_prio_queue.enqueue(
395394
task_instance.run,
396395
kwargs=task_kwargs or {},
397-
job_timeout=TASK_TIMEOUT,
396+
job_timeout=task_instance.timeout,
398397
result_ttl=TASK_RESULT_TTL,
399398
meta={
400399
"task_name": task_instance.title,

backend/handler/metadata/launchbox_handler/handler.py

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from .remote_source import RemoteSource
1515
from .types import (
1616
DASH_COLON_REGEX,
17+
LAUNCHBOX_METADATA_INITIAL_IMPORT_KEY,
1718
LAUNCHBOX_METADATA_NAME_KEY,
1819
LAUNCHBOX_PLATFORMS_DIR,
1920
LAUNCHBOX_TAG_REGEX,
@@ -39,8 +40,31 @@ def is_local_enabled(cls) -> bool:
3940
def is_enabled(cls) -> bool:
4041
return cls.is_cloud_enabled() or cls.is_local_enabled()
4142

43+
@staticmethod
44+
async def is_remote_store_populated() -> bool:
45+
return bool(await async_cache.exists(LAUNCHBOX_METADATA_NAME_KEY))
46+
47+
@staticmethod
48+
async def is_remote_store_importing() -> bool:
49+
return bool(await async_cache.exists(LAUNCHBOX_METADATA_INITIAL_IMPORT_KEY))
50+
4251
async def heartbeat(self) -> bool:
43-
return self.is_enabled()
52+
if self.is_local_enabled():
53+
return True
54+
55+
if not self.is_cloud_enabled():
56+
return False
57+
58+
# A first import commits in batches, so the store starts answering for a
59+
# handful of names long before it holds the whole dump. Until that run
60+
# finishes, most lookups still miss.
61+
if await self.is_remote_store_importing():
62+
return False
63+
64+
# Cloud lookups read from a cache the metadata update task fills. Until
65+
# it has run, every lookup returns nothing, so reporting healthy here
66+
# would be a lie.
67+
return await self.is_remote_store_populated()
4468

4569
def get_platform(self, slug: str) -> LaunchboxPlatform:
4670
return get_platform(slug)
@@ -60,9 +84,7 @@ async def get_rom(
6084

6185
local = await self._local.get_rom(fs_name, platform_slug)
6286

63-
remote_available = remote_enabled and bool(
64-
await async_cache.exists(LAUNCHBOX_METADATA_NAME_KEY)
65-
)
87+
remote_available = remote_enabled and await self.is_remote_store_populated()
6688

6789
if local is not None:
6890
launchbox_id_local = safe_int(local.get("DatabaseID"))
@@ -238,6 +260,13 @@ async def get_matched_roms_by_name(
238260
if not self.is_enabled():
239261
return []
240262

263+
if self.is_cloud_enabled() and not await self.is_remote_store_populated():
264+
log.warning(
265+
"LaunchBox metadata store is empty, so no cloud results can be "
266+
"returned. Set ENABLE_SCHEDULED_UPDATE_LAUNCHBOX_METADATA=true and "
267+
"run the LaunchBox metadata update task to populate it."
268+
)
269+
241270
rom = await self.get_rom(search_term, platform_slug, keep_tags=True)
242271
return [rom]
243272

backend/handler/metadata/launchbox_handler/platforms.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ class SlugToLaunchboxId(TypedDict):
5252
UPS.CAMPUTERS_LYNX: {"id": 61, "name": "Camputers Lynx"},
5353
UPS.CASIO_LOOPY: {"id": 114, "name": "Casio Loopy"},
5454
UPS.CASIO_PV_1000: {"id": 115, "name": "Casio PV-1000"},
55-
UPS.COLECOADAM: {"id": 117, "name": "Coleco Adam"},
55+
UPS.COLECOADAM: {"id": 117, "name": "Coleco ADAM"},
5656
UPS.COLECOVISION: {"id": 13, "name": "ColecoVision"},
5757
UPS.COLOUR_GENIE: {"id": 73, "name": "EACA EG2000 Colour Genie"},
5858
UPS.COMMODORE_CDTV: {"id": 120, "name": "Commodore CDTV"},
@@ -76,7 +76,7 @@ class SlugToLaunchboxId(TypedDict):
7676
"id": 58,
7777
"name": "Fairchild Channel F",
7878
},
79-
UPS.FAMICOM: {"id": 27, "name": "Nintendo Famicom"},
79+
UPS.FAMICOM: {"id": 27, "name": "Nintendo Entertainment System"},
8080
UPS.FDS: {"id": 157, "name": "Nintendo Famicom Disk System"},
8181
UPS.FM_7: {"id": 186, "name": "Fujitsu FM-7"},
8282
UPS.FM_TOWNS: {"id": 124, "name": "Fujitsu FM Towns Marty"},
@@ -161,7 +161,7 @@ class SlugToLaunchboxId(TypedDict):
161161
UPS.SEGACD: {"id": 39, "name": "Sega CD"},
162162
UPS.SEGACD32: {"id": 173, "name": "Sega CD 32X"},
163163
UPS.SERIES_X_S: {"id": 222, "name": "Microsoft Xbox Series X/S"},
164-
UPS.SFAM: {"id": 53, "name": "Super Famicom"},
164+
UPS.SFAM: {"id": 53, "name": "Super Nintendo Entertainment System"},
165165
UPS.SG1000: {"id": 80, "name": "Sega SG-1000"},
166166
UPS.SHARP_MZ_80B20002500: {"id": 205, "name": "Sharp MZ-2500"},
167167
UPS.SHARP_X68000: {"id": 128, "name": "Sharp X68000"},

backend/handler/metadata/launchbox_handler/remote_source.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,14 @@ async def get_rom(
7070
metadata_database_index_entry = await async_cache.hget(
7171
LAUNCHBOX_METADATA_DATABASE_ID_KEY, database_id
7272
)
73-
if metadata_database_index_entry:
74-
return json.loads(metadata_database_index_entry)
73+
if not metadata_database_index_entry:
74+
continue
75+
76+
# The alternate name index is not keyed by platform, so a hit can
77+
# point at a same-titled game on a completely different system.
78+
entry = json.loads(metadata_database_index_entry)
79+
if entry.get("Platform") == platform_name:
80+
return entry
7581

7682
return None
7783

backend/handler/metadata/launchbox_handler/types.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616
LAUNCHBOX_METADATA_IMAGE_KEY: Final[str] = "romm:launchbox_metadata_image"
1717
LAUNCHBOX_MAME_KEY: Final[str] = "romm:launchbox_mame"
1818
LAUNCHBOX_FILES_KEY: Final[str] = "romm:launchbox_files"
19+
# Set while the store is being filled for the first time
20+
LAUNCHBOX_METADATA_INITIAL_IMPORT_KEY: Final[str] = (
21+
"romm:launchbox_metadata_initial_import"
22+
)
1923

2024
LAUNCHBOX_LOCAL_DIR: Final[Path] = Path(ROMM_BASE_PATH) / "launchbox"
2125
LAUNCHBOX_PLATFORMS_DIR: Final[Path] = LAUNCHBOX_LOCAL_DIR / "Data" / "Platforms"

0 commit comments

Comments
 (0)