feat: Backend prerequisite changes for the new dashboard. - #686
Draft
GabuTheDev wants to merge 16 commits into
Draft
feat: Backend prerequisite changes for the new dashboard.#686GabuTheDev wants to merge 16 commits into
GabuTheDev wants to merge 16 commits into
Conversation
cyperdark
requested changes
Aug 7, 2026
| import fs from 'fs'; | ||
| import path from 'path'; | ||
|
|
||
| const OVERLAYS_API_URL = 'https://tosu.app/api.json'; |
Collaborator
There was a problem hiding this comment.
it should an array of urls to support mirrors incase if some countries have banned tosu.app ip's
Comment on lines
+80
to
+86
| const width = parseInt(String(w), 10); | ||
| const height = parseInt(String(h), 10); | ||
|
|
||
| return { | ||
| width: Number.isNaN(width) ? null : width, | ||
| height: Number.isNaN(height) ? null : height | ||
| }; |
Collaborator
There was a problem hiding this comment.
- wtf is this
- use isRealNumber
|
|
||
| private async fetchRepoOverlays(): Promise<Overlay[]> { | ||
| try { | ||
| const res = await fetch(OVERLAYS_API_URL); |
Collaborator
There was a problem hiding this comment.
add support for multiple hosts and timeout of 5_000ms
storycraft
requested changes
Aug 8, 2026
storycraft
left a comment
Member
There was a problem hiding this comment.
- Never mix sync io in async code. Legacy codes were partially allowed because of architecture issues, but new codes must not.
- The new
/api/overlaysendpoints would be better withouts./api/overlays/:id/settings->/api/overlay/:id/settingsOverlaysService->OverlayService
I think few small changes like downloader.ts can be cherry-picked and be done in another pr so this pr gets smaller.
| return { stop }; | ||
| } | ||
|
|
||
| public static debounce<T extends (...args: any[]) => void>( |
Member
There was a problem hiding this comment.
I can imagine debounce and Task.debounce being mixed everywhere in the future. If there are type issue in debounce function, please fix it instead.
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.
This PR aims to improve some server-side code and introduce needed features for the future dashboard.
Caution
This PR is work-in-progress and not ready for a review. Things may change.
Most code should be self-explainatory and easily readable, but to summarize:
Changes
1. WebSocket Cleaning & The Sockets Registry (4acb6ed, cbf71d1)
The entire
WebSocketclass was rewritten and transformed into a lightweight, decoupledWebSocketChannelclass.Key changes include:
InstanceManagerand hardcoded state-getter function names (getState,getStateV2, etc.) from the class constructor.WsConnectionstored in aMap<string, WsConnection>.while (true)infinite polling loops inside the class. Pushing data is now driven explicitly by caller-managedbroadcast(data)anddispatchCommand(...)methods.broadcast()to cache JSON strings so payloads are serialized once per tick rather than re-strigified per connected client.sockets: Record<string, WebSocketChannel>registry and map-driven HTTPupgraderouting.why?
Websocketinstance was tightly coupled to backend game state polling; every channel spawn it's own un-cancelablewhile (true)loop that reached intoInstanceManagerdirectly to fetch data.wsobjects were mutated directly with custom properties, which is sloppy and can introduce runtime type leaks.my solution
WebSocketChannelinto a pure, generic transport layer responsible only for connection management, command dispatching, and data broadcasting.Task.recur), allowing the channel to broadcast pre-serialized JSON efficiently across all open sockets.2. Modernized HTTP Server & Router Architecture (cbf71d1, fb49c13)
The core
HttpServerclass and router setup were completely rewritten:routes: Record<string, Route[]>) with a unified route stack. String route paths are pre-compiled on registration into{ pattern, keys }viapathToRegex(), eliminating redundant runtime regex compilation.POST,PUT, andPATCHrequests, body streaming enforces a hard 10MB limit (maxBodyLength). If the incoming data stream exceeds 10MB, the server immediately emits413 Payload Too Largeand aborts the socket viareq.destroy().next(err?:unknown)pipeline (Express Serverstandard, or so I have found on da internet). Middleware exceptions are caught cleanly and passed tonext(exc)to render a500 errorinstead of silently swallowing failures.why this
route.path.exec(pathname)up to three separate times per route match during request dispatching (once to test the regex, once to inspect groups, and once to pull values), creating unnecessary CPU overhead on every request.next(index + 1)that caught synchronous errors but didn't pass them downstream, risking hanging requests on failure.3. The new
/api/overlaysAPI.As of last year, the word
counters(refering topp counters) was abandoned in favor ofoverlays. I took the rename as a chance to also rewrite the internal API to a more robust RESTful API.So, I introduced a centralized
OverlaysService. The new REST API provides standardized management routes.Here's a table to showcase the old-to-new mapping:
GET /GET /api/overlays?status=installedGET /availableGET /api/overlays?status=availableGET /api/counters/search/:queryGET /api/overlaysGET /api/counters/download/:url?name=...POST /api/overlays/:id/downloadGET /api/counters/open/:namePOST /api/overlays/:id/openGET /api/counters/delete/:nameDELETE /api/overlays/:idGET /api/counters/settings/:nameGET /api/overlays/:id/settingsPOST /api/counters/settings/:namePOST /api/overlays/:id/settingswhyyyy
buildLocalCounters).3. Removal of
?l=& Upgrade to Overlay Runtime InjectionRemoved the legacy
?l=query flag parsing andwindow.COUNTER_PATHscript string appending in favor of a modern runtime injection system.Key changes include:
addCounterMetadatatoinjectOverlayRuntime(html, token)and updated static file serving to inject<head>runtime metadata instead of appending scripts to the end of the HTML body.window.TOSU_TOKEN) per overlay directory viacreateOverlayToken()instead of passing raw directory paths in URL query strings (?l=folder_name).background: transparent !important) into served overlay HTML files so they render seamlessly when embedded in dashboard previews.if (window.top !== window.self)) to suppress overlay console.log noise in the main dashboard web developer console.4. Introduction of Task Asynchronous Task Utilities
Added a static utility class that standardizes recurring background loops, conditional polling, and debouncing.
idk what to write here. I guess usage?
Task.recur(getInterval, callback).getInterval()on every cycle to dynamically adjust polling speed..stop()teardown method. (is also self stoppable / loop can stop itself)Task.once(predicate, action, checkIntervalMs)predicate()). Once the condition evaluates to truthy, it automatically terminates polling and executes the targetaction(result).Task.debounce(delayMs, fn)debouncemethod. Nothing new here.6. Downloader Engine Modernization & Streaming Checksums
I researched a bit and it seems like most of our issues (For example the SLL error) are because
http.getis shit and deprecated. I replaced it with the nativefetchfunction + Node stream pipelines.verifyDownloadto calculate file hashes using a stream pipeline instead of reading the whole file into RAM.