-
Couldn't load subscription status.
- Fork 2.7k
feat(multipart-parser): add streaming support #10764
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
base: main
Are you sure you want to change the base?
Conversation
This comment was marked as outdated.
This comment was marked as outdated.
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.
Pull Request Overview
This PR adds streaming support to the multipart-parser by refactoring the architecture to separate header and content handling, enabling backpressure control and streaming capabilities.
- Converts synchronous generators to async generators with await support for backpressure
- Introduces a two-class hierarchy separating
MultipartPart(headers only) andMultipartContentPart(headers + content) - Adds configuration options
useContentPartandonCreatePartto control streaming behavior
Reviewed Changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| packages/multipart-parser/src/lib/multipart.ts | Core implementation adding streaming options, async generator support, and class hierarchy refactoring |
| packages/multipart-parser/src/lib/multipart.node.ts | Updates Node.js wrapper to use async generator interface |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
Co-authored-by: Copilot <[email protected]>
047990c to
382a257
Compare
|
I felt like setting the append method on the part was a little too hacky, so I changed it to accept a second callback. const filestreams = new Map<MultipartPart, WritableStream>();
for await (let part of parseNodeMultipartStream(this.reader, {
boundary,
useContentPart: false,
onCreatePart: async (part) => {
// open a forwarding request to s3 or create a filestream object
const filename = "some_filename";
await someAsyncChecks();
filestreams.set(part, fs.createWriteStream(filename));
},
onEmitBytes: async (part, chunk) => {
await new Promise<void>((resolve) => {
const filestream = filestreams.get(part);
// write returns true if we can keep going, false if we need to wait for drain
filestream!.write(chunk) ? resolve() : filestream!.once("drain", () => resolve());
});
}
})) {
filestreams.get(part).end();
filestreams.delete(part);
await somethingElse();
} |
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.
Pull Request Overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
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.
Most of the complaints in the last copilot review were junk.
|
I’m curious why the |
I'm guessing it's because the stream has to be parsed as bytes, so that would just be extra boilerplate. If someone wants a ReadableStream, this PR makes that very simple. |
This PR adds streaming support to the multipart-parser.
MultipartPartinto two classes.The base class has the header related fields, and the sub class has the fields related to the content array. Both classes have their own append method, but in the base class it throws by default, so it must be set manually in
onCreatePart. If append returns a promise, it is awaited, allowing back pressure.onCreatePartis called each time a part is created, anduseContentPartdetermines whether to use the base class with just the header components, or the subclass, which includes the contents array and related fields. IfuseContentPartis false,onEmitBytesmust be set, so the default is true.This should fix
I have not tested this code on a server (although I did implement it in a project I'm working on), and I have not written any unit tests.