Skip to content

Commit ecb53c1

Browse files
appkit-frameworkWyriHaximus
authored andcommitted
Fix handling of exceptions thrown by frame handlers
1 parent d259b44 commit ecb53c1

3 files changed

Lines changed: 145 additions & 4 deletions

File tree

spec/generate.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -288,9 +288,15 @@ function amqpTypeToLength(string $type, string $e): array
288288
$connectionContent .= " while ((\$frame = \$this->reader->consumeFrame(\$this->readBuffer)) !== null) {\n";
289289
$connectionContent .= " \$frameInAwaitList = false;\n";
290290
$connectionContent .= " foreach (\$this->awaitList as \$index => \$frameHandler) {\n";
291-
$connectionContent .= " if (\$frameHandler['filter'](\$frame)) {\n";
291+
$connectionContent .= " try {\n";
292+
$connectionContent .= " if (\$frameHandler['filter'](\$frame)) {\n";
293+
$connectionContent .= " unset(\$this->awaitList[\$index]);\n";
294+
$connectionContent .= " \$frameHandler['promise']->resolve(\$frame);\n";
295+
$connectionContent .= " \$frameInAwaitList = true;\n";
296+
$connectionContent .= " }\n";
297+
$connectionContent .= " } catch (Throwable \$exception) {\n";
292298
$connectionContent .= " unset(\$this->awaitList[\$index]);\n";
293-
$connectionContent .= " \$frameHandler['promise']->resolve(\$frame);\n";
299+
$connectionContent .= " \$frameHandler['promise']->reject(\$exception);\n";
294300
$connectionContent .= " \$frameInAwaitList = true;\n";
295301
$connectionContent .= " }\n";
296302
$connectionContent .= " }\n";

src/Connection.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,15 @@ public function __construct(
7070
while (($frame = $this->reader->consumeFrame($this->readBuffer)) !== null) {
7171
$frameInAwaitList = false;
7272
foreach ($this->awaitList as $index => $frameHandler) {
73-
if ($frameHandler['filter']($frame)) {
73+
try {
74+
if ($frameHandler['filter']($frame)) {
75+
unset($this->awaitList[$index]);
76+
$frameHandler['promise']->resolve($frame);
77+
$frameInAwaitList = true;
78+
}
79+
} catch (Throwable $exception) {
7480
unset($this->awaitList[$index]);
75-
$frameHandler['promise']->resolve($frame);
81+
$frameHandler['promise']->reject($exception);
7682
$frameInAwaitList = true;
7783
}
7884
}

test/ConnectionTest.php

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
<?php
2+
3+
/** @noinspection PhpUnhandledExceptionInspection */
4+
5+
declare(strict_types=1);
6+
7+
namespace Bunny\Test;
8+
9+
use Bunny\Channels;
10+
use Bunny\Configuration;
11+
use Bunny\Connection;
12+
use Bunny\Protocol\Buffer;
13+
use Bunny\Protocol\ProtocolReader;
14+
use Bunny\Protocol\ProtocolWriter;
15+
use Bunny\Test\Library\ClientHelper;
16+
use Evenement\EventEmitterTrait;
17+
use PHPUnit\Framework\TestCase;
18+
use React\EventLoop\Loop;
19+
use React\Promise\Deferred;
20+
use React\Socket\ConnectionInterface;
21+
use React\Stream\WritableStreamInterface;
22+
use WyriHaximus\React\PHPUnit\RunTestsInFibersTrait;
23+
use function React\Async\await;
24+
25+
class ConnectionTest extends TestCase
26+
{
27+
use RunTestsInFibersTrait;
28+
29+
private ClientHelper $helper;
30+
31+
protected function setUp(): void
32+
{
33+
parent::setUp();
34+
35+
$this->helper = new ClientHelper();
36+
}
37+
38+
public function testThrowOn(): void
39+
{
40+
// phpcs:disable
41+
$mockConnection = new class () implements ConnectionInterface {
42+
use EventEmitterTrait;
43+
44+
/**
45+
* @return string
46+
*/
47+
public function getRemoteAddress()
48+
{
49+
return '127.0.0.1:666';
50+
}
51+
52+
/**
53+
* @return string
54+
*/
55+
public function getLocalAddress()
56+
{
57+
return '127.0.0.1:666';
58+
}
59+
60+
public function isReadable(): void
61+
{
62+
// TODO: Implement isReadable() method.
63+
}
64+
65+
public function pause(): void
66+
{
67+
// TODO: Implement pause() method.
68+
}
69+
70+
public function resume(): void
71+
{
72+
// TODO: Implement resume() method.
73+
}
74+
75+
/**
76+
* @param array $options
77+
*/
78+
public function pipe(WritableStreamInterface $dest, array $options = []): void
79+
{
80+
// TODO: Implement pipe() method.
81+
}
82+
83+
public function close(): void
84+
{
85+
// TODO: Implement close() method.
86+
}
87+
88+
public function isWritable(): void
89+
{
90+
// TODO: Implement isWritable() method.
91+
}
92+
93+
/**
94+
* @param string $data
95+
*/
96+
public function write($data): void
97+
{
98+
// TODO: Implement write() method.
99+
}
100+
101+
/**
102+
* @param ?string $data
103+
*/
104+
public function end($data = null): void
105+
{
106+
// TODO: Implement end() method.
107+
}
108+
};
109+
// phpcs:enable
110+
$connection = new Connection(
111+
$this->helper->createClient(),
112+
$mockConnection,
113+
new Buffer(),
114+
new Buffer(),
115+
new ProtocolReader(),
116+
new ProtocolWriter(),
117+
new Channels(),
118+
new Configuration(),
119+
);
120+
$mockConnection->emit(
121+
'data',
122+
[
123+
''
124+
],
125+
);
126+
// $connection->awaitAck(666);
127+
// $connection->awaitContentHeader(666);
128+
}
129+
}

0 commit comments

Comments
 (0)