sync: dev with v4 - #165
Conversation
…thods, and adjust navigation layout
Signed-off-by: Lucas Morais Rodrigues <76886832+1Lucas1apk@users.noreply.github.com>
…nd improve auto-resume logic
…check mechanism and improved error handling during node transfers
…ug logging - Introduced `isResuming` flag for players to track resumption state. - Improved WebSocket error handling by categorizing fatal and client error codes. - Added debug logs for ignored `WebSocketClosedEvent` during resumption and exceeded reconnect attempts.
…ing health checks - Enhanced `_handleAutoplay` to return a boolean for better flow control. - Added `trackStale` event to manage stale track scenarios. - Improved player health check to handle track resumption, skipping, or stopping gracefully. - Removed redundant `handleTrackEnd` method logic.
…tialization - Introduced `autoJoin` to simplify player setup by handling voice and text channel assignments, including reconnections.
…debug logs - Enhanced `VOICE_STATE_UPDATE` and `VOICE_SERVER_UPDATE` packet handling with additional validation and debugging. - Ensured players handle voice channel changes, disconnections, and session updates accurately. - Improved debug logs to track user actions and session transitions. - Fixed potential playback issues by enforcing proper self-mute and server-mute behavior.
…ayload handling - Added a `MAX_PAYLOAD_SIZE` constant to the WebSocket service, allowing better control over payload limits.
…namespace - Adjusted `EventEmitter` import to use `node:events` for better clarity and Node.js compatibility.
- Introduced `isValidDiscordId` to validate Discord IDs for enhanced input verification.
- Changed `http` import to `node:http` for consistency with Node.js module resolution and better clarity.
…ner` - Renamed `connect` to `connectBun` and introduced `connectNode` for platform-specific implementation. - Removed the unused `addEventListener` method definition from the WebSocket class.
- Updated package version in `package.json` to 4.60.18. - Changed User-Agent identifier from `Epiphany` to `Malodorus`. - Updated `.npmignore` to exclude `.idea` and `assets` directories.
There was a problem hiding this comment.
Code Review
This pull request appears to be a large synchronization, introducing a wide range of improvements and refactorings. Key enhancements include a more robust WebSocket implementation with support for both Node.js and Bun, a new player health check mechanism to handle stale tracks and unresponsive nodes, and significantly improved voice state handling in the manager. While these changes greatly improve the library's stability and feature set, I've identified a critical issue in the new WebSocket implementation where client-sent frames are not being masked, which will cause connections to fail. Additionally, IDE-specific configuration files are being added to the repository, which should be avoided by updating the .gitignore file.
| sendFrame(opcode, payload) { | ||
| const payloadLength = payload.length; | ||
| let header; | ||
| let headerLength = 2; | ||
| if (payloadLength < 126) { | ||
| header = Buffer.alloc(headerLength); | ||
| header[1] = payloadLength; | ||
| } | ||
| else if (payloadLength > 125) { | ||
| header[1] = 0x80 | 126; | ||
| else if (payloadLength < 65536) { | ||
| headerLength = 4; | ||
| header = Buffer.alloc(headerLength); | ||
| header[1] = 126; | ||
| header.writeUInt16BE(payloadLength, 2); | ||
| } | ||
| else { | ||
| header[1] = 0x80 | payloadLength; | ||
| } | ||
| const mask = (0, crypto_1.randomBytes)(4); | ||
| mask.copy(header, headerLength - 4); | ||
| const maskedPayload = Buffer.alloc(payloadLength); | ||
| for (let i = 0; i < payloadLength; i++) { | ||
| maskedPayload[i] = payload[i] ^ mask[i % 4]; | ||
| headerLength = 10; | ||
| header = Buffer.alloc(headerLength); | ||
| header[1] = 127; | ||
| header.writeBigUInt64BE(BigInt(payloadLength), 2); | ||
| } | ||
| this.netSocket.write(Buffer.concat([header, maskedPayload]), cb); | ||
| header[0] = 0x80 | opcode; | ||
| this.netSocket.write(Buffer.concat([header, payload])); | ||
| } |
There was a problem hiding this comment.
The WebSocket frames sent from the client to the server must be masked according to RFC 6455, Section 5.1. This implementation is missing the payload masking. A server must close the connection upon receiving an unmasked frame from a client, which will cause this implementation to fail. You need to set the MASK bit in the header, generate a 4-byte masking key, include it in the header, and XOR the payload with the key before sending.
sendFrame(opcode, payload) {
const payloadLength = payload.length;
let header;
let headerLength = 2;
if (payloadLength < 126) {
headerLength += 4;
header = Buffer.alloc(headerLength);
header[1] = 0x80 | payloadLength;
}
else if (payloadLength < 65536) {
headerLength = 4 + 4;
header = Buffer.alloc(headerLength);
header[1] = 0x80 | 126;
header.writeUInt16BE(payloadLength, 2);
}
else {
headerLength = 10 + 4;
header = Buffer.alloc(headerLength);
header[1] = 0x80 | 127;
header.writeBigUInt64BE(BigInt(payloadLength), 2);
}
header[0] = 0x80 | opcode;
const mask = (0, node_crypto_1.randomBytes)(4);
mask.copy(header, headerLength - 4);
const maskedPayload = Buffer.alloc(payloadLength);
for (let i = 0; i < payloadLength; i++) {
maskedPayload[i] = payload[i] ^ mask[i % 4];
}
this.netSocket.write(Buffer.concat([header, maskedPayload]));
}
No description provided.