Skip to content

Commit

Permalink
Merge pull request #86 from clue-labs/end
Browse files Browse the repository at this point in the history
Consistent semantics for DuplexStreamInterface::end() to ensure it SHOULD also end readable side
  • Loading branch information
jsor authored Mar 26, 2017
2 parents 5f7bd5b + 7ff110b commit dcc0c46
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 0 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,16 @@ $stream->write('nope'); // NO-OP
$stream->end(); // NO-OP
```

If this stream is a `DuplexStreamInterface`, calling this method SHOULD
also end its readable side, unless the stream supports half-open mode.
In other words, after calling this method, these streams SHOULD switch
into non-writable AND non-readable mode, see also `isReadable()`.
This implies that in this case, the stream SHOULD NOT emit any `data`
or `end` events anymore.
Streams MAY choose to use the `pause()` method logic for this, but
special care may have to be taken to ensure a following call to the
`resume()` method SHOULD NOT continue emitting readable events.

Note that this method should not be confused with the `close()` method.

#### close()
Expand Down
5 changes: 5 additions & 0 deletions src/CompositeStream.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ public function pause()

public function resume()
{
if (!$this->writable->isWritable()) {
return;
}

if ($this->pipeSource) {
$this->pipeSource->resume();
}
Expand All @@ -70,6 +74,7 @@ public function write($data)

public function end($data = null)
{
$this->readable->pause();
$this->writable->end($data);
}

Expand Down
1 change: 1 addition & 0 deletions src/DuplexResourceStream.php
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ public function end($data = null)

$this->readable = false;
$this->writable = false;
$this->pause();

$this->buffer->end($data);
}
Expand Down
10 changes: 10 additions & 0 deletions src/WritableStreamInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,16 @@ public function write($data);
* $stream->end(); // NO-OP
* ```
*
* If this stream is a `DuplexStreamInterface`, calling this method SHOULD
* also end its readable side, unless the stream supports half-open mode.
* In other words, after calling this method, these streams SHOULD switch
* into non-writable AND non-readable mode, see also `isReadable()`.
* This implies that in this case, the stream SHOULD NOT emit any `data`
* or `end` events anymore.
* Streams MAY choose to use the `pause()` method logic for this, but
* special care may have to be taken to ensure a following call to the
* `resume()` method SHOULD NOT continue emitting readable events.
*
* Note that this method should not be confused with the `close()` method.
*
* @param mixed|string|null $data
Expand Down
22 changes: 22 additions & 0 deletions tests/CompositeStreamTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,35 @@ public function itShouldForwardReadableCallsToReadableStream()
->expects($this->once())
->method('resume');
$writable = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock();
$writable
->expects($this->any())
->method('isWritable')
->willReturn(true);

$composite = new CompositeStream($readable, $writable);
$composite->isReadable();
$composite->pause();
$composite->resume();
}

/** @test */
public function itShouldNotForwardResumeIfStreamIsNotWritable()
{
$readable = $this->getMockBuilder('React\Stream\ReadableStreamInterface')->getMock();
$readable
->expects($this->never())
->method('resume');

$writable = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock();
$writable
->expects($this->once())
->method('isWritable')
->willReturn(false);

$composite = new CompositeStream($readable, $writable);
$composite->resume();
}

/** @test */
public function endShouldDelegateToWritableWithData()
{
Expand Down
13 changes: 13 additions & 0 deletions tests/DuplexResourceStreamTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,19 @@ public function testEnd()
$this->assertFalse($conn->isWritable());
}

/**
* @covers React\Stream\DuplexResourceStream::end
*/
public function testEndRemovesReadStreamFromLoop()
{
$stream = fopen('php://temp', 'r+');
$loop = $this->createLoopMock();
$loop->expects($this->once())->method('removeReadStream');

$conn = new DuplexResourceStream($stream, $loop);
$conn->end('bye');
}

public function testEndedStreamsShouldNotWrite()
{
$file = tempnam(sys_get_temp_dir(), 'reactphptest_');
Expand Down

0 comments on commit dcc0c46

Please sign in to comment.