-
-
Notifications
You must be signed in to change notification settings - Fork 252
feat: Optimize network traffic with patch-based sync for Node.js server #942
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
| return; | ||
| } | ||
|
|
||
| try { |
Check failure
Code scanning / CodeQL
Uncontrolled data used in path expression High
user-provided value
| @@ -388,19 +622,19 @@ | |||
| try { | |||
|
|
|||
| const port = process.env.PORT || 6001; | |||
| const httpsOptions = await getHttpsOptions(); | |||
|
|
|||
| if (httpsOptions) { | |||
| const httpsOptions = await getHttpsOptions(); if (httpsOptions) { | |||
| // HTTPS | |||
| https.createServer(httpsOptions, app).listen(port, () => { | |||
| console.log("[Server] HTTPS server is running."); | |||
| console.log(`[Server] https://localhost:${port}/`); | |||
| console.log(`[Server] Patch sync: ${enablePatchSync ? 'ENABLED' : 'DISABLED'}`); | |||
| }); | |||
| } else { | |||
| // HTTP | |||
| app.listen(port, () => { | |||
| console.log("[Server] HTTP server is running."); | |||
| console.log(`[Server] http://localhost:${port}/`); | |||
| console.log(`[Server] Patch sync: ${enablePatchSync ? 'ENABLED' : 'DISABLED'}`); | |||
| }); | |||
| } | |||
| } catch (error) { | |||
Check failure
Code scanning / CodeQL
Missing rate limiting High
a file system access
This route handler performs
a file system access
| await fs.writeFile(fullPath, dataToSave); | ||
| // Create backup for database files after successful save | ||
| if (decodedFilePath.includes('database/database.bin')) { | ||
| try { |
Check failure
Code scanning / CodeQL
Uncontrolled data used in path expression High
user-provided value
| // Create backup for database files after successful save | ||
| if (decodedFilePath.includes('database/database.bin')) { | ||
| try { | ||
| const timestamp = Math.floor(Date.now() / 100).toString(); |
Check failure
Code scanning / CodeQL
Uncontrolled data used in path expression High
user-provided value
| newVersion: newVersion | ||
| }); | ||
| } catch (error) { | ||
| console.error(`[Patch] Error applying patch to ${filePath}:`, error); |
Check failure
Code scanning / CodeQL
Uncontrolled data used in path expression High
user-provided value
|
|
||
| const port = process.env.PORT || 6001; | ||
| const httpsOptions = await getHttpsOptions(); | ||
|
|
Check failure
Code scanning / CodeQL
Use of externally-controlled format string High
user-provided value
| } else { | ||
| // HTTP | ||
| app.listen(port, () => { | ||
| console.log("[Server] HTTP server is running."); |
Check failure
Code scanning / CodeQL
Use of externally-controlled format string High
user-provided value
This reverts commit 0027dd9.
PR Checklist
Description
This pull request introduces a highly efficient patch-based database synchronization system for the Node.js server environment. This fundamentally changes how the client and server communicate for the two most frequent and data-intensive operations: saving the database and managing backups.
Instead of transferring the entire multi-megabyte database on every change, the client now sends only a small patch (a few kilobytes) describing the modifications. This dramatically reduces network traffic, improves application performance, and enhances data integrity.
This feature is off by default and must be explicitly enabled via the
--patch-syncflag when running the Node.js server. When disabled, the application functions exactly as it did before, ensuring full backward compatibility.Background & Motivation
The application's primary performance bottleneck was network traffic. The two most frequent operations were:
These two operations occurred repeatedly with every database modification, resulting in constant, heavy data transfer. This constant, heavy data transfer resulted in significant server load and bandwidth costs. This PR optimizes both of these hotspots, reducing network usage to near-negligible levels for most operations.
Implementation Details
fast-json-patchis used to efficiently compute data differences on the client.Client Logic (
globalApi.svelte.ts&autoStorage.ts)Server Logic (
server.cjs)/api/patchEndpoint: A new endpoint handles incoming patches.409 Conflict, triggering the client's fallback mechanism./api/listendpoint now uses thekey-prefixheader to filter file lists before sending the response.Activation
This feature is opt-in. It can be enabled by running
pnpm run runserver:patchor by setting theRISU_PATCH_SYNCenvironment variable to1.🚨 Important: Node.js Version Requirement 🚨
This feature relies on the
msgpackrlibrary for efficient data encoding. Due to a bug in the Node.js core, specific versions can cause server-side encoding errors and crashes.v22.8.0or higher (LTS).v22.7.0,v23, andv24are known to have this issue. Versions belowv22.7.0are not affected.The server code includes a safeguard that will automatically disable patch-sync if it detects a problematic Node.js version, ensuring stability.
For more details, see the official Node.js issue and pull request:
Expected Benefits
Trade-offs