-
Notifications
You must be signed in to change notification settings - Fork 393
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
WIP: feat: send data by chunk in websocket #3988
base: main
Are you sure you want to change the base?
Conversation
Warning Rate limit exceeded@bytemain has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 25 minutes and 45 seconds before requesting another review. How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. Walkthrough此次更改涉及多个文件,主要集中在 Changes
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
🚅 Previously deployed to Railway in the core project. Environment has been deleted. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Outside diff range, codebase verification and nitpick comments (7)
packages/connection/src/common/constants.ts (1)
3-6
: 代码变更看起来不错!新增的
chunkSize
常量与 PR 的目标一致,用于实现 WebSocket 连接的分块数据传输。8MB 的大小选择合理。建议为注释添加英文翻译,以便于国际协作。例如:
/** * 分片大小, 8MB + * Chunk size, 8MB */ export const chunkSize = 8 * 1024 * 1024;
packages/connection/src/common/connection/drivers/ws-websocket.ts (1)
11-11
: 新增的decoder
成员看起来不错,但可以考虑添加注释。新增的
decoder
成员用于处理传入的消息,这是一个很好的改进。建议为
decoder
成员添加简短的注释,解释其用途和重要性。例如:// 用于解码和处理传入的 WebSocket 消息 protected decoder = new LengthFieldBasedFrameDecoder();packages/connection/src/common/connection/drivers/reconnecting-websocket.ts (2)
20-30
: 更新构造函数和 send 方法构造函数中新增的事件监听器和
send
方法的重写都很好地实现了分块数据传输的目标。这些更改与 PR 的目标一致,有助于提高大文件传输的性能。然而,我建议在
send
方法中添加一个注释,解释为什么要使用分块传输,以及chunkSize
的值是多少。这将有助于其他开发者理解这个实现的目的。建议在
send
方法开始处添加如下注释:/** * 发送数据,使用分块传输以避免大文件传输时的线程阻塞。 * 每个块的大小为 ${chunkSize} 字节。 */
87-103
: 新增 dataHandler 方法和更新 dispose 方法新增的
dataHandler
方法很好地处理了不同类型的传入数据,包括 Blob、ArrayBuffer 和 Buffer。这种实现提高了代码的健壮性。dispose
方法的更新确保了正确的资源清理。然而,我建议在
dataHandler
方法中添加错误处理,以防在数据处理过程中出现异常。建议在
dataHandler
方法中添加错误处理:private dataHandler = (e: MessageEvent) => { // ... 现有代码 ... buffer.then((v) => this.decoder.push(new Uint8Array(v, 0, v.byteLength))) .catch((error) => { console.error('处理传入消息时出错:', error); // 可以在这里添加额外的错误处理逻辑 }); };packages/connection/src/common/connection/drivers/frame-decoder.ts (2)
67-69
: 数据发送逻辑的更新这个更改与新的监听器管理方法保持一致,直接调用
_onDataListener
而不是发出事件。建议添加一个空值检查,以增加代码的健壮性:
if (this._onDataListener && typeof this._onDataListener === 'function') { this._onDataListener(binary); }这样可以避免在
_onDataListener
不是函数时可能出现的运行时错误。
166-166
: dispose 方法的更新这个更改与新的监听器管理方法保持一致,但是使用
undefined
而不是null
与onData
方法中的做法不一致。为了保持一致性,建议将这行改为:
this._onDataListener = null;这样可以确保在整个类中使用相同的方式来表示监听器被移除。
packages/connection/__test__/common/frame-decoder.test.ts (1)
Line range hint
38-121
: 总结:数据包构造方法的系统性更新整个文件中,所有数据包构造的地方都一致地添加了
.dump()
方法的调用。这种系统性的更改可能反映了LengthFieldBasedFrameDecoder
类实现的变化。建议:
- 确保这些更改与
LengthFieldBasedFrameDecoder
类的最新实现保持同步。- 考虑在测试文件的开头添加一个注释,解释为什么需要使用
.dump()
方法,以及它对测试结果的影响。- 如果
.dump()
方法改变了数据包的结构或内容,可能需要更新其他依赖于这些测试的部分。
const handle = LengthFieldBasedFrameDecoder.construct(data).dumpAndOwn(); | ||
const packet = handle.get(); | ||
for (let i = 0; i < packet.byteLength; i += chunkSize) { | ||
this.socket.send(packet.subarray(i, i + chunkSize)); | ||
} | ||
|
||
handle.dispose(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
send
方法的改进很好,但可以考虑进一步优化。
新的 send
方法使用 LengthFieldBasedFrameDecoder
构造数据包并分块发送,这是一个很好的改进,可以更好地处理大型消息。
为了进一步优化性能,您可以考虑以下建议:
- 使用
ArrayBuffer
或SharedArrayBuffer
来减少内存复制。 - 考虑使用
WebSocket.bufferedAmount
来控制发送速率,避免缓冲区溢出。
示例实现:
send(data: Uint8Array): void {
const handle = LengthFieldBasedFrameDecoder.construct(data).dumpAndOwn();
const packet = handle.get();
const sendChunk = (start: number) => {
while (start < packet.byteLength && this.socket.bufferedAmount < 1024 * 1024) { // 1MB buffer threshold
const end = Math.min(start + chunkSize, packet.byteLength);
this.socket.send(packet.subarray(start, end));
start = end;
}
if (start < packet.byteLength) {
setTimeout(() => sendChunk(start), 0);
} else {
handle.dispose();
}
};
sendChunk(0);
}
这个实现使用了递归的方式来控制发送速率,避免一次性将所有数据推入缓冲区。
private _onDataListener: MaybeNull<(data: Uint8Array) => void>; | ||
onData(listener: (data: Uint8Array) => void) { | ||
this._onDataListener = listener; | ||
return { | ||
dispose: () => { | ||
this._onDataListener = null; | ||
}, | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
监听器管理方式的重大变更
这个变更将之前基于 Emitter
的多监听器方法改为了单一监听器方法。虽然这简化了事件处理机制,但也限制了类只能同时处理一个监听器。
考虑以下几点:
- 这种改变可能会影响依赖多个监听器的现有代码。
- 单一监听器模式可能会在某些使用场景下造成限制。
建议考虑以下改进:
- 如果确实需要多个监听器,可以考虑使用数组来存储多个监听器函数。
- 添加清晰的文档注释,说明这个类现在只支持单一监听器,以防止误用。
- 考虑添加一个
removeListener
方法,使 API 更加完整和直观。
private _onDataListeners: Array<(data: Uint8Array) => void> = [];
onData(listener: (data: Uint8Array) => void) {
this._onDataListeners.push(listener);
return {
dispose: () => {
const index = this._onDataListeners.indexOf(listener);
if (index > -1) {
this._onDataListeners.splice(index, 1);
}
},
};
}
removeListener(listener: (data: Uint8Array) => void) {
const index = this._onDataListeners.indexOf(listener);
if (index > -1) {
this._onDataListeners.splice(index, 1);
}
}
这样的实现既保持了简单性,又提供了更大的灵活性。
Types
Background or solution
一次性发送几十M的文件会导致线程卡顿,大文件分 chunk 发送
Changelog
Summary by CodeRabbit
新功能
LengthFieldBasedFrameDecoder
实例以改进 WebSocket 消息的处理。chunkSize
,设定为 8MB,用于数据处理和传输。功能增强
修复