Skip to content

Commit 8d0eaea

Browse files
authored
Merge pull request #40 from clue-labs/uris
Consistently require URL when creating client
2 parents 8cda514 + 5f9957c commit 8d0eaea

4 files changed

Lines changed: 40 additions & 45 deletions

File tree

README.md

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,12 @@ $factory = new Factory($loop, $connector);
9999

100100
#### createClient()
101101

102-
The `createClient(string $amiUrl): PromiseInterface<Client>` method can be used to create a new [`Client`](#client).
103-
It helps with establishing a plain TCP/IP or secure SSL/TLS connection to the AMI
104-
and issuing an initial `login` action.
102+
The `createClient(string $url): PromiseInterface<Client>` method can be used to create a new [`Client`](#client).
103+
It helps with establishing a plain TCP/IP or secure TLS connection to the AMI
104+
and optionally issuing an initial `login` action.
105105

106106
```php
107-
$factory->createClient($amiUrl)->then(
107+
$factory->createClient($url)->then(
108108
function (Client $client) {
109109
// client connected (and authenticated)
110110
},
@@ -114,16 +114,18 @@ $factory->createClient($amiUrl)->then(
114114
);
115115
```
116116

117-
The `$amiUrl` contains the host and optional port to connect to:
117+
The method returns a [Promise](https://github.com/reactphp/promise) that will
118+
resolve with the [`Client`](#client) instance on success or will reject with an
119+
`Exception` if the URL is invalid or the connection or authentication fails.
120+
121+
The `$url` parameter contains the host and optional port (which defaults to
122+
`5038` for plain TCP/IP connections) to connect to:
118123

119124
```php
120-
$factory->createClient('127.0.0.1:5038');
125+
$factory->createClient('localhost:5038');
121126
```
122127

123-
> If the `$amiUrl` is `null` (or omitted) this method defaults to connecting
124-
to your local host (`127.0.0.1:5038`).
125-
126-
The above examples to not pass any authentication details, so you may have to
128+
The above example does not pass any authentication details, so you may have to
127129
call `ActionSender::login()` after connecting or use the recommended shortcut
128130
to pass a username and secret for your AMI login details like this:
129131

@@ -132,10 +134,11 @@ $factory->createClient('user:secret@localhost');
132134
```
133135

134136
The `Factory` defaults to establishing a plaintext TCP connection.
135-
If you want to connect through a secure TLS proxy, you can use the `tls` scheme:
137+
If you want to create a secure TLS connection, you can use the `tls` scheme
138+
(which defaults to port `5039`):
136139

137140
```php
138-
$factory->createClient('tls://user:secret@localhost:12345');
141+
$factory->createClient('tls://user:secret@localhost:5039');
139142
```
140143

141144
### Client

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"php": ">=5.3",
1515
"evenement/evenement": "^3.0 || ^2.0 || ^1.0",
1616
"react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3",
17-
"react/promise": "^2.0 || ^1.0",
17+
"react/promise": "^2.0 || ^1.1",
1818
"react/socket": "^1.0 || ^0.8.2"
1919
},
2020
"require-dev": {

src/Factory.php

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use React\Socket\Connector;
88
use React\Socket\ConnectorInterface;
99
use InvalidArgumentException;
10+
use React\Promise;
1011

1112
class Factory
1213
{
@@ -23,15 +24,19 @@ public function __construct(LoopInterface $loop, ConnectorInterface $connector =
2324
$this->connector = $connector;
2425
}
2526

26-
public function createClient($address = null)
27+
public function createClient($url)
2728
{
28-
$parts = $this->parseUrl($address);
29+
$parts = parse_url((strpos($url, '://') === false ? 'tcp://' : '') . $url);
30+
if (!$parts || !isset($parts['scheme'], $parts['host'])) {
31+
return Promise\reject(new InvalidArgumentException('Given URL "' . $url . '" can not be parsed'));
32+
}
2933

30-
if (isset($parts['scheme']) && $parts['scheme'] !== 'tcp') {
31-
$parts['host'] = 'tls://' . $parts['host'];
34+
// use default port 5039 for `tls://` or 5038 otherwise
35+
if (!isset($parts['port'])) {
36+
$parts['port'] = $parts['scheme'] === 'tls' ? 5039 : 5038;
3237
}
3338

34-
$promise = $this->connector->connect($parts['host'] . ':' . $parts['port'])->then(function (ConnectionInterface $stream) {
39+
$promise = $this->connector->connect($parts['scheme'] . '://' . $parts['host'] . ':' . $parts['port'])->then(function (ConnectionInterface $stream) {
3540
return new Client($stream);
3641
});
3742

@@ -53,25 +58,4 @@ function ($error) use ($client) {
5358

5459
return $promise;
5560
}
56-
57-
private function parseUrl($target)
58-
{
59-
if ($target === null) {
60-
$target = 'tcp://127.0.0.1';
61-
}
62-
if (strpos($target, '://') === false) {
63-
$target = 'tcp://' . $target;
64-
}
65-
66-
$parts = parse_url($target);
67-
if ($parts === false || !isset($parts['host'])) {
68-
throw new InvalidArgumentException('Given URL can not be parsed');
69-
}
70-
71-
if (!isset($parts['port'])) {
72-
$parts['port'] = '5038';
73-
}
74-
75-
return $parts;
76-
}
7761
}

tests/FactoryTest.php

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use Clue\React\Ami\Factory;
44
use React\Promise\Promise;
5+
56
class FactoryTest extends TestCase
67
{
78
private $loop;
@@ -21,20 +22,20 @@ public function testDefaultCtor()
2122
$this->factory = new Factory($this->loop);
2223
}
2324

24-
public function testCreateClientUsesTcpConnectorWithDefaultLocation()
25+
public function testCreateClientUsesDefaultPortForTcpConnection()
2526
{
2627
$promise = new Promise(function () { });
27-
$this->tcp->expects($this->once())->method('connect')->with('127.0.0.1:5038')->willReturn($promise);
28+
$this->tcp->expects($this->once())->method('connect')->with('tcp://localhost:5038')->willReturn($promise);
2829

29-
$this->factory->createClient();
30+
$this->factory->createClient('localhost');
3031
}
3132

32-
public function testCreateClientUsesDefaultPortForTcpConnection()
33+
public function testCreateClientUsesTlsPortForTlsConnection()
3334
{
3435
$promise = new Promise(function () { });
35-
$this->tcp->expects($this->once())->method('connect')->with('localhost:5038')->willReturn($promise);
36+
$this->tcp->expects($this->once())->method('connect')->with('tls://localhost:5039')->willReturn($promise);
3637

37-
$this->factory->createClient('localhost');
38+
$this->factory->createClient('tls://localhost');
3839
}
3940

4041
public function testCreateClientUsesTlsConnectorWithTlsLocation()
@@ -44,4 +45,11 @@ public function testCreateClientUsesTlsConnectorWithTlsLocation()
4445

4546
$this->factory->createClient('tls://ami.local:1234');
4647
}
48+
49+
public function testCreateClientWithInvalidUrlWillRejectPromise()
50+
{
51+
$promise = $this->factory->createClient('///');
52+
53+
$promise->then(null, $this->expectCallableOnce());
54+
}
4755
}

0 commit comments

Comments
 (0)