Skip to content

Commit 7e6d7fd

Browse files
authored
Merge pull request #26 from boenrobot/retry-support
Added support for the "retry" field.
2 parents 09bc48a + 5e2cc55 commit 7e6d7fd

File tree

4 files changed

+108
-0
lines changed

4 files changed

+108
-0
lines changed

src/EventSource.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@ private function request()
195195
$this->lastEventId = $message->lastEventId;
196196
}
197197

198+
if ($message->retry !== null) {
199+
$this->reconnectTime = $message->retry / 1000;
200+
}
201+
198202
if ($message->data !== '') {
199203
$this->emit($message->type, array($message));
200204
if ($this->readyState === self::CLOSED) {

src/MessageEvent.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ public static function parse($data)
2929
$message->lastEventId .= $value;
3030
} elseif ($name === 'event') {
3131
$message->type = $value;
32+
} elseif ($name === 'retry' && $value === (string)(int)$value && $value >= 0) {
33+
$message->retry = (int)$value;
3234
}
3335
}
3436

@@ -53,4 +55,10 @@ public static function parse($data)
5355
* @var string
5456
*/
5557
public $type = 'message';
58+
59+
/**
60+
* @internal
61+
* @var ?int
62+
*/
63+
public $retry;
5664
}

tests/EventSourceTest.php

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,78 @@ public function testReconnectAfterStreamClosesUsesLastEventIdFromParsedEventStre
583583
$timerReconnect();
584584
}
585585

586+
public function testReconnectAfterStreamClosesUsesSpecifiedRetryTime()
587+
{
588+
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
589+
$timerReconnect = null;
590+
$loop->expects($this->once())->method('addTimer')->with(
591+
2.543,
592+
$this->callback(function ($cb) use (&$timerReconnect) {
593+
$timerReconnect = $cb;
594+
return true;
595+
})
596+
);
597+
598+
$deferred = new Deferred();
599+
$browser = $this->getMockBuilder('React\Http\Browser')->disableOriginalConstructor()->getMock();
600+
$browser->expects($this->once())->method('withRejectErrorResponse')->willReturnSelf();
601+
$browser->expects($this->exactly(2))->method('requestStreaming')->withConsecutive(
602+
['GET', 'http://example.com', ['Accept' => 'text/event-stream', 'Cache-Control' => 'no-cache']],
603+
['GET', 'http://example.com', ['Accept' => 'text/event-stream', 'Cache-Control' => 'no-cache']]
604+
)->willReturnOnConsecutiveCalls(
605+
$deferred->promise(),
606+
new Promise(function () { })
607+
);
608+
609+
$es = new EventSource('http://example.com', $browser, $loop);
610+
611+
$stream = new ThroughStream();
612+
$response = new Response(200, array('Content-Type' => 'text/event-stream'), new ReadableBodyStream($stream));
613+
$deferred->resolve($response);
614+
615+
$stream->write("retry:2543\n\n");
616+
$stream->end();
617+
618+
$this->assertNotNull($timerReconnect);
619+
$timerReconnect();
620+
}
621+
622+
public function testReconnectAfterStreamClosesIgnoresInvalidRetryTime()
623+
{
624+
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
625+
$timerReconnect = null;
626+
$loop->expects($this->once())->method('addTimer')->with(
627+
3,
628+
$this->callback(function ($cb) use (&$timerReconnect) {
629+
$timerReconnect = $cb;
630+
return true;
631+
})
632+
);
633+
634+
$deferred = new Deferred();
635+
$browser = $this->getMockBuilder('React\Http\Browser')->disableOriginalConstructor()->getMock();
636+
$browser->expects($this->once())->method('withRejectErrorResponse')->willReturnSelf();
637+
$browser->expects($this->exactly(2))->method('requestStreaming')->withConsecutive(
638+
['GET', 'http://example.com', ['Accept' => 'text/event-stream', 'Cache-Control' => 'no-cache']],
639+
['GET', 'http://example.com', ['Accept' => 'text/event-stream', 'Cache-Control' => 'no-cache']]
640+
)->willReturnOnConsecutiveCalls(
641+
$deferred->promise(),
642+
new Promise(function () { })
643+
);
644+
645+
$es = new EventSource('http://example.com', $browser, $loop);
646+
647+
$stream = new ThroughStream();
648+
$response = new Response(200, array('Content-Type' => 'text/event-stream'), new ReadableBodyStream($stream));
649+
$deferred->resolve($response);
650+
651+
$stream->write("retry:now\n\n");
652+
$stream->end();
653+
654+
$this->assertNotNull($timerReconnect);
655+
$timerReconnect();
656+
}
657+
586658
public function setExpectedException($exception, $exceptionMessage = '', $exceptionCode = null)
587659
{
588660
if (method_exists($this, 'expectException')) {

tests/MessageEventTest.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,28 @@ public function testParseDataWithCarrigeReturnAndNewlineOverTwoLines()
5555

5656
$this->assertEquals("hello\n", $message->data);
5757
}
58+
59+
public function retryTimeDataProvider()
60+
{
61+
return [
62+
['retry: 1234', 1234,],
63+
['retry: 0', 0,],
64+
['retry: ' . PHP_INT_MAX, PHP_INT_MAX,],
65+
['retry: ' . PHP_INT_MAX . '9', null,],
66+
['retry: 1.234', null,],
67+
['retry: now', null,],
68+
['retry: -1', null,],
69+
['retry: -1.234', null,],
70+
];
71+
}
72+
73+
/**
74+
* @dataProvider retryTimeDataProvider
75+
*/
76+
public function testParseRetryTime($input, $expected)
77+
{
78+
$message = MessageEvent::parse($input);
79+
80+
$this->assertSame($expected, $message->retry);
81+
}
5882
}

0 commit comments

Comments
 (0)