-
-
Notifications
You must be signed in to change notification settings - Fork 13
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
Optional maximum length argument for the buffer function #3
Conversation
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.
Nice progress, would love to get this feature in!
README.md
Outdated
a `Promise` which resolves with the stream data buffer. | ||
The `buffer(ReadableStreamInterface $stream, int $maxLength = 0)` function can be used to create | ||
a `Promise` which resolves with the stream data buffer. With an optional maximum length argument | ||
which defaults to no limit. |
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.
IMO 0
is a valid limit to ensure no data is sent. I think a default null
parameter to mean "no limit" makes more sense here 👍
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.
Changed it, but using a limit of 0
is kinda pointless 🤐
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.
I agree that there aren't many use cases for this, but IMO it makes more sense as a extreme value instead of "no value" which would be closer to the other end of the range :-)
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.
True =D
README.md
Outdated
var_dump(json_decode($contents)); | ||
}, function ($error) { | ||
// Reaching here when the stream buffer goes above the max size. | ||
// (In this example that is 1024 bytes.) |
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.
Note that the promise will also be rejected when a stream error
is emitted or when the promise is cancelled.
src/functions.php
Outdated
}; | ||
$stream->on('data', $bufferer); | ||
|
||
$promise = new Promise\Promise(function ($resolve, $reject) use ($stream, &$buffer) { | ||
$promise = new Promise\Promise(function ($resolve, $reject) use ($stream, $deferred, &$buffer) { | ||
$deferred->promise()->done($resolve, $reject); |
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.
This requires Promise v2 API.
src/functions.php
Outdated
$buffer .= $data; | ||
if ($maxLength > 0 && strlen($buffer) > $maxLength) { | ||
$deferred->reject(new \RuntimeException('Buffer exceeded maximum length')); | ||
} |
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.
Should probably also stop buffering in the background?
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.
Actually when the promise is rejected it is automatically removing the buffer listener
@clue updated the PR, will squash it once all feedback has been worked in to it and both of you approved the PR 👍 |
src/functions.php
Outdated
$buffer .= $data; | ||
if ($maxLength !== null && strlen($buffer) > (int)$maxLength) { | ||
$deferred->reject(new \RuntimeException('Buffer exceeded maximum length')); | ||
} | ||
}; |
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.
Probably micro-optimization, but what about incremental buffer size counting?
$buffer = '';
$bufferLength = 0;
$bufferer = function ($data) use (&$buffer, &$bufferLength, &$bufferer, $deferred, $maxLength) {
$buffer .= $data;
if (null === $maxLength) {
return;
}
$bufferLength += strlen($data);
if ($bufferLength > $maxLength) {
$deferred->reject(new \RuntimeException('Buffer exceeded maximum length'));
}
};
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.
Talking about optimizations, strlen()
is actually O(1)
, so not much would be gained :-) As an alternative, you can use isset($buffer[$maxLength])
to avoid the expensive function call 👍
010e235
to
7f505f3
Compare
src/functions.php
Outdated
$buffer .= $data; | ||
if ($maxLength !== null && isset($buffer[$maxLength])) { | ||
$deferred->reject(new \RuntimeException('Buffer exceeded maximum length')); |
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.
This doesn't unregister the data callback, so it might result in a double resolution of the deferred, no?
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.
There is no double resolution in react/promise, first come, first serve. Subsequent resolutions are ignored.
There is room for improvement for this function in general, but that's something for a follow-up PR.
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.
What @jsor says, but also when rejecting there the error passes through https://github.com/WyriHaximus-labs/promise-stream/blob/7f505f3915e331b90b6e3a6040a33d4104243e15/src/functions.php#L49-L55 which does remove the listener
7f505f3
to
0ab3812
Compare
src/functions.php
Outdated
@@ -12,22 +12,29 @@ | |||
* Creates a `Promise` which resolves with the stream data buffer | |||
* | |||
* @param ReadableStreamInterface $stream | |||
* @param int $maxLength |
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.
@param int|null $maxLength maximum number of bytes to buffer or null=unlimited
? See also signature in README.
src/functions.php
Outdated
$buffer .= $data; | ||
if ($maxLength !== null && isset($buffer[$maxLength])) { | ||
$deferred->reject(new \RuntimeException('Buffer exceeded maximum length')); |
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.
I would suggest using an OverflowException
here and explicitly document this in the README. This way, the user can easily discern normal stream errors from buffer overflow errors 👍
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.
Same as my comment here reactphp/http#232 (comment), OverflowException
would be nice.
tests/BufferTest.php
Outdated
|
||
public function testMaximumSize() | ||
{ | ||
$this->setExpectedException('\RuntimeException', 'Buffer exceeded maximum length'); |
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.
Should be moved down to the Block\await()
?
8784edc
to
5835e5b
Compare
5835e5b
to
2744beb
Compare
Can this PR be readied for merge + release as it blocks HTTP Server? |
$buffer .= $data; | ||
if ($maxLength !== null && isset($buffer[$maxLength])) { | ||
$deferred->reject(new \OverflowException('Buffer exceeded maximum length')); |
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.
LGTM, but should be added to documentation 👍
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.
Will do 👍
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.
@clue done
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.
Nice, squashed changes, now let's get this in!
@clue awesome! Thanks for the squashing 👍 |
As discussed on hangouts added an optional maximum length argument to the buffer function.