Skip to content

Commit 2954976

Browse files
committed
Allow server callback to return PromiseInterface
1 parent 75d67cd commit 2954976

File tree

4 files changed

+45
-13
lines changed

4 files changed

+45
-13
lines changed

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
],
1818
"require": {
1919
"react/socket": "^1.1",
20+
"react/promise": "^2.7",
2021
"psr/log": "^1.0",
2122
"myclabs/php-enum": "^1.5",
2223
"evenement/evenement": "3.0"
@@ -29,4 +30,4 @@
2930
"require-dev": {
3031
"phpunit/phpunit": "^6.5"
3132
}
32-
}
33+
}

composer.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Server.php

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,12 @@
2727
namespace PhpBg\Rtsp;
2828

2929
use Evenement\EventEmitter;
30+
use PhpBg\Rtsp\Message\MessageFactory;
3031
use PhpBg\Rtsp\Message\Request;
3132
use PhpBg\Rtsp\Message\RequestParser;
3233
use PhpBg\Rtsp\Message\Response;
34+
use React\Promise\FulfilledPromise;
35+
use React\Promise\PromiseInterface;
3336
use React\Socket\ConnectionInterface;
3437
use React\Socket\ServerInterface;
3538

@@ -56,7 +59,10 @@ class Server extends EventEmitter
5659
/**
5760
* Server constructor
5861
*
59-
* @param callable $callback Callback that will receive (Request, React\Socket\ConnectionInterface) and may return a Response
62+
* @param callable $callback
63+
* Callback that will receive (PhpBg\Rtsp\Message\Request, React\Socket\ConnectionInterface) and return
64+
* * a PhpBg\Rtsp\Message\Response
65+
* * a React\Promise\PromiseInterface that will resolve in a Response
6066
*/
6167
public function __construct(Callable $callback)
6268
{
@@ -120,12 +126,33 @@ protected function handleRequest(Request $request, ConnectionInterface $connecti
120126
$this->emit('error', [$e]);
121127
return;
122128
}
123-
if (isset($response)) {
124-
if ($response instanceof Response) {
125-
$connection->write($response->toTransport());
129+
// Convert all non-promise response to promises
130+
// There is little overhead for this, but this allows simpler code
131+
if (!isset($response) || !$response instanceof PromiseInterface) {
132+
$response = new FulfilledPromise($response);
133+
}
134+
135+
$response->done(function ($resolvedResponse) use ($connection) {
136+
if ($resolvedResponse instanceof Response) {
137+
$connection->write($resolvedResponse->toTransport());
126138
return;
127139
}
128-
$this->emit('error', [new ServerException("Your handler did return something, but it wasn't a Response")]);
129-
}
140+
$message = 'The response callback is expected to resolve with an object implementing PhpBg\Rtsp\Message\Response, but resolved with "%s" instead.';
141+
$message = sprintf($message, is_object($resolvedResponse) ? get_class($resolvedResponse) : gettype($resolvedResponse));
142+
$this->emit('error', [new ServerException($message)]);
143+
}, function ($error) use ($connection) {
144+
$message = 'The response callback is expected to resolve with an object implementing PhpBg\Rtsp\Message\Response, but rejected with "%s" instead.';
145+
$message = sprintf($message, is_object($error) ? get_class($error) : gettype($error));
146+
$previous = null;
147+
if ($error instanceof \Throwable || $error instanceof \Exception) {
148+
$previous = $error;
149+
}
150+
$exception = new \RuntimeException($message, null, $previous);
151+
$this->emit('error', [$exception]);
152+
153+
$rtspResponse = MessageFactory::response(500, [], null, 'internal server error');
154+
$connection->write($rtspResponse->toTransport());
155+
});
130156
}
157+
131158
}

tests/ServerTest.php

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use PhpBg\Rtsp\Message\MessageFactory;
77
use PhpBg\Rtsp\Message\Request;
88
use PhpBg\Rtsp\Server;
9+
use PhpBg\Rtsp\ServerException;
910
use PHPUnit\Framework\TestCase;
1011
use React\Socket\ConnectionInterface;
1112

@@ -48,6 +49,8 @@ public function testSimpleRequest() {
4849
/** @var Request $request */
4950
$this->assertSame(1, count($request->headers));
5051
$this->assertSame('1', $request->getHeader('cseq'));
52+
53+
return MessageFactory::response();
5154
});
5255

5356
$server->on('error', function($exception) {
@@ -80,22 +83,23 @@ public function testInvalidMethodRequest() {
8083
$this->assertInstanceOf(MessageException::class, $error);
8184
}
8285

83-
/**
84-
* @expectedException \PhpBg\Rtsp\ServerException
85-
*/
8686
public function testCallbackDoNotReturnResponse() {
8787
$server = new Server(function () {
8888
return false;
8989
});
9090

91-
$server->on('error', function($exception) {
92-
throw $exception;
91+
$error = null;
92+
$server->on('error', function($exception) use (&$error) {
93+
$error = $exception;
9394
});
9495

9596
$server->listen($this->socket);
9697

9798
$this->socket->emit('connection', array($this->connection));
9899
$this->connection->emit('data', array("OPTIONS / RTSP/1.0\r\nCseq:1\r\n\r\n"));
100+
101+
$this->assertInstanceOf(ServerException::class, $error);
102+
$this->assertTrue(strpos($error->getMessage(), 'boolean')>0);
99103
}
100104

101105
public function testRequestWithResponse() {

0 commit comments

Comments
 (0)