8000 Merge pull request #1 from rtckit/v0.8.5 · rtckit/reactphp-esl@23c7201 · GitHub
[go: up one dir, main page]

Skip to content

Commit 23c7201

Browse files
authored
Merge pull request #1 from rtckit/v0.8.5
v0.8.5
2 parents f868f94 + 8b70f55 commit 23c7201

9 files changed

+100
-53
lines changed

composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "rtckit/react-esl",
33
"description": "Asynchronous FreeSWITCH Event Socket Layer (ESL) Library",
4-
"version": "0.8.0",
4+
"version": "0.8.5",
55
"type": "library",
66
"keywords": [
77
"freeswitch",
@@ -34,7 +34,7 @@
3434
"clue/stdio-react": "^2.5",
3535
"phpstan/phpstan": "^1.4",
3636
"phpunit/phpunit": "^9.5",
37-
"vimeo/psalm": "^4.18"
37+
"vimeo/psalm": "^4.20"
3838
},
3939
"autoload": {
4040
"psr-4": {

src/InboundClient.php

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
Response,
2626
ResponseInterface
2727
};
28-
USE Closure;
28+
use Closure;
2929
use Throwable;
3030

3131
/**
@@ -105,12 +105,18 @@ public function connect(): PromiseInterface
105105
* Processes raw inbound bytes
106106
*
107107
* @param string $chunk
108-
* @throws ReactESLException
109108
*/
110109
protected function dataHandler(string $chunk): void
111110
{
112111
$responses = [];
113-
$ret = $this->esl->consume($chunk, $responses);
112+
113+
try {
114+
$ret = $this->esl->consume($chunk, $responses);
115+
} catch (Throwable $t) {
116+
$this->emit('error', [$t]);
117+
118+
return;
119+
}
114120

115121
assert(!is_null($responses));
116122

@@ -143,26 +149,28 @@ protected function dataHandler(string $chunk): void
143149
continue;
144150
}
145151

146-
if (empty($this->queue)) {
152+
$deferred = array_shift($this->queue);
153+
154+
if (is_null($deferred)) {
147155
$contentType = $response->getHeader(AbstractHeader::CONTENT_TYPE) ?? '';
148156

149-
throw new ReactESLException(
150-
'Unexpected reply received (ENOMSG) ' . $contentType,
151-
defined('SOCKET_ENOMSG') ? SOCKET_ENOMSG : 42
157+
$this->emit(
158+
'error',
159+
[new ReactESLException(
160+
'Unexpected reply received (ENOMSG) ' . $contentType,
161+
defined('SOCKET_ENOMSG') ? SOCKET_ENOMSG : 42
162+
)]
152163
);
164+
} else {
165+
$deferred->resolve($response);
153166
}
154-
155-
$deferred = array_shift($this->queue);
156-
$deferred->resolve($response);
157167
}
158168
}
159169

160170
/**
161171
* Processes early inbound messages (authentication)
162172
*
163173
* @param MessageInterface $response
164-
*
165-
* @throws ReactESLException
166174
*/
167175
public function preAuthHandler(MessageInterface $response): void
168176
{
@@ -181,14 +189,14 @@ public function preAuthHandler(MessageInterface $response): void
181189
$this->authenticated = true;
182190
$this->deferredConnect->resolve($this);
183191
} else {
184-
throw new ReactESLException('Authentication failed');
192+
$this->deferredConnect->reject(new ReactESLException('Authentication failed'));
185193
}
186194
} else if ($response instanceof Response\TextDisconnectNotice) {
187195
$this->emit('disconnect', [$response]);
188196
} else if ($response instanceof Response\TextRudeRejection) {
189197
$this->deferredConnect->reject(new ReactESLException('Access denied'));
190198
} else {
191-
throw new ReactESLException('Unexpected response (expecting auth/request)');
199+
$this->deferredConnect->reject(new ReactESLException('Unexpected response (expecting auth/request)'));
192200
}
193201
}
194202

src/InboundServer.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
Request
1818
};
1919
use Closure;
20+
use Throwable;
2021

2122
/**
2223
* Inbound ESL Server class
@@ -69,7 +70,13 @@ protected function connectionHandler(DuplexStreamInterface $stream): void
6970
$client = new RemoteInboundClient($esl);
7071

7172
$stream->on('data', function (string $chunk) use ($client, $esl) {
72-
$esl->consume($chunk, $requests);
73+
try {
74+
$esl->consume($chunk, $requests);
75+
} catch (Throwable $t) {
76+
$client->emit('error', [$t]);
77+
78+
return;
79+
}
7380

7481
assert(!is_null($requests));
7582

src/OutboundClient.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,16 @@ public function connect(): PromiseInterface
8383
* Processes raw inbound bytes
8484
*
8585
* @param string $chunk
86-
* @throws ReactESLException
8786
*/
8887
protected function dataHandler(string $chunk): void
8988
{
90-
$requests = [];
91-
$ret = $this->esl->consume($chunk, $requests);
89+
try {
90+
$this->esl->consume($chunk, $requests);
91+
} catch (Throwable $t) {
92+
$this->emit('error', [$t]);
93+
94+
return;
95+
}
9296

9397
assert(!is_null($requests));
9498

src/OutboundServer.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
Response
2121
};
2222
use Closure;
23+
use Throwable;
2324

2425
/**
2526
* Outbound ESL Server class
@@ -74,7 +75,13 @@ protected function connectionHandler(DuplexStreamInterface $stream): void
7475
$client = new RemoteOutboundClient($esl);
7576

7677
$stream->on('data', function (string $chunk) use ($client, $esl) {
77-
$esl->consume($chunk, $responses);
78+
try {
79+
$esl->consume($chunk, $responses);
80+
} catch (Throwable $t) {
81+
$client->emit('error', [$t]);
82+
83+
return;
84+
}
7885

7986
assert(!is_null($responses));
8087

tests/InboundClientTest.php

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,21 @@ public function testConnectFailed(): void
114114
$this->assertFalse($this->isPropertyInitialized($client, 'esl'));
115115
}
116116

117+
public function testDataHandlerOnParsingError(): void
118+
{
119+
$context = $this->prepareClientAndConnectors();
120+
$this->setPropertyValue($context->client, 'authenticated', true);
121+
$dataHandler = $this->getMethod($context->client, 'dataHandler');
122+
123+
$this->setPropertyValue($context->client, 'esl', new AsyncConnection(AsyncConnection::INBOUND_CLIENT));
124+
125+
$context->client->on('error', function (\Throwable $t) {
126+
$this->assertInstanceOf(ESL\Exception\ESLException::class, $t);
127+
});
128+
129+
$dataHandler->invokeArgs($context->client, ["Content-Type: bogus/no-such-thing\n\n"]);
130+
}
131+
117132
public function testDataHandlerOnPreAuth(): void
118133
{
119134
$context = $this->prepareClientAndConnectors();
@@ -253,6 +268,10 @@ public function testDataHandlerOnOutOfSequence(): void
253268

254269
$response = "Content-Type: api/response\n\n";
255270

271+
$context->client->on('error', function (\Throwable $t) {
272+
$this->assertInstanceOf(ReactESLException::class, $t);
273+
});
274+
256275
$context->esl
257276
->method('consume')
258277
->with($response, [])
@@ -262,7 +281,6 @@ public function testDataHandlerOnOutOfSequence(): void
262281
return ESL\Connection::SUCCESS;
263282
}));
264283

265-
$this->expectException(ReactESLException::class);
266284
$dataHandler->invokeArgs($context->client, [$response]);
267285
}
268286

@@ -334,17 +352,6 @@ public function testPreAuthHandlerOnCommandReplySuccess(): void
334352
$this->assertTrue($this->getPropertyValue($context->client, 'authenticated'));
335353
}
336354

337-
public function testPreAuthHandlerOnCommandReplyFailure(): void
338-
{
339-
$context = $this->prepareClientAndConnectors();
340-
$preAuthHandler = $this->getMethod($context->client, 'preAuthHandler');
341-
342-
$this->expectException(ReactESLException::class);
343-
$preAuthHandler->invokeArgs($context->client, [
344-
(new ESL\Response\CommandReply)->setHeader(ESL\AbstractHeader::REPLY_TEXT, '-ERR invalid')
345-
]);
346-
}
347-
348355
public function testPreAuthHandlerOnDisconnectNotice(): void
349356
{
350357
$context = $this->prepareClientAndConnectors();
@@ -377,8 +384,22 @@ public function testPreAuthHandlerOnUnexpectedResponse(): void
377384
$context = $this->prepareClientAndConnectors();
378385
$preAuthHandler = $this->getMethod($context->client, 'preAuthHandler');
379386

380-
$this->expectException(ReactESLException::class);
381387
$preAuthHandler->invokeArgs($context->client, [new ESL\Response\ApiResponse]);
388+
$context->promise
389+
->then(function () {
390+
$this->fail('Should never resolve');
391+
})
392+
->otherwise(function (\Throwable $t) {
393+
$this->assertInstanceOf(ReactESLException::class, $t);
394+
});
395+
}
396+
397+
public function testClose(): void
398+
{
399+
$context = $this->prepareClientAndConnectors();
400+
401+
$context->stream->expects($this->once())->method('close');
402+
$context->client->close();
382403
}
383404

384405
private function prepareClientAndConnectors(): stdClass
@@ -408,12 +429,4 @@ private function prepareClientAndConnectors(): stdClass
408429

409430
return $ret;
410431
}
411-
412-
public function testClose(): void
413-
{
414-
$context = $this->prepareClientAndConnectors();
415-
416-
$context->stream->expects($this->once())->method('close');
417-
$context->client->close();
418-
}
419432
}

tests/InboundServerTest.php

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -85,25 +85,22 @@ public function testConnectionHandler(): void
8585
if ($response instanceof ESL\Response\AuthRequest) {
8686
return (new ESL\Request\Auth)->setParameters('ClueCon')->render();
8787
}
88-
89-
return '';
90-
} catch (ESL\Exception\ESLException $e) {
91-
$request = ESL\Request::parse($bytes);
92-
93-
$this->assertInstanceOf(ESL\Request\Api::class, $request);
94-
$this->assertEquals('version', $request->getParameters());
95-
}
88+
} catch (ESL\Exception\ESLException $e) {}
9689

9790
return $bytes;
9891
});
9992

10093
$server->on('auth', function (RemoteInboundClient $client, ESL\Request\Auth $request) use ($stream) {
94+
$client->on('error', function (\Throwable $t) {
95+
$this->assertInstanceOf(ESL\Exception\ESLException::class, $t);
96+
});
97+
10198
$this->assertEquals('ClueCon', $request->getParameters());
10299

103-
$client->send((new ESL\Response\CommandReply)->setHeader('reply-text', '+OK accepted'));
104100
$client->setAuthenticated(true);
105101

106102
$stream->write("api version\n\n");
103+
$stream->write("bogus\n\n");
107104
});
108105

109106
$connHandler->invokeArgs($server, [$stream]);

tests/OutboundClientTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,12 @@ public function testDataHandler(): void
119119
"linger\n\n" .
120120
"myevents json\n\n"
121121
]);
122+
123+
$client->on('error', function (\Throwable $t) {
124+
$this->assertInstanceOf(ESL\Exception\ESLException::class, $t);
125+
});
126+
127+
$dataHandler->invokeArgs($client, ["bogus\n\n"]);
122128
}
123129

124130
public function testClose(): void

tests/OutboundServerTest.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,13 +129,13 @@ public function testConnectionHandler(): void
129129
$client->on('error', function (\Throwable $t) {
130130
if ($t instanceof ReactESLException) {
131131
$this->assertTrue(true, 'Received out of sequence exception');
132+
} else if ($t instanceof ESL\Exception\ESLException) {
133+
$this->assertTrue(true, 'Received parsing exception');
132134
} else {
133135
$this->fail('Unrecognized exception');
134136
}
135137
});
136138

137-
$stream->write("content-type: api/response\nexpected: false\n\n");
138-
139139
$deferred = new Deferred;
140140
$this->setPropertyValue($client, 'queue', [$deferred]);
141141

@@ -146,6 +146,11 @@ public function testConnectionHandler(): void
146146
$this->assertEquals('true', $response->getHeader('expected'));
147147
});
148148

149+
$this->setPropertyValue($client, 'queue', []);
150+
$stream->write("content-type: api/response\nexpected: false\n\n");
151+
152+
$stream->write("content-type: bogus\n\n");
153+
149154
$stream->close();
150155
});
151156

0 commit comments

Comments
 (0)
0