Georges-Antoine AssiandClaude Opus 5.5 75e8a9efae fix(sync): keep RetroArch Cloud Sync from stalling the event loop (#5171)
* fix(sync): keep RetroArch Cloud Sync from stalling the event loop

Basic auth ran its bcrypt check (~250ms) on the event loop for every
WebDAV request, and the manifest ran its queries there too, so parallel
RetroArch requests queued behind each other. Both now run in a thread.

Cloud Sync resolves every save and state to a ROM by fs_name_no_ext,
which no index led with; 0149 adds one so unmatched uploads fail fast.

The upload dialog now offers a core for saves as well as states, so a
manually uploaded save lands in the core folder RetroArch reads, and its
slot hint says only unslotted saves reach RetroArch.

Refs #5158

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* test(sync): cover manifest queries running off the event loop

Addresses Greptile review on #5171: trim the 0149 migration docstring to
its summary, annotate the new MockConnection constructor, and add
regression tests that build_manifest and list_manifest_paths query from a
worker thread.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* fix(auth): mark Basic-auth users active off the event loop

pr-ready step 2 (code-review): run the user lookup, password check and
set_last_active in one worker-thread hop, and test that SaveDataTab offers
save cores and forwards the picked core on upload.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* test(v2): build SaveDataTab test saves and states from shared fixtures

pr-ready step 3 (simplify): replace the hand-cast UserSaveSchema and
UserStateSchema stubs with saveFixture/stateFixture plus toUserSave/toUserState.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* chore(sync): drop restating index comment and type the test spy

pr-ready step 4 (review-polish): remove the comment that only restated
idx_roms_fs_name_no_ext, and type the manifest test's get_saves spy so mypy
passes across the backend.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* fix(auth): check the password grant's credentials off the event loop

The OAuth password grant ran bcrypt (~250ms) on the event loop, stalling
every other request the worker was serving.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* fix(sync): run RetroArch WebDAV database work off the event loop

GET, PUT, DELETE and PROPFIND resolved ROMs, looked up and wrote save,
state and screenshot rows, and listed whole platforms synchronously inside
async handlers; the PSP bundle helpers did the same. Each now runs that
work in a worker thread.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* fix(saves): keep another core's same-named save on upload

A slot-less upload matched an existing save by file name alone, so
uploading game.srm for a second core rewrote the first core's row to the
new folder and deleted its file. The lookup now only matches a save made
with the requested core. Clients that send no core still match any, so
device conflict detection is unchanged, preferring a save filed under no
core.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* feat(v2): file a save picked with a core out of the slots

RetroArch Cloud Sync only lists unslotted saves, so picking a core in the
upload dialog moves an untouched slot from autosave to "No slot", and
clearing the core moves it back. A slot the user picked is kept.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* revert(i18n): restore the original upload slot hint

Picking a core now files a save out of the slots, so the hint no longer
needs to explain RetroArch Cloud Sync.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-07 14:37:36 -04:00
2026-04-15 19:20:17 -04:00
2024-05-21 19:22:14 -04:00
2024-02-11 16:41:36 +01:00
2024-07-09 13:43:14 +02:00

romm logo

A beautiful, powerful, self-hosted ROM manager and player.

Trendshift hackernews badge
selfh.st badge Discord

Overview

Scan, enrich, browse and play your ROM collection from one beautiful & free self-hosted app. Metadata from 10+ providers, save sync across your devices, and support for over 400 platforms. RomM is a must-have for anyone who plays on emulators.

Browsing a library and playing a game in RomM

Features

Installation

The easiest way to start is with the Quick Start Guide in the docs. If you're having trouble with setup, please review the page for troubleshooting steps.

Prefer a hosted deploy over wiring up the stack yourself?

Deploy on Hostinger
Starting at $6.49/mo · Setup guide

Deployment and infrastructure support for this install is handled by Hostinger. Prices are indicative and may not reflect current offerings. Signups through the link above send a share of the revenue back to us, which helps fund the project.

Official apps

Playnite libraryPlaynite logo Playnite plugin

Effortlessly integrate your retro game collection into Playnite, the open-source game library manager that provides a unified interface for all of your games on PC.

Windows Desktop QR pairing

Install  by @gantoine


Argosy libraryArgosy logo Argosy

Sync your library, download games on demand and track your achievements, from a gamepad-first interface designed for Anbernic, Retroid Pocket, Odin, and similar devices.

Android Handhelds QR pairing Save sync

Download  by @tmgast


Grout multi-selectGrout logo Grout

A lightweight client for your favorite handheld custom firmwares*. Download games, box art and BIOS files wirelessly, and sync your saves automatically as you play.

Linux Handhelds Save sync

Quick start  by @BrandonKowalski

*Supports Allium, Batocera, Knulli, MinUI, muOS, NextUI, Onion, ROCKNIX, Spruce and TrimUI.

Community

Here are some cool projects maintained by members of our community. Please note that our team does not regularly review their source code.

Mobile and TV

Desktop

Handhelds and Steam Deck

Sync

Integrations

Support the project

Consider supporting this project on Open Collective. Funds cover hosting, development, and maintenance, and we pass some along to community projects to nurture a healthy ecosystem of apps.

Open Collective

Our Friends

Here are a few projects that we think you might like:

  • Lutris: Open gaming platform for Linux
  • Cocoon: Controller-first Android frontend for retro handhelds
  • muOS: Custom firmware for Anbernic and other handhelds
  • RetroDECK: Retro gaming on SteamOS and Linux
  • Steam ROM Manager: An app for managing ROMs in Steam
  • Hasheous: Hash lookup service that maps ROMs to game metadata
  • Gaseous: Another ROM manager with web-based emulator
  • Playmatch: Microservice for matching ROM hashes to games
  • EmulatorJS: An embeddable, browser-based emulator
  • PortMaster: Native game ports for Linux handhelds
  • MelonLoader: Universal mod loader for Unity games
  • NextUI: MinUI-based custom firmware for TrimUI handhelds
  • RetroAchievements: Achievements for retro games

Supported By

These companies support us by providing their tools for free:

Greptile Socket
S
Description
A beautiful, powerful, self-hosted ROM manager and player.
Readme AGPL-3.0
466 MiB
Languages
Python 55.8%
Vue 24.5%
TypeScript 18.8%
CSS 0.4%
JavaScript 0.2%
Other 0.3%