fix(netplay): correct room-list and socket URLs behind a reverse proxy#3839
Merged
Conversation
RomM's netplay overrides targeted an outdated EmulatorJS API, so on the nightly build they were dead code and the emulator's own URL logic ran. That built the room-list request from `netplay.url` (the page host with no scheme), which resolved relative to the SPA route and duplicated the domain inside the path. nginx's SPA fallback then answered with index.html, so the room list was always empty. The socket also used the default socket.io path instead of RomM's mounted /netplay/socket.io. - Set EJS_netplayServer to window.location.origin (scheme included). - Override netplay.getOpenRooms on the current netplay instance to hit /api/netplay/list with a root-relative path. - Wrap the EmulatorJS-bundled global io to inject the /netplay/socket.io path. Fixes #3799 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
Greptile SummaryThis PR updates EmulatorJS netplay URLs for reverse-proxy deployments. The main changes are:
Confidence Score: 4/5The netplay override timing needs to be fixed before merging.
frontend/src/views/Player/EmulatorJS/Player.vue Important Files Changed
Prompt To Fix All With AIFix the following 1 code review issue. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 1
frontend/src/views/Player/EmulatorJS/Player.vue:478
**Overrides Install After Startup Waits**
These overrides run near the end of the async `EJS_onGameStart` callback, after its save and game-manager waits. If room polling or a Create/Join action starts while that callback is suspended, EmulatorJS still uses its original room URL and default Socket.IO path, so the room list remains empty or the socket connection fails. Install both overrides synchronously before the callback's first wait.
Reviews (1): Last reviewed commit: "fix(netplay): correct room-list and sock..." | Re-trigger Greptile |
Move the getOpenRooms and io-wrap overrides to the top of EJS_onGameStart so they are installed synchronously, before room polling or a Create/Join action can start, rather than at the tail of the callback. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Fixes #3799 — behind a reverse proxy / custom domain, the netplay room list is always empty and Create/Join Room do nothing.
Root cause
RomM's netplay overrides in
Player.vuetargeted an outdated EmulatorJS API (the netplay functions moved from the emulator object onto thenetplayinstance in the nightly build). On the currentnightlybuild those overrides are dead code, so the emulator's own URL logic runs instead:getOpenRooms()builds the request fromnetplay.url, which RomM set towindow.location.host(a bare host, no scheme). The browser resolves that relative to the current SPA route, producinghttps://<domain>/<route>/<domain>/list?...— the domain duplicated inside the path, exactly as in the report. nginx's SPA fallback (try_files ... /index.html) then answers withindex.html(200,text/html),JSON.parsefails, the error is swallowed, and the room list is always empty.io(netplay.url)using Socket.IO's default path instead of RomM's mounted/netplay/socket.io, so creating/joining a room silently does nothing.Changes (
frontend/src/views/Player/EmulatorJS/Player.vue)EJS_netplayServer:window.location.host→window.location.origin(scheme included, soio()has an unambiguous absolute server).netplay.getOpenRoomson the actual netplay instance to hit/api/netplay/list?game_id=...with a root-relative path (correct on any domain / proxy). The/api/netplay/listendpoint already exists in the backend.io(socket.io is bundled UMD ontowindow.io, and netplay'sio(this.url)uses that global) to injectpath: "/netplay/socket.io". The wrap is idempotent and only affects EmulatorJS — RomM's own app socket imports the client module rather than using the global.No backend changes required.
AI assistance disclosure
This change was investigated and implemented with AI assistance (Claude Code): root-cause analysis of the EmulatorJS nightly netplay source, the fix, and this description. All changes were reviewed by a human.
Checklist
Note on testing: typecheck and
trunk fmt/trunk checkpass clean. End-to-end netplay could not be exercised here (it requires the livenightlyCDN build, STUN/TURN, and a custom domain). Please smoke-test behind a reverse proxy: confirm the polling request in DevTools hits/api/netplay/list?...and returns JSON, and that Create/Join rooms connect over/netplay/socket.io.Known fragility: netplay pins EmulatorJS to
nightly, so this class of breakage can recur whenever upstream refactors the netplay API.