Skip to content

Commit dce6a05

Browse files
authored
Merge pull request #4 from mbonneau/rfc_dep
Remove RFC code depend on RFC project
2 parents e884686 + 547a2b6 commit dce6a05

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+219
-2092
lines changed

.travis.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ matrix:
1111

1212
before_install:
1313
- export PATH=$HOME/.local/bin:$PATH
14-
- pip install autobahntestsuite --user `whoami`
15-
- pip list autobahntestsuite --user `whoami`
14+
- pip install --user autobahntestsuite
15+
- pip list --user autobahntestsuite
1616

1717
before_script:
1818
- composer install
1919
- sh test/ab/run_ab_tests.sh
2020

2121
script:
22-
- phpunit
22+
- vendor/bin/phpunit

CHANGELOG.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# 0.10.0
2+
3+
## Changes/Additions
4+
5+
- Project now uses [RFC6455](https://github.com/ratchetphp/RFC6455) library for underlying protocol support
6+
- Message subject now emits `Ratchet\RFC6455\Messaging\Message` instead of `Rx\Websocket\Message`
7+
- `Client` is no longer a `Subject`

README.md

+17-35
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,19 @@ Rx\Websocket is a PHP Websocket library.
66

77
#### Client
88
```php
9-
<?php
9+
$client = new \Rx\Websocket\Client('ws://127.0.0.1:9191/');
1010

11-
require_once __DIR__ . '/vendor/autoload.php';
12-
13-
$client = new \Rx\Websocket\Client("ws://127.0.0.1:9191/");
14-
15-
$client->subscribe(new \Rx\Observer\CallbackObserver(
11+
$client->subscribeCallback(
1612
function (\Rx\Websocket\MessageSubject $ms) {
17-
$ms->subscribe(new \Rx\Observer\CallbackObserver(
13+
$ms->subscribeCallback(
1814
function ($message) {
1915
echo $message . "\n";
2016
}
21-
));
17+
);
2218

23-
$sayHello = function () use ($ms) { $ms->onNext("Hello"); };
19+
$sayHello = function () use ($ms) {
20+
$ms->onNext('Hello');
21+
};
2422

2523
$sayHello();
2624
\EventLoop\addPeriodicTimer(5, $sayHello);
@@ -31,43 +29,27 @@ $client->subscribe(new \Rx\Observer\CallbackObserver(
3129
function () {
3230
// stopped trying to connect here
3331
}
34-
));
32+
);
3533
```
3634

3735
#### An Echo Server
3836
```php
39-
<?php
40-
41-
require_once __DIR__ . "/vendor/autoload.php";
42-
43-
$server = new \Rx\Websocket\Server("127.0.0.1", 9191);
37+
$server = new \Rx\Websocket\Server('127.0.0.1', 9191);
4438

45-
$server
46-
->subscribe(new \Rx\Observer\CallbackObserver(
47-
function (\Rx\Websocket\MessageSubject $cs) {
48-
$cs->subscribe($cs);
49-
}
50-
));
39+
$server->subscribeCallback(function (\Rx\Websocket\MessageSubject $cs) {
40+
$cs->subscribe($cs);
41+
});
5142
```
5243

5344
#### Server that dumps everything to the console
5445
```php
55-
<?php
56-
57-
require_once __DIR__ . '/vendor/autoload.php';
58-
5946
$server = new \Rx\Websocket\Server('127.0.0.1', 9191);
6047

61-
$server
62-
->subscribe(new \Rx\Observer\CallbackObserver(
63-
function (\Rx\Websocket\MessageSubject $cs) {
64-
$cs->subscribe(new \Rx\Observer\CallbackObserver(
65-
function ($message) {
66-
echo $message;
67-
}
68-
));
69-
}
70-
));
48+
$server->subscribeCallback(function (\Rx\Websocket\MessageSubject $cs) {
49+
$cs->subscribeCallback(function ($message) {
50+
echo $message;
51+
});
52+
});
7153
```
7254

7355
## Installation

composer.json

+11-8
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,19 @@
2222
"name": "David Dan", "email": "[email protected]", "role": "Developer"
2323
}
2424
],
25-
"require": {
26-
"react/http": "^0.4.1",
27-
"react/http-client": "^0.4.8",
28-
"voryx/event-loop": "^0.2.0",
29-
"reactivex/rxphp": "^1.0",
30-
"guzzlehttp/psr7": "^1.2"
31-
},
3225
"autoload": {
3326
"psr-4": {
34-
"Rx\\Websocket\\": "src/Websocket/"
27+
"Rx\\Websocket\\": "src/"
3528
}
29+
},
30+
"require": {
31+
"react/http": "^0.4.1",
32+
"react/http-client": "^0.4.10",
33+
"voryx/event-loop": "^0.2.1",
34+
"reactivex/rxphp": "^1.5.1",
35+
"ratchet/rfc6455": "^0.2.2"
36+
},
37+
"require-dev": {
38+
"phpunit/phpunit": "^5.7.0"
3639
}
3740
}

phpunit.xml

-3
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,6 @@
1313
<testsuites>
1414
<testsuite name="RxWebsocket Test">
1515
<directory>test/</directory>
16-
<exclude>
17-
<directory>test/ab</directory>
18-
</exclude>
1916
</testsuite>
2017
</testsuites>
2118

src/Websocket/Client.php src/Client.php

+40-53
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,19 @@
22

33
namespace Rx\Websocket;
44

5-
use Exception;
6-
use Rx\Websocket\RFC6455\Handshake\ClientNegotiator;
5+
use GuzzleHttp\Psr7\Uri;
6+
use Ratchet\RFC6455\Handshake\ClientNegotiator;
77
use React\Dns\Resolver\Factory;
88
use React\HttpClient\Request;
99
use React\HttpClient\Response;
1010
use Rx\Disposable\CallbackDisposable;
11+
use Rx\Observable;
1112
use Rx\Observable\AnonymousObservable;
1213
use Rx\Observer\CallbackObserver;
1314
use Rx\ObserverInterface;
14-
use Rx\Subject\Subject;
15+
use Rx\SchedulerInterface;
1516

16-
class Client extends Subject
17+
class Client extends Observable
1718
{
1819
/** @var string */
1920
protected $url;
@@ -32,40 +33,46 @@ class Client extends Subject
3233
*/
3334
public function __construct($url, $useMessageObject = false, array $subProtocols = [])
3435
{
35-
$this->url = $url;
36+
$this->url = $url;
3637
$this->useMessageObject = $useMessageObject;
37-
$this->subProtocols = $subProtocols;
38+
$this->subProtocols = $subProtocols;
3839
}
3940

40-
private function startConnection()
41+
public function subscribe(ObserverInterface $clientObserver, $scheduler = null)
4142
{
4243
$loop = \EventLoop\getLoop();
4344

4445
$dnsResolverFactory = new Factory();
46+
4547
$dnsResolver = $dnsResolverFactory->createCached('8.8.8.8', $loop);
4648

4749
$factory = new \React\HttpClient\Factory();
48-
$client = $factory->create($loop, $dnsResolver);
50+
$client = $factory->create($loop, $dnsResolver);
51+
52+
$cNegotiator = new ClientNegotiator();
4953

50-
$cNegotiator = new ClientNegotiator($this->url, $this->subProtocols);
54+
/** @var \GuzzleHttp\Psr7\Request $nRequest */
55+
$nRequest = $cNegotiator->generateRequest(new Uri($this->url));
56+
57+
if (!empty($this->subProtocols)) {
58+
$nRequest = $nRequest
59+
->withoutHeader('Sec-WebSocket-Protocol')
60+
->withHeader('Sec-WebSocket-Protocol', $this->subProtocols);
61+
}
5162

52-
$headers = $cNegotiator->getRequest()->getHeaders();
63+
$headers = $nRequest->getHeaders();
5364

5465
$flatHeaders = [];
5566
foreach ($headers as $k => $v) {
5667
$flatHeaders[$k] = $v[0];
5768
}
5869

59-
$request = $client->request("GET", $this->url, $flatHeaders, '1.1');
70+
$request = $client->request('GET', $this->url, $flatHeaders, '1.1');
6071

61-
$request->on('response', function (Response $response, Request $request) use ($cNegotiator) {
72+
$request->on('response', function (Response $response, Request $request) use ($flatHeaders, $cNegotiator, $nRequest, $clientObserver) {
6273
if ($response->getCode() !== 101) {
63-
throw new \Exception("Unexpected response code " . $response->getCode());
74+
throw new \Exception('Unexpected response code ' . $response->getCode());
6475
}
65-
// TODO: Should validate response
66-
//$cNegotiator->validateResponse($response);
67-
68-
$subprotoHeader = "";
6976

7077
$psr7Response = new \GuzzleHttp\Psr7\Response(
7178
$response->getCode(),
@@ -74,12 +81,17 @@ private function startConnection()
7481
$response->getVersion()
7582
);
7683

77-
if (count($psr7Response->getHeader('Sec-WebSocket-Protocol')) == 1) {
78-
$subprotoHeader = $psr7Response->getHeader('Sec-WebSocket-Protocol')[0];
84+
$psr7Request = new \GuzzleHttp\Psr7\Request('GET', $this->url, $flatHeaders);
85+
86+
if (!$cNegotiator->validateResponse($psr7Request, $psr7Response)) {
87+
throw new \Exception('Invalid response');
7988
}
8089

81-
parent::onNext(new MessageSubject(
82-
new AnonymousObservable(function (ObserverInterface $observer) use ($response) {
90+
$subprotoHeader = $psr7Response->getHeader('Sec-WebSocket-Protocol');
91+
92+
$clientObserver->onNext(new MessageSubject(
93+
new AnonymousObservable(function (ObserverInterface $observer, SchedulerInterface $scheduler) use ($response, $clientObserver) {
94+
8395
$response->on('data', function ($data) use ($observer) {
8496
$observer->onNext($data);
8597
});
@@ -92,18 +104,19 @@ private function startConnection()
92104
$observer->onCompleted();
93105
});
94106

95-
$response->on('end', function () use ($observer) {
107+
$response->on('end', function () use ($observer, $clientObserver) {
96108
$observer->onCompleted();
97109

98110
// complete the parent observer - we only do 1 connection
99-
parent::onCompleted();
111+
$clientObserver->onCompleted();
100112
});
101113

102114

103115
return new CallbackDisposable(function () use ($response) {
104116
// commented this out because disposal was causing the other
105117
// end (the request) to close also - which causes the pending messages
106118
// to get tossed
119+
// maybe try with $response->end()?
107120
//$response->close();
108121
});
109122
}),
@@ -121,41 +134,15 @@ function () use ($request) {
121134
true,
122135
$this->useMessageObject,
123136
$subprotoHeader,
124-
$cNegotiator->getRequest(),
137+
$nRequest,
125138
$psr7Response
126139
));
127140
});
128141

129142
$request->writeHead();
130-
}
131-
132-
public function subscribe(ObserverInterface $observer, $scheduler = null)
133-
{
134-
if (!$this->isStopped) {
135-
$this->startConnection();
136-
}
137-
138-
return parent::subscribe($observer, $scheduler);
139-
}
140-
141-
public function send($value)
142-
{
143-
$this->onNext($value);
144-
}
145-
146-
// Not sure we need this object to be a subject - just being an observer should be good enough I think
147-
public function onNext($value)
148-
{
149-
150-
}
151-
152-
public function onError(Exception $exception)
153-
{
154-
155-
}
156-
157-
public function onCompleted()
158-
{
159143

144+
return new CallbackDisposable(function () use ($request) {
145+
$request->close();
146+
});
160147
}
161148
}

0 commit comments

Comments
 (0)