From 09f9fdc764fa47424d0bab151e2ac6690699496a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20L=C3=BCck?= Date: Sun, 5 Mar 2017 11:30:17 +0100 Subject: [PATCH 1/7] Consistent write() semantics and documentation --- README.md | 47 ++++++++++++++++++++++++++++++--- src/Buffer.php | 2 +- src/BufferedSink.php | 6 +++++ src/ThroughStream.php | 6 +++++ src/WritableStream.php | 1 + src/WritableStreamInterface.php | 47 +++++++++++++++++++++++++++++++++ 6 files changed, 104 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index fa36171..cd586d6 100644 --- a/README.md +++ b/README.md @@ -119,10 +119,49 @@ $dest->close(); // calls $source->pause() * `isWritable()`: Check if the stream can still be written to. It cannot be written to after an error or when it is closed. -* `write($data)`: Write some data into the stream. If the stream cannot handle - it, it should buffer the data or emit and `error` event. If the internal - buffer is full after adding `$data`, `write` should return false, indicating - that the caller should stop sending data until the buffer `drain`s. +* `write($data)`: +The `write(mixed $data): bool` method can be used to +write some data into the stream. + +A successful write MUST be confirmed with a boolean `true`, which means +that either the data was written (flushed) immediately or is buffered and +scheduled for a future write. Note that this interface gives you no +control over explicitly flushing the buffered data, as finding the +appropriate time for this is beyond the scope of this interface and left +up to the implementation of this interface. + +Many common streams (such as a TCP/IP connection or file-based stream) +may choose to buffer all given data and schedule a future flush by using +an underlying EventLoop to check when the resource is actually writable. + +If a stream cannot handle writing (or flushing) the data, it SHOULD emit +an `error` event and MAY `close()` the stream if it can not recover from +this error. + +If the internal buffer is full after adding `$data`, then `write()` +SHOULD return `false`, indicating that the caller should stop sending +data until the buffer `drain`s. + +Similarly, if the the stream is not writable (already in a closed state) +it MUST NOT process the given `$data` and SHOULD return `false`, +indicating that the caller should stop sending data. + +The given `$data` argument MAY be of mixed type, but it's usually +recommended it SHOULD be a `string` value or MAY use a type that allows +representation as a `string` for maximum compatibility. + +Many common streams (such as a TCP/IP connection or a file-based stream) +will only accept the raw (binary) payload data that is transferred over +the wire as chunks of `string` values. + +Due to the stream-based nature of this, the sender may send any number +of chunks with varying sizes. There are no guarantees that these chunks +will be received with the exact same framing the sender intended to send. +In other words, many lower-level protocols (such as TCP/IP) transfer the +data in chunks that may be anywhere between single-byte values to several +dozens of kilobytes. You may want to apply a higher-level protocol to +these low-level data chunks in order to achieve proper message framing. + * `end($data = null)`: Optionally write some final data to the stream, empty the buffer, then close it. diff --git a/src/Buffer.php b/src/Buffer.php index d2ea7b4..614edb3 100644 --- a/src/Buffer.php +++ b/src/Buffer.php @@ -33,7 +33,7 @@ public function isWritable() public function write($data) { if (!$this->writable) { - return; + return false; } $this->data .= $data; diff --git a/src/BufferedSink.php b/src/BufferedSink.php index 730c808..1ef409e 100644 --- a/src/BufferedSink.php +++ b/src/BufferedSink.php @@ -31,8 +31,14 @@ public function handleErrorEvent($e) public function write($data) { + if ($this->closed) { + return false; + } + $this->buffer .= $data; $this->deferred->progress($data); + + return true; } public function close() diff --git a/src/ThroughStream.php b/src/ThroughStream.php index 29789df..93db37f 100644 --- a/src/ThroughStream.php +++ b/src/ThroughStream.php @@ -19,7 +19,13 @@ public function filter($data) public function write($data) { + if (!$this->writable) { + return false; + } + $this->readable->emit('data', array($this->filter($data))); + + return true; } public function end($data = null) diff --git a/src/WritableStream.php b/src/WritableStream.php index 612450a..7b96b62 100644 --- a/src/WritableStream.php +++ b/src/WritableStream.php @@ -10,6 +10,7 @@ class WritableStream extends EventEmitter implements WritableStreamInterface public function write($data) { + return false; } public function end($data = null) diff --git a/src/WritableStreamInterface.php b/src/WritableStreamInterface.php index 93eac90..d7ac97d 100644 --- a/src/WritableStreamInterface.php +++ b/src/WritableStreamInterface.php @@ -13,7 +13,54 @@ interface WritableStreamInterface extends EventEmitterInterface { public function isWritable(); + + /** + * Write some data into the stream. + * + * A successful write MUST be confirmed with a boolean `true`, which means + * that either the data was written (flushed) immediately or is buffered and + * scheduled for a future write. Note that this interface gives you no + * control over explicitly flushing the buffered data, as finding the + * appropriate time for this is beyond the scope of this interface and left + * up to the implementation of this interface. + * + * Many common streams (such as a TCP/IP connection or file-based stream) + * may choose to buffer all given data and schedule a future flush by using + * an underlying EventLoop to check when the resource is actually writable. + * + * If a stream cannot handle writing (or flushing) the data, it SHOULD emit + * an `error` event and MAY `close()` the stream if it can not recover from + * this error. + * + * If the internal buffer is full after adding `$data`, then `write()` + * SHOULD return `false`, indicating that the caller should stop sending + * data until the buffer `drain`s. + * + * Similarly, if the the stream is not writable (already in a closed state) + * it MUST NOT process the given `$data` and SHOULD return `false`, + * indicating that the caller should stop sending data. + * + * The given `$data` argument MAY be of mixed type, but it's usually + * recommended it SHOULD be a `string` value or MAY use a type that allows + * representation as a `string` for maximum compatibility. + * + * Many common streams (such as a TCP/IP connection or a file-based stream) + * will only accept the raw (binary) payload data that is transferred over + * the wire as chunks of `string` values. + * + * Due to the stream-based nature of this, the sender may send any number + * of chunks with varying sizes. There are no guarantees that these chunks + * will be received with the exact same framing the sender intended to send. + * In other words, many lower-level protocols (such as TCP/IP) transfer the + * data in chunks that may be anywhere between single-byte values to several + * dozens of kilobytes. You may want to apply a higher-level protocol to + * these low-level data chunks in order to achieve proper message framing. + * + * @param mixed|string $data + * @return bool + */ public function write($data); + public function end($data = null); public function close(); } From 2910f62f23248322c4c98699d295c383a5e4eb8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20L=C3=BCck?= Date: Mon, 6 Mar 2017 13:34:11 +0100 Subject: [PATCH 2/7] Consistent end() semantics and documentation --- README.md | 59 ++++++++++++++++++++++++++++++-- src/WritableStreamInterface.php | 60 +++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cd586d6..0d485f2 100644 --- a/README.md +++ b/README.md @@ -162,8 +162,63 @@ data in chunks that may be anywhere between single-byte values to several dozens of kilobytes. You may want to apply a higher-level protocol to these low-level data chunks in order to achieve proper message framing. -* `end($data = null)`: Optionally write some final data to the stream, empty - the buffer, then close it. +* `end($data = null)`: +The `end(mixed $data = null): void` method can be used to +successfully end the stream (after optionally sending some final data). + +This method can be used to successfully end the stream, i.e. close +the stream after sending out all data that is currently buffered. + +```php +$stream->write('hello'); +$stream->write('world'); +$stream->end(); +``` + +If there's no data currently buffered and nothing to be flushed, then +this method MAY `close()` the stream immediately. + +If there's still data in the buffer that needs to be flushed first, then +this method SHOULD try to write out this data and only then `close()` +the stream. + +Note that this interface gives you no control over explicitly flushing +the buffered data, as finding the appropriate time for this is beyond the +scope of this interface and left up to the implementation of this +interface. + +Many common streams (such as a TCP/IP connection or file-based stream) +may choose to buffer all given data and schedule a future flush by using +an underlying EventLoop to check when the resource is actually writable. + +You can optionally pass some final data that is written to the stream +before ending the stream. If a non-`null` value is given as `$data`, then +this method will behave just like calling `write($data)` before ending +with no data. + +```php +// shorter version +$stream->end('bye'); + +// same as longer version +$stream->write('bye'); +$stream->end(); +``` + +After calling this method, the stream MUST switch into a non-writable +mode, see also `isWritable()`. +This means that no further writes are possible, so any additional +`write()` or `end()` calls have no effect. + +```php +$stream->end(); +assert($stream->isWritable() === false); + +$stream->write('nope'); // NO-OP +$stream->end(); // NO-OP +``` + +Note that this method should not be confused with the `close()` method. ## Usage ```php diff --git a/src/WritableStreamInterface.php b/src/WritableStreamInterface.php index d7ac97d..b9c174b 100644 --- a/src/WritableStreamInterface.php +++ b/src/WritableStreamInterface.php @@ -61,6 +61,66 @@ public function isWritable(); */ public function write($data); + /** + * Successfully ends the stream (after optionally sending some final data). + * + * This method can be used to successfully end the stream, i.e. close + * the stream after sending out all data that is currently buffered. + * + * ```php + * $stream->write('hello'); + * $stream->write('world'); + * $stream->end(); + * ``` + * + * If there's no data currently buffered and nothing to be flushed, then + * this method MAY `close()` the stream immediately. + * + * If there's still data in the buffer that needs to be flushed first, then + * this method SHOULD try to write out this data and only then `close()` + * the stream. + * + * Note that this interface gives you no control over explicitly flushing + * the buffered data, as finding the appropriate time for this is beyond the + * scope of this interface and left up to the implementation of this + * interface. + * + * Many common streams (such as a TCP/IP connection or file-based stream) + * may choose to buffer all given data and schedule a future flush by using + * an underlying EventLoop to check when the resource is actually writable. + * + * You can optionally pass some final data that is written to the stream + * before ending the stream. If a non-`null` value is given as `$data`, then + * this method will behave just like calling `write($data)` before ending + * with no data. + * + * ```php + * // shorter version + * $stream->end('bye'); + * + * // same as longer version + * $stream->write('bye'); + * $stream->end(); + * ``` + * + * After calling this method, the stream MUST switch into a non-writable + * mode, see also `isWritable()`. + * This means that no further writes are possible, so any additional + * `write()` or `end()` calls have no effect. + * + * ```php + * $stream->end(); + * assert($stream->isWritable() === false); + * + * $stream->write('nope'); // NO-OP + * $stream->end(); // NO-OP + * ``` + * + * Note that this method should not be confused with the `close()` method. + * + * @param mixed|string|null $data + * @return void + */ public function end($data = null); public function close(); } From 89b1fc955a5a7427b4ea33c200e021f0d7533af9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20L=C3=BCck?= Date: Mon, 6 Mar 2017 13:55:01 +0100 Subject: [PATCH 3/7] Consistent isWritable() semantics and documentation --- README.md | 25 +++++++++++++++++++++++-- src/WritableStreamInterface.php | 24 ++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0d485f2..48e36a4 100644 --- a/README.md +++ b/README.md @@ -117,8 +117,29 @@ $dest->close(); // calls $source->pause() ### Methods -* `isWritable()`: Check if the stream can still be written to. It cannot be - written to after an error or when it is closed. +* `isWritable()`: +The `isWritable(): bool` method can be used to +check whether this stream is in a writable state (not closed already). + +This method can be used to check if the stream still accepts writing +any data or if it is ended or closed already. +Writing any data to a non-writable stream is a NO-OP: + +```php +assert($stream->isWritable() === false); + +$stream->write('end'); // NO-OP +$stream->end('end'); // NO-OP +``` + +A successfully opened stream always MUST start in writable mode. + +Once the stream ends or closes, it MUST switch to non-writable mode. +This can happen any time, explicitly through `end()` or `close()` or +implicitly due to a remote close or an unrecoverable transmission error. +Once a stream has switched to non-writable mode, it MUST NOT transition +back to writable mode. + * `write($data)`: The `write(mixed $data): bool` method can be used to write some data into the stream. diff --git a/src/WritableStreamInterface.php b/src/WritableStreamInterface.php index b9c174b..063a7d1 100644 --- a/src/WritableStreamInterface.php +++ b/src/WritableStreamInterface.php @@ -12,6 +12,30 @@ */ interface WritableStreamInterface extends EventEmitterInterface { + /** + * Checks whether this stream is in a writable state (not closed already). + * + * This method can be used to check if the stream still accepts writing + * any data or if it is ended or closed already. + * Writing any data to a non-writable stream is a NO-OP: + * + * ```php + * assert($stream->isWritable() === false); + * + * $stream->write('end'); // NO-OP + * $stream->end('end'); // NO-OP + * ``` + * + * A successfully opened stream always MUST start in writable mode. + * + * Once the stream ends or closes, it MUST switch to non-writable mode. + * This can happen any time, explicitly through `end()` or `close()` or + * implicitly due to a remote close or an unrecoverable transmission error. + * Once a stream has switched to non-writable mode, it MUST NOT transition + * back to writable mode. + * + * @return bool + */ public function isWritable(); /** From a4644379b5f4378b549fb3faba3c945854735338 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20L=C3=BCck?= Date: Mon, 6 Mar 2017 15:02:46 +0100 Subject: [PATCH 4/7] Consistent isReadable() semantics and documentation --- README.md | 37 ++++++++++++++++++++++++++++++--- src/ReadableStreamInterface.php | 31 +++++++++++++++++++++++++++ src/WritableStreamInterface.php | 5 +++++ 3 files changed, 70 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 48e36a4..594dedb 100644 --- a/README.md +++ b/README.md @@ -31,9 +31,35 @@ This component depends on `événement`, which is an implementation of the ### Methods -* `isReadable()`: Check if the stream is still in a state allowing it to be - read from. It becomes unreadable when the stream ends, closes or an - error occurs. +* `isReadable()`: +The `isReadable(): bool` method can be used to +check whether this stream is in a readable state (not closed already). + +This method can be used to check if the stream still accepts incoming +data events or if it is ended or closed already. +Once the stream is non-readable, no further `data` or `end` events SHOULD +be emitted. + +```php +assert($stream->isReadable() === false); + +$stream->on('data', assertNeverCalled()); +$stream->on('end', assertNeverCalled()); +``` + +A successfully opened stream always MUST start in readable mode. + +Once the stream ends or closes, it MUST switch to non-readable mode. +This can happen any time, explicitly through `close()` or +implicitly due to a remote close or an unrecoverable transmission error. +Once a stream has switched to non-readable mode, it MUST NOT transition +back to readable mode. + +If this stream is a `DuplexStreamInterface`, you should also notice +how the writable side of the stream also implements an `isWritable()` +method. Unless this is a half-open duplex stream, they SHOULD usually +have the same return value. + * `pause()`: Remove the data source file descriptor from the event loop. This allows you to throttle incoming data. * `resume()`: Re-attach the data source after a `pause()`. @@ -140,6 +166,11 @@ implicitly due to a remote close or an unrecoverable transmission error. Once a stream has switched to non-writable mode, it MUST NOT transition back to writable mode. +If this stream is a `DuplexStreamInterface`, you should also notice +how the readable side of the stream also implements an `isReadable()` +method. Unless this is a half-open duplex stream, they SHOULD usually +have the same return value. + * `write($data)`: The `write(mixed $data): bool` method can be used to write some data into the stream. diff --git a/src/ReadableStreamInterface.php b/src/ReadableStreamInterface.php index e4a5d14..b410d26 100644 --- a/src/ReadableStreamInterface.php +++ b/src/ReadableStreamInterface.php @@ -12,7 +12,38 @@ */ interface ReadableStreamInterface extends EventEmitterInterface { + /** + * Checks whether this stream is in a readable state (not closed already). + * + * This method can be used to check if the stream still accepts incoming + * data events or if it is ended or closed already. + * Once the stream is non-readable, no further `data` or `end` events SHOULD + * be emitted. + * + * ```php + * assert($stream->isReadable() === false); + * + * $stream->on('data', assertNeverCalled()); + * $stream->on('end', assertNeverCalled()); + * ``` + * + * A successfully opened stream always MUST start in readable mode. + * + * Once the stream ends or closes, it MUST switch to non-readable mode. + * This can happen any time, explicitly through `close()` or + * implicitly due to a remote close or an unrecoverable transmission error. + * Once a stream has switched to non-readable mode, it MUST NOT transition + * back to readable mode. + * + * If this stream is a `DuplexStreamInterface`, you should also notice + * how the writable side of the stream also implements an `isWritable()` + * method. Unless this is a half-open duplex stream, they SHOULD usually + * have the same return value. + * + * @return bool + */ public function isReadable(); + public function pause(); public function resume(); diff --git a/src/WritableStreamInterface.php b/src/WritableStreamInterface.php index 063a7d1..26387a3 100644 --- a/src/WritableStreamInterface.php +++ b/src/WritableStreamInterface.php @@ -34,6 +34,11 @@ interface WritableStreamInterface extends EventEmitterInterface * Once a stream has switched to non-writable mode, it MUST NOT transition * back to writable mode. * + * If this stream is a `DuplexStreamInterface`, you should also notice + * how the readable side of the stream also implements an `isReadable()` + * method. Unless this is a half-open duplex stream, they SHOULD usually + * have the same return value. + * * @return bool */ public function isWritable(); From e96da5311c687dbafefad0c45eb9a9bd76003e4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20L=C3=BCck?= Date: Mon, 6 Mar 2017 14:45:05 +0100 Subject: [PATCH 5/7] Consistent close() semantics and documentation --- README.md | 71 +++++++++++++++++++++++++++++++++ src/ReadableStreamInterface.php | 30 ++++++++++++++ src/WritableStreamInterface.php | 46 +++++++++++++++++++++ 3 files changed, 147 insertions(+) diff --git a/README.md b/README.md index 594dedb..ce239ea 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,34 @@ $source->pipe($dest); $dest->close(); // calls $source->pause() ``` +* `close()`: +The `close(): void` method can be used to +close the stream (forcefully). + +This method can be used to (forcefully) close the stream. + +```php +$stream->close(); +``` + +After calling this method, the stream MUST switch into a non-readable +mode, see also `isReadable()`. +This means that no further `data` or `end` events SHOULD be emitted. + +```php +$stream->close(); +assert($stream->isReadable() === false); + +$stream->on('data', assertNeverCalled()); +$stream->on('end', assertNeverCalled()); +``` + +If this stream is a `DuplexStreamInterface`, you should also notice +how the writable side of the stream also implements a `close()` method. +In other words, after calling this method, the stream MUST switch into +non-writable AND non-readable mode, see also `isWritable()`. +Note that this method should not be confused with the `end()` method. + ## Writable Streams ### EventEmitter Events @@ -272,6 +300,49 @@ $stream->end(); // NO-OP Note that this method should not be confused with the `close()` method. +* `close()`: +The `close(): void` method can be used to +close the stream (forcefully). + +This method can be used to forcefully close the stream, i.e. close +the stream without waiting for any buffered data to be flushed. +If there's still data in the buffer, this data SHOULD be discarded. + +```php +$stream->close(); +``` + +After calling this method, the stream MUST switch into a non-writable +mode, see also `isWritable()`. +This means that no further writes are possible, so any additional +`write()` or `end()` calls have no effect. + +```php +$stream->close(); +assert($stream->isWritable() === false); + +$stream->write('nope'); // NO-OP +$stream->end(); // NO-OP +``` + +Note that this method should not be confused with the `end()` method. +Unlike the `end()` method, this method does not take care of any existing +buffers and simply discards any buffer contents. +Likewise, this method may also be called after calling `end()` on a +stream in order to stop waiting for the stream to flush its final data. + +```php +$stream->end(); +$loop->addTimer(1.0, function () use ($stream) { + $stream->close(); +}); +``` + +If this stream is a `DuplexStreamInterface`, you should also notice +how the readable side of the stream also implements a `close()` method. +In other words, after calling this method, the stream MUST switch into +non-writable AND non-readable mode, see also `isReadable()`. + ## Usage ```php $loop = React\EventLoop\Factory::create(); diff --git a/src/ReadableStreamInterface.php b/src/ReadableStreamInterface.php index b410d26..8f17d99 100644 --- a/src/ReadableStreamInterface.php +++ b/src/ReadableStreamInterface.php @@ -119,5 +119,35 @@ public function resume(); */ public function pipe(WritableStreamInterface $dest, array $options = array()); + /** + * Closes the stream (forcefully). + * + * This method can be used to (forcefully) close the stream. + * + * ```php + * $stream->close(); + * ``` + * + * After calling this method, the stream MUST switch into a non-readable + * mode, see also `isReadable()`. + * This means that no further `data` or `end` events SHOULD be emitted. + * + * ```php + * $stream->close(); + * assert($stream->isReadable() === false); + * + * $stream->on('data', assertNeverCalled()); + * $stream->on('end', assertNeverCalled()); + * ``` + * + * If this stream is a `DuplexStreamInterface`, you should also notice + * how the writable side of the stream also implements a `close()` method. + * In other words, after calling this method, the stream MUST switch into + * non-writable AND non-readable mode, see also `isWritable()`. + * Note that this method should not be confused with the `end()` method. + * + * @return void + * @see WritableStreamInterface::close() + */ public function close(); } diff --git a/src/WritableStreamInterface.php b/src/WritableStreamInterface.php index 26387a3..0f33686 100644 --- a/src/WritableStreamInterface.php +++ b/src/WritableStreamInterface.php @@ -151,5 +151,51 @@ public function write($data); * @return void */ public function end($data = null); + + /** + * Closes the stream (forcefully). + * + * This method can be used to forcefully close the stream, i.e. close + * the stream without waiting for any buffered data to be flushed. + * If there's still data in the buffer, this data SHOULD be discarded. + * + * ```php + * $stream->close(); + * ``` + * + * After calling this method, the stream MUST switch into a non-writable + * mode, see also `isWritable()`. + * This means that no further writes are possible, so any additional + * `write()` or `end()` calls have no effect. + * + * ```php + * $stream->close(); + * assert($stream->isWritable() === false); + * + * $stream->write('nope'); // NO-OP + * $stream->end(); // NO-OP + * ``` + * + * Note that this method should not be confused with the `end()` method. + * Unlike the `end()` method, this method does not take care of any existing + * buffers and simply discards any buffer contents. + * Likewise, this method may also be called after calling `end()` on a + * stream in order to stop waiting for the stream to flush its final data. + * + * ```php + * $stream->end(); + * $loop->addTimer(1.0, function () use ($stream) { + * $stream->close(); + * }); + * ``` + * + * If this stream is a `DuplexStreamInterface`, you should also notice + * how the readable side of the stream also implements a `close()` method. + * In other words, after calling this method, the stream MUST switch into + * non-writable AND non-readable mode, see also `isReadable()`. + * + * @return void + * @see ReadableStreamInterface::close() + */ public function close(); } From 51ec15086ce418035f21feb252f1dfd6dafd40f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20L=C3=BCck?= Date: Mon, 6 Mar 2017 15:21:51 +0100 Subject: [PATCH 6/7] Consistent pause() and resume() semantics and documentation --- README.md | 52 +++++++++++++++++++++++++++++++-- src/ReadableStreamInterface.php | 50 +++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ce239ea..d926443 100644 --- a/README.md +++ b/README.md @@ -60,9 +60,55 @@ how the writable side of the stream also implements an `isWritable()` method. Unless this is a half-open duplex stream, they SHOULD usually have the same return value. -* `pause()`: Remove the data source file descriptor from the event loop. This - allows you to throttle incoming data. -* `resume()`: Re-attach the data source after a `pause()`. +* `pause()`: +The `pause(): void` method can be used to +pause reading incoming data events. + +Removes the data source file descriptor from the event loop. This +allows you to throttle incoming data. + +Unless otherwise noted, a successfully opened stream SHOULD NOT start +in paused state. + +Once the stream is paused, no futher `data` or `end` events SHOULD +be emitted. + +```php +$stream->pause(); + +$stream->on('data', assertShouldNeverCalled()); +$stream->on('end', assertShouldNeverCalled()); +``` + +This method is advisory-only, though generally not recommended, the +stream MAY continue emitting `data` events. + +You can continue processing events by calling `resume()` again. + +Note that both methods can be called any number of times, in particular +calling `pause()` more than once SHOULD NOT have any effect. + +See also `resume()`. + +* `resume()`: +The `resume(): void` method can be used to +resume reading incoming data events. + +Re-attach the data source after a previous `pause()`. + +```php +$stream->pause(); + +$loop->addTimer(1.0, function () use ($stream) { + $stream->resume(); +}); +``` + +Note that both methods can be called any number of times, in particular +calling `resume()` without a prior `pause()` SHOULD NOT have any effect. + +See also `pause()`. + * `pipe(WritableStreamInterface $dest, array $options = [])`: Pipe all the data from this readable source into the given writable destination. diff --git a/src/ReadableStreamInterface.php b/src/ReadableStreamInterface.php index 8f17d99..0009d1a 100644 --- a/src/ReadableStreamInterface.php +++ b/src/ReadableStreamInterface.php @@ -44,7 +44,57 @@ interface ReadableStreamInterface extends EventEmitterInterface */ public function isReadable(); + /** + * Pauses reading incoming data events. + * + * Removes the data source file descriptor from the event loop. This + * allows you to throttle incoming data. + * + * Unless otherwise noted, a successfully opened stream SHOULD NOT start + * in paused state. + * + * Once the stream is paused, no futher `data` or `end` events SHOULD + * be emitted. + * + * ```php + * $stream->pause(); + * + * $stream->on('data', assertShouldNeverCalled()); + * $stream->on('end', assertShouldNeverCalled()); + * ``` + * + * This method is advisory-only, though generally not recommended, the + * stream MAY continue emitting `data` events. + * + * You can continue processing events by calling `resume()` again. + * + * Note that both methods can be called any number of times, in particular + * calling `pause()` more than once SHOULD NOT have any effect. + * + * @see self::resume() + * @return void + */ public function pause(); + + /** + * Resumes reading incoming data events. + * + * Re-attach the data source after a previous `pause()`. + * + * ```php + * $stream->pause(); + * + * $loop->addTimer(1.0, function () use ($stream) { + * $stream->resume(); + * }); + * ``` + * + * Note that both methods can be called any number of times, in particular + * calling `resume()` without a prior `pause()` SHOULD NOT have any effect. + * + * @see self::pause() + * @return void + */ public function resume(); /** From a6c19bef7ab0055fb463e696fc5bb6f388bdf1dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20L=C3=BCck?= Date: Mon, 6 Mar 2017 20:18:05 +0100 Subject: [PATCH 7/7] Add TOC --- README.md | 61 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index d926443..133b653 100644 --- a/README.md +++ b/README.md @@ -14,9 +14,30 @@ descriptor based implementation with an in-memory write buffer. This component depends on `événement`, which is an implementation of the `EventEmitter`. -## Readable Streams - -### EventEmitter Events +**Table of contents** + +* [API](#api) + * [ReadableStreamInterface](#readablestreaminterface) + * [EventEmitter Events](#eventemitter-events) + * [isReadable()](#isreadable) + * [pause()](#pause) + * [resume()](#resume) + * [pipe()](#pipe) + * [close()](#close) + * [WritableStreamInterface](#writablestreaminterface) + * [EventEmitter Events](#eventemitter-events-1) + * [isWritable()](#iswritable) + * [write()](#write) + * [end()](#end) + * [close()](#close-1) +* [Usage](#usage) +* [Install](#install) + +## API + +### ReadableStreamInterface + +#### EventEmitter Events * `data`: Emitted whenever data was read from the source with a single mixed argument for incoming data. @@ -29,9 +50,8 @@ This component depends on `événement`, which is an implementation of the with a single `Exception` argument for error instance. * `close`: Emitted when the stream is closed. -### Methods +#### isReadable() -* `isReadable()`: The `isReadable(): bool` method can be used to check whether this stream is in a readable state (not closed already). @@ -60,7 +80,8 @@ how the writable side of the stream also implements an `isWritable()` method. Unless this is a half-open duplex stream, they SHOULD usually have the same return value. -* `pause()`: +#### pause() + The `pause(): void` method can be used to pause reading incoming data events. @@ -90,7 +111,8 @@ calling `pause()` more than once SHOULD NOT have any effect. See also `resume()`. -* `resume()`: +#### resume() + The `resume(): void` method can be used to resume reading incoming data events. @@ -109,8 +131,10 @@ calling `resume()` without a prior `pause()` SHOULD NOT have any effect. See also `pause()`. -* `pipe(WritableStreamInterface $dest, array $options = [])`: -Pipe all the data from this readable source into the given writable destination. +#### pipe() + +The `pipe(WritableStreamInterface $dest, array $options = [])` method can be used to +pipe all the data from this readable source into the given writable destination. Automatically sends all incoming data to the destination. Automatically throttles the source based on what the destination can handle. @@ -175,7 +199,8 @@ $source->pipe($dest); $dest->close(); // calls $source->pause() ``` -* `close()`: +#### close() + The `close(): void` method can be used to close the stream (forcefully). @@ -203,9 +228,9 @@ In other words, after calling this method, the stream MUST switch into non-writable AND non-readable mode, see also `isWritable()`. Note that this method should not be confused with the `end()` method. -## Writable Streams +### WritableStreamInterface -### EventEmitter Events +#### EventEmitter Events * `drain`: Emitted if the write buffer became full previously and is now ready to accept more data. @@ -215,9 +240,8 @@ Note that this method should not be confused with the `end()` method. * `pipe`: Emitted whenever a readable stream is `pipe()`d into this stream with a single `ReadableStreamInterface` argument for source stream. -### Methods +#### isWritable() -* `isWritable()`: The `isWritable(): bool` method can be used to check whether this stream is in a writable state (not closed already). @@ -245,7 +269,8 @@ how the readable side of the stream also implements an `isReadable()` method. Unless this is a half-open duplex stream, they SHOULD usually have the same return value. -* `write($data)`: +#### write() + The `write(mixed $data): bool` method can be used to write some data into the stream. @@ -288,7 +313,8 @@ data in chunks that may be anywhere between single-byte values to several dozens of kilobytes. You may want to apply a higher-level protocol to these low-level data chunks in order to achieve proper message framing. -* `end($data = null)`: +#### end() + The `end(mixed $data = null): void` method can be used to successfully end the stream (after optionally sending some final data). @@ -346,7 +372,8 @@ $stream->end(); // NO-OP Note that this method should not be confused with the `close()` method. -* `close()`: +#### close() + The `close(): void` method can be used to close the stream (forcefully).