571 changed files with 34 additions and 73228 deletions
@ -1,50 +1,2 @@ |
|||||||
# Windows image file caches |
Server.php |
||||||
Thumbs.db |
/vendor/ |
||||||
ehthumbs.db |
|
||||||
|
|
||||||
# Folder config file |
|
||||||
Desktop.ini |
|
||||||
|
|
||||||
# Recycle Bin used on file shares |
|
||||||
$RECYCLE.BIN/ |
|
||||||
|
|
||||||
# Windows Installer files |
|
||||||
*.cab |
|
||||||
*.msi |
|
||||||
*.msm |
|
||||||
*.msp |
|
||||||
|
|
||||||
# Windows shortcuts |
|
||||||
*.lnk |
|
||||||
|
|
||||||
# ========================= |
|
||||||
# Operating System Files |
|
||||||
# ========================= |
|
||||||
|
|
||||||
# OSX |
|
||||||
# ========================= |
|
||||||
|
|
||||||
.DS_Store |
|
||||||
.AppleDouble |
|
||||||
.LSOverride |
|
||||||
|
|
||||||
# Thumbnails |
|
||||||
._* |
|
||||||
|
|
||||||
# Files that might appear in the root of a volume |
|
||||||
.DocumentRevisions-V100 |
|
||||||
.fseventsd |
|
||||||
.Spotlight-V100 |
|
||||||
.TemporaryItems |
|
||||||
.Trashes |
|
||||||
.VolumeIcon.icns |
|
||||||
|
|
||||||
# Directories potentially created on remote AFP share |
|
||||||
.AppleDB |
|
||||||
.AppleDesktop |
|
||||||
Network Trash Folder |
|
||||||
Temporary Items |
|
||||||
.apdisk |
|
||||||
/nbproject/private/ |
|
||||||
|
|
||||||
Server.php |
|
@ -1,7 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
// autoload.php @generated by Composer |
|
||||||
|
|
||||||
require_once __DIR__ . '/composer/autoload_real.php'; |
|
||||||
|
|
||||||
return ComposerAutoloaderInita3d708ca3bb0f3f4e817238e4fb57153::getLoader(); |
|
@ -1,5 +0,0 @@ |
|||||||
phpunit.xml |
|
||||||
reports |
|
||||||
sandbox |
|
||||||
vendor |
|
||||||
composer.lock |
|
@ -1,12 +0,0 @@ |
|||||||
language: php |
|
||||||
|
|
||||||
php: |
|
||||||
- 5.4 |
|
||||||
- 5.5 |
|
||||||
- 5.6 |
|
||||||
- 7 |
|
||||||
- hhvm |
|
||||||
|
|
||||||
before_script: |
|
||||||
- sh -c 'if [ "$TRAVIS_PHP_VERSION" != "hhvm" ]; then echo "session.serialize_handler = php" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi;' |
|
||||||
- composer install --dev --prefer-source |
|
@ -1,140 +0,0 @@ |
|||||||
CHANGELOG |
|
||||||
========= |
|
||||||
|
|
||||||
###Legend |
|
||||||
|
|
||||||
* "BC": Backwards compatibility break (from public component APIs) |
|
||||||
* "BF": Bug fix |
|
||||||
|
|
||||||
--- |
|
||||||
|
|
||||||
* 0.4 (2016-) |
|
||||||
|
|
||||||
* BC: $conn->WebSocket->request replaced with $conn->httpRequest which is a PSR-7 object |
|
||||||
* Binary messages now supported via Ratchet\WebSocket\MessageComponentInterface |
|
||||||
* Added heartbeat support via ping/pong in WsServer |
|
||||||
* BC: No longer support old (and insecure) Hixie76 and Hybi protocols |
|
||||||
* BC: No longer support disabling UTF-8 checks |
|
||||||
* BC: The Session component implements HttpServerInterface instead of WsServerInterface |
|
||||||
* BC: PHP 5.3 no longer supported |
|
||||||
* Significant performance enhancements |
|
||||||
|
|
||||||
* 0.3.4 (2015-12-23) |
|
||||||
|
|
||||||
* BF: Edge case where version check wasn't run on message coalesce |
|
||||||
* BF: Session didn't start when using pdo_sqlite |
|
||||||
* BF: WAMP currie prefix check when using '#' |
|
||||||
* Compatibility with Symfony 3 |
|
||||||
|
|
||||||
* 0.3.3 (2015-05-26) |
|
||||||
|
|
||||||
* BF: Framing bug on large messages upon TCP fragmentation |
|
||||||
* BF: Symfony Router query parameter defaults applied to Request |
|
||||||
* BF: WAMP CURIE on all URIs |
|
||||||
* OriginCheck rules applied to FlashPolicy |
|
||||||
* Switched from PSR-0 to PSR-4 |
|
||||||
|
|
||||||
* 0.3.2 (2014-06-08) |
|
||||||
|
|
||||||
* BF: No messages after closing handshake (fixed rare race condition causing 100% CPU) |
|
||||||
* BF: Fixed accidental BC break from v0.3.1 |
|
||||||
* Added autoDelete parameter to Topic to destroy when empty of connections |
|
||||||
* Exposed React Socket on IoServer (allowing FlashPolicy shutdown in App) |
|
||||||
* Normalized Exceptions in WAMP |
|
||||||
|
|
||||||
* 0.3.1 (2014-05-26) |
|
||||||
|
|
||||||
* Added query parameter support to Router, set in HTTP request (ws://server?hello=world) |
|
||||||
* HHVM compatibility |
|
||||||
* BF: React/0.4 support; CPU starvation bug fixes |
|
||||||
* BF: Allow App::route to ignore Host header |
|
||||||
* Added expected filters to WAMP Topic broadcast method |
|
||||||
* Resource cleanup in WAMP TopicManager |
|
||||||
|
|
||||||
* 0.3.0 (2013-10-14) |
|
||||||
|
|
||||||
* Added the `App` class to help making Ratchet so easy to use it's silly |
|
||||||
* BC: Require hostname to do HTTP Host header match and do Origin HTTP header check, verify same name by default, helping prevent CSRF attacks |
|
||||||
* Added Symfony/2.2 based HTTP Router component to allowing for a single Ratchet server to handle multiple apps -> Ratchet\Http\Router |
|
||||||
* BC: Decoupled HTTP from WebSocket component -> Ratchet\Http\HttpServer |
|
||||||
* BF: Single sub-protocol selection to conform with RFC6455 |
|
||||||
* BF: Sanity checks on WAMP protocol to prevent errors |
|
||||||
|
|
||||||
* 0.2.8 (2013-09-19) |
|
||||||
|
|
||||||
* React 0.3 support |
|
||||||
|
|
||||||
* 0.2.7 (2013-06-09) |
|
||||||
|
|
||||||
* BF: Sub-protocol negotation with Guzzle 3.6 |
|
||||||
|
|
||||||
* 0.2.6 (2013-06-01) |
|
||||||
|
|
||||||
* Guzzle 3.6 support |
|
||||||
|
|
||||||
* 0.2.5 (2013-04-01) |
|
||||||
|
|
||||||
* Fixed Hixie-76 handshake bug |
|
||||||
|
|
||||||
* 0.2.4 (2013-03-09) |
|
||||||
|
|
||||||
* Support for Symfony 2.2 and Guzzle 2.3 |
|
||||||
* Minor bug fixes when handling errors |
|
||||||
|
|
||||||
* 0.2.3 (2012-11-21) |
|
||||||
|
|
||||||
* Bumped dep: Guzzle to v3, React to v0.2.4 |
|
||||||
* More tests |
|
||||||
|
|
||||||
* 0.2.2 (2012-10-20) |
|
||||||
|
|
||||||
* Bumped deps to use React v0.2 |
|
||||||
|
|
||||||
* 0.2.1 (2012-10-13) |
|
||||||
|
|
||||||
* BF: No more UTF-8 warnings in browsers (no longer sending empty sub-protocol string) |
|
||||||
* Documentation corrections |
|
||||||
* Using new composer structure |
|
||||||
|
|
||||||
* 0.2 (2012-09-07) |
|
||||||
|
|
||||||
* Ratchet passes every non-binary-frame test from the Autobahn Testsuite |
|
||||||
* Major performance improvements |
|
||||||
* BC: Renamed "WampServer" to "ServerProtocol" |
|
||||||
* BC: New "WampServer" component passes Topic container objects of subscribed Connections |
|
||||||
* Option to turn off UTF-8 checks in order to increase performance |
|
||||||
* Switched dependency guzzle/guzzle to guzzle/http (no API changes) |
|
||||||
* mbstring no longer required |
|
||||||
|
|
||||||
* 0.1.5 (2012-07-12) |
|
||||||
|
|
||||||
* BF: Error where service wouldn't run on PHP <= 5.3.8 |
|
||||||
* Dependency library updates |
|
||||||
|
|
||||||
* 0.1.4 (2012-06-17) |
|
||||||
|
|
||||||
* Fixed dozens of failing AB tests |
|
||||||
* BF: Proper socket buffer handling |
|
||||||
|
|
||||||
* 0.1.3 (2012-06-15) |
|
||||||
|
|
||||||
* Major refactor inside WebSocket protocol handling, more loosley coupled |
|
||||||
* BF: Proper error handling on failed WebSocket connections |
|
||||||
* BF: Handle TCP message concatenation |
|
||||||
* Inclusion of the AutobahnTestSuite checking WebSocket protocol compliance |
|
||||||
* mb_string now a requirement |
|
||||||
|
|
||||||
* 0.1.2 (2012-05-19) |
|
||||||
|
|
||||||
* BC/BF: Updated WAMP API to coincide with the official spec |
|
||||||
* Tweaks to improve running as a long lived process |
|
||||||
|
|
||||||
* 0.1.1 (2012-05-14) |
|
||||||
|
|
||||||
* Separated interfaces allowing WebSockets to support multiple sub protocols |
|
||||||
* BF: remoteAddress variable on connections returns proper value |
|
||||||
|
|
||||||
* 0.1 (2012-05-11) |
|
||||||
|
|
||||||
* First release with components: IoServer, WsServer, SessionProvider, WampServer, FlashPolicy, IpBlackList |
|
||||||
* I/O now handled by React, making Ratchet fully asynchronous |
|
@ -1,19 +0,0 @@ |
|||||||
Copyright (c) 2011-2016 Chris Boden |
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
|
||||||
of this software and associated documentation files (the "Software"), to deal |
|
||||||
in the Software without restriction, including without limitation the rights |
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
||||||
copies of the Software, and to permit persons to whom the Software is furnished |
|
||||||
to do so, subject to the following conditions: |
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all |
|
||||||
copies or substantial portions of the Software. |
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
||||||
THE SOFTWARE. |
|
@ -1,37 +0,0 @@ |
|||||||
# This file is intended to ease the author's development and testing process
|
|
||||||
# Users do not need to use `make`; Ratchet does not need to be compiled
|
|
||||||
|
|
||||||
test: |
|
||||||
phpunit |
|
||||||
|
|
||||||
cover: |
|
||||||
phpunit --coverage-text --coverage-html=reports/coverage |
|
||||||
|
|
||||||
abtests: |
|
||||||
ulimit -n 2048 && php tests/autobahn/bin/fuzzingserver.php 8001 LibEvent & |
|
||||||
ulimit -n 2048 && php tests/autobahn/bin/fuzzingserver.php 8002 StreamSelect & |
|
||||||
ulimit -n 2048 && php tests/autobahn/bin/fuzzingserver.php 8004 LibEv & |
|
||||||
wstest -m testeeserver -w ws://localhost:8000 & |
|
||||||
sleep 1 |
|
||||||
wstest -m fuzzingclient -s tests/autobahn/fuzzingclient-all.json |
|
||||||
killall php wstest |
|
||||||
|
|
||||||
abtest: |
|
||||||
ulimit -n 2048 && php tests/autobahn/bin/fuzzingserver.php 8000 StreamSelect & |
|
||||||
sleep 1 |
|
||||||
wstest -m fuzzingclient -s tests/autobahn/fuzzingclient-quick.json |
|
||||||
killall php |
|
||||||
|
|
||||||
profile: |
|
||||||
php -d 'xdebug.profiler_enable=1' tests/autobahn/bin/fuzzingserver.php 8000 LibEvent & |
|
||||||
sleep 1 |
|
||||||
wstest -m fuzzingclient -s tests/autobahn/fuzzingclient-profile.json |
|
||||||
killall php |
|
||||||
|
|
||||||
apidocs: |
|
||||||
apigen --title Ratchet -d reports/api -s src/ \
|
|
||||||
-s vendor/react \
|
|
||||||
-s vendor/guzzle \
|
|
||||||
-s vendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Session \
|
|
||||||
-s vendor/symfony/routing/Symfony/Component/Routing \
|
|
||||||
-s vendor/evenement/evenement/src/Evenement |
|
@ -1,83 +0,0 @@ |
|||||||
#Ratchet |
|
||||||
|
|
||||||
[](http://travis-ci.org/ratchetphp/Ratchet) |
|
||||||
[](http://socketo.me/reports/ab/index.html) |
|
||||||
[](https://packagist.org/packages/cboden/ratchet) |
|
||||||
|
|
||||||
A PHP 5.4 library for asynchronously serving WebSockets. |
|
||||||
Build up your application through simple interfaces and re-use your application without changing any of its code just by combining different components. |
|
||||||
|
|
||||||
##Requirements |
|
||||||
|
|
||||||
Shell access is required and root access is recommended. |
|
||||||
To avoid proxy/firewall blockage it's recommended WebSockets are requested on port 80 or 443 (SSL), which requires root access. |
|
||||||
In order to do this, along with your sync web stack, you can either use a reverse proxy or two separate machines. |
|
||||||
You can find more details in the [server conf docs](http://socketo.me/docs/deploy#serverconfiguration). |
|
||||||
|
|
||||||
### Documentation |
|
||||||
|
|
||||||
User and API documentation is available on Ratchet's website: http://socketo.me |
|
||||||
|
|
||||||
See https://github.com/cboden/Ratchet-examples for some out-of-the-box working demos using Ratchet. |
|
||||||
|
|
||||||
Need help? Have a question? Want to provide feedback? Write a message on the [Google Groups Mailing List](https://groups.google.com/forum/#!forum/ratchet-php). |
|
||||||
|
|
||||||
--- |
|
||||||
|
|
||||||
###A quick example |
|
||||||
|
|
||||||
```php |
|
||||||
<?php |
|
||||||
use Ratchet\MessageComponentInterface; |
|
||||||
use Ratchet\ConnectionInterface; |
|
||||||
|
|
||||||
// Make sure composer dependencies have been installed |
|
||||||
require __DIR__ . '/vendor/autoload.php'; |
|
||||||
|
|
||||||
/** |
|
||||||
* chat.php |
|
||||||
* Send any incoming messages to all connected clients (except sender) |
|
||||||
*/ |
|
||||||
class MyChat implements MessageComponentInterface { |
|
||||||
protected $clients; |
|
||||||
|
|
||||||
public function __construct() { |
|
||||||
$this->clients = new \SplObjectStorage; |
|
||||||
} |
|
||||||
|
|
||||||
public function onOpen(ConnectionInterface $conn) { |
|
||||||
$this->clients->attach($conn); |
|
||||||
} |
|
||||||
|
|
||||||
public function onMessage(ConnectionInterface $from, $msg) { |
|
||||||
foreach ($this->clients as $client) { |
|
||||||
if ($from != $client) { |
|
||||||
$client->send($msg); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public function onClose(ConnectionInterface $conn) { |
|
||||||
$this->clients->detach($conn); |
|
||||||
} |
|
||||||
|
|
||||||
public function onError(ConnectionInterface $conn, \Exception $e) { |
|
||||||
$conn->close(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Run the server application through the WebSocket protocol on port 8080 |
|
||||||
$app = new Ratchet\App('localhost', 8080); |
|
||||||
$app->route('/chat', new MyChat); |
|
||||||
$app->route('/echo', new Ratchet\Server\EchoServer, array('*')); |
|
||||||
$app->run(); |
|
||||||
``` |
|
||||||
|
|
||||||
$ php chat.php |
|
||||||
|
|
||||||
```javascript |
|
||||||
// Then some JavaScript in the browser: |
|
||||||
var conn = new WebSocket('ws://localhost:8080/echo'); |
|
||||||
conn.onmessage = function(e) { console.log(e.data); }; |
|
||||||
conn.send('Hello Me!'); |
|
||||||
``` |
|
@ -1,36 +0,0 @@ |
|||||||
{ |
|
||||||
"name": "cboden/ratchet" |
|
||||||
, "type": "library" |
|
||||||
, "description": "PHP WebSocket library" |
|
||||||
, "keywords": ["WebSockets", "Server", "Ratchet", "Sockets", "WebSocket"] |
|
||||||
, "homepage": "http://socketo.me" |
|
||||||
, "license": "MIT" |
|
||||||
, "authors": [ |
|
||||||
{ |
|
||||||
"name": "Chris Boden" |
|
||||||
, "email": "cboden@gmail.com" |
|
||||||
, "role": "Developer" |
|
||||||
} |
|
||||||
] |
|
||||||
, "support": { |
|
||||||
"forum": "https://groups.google.com/forum/#!forum/ratchet-php" |
|
||||||
, "issues": "https://github.com/ratchetphp/Ratchet/issues" |
|
||||||
, "irc": "irc://irc.freenode.org/reactphp" |
|
||||||
} |
|
||||||
, "autoload": { |
|
||||||
"psr-4": { |
|
||||||
"Ratchet\\": "src/Ratchet" |
|
||||||
} |
|
||||||
} |
|
||||||
, "suggest": { |
|
||||||
"ext-pecl_http": "^2.0" |
|
||||||
} |
|
||||||
, "require": { |
|
||||||
"php": ">=5.4.2" |
|
||||||
, "ratchet/rfc6455": "^0.2" |
|
||||||
, "react/socket": "^0.3 || ^0.4" |
|
||||||
, "guzzlehttp/psr7": "^1.0" |
|
||||||
, "symfony/http-foundation": "^2.2|^3.0" |
|
||||||
, "symfony/routing": "^2.2|^3.0" |
|
||||||
} |
|
||||||
} |
|
@ -1,30 +0,0 @@ |
|||||||
<?xml version="1.0" encoding="UTF-8"?> |
|
||||||
<phpunit |
|
||||||
forceCoversAnnotation="true" |
|
||||||
mapTestClassNameToCoveredClassName="true" |
|
||||||
bootstrap="tests/bootstrap.php" |
|
||||||
colors="true" |
|
||||||
backupGlobals="false" |
|
||||||
backupStaticAttributes="false" |
|
||||||
syntaxCheck="false" |
|
||||||
stopOnError="false" |
|
||||||
> |
|
||||||
|
|
||||||
<testsuites> |
|
||||||
<testsuite name="unit"> |
|
||||||
<directory>./tests/unit/</directory> |
|
||||||
</testsuite> |
|
||||||
</testsuites> |
|
||||||
|
|
||||||
<testsuites> |
|
||||||
<testsuite name="integration"> |
|
||||||
<directory>./tests/integration/</directory> |
|
||||||
</testsuite> |
|
||||||
</testsuites> |
|
||||||
|
|
||||||
<filter> |
|
||||||
<whitelist> |
|
||||||
<directory>./src/</directory> |
|
||||||
</whitelist> |
|
||||||
</filter> |
|
||||||
</phpunit> |
|
@ -1,41 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet; |
|
||||||
|
|
||||||
/** |
|
||||||
* Wraps ConnectionInterface objects via the decorator pattern but allows |
|
||||||
* parameters to bubble through with magic methods |
|
||||||
* @todo It sure would be nice if I could make most of this a trait... |
|
||||||
*/ |
|
||||||
abstract class AbstractConnectionDecorator implements ConnectionInterface { |
|
||||||
/** |
|
||||||
* @var ConnectionInterface |
|
||||||
*/ |
|
||||||
protected $wrappedConn; |
|
||||||
|
|
||||||
public function __construct(ConnectionInterface $conn) { |
|
||||||
$this->wrappedConn = $conn; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @return ConnectionInterface |
|
||||||
*/ |
|
||||||
protected function getConnection() { |
|
||||||
return $this->wrappedConn; |
|
||||||
} |
|
||||||
|
|
||||||
public function __set($name, $value) { |
|
||||||
$this->wrappedConn->$name = $value; |
|
||||||
} |
|
||||||
|
|
||||||
public function __get($name) { |
|
||||||
return $this->wrappedConn->$name; |
|
||||||
} |
|
||||||
|
|
||||||
public function __isset($name) { |
|
||||||
return isset($this->wrappedConn->$name); |
|
||||||
} |
|
||||||
|
|
||||||
public function __unset($name) { |
|
||||||
unset($this->wrappedConn->$name); |
|
||||||
} |
|
||||||
} |
|
@ -1,150 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet; |
|
||||||
use React\EventLoop\LoopInterface; |
|
||||||
use React\EventLoop\Factory as LoopFactory; |
|
||||||
use React\Socket\Server as Reactor; |
|
||||||
use Ratchet\Http\HttpServerInterface; |
|
||||||
use Ratchet\Http\OriginCheck; |
|
||||||
use Ratchet\Wamp\WampServerInterface; |
|
||||||
use Ratchet\Server\IoServer; |
|
||||||
use Ratchet\Server\FlashPolicy; |
|
||||||
use Ratchet\Http\HttpServer; |
|
||||||
use Ratchet\Http\Router; |
|
||||||
use Ratchet\WebSocket\WsServer; |
|
||||||
use Ratchet\Wamp\WampServer; |
|
||||||
use Symfony\Component\Routing\RouteCollection; |
|
||||||
use Symfony\Component\Routing\Route; |
|
||||||
use Symfony\Component\Routing\RequestContext; |
|
||||||
use Symfony\Component\Routing\Matcher\UrlMatcher; |
|
||||||
|
|
||||||
/** |
|
||||||
* An opinionated facade class to quickly and easily create a WebSocket server. |
|
||||||
* A few configuration assumptions are made and some best-practice security conventions are applied by default. |
|
||||||
*/ |
|
||||||
class App { |
|
||||||
/** |
|
||||||
* @var \Symfony\Component\Routing\RouteCollection |
|
||||||
*/ |
|
||||||
public $routes; |
|
||||||
|
|
||||||
/** |
|
||||||
* @var \Ratchet\Server\IoServer |
|
||||||
*/ |
|
||||||
public $flashServer; |
|
||||||
|
|
||||||
/** |
|
||||||
* @var \Ratchet\Server\IoServer |
|
||||||
*/ |
|
||||||
protected $_server; |
|
||||||
|
|
||||||
/** |
|
||||||
* The Host passed in construct used for same origin policy |
|
||||||
* @var string |
|
||||||
*/ |
|
||||||
protected $httpHost; |
|
||||||
|
|
||||||
/*** |
|
||||||
* The port the socket is listening |
|
||||||
* @var int |
|
||||||
*/ |
|
||||||
protected $port; |
|
||||||
|
|
||||||
/** |
|
||||||
* @var int |
|
||||||
*/ |
|
||||||
protected $_routeCounter = 0; |
|
||||||
|
|
||||||
/** |
|
||||||
* @param string $httpHost HTTP hostname clients intend to connect to. MUST match JS `new WebSocket('ws://$httpHost');` |
|
||||||
* @param int $port Port to listen on. If 80, assuming production, Flash on 843 otherwise expecting Flash to be proxied through 8843 |
|
||||||
* @param string $address IP address to bind to. Default is localhost/proxy only. '0.0.0.0' for any machine. |
|
||||||
* @param LoopInterface $loop Specific React\EventLoop to bind the application to. null will create one for you. |
|
||||||
*/ |
|
||||||
public function __construct($httpHost = 'localhost', $port = 8080, $address = '127.0.0.1', LoopInterface $loop = null) { |
|
||||||
if (extension_loaded('xdebug')) { |
|
||||||
trigger_error('XDebug extension detected. Remember to disable this if performance testing or going live!', E_USER_WARNING); |
|
||||||
} |
|
||||||
|
|
||||||
if (3 !== strlen('✓')) { |
|
||||||
throw new \DomainException('Bad encoding, length of unicode character ✓ should be 3. Ensure charset UTF-8 and check ini val mbstring.func_autoload'); |
|
||||||
} |
|
||||||
|
|
||||||
if (null === $loop) { |
|
||||||
$loop = LoopFactory::create(); |
|
||||||
} |
|
||||||
|
|
||||||
$this->httpHost = $httpHost; |
|
||||||
$this->port = $port; |
|
||||||
|
|
||||||
$socket = new Reactor($loop); |
|
||||||
$socket->listen($port, $address); |
|
||||||
|
|
||||||
$this->routes = new RouteCollection; |
|
||||||
$this->_server = new IoServer(new HttpServer(new Router(new UrlMatcher($this->routes, new RequestContext))), $socket, $loop); |
|
||||||
|
|
||||||
$policy = new FlashPolicy; |
|
||||||
$policy->addAllowedAccess($httpHost, 80); |
|
||||||
$policy->addAllowedAccess($httpHost, $port); |
|
||||||
$flashSock = new Reactor($loop); |
|
||||||
$this->flashServer = new IoServer($policy, $flashSock); |
|
||||||
if (80 == $port) { |
|
||||||
$flashSock->listen(843, '0.0.0.0'); |
|
||||||
} else { |
|
||||||
$flashSock->listen(8843); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Add an endpoint/application to the server |
|
||||||
* @param string $path The URI the client will connect to |
|
||||||
* @param ComponentInterface $controller Your application to server for the route. If not specified, assumed to be for a WebSocket |
|
||||||
* @param array $allowedOrigins An array of hosts allowed to connect (same host by default), ['*'] for any |
|
||||||
* @param string $httpHost Override the $httpHost variable provided in the __construct |
|
||||||
* @return ComponentInterface|WsServer |
|
||||||
*/ |
|
||||||
public function route($path, ComponentInterface $controller, array $allowedOrigins = array(), $httpHost = null) { |
|
||||||
if ($controller instanceof HttpServerInterface || $controller instanceof WsServer) { |
|
||||||
$decorated = $controller; |
|
||||||
} elseif ($controller instanceof WampServerInterface) { |
|
||||||
$decorated = new WsServer(new WampServer($controller)); |
|
||||||
} elseif ($controller instanceof MessageComponentInterface) { |
|
||||||
$decorated = new WsServer($controller); |
|
||||||
} else { |
|
||||||
$decorated = $controller; |
|
||||||
} |
|
||||||
|
|
||||||
if ($decorated instanceof WsServer) { |
|
||||||
$decorated->enableKeepAlive($this->_server->loop, 30); |
|
||||||
} |
|
||||||
|
|
||||||
if ($httpHost === null) { |
|
||||||
$httpHost = $this->httpHost; |
|
||||||
} |
|
||||||
|
|
||||||
$allowedOrigins = array_values($allowedOrigins); |
|
||||||
if (0 === count($allowedOrigins)) { |
|
||||||
$allowedOrigins[] = $httpHost; |
|
||||||
} |
|
||||||
if ('*' !== $allowedOrigins[0]) { |
|
||||||
$decorated = new OriginCheck($decorated, $allowedOrigins); |
|
||||||
} |
|
||||||
|
|
||||||
//allow origins in flash policy server |
|
||||||
if(empty($this->flashServer) === false) { |
|
||||||
foreach($allowedOrigins as $allowedOrgin) { |
|
||||||
$this->flashServer->app->addAllowedAccess($allowedOrgin, $this->port); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
$this->routes->add('rr-' . ++$this->_routeCounter, new Route($path, array('_controller' => $decorated), array('Origin' => $this->httpHost), array(), $httpHost)); |
|
||||||
|
|
||||||
return $decorated; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Run the server by entering the event loop |
|
||||||
*/ |
|
||||||
public function run() { |
|
||||||
$this->_server->run(); |
|
||||||
} |
|
||||||
} |
|
@ -1,31 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet; |
|
||||||
|
|
||||||
/** |
|
||||||
* This is the interface to build a Ratchet application with. |
|
||||||
* It implements the decorator pattern to build an application stack |
|
||||||
*/ |
|
||||||
interface ComponentInterface { |
|
||||||
/** |
|
||||||
* When a new connection is opened it will be passed to this method |
|
||||||
* @param ConnectionInterface $conn The socket/connection that just connected to your application |
|
||||||
* @throws \Exception |
|
||||||
*/ |
|
||||||
function onOpen(ConnectionInterface $conn); |
|
||||||
|
|
||||||
/** |
|
||||||
* This is called before or after a socket is closed (depends on how it's closed). SendMessage to $conn will not result in an error if it has already been closed. |
|
||||||
* @param ConnectionInterface $conn The socket/connection that is closing/closed |
|
||||||
* @throws \Exception |
|
||||||
*/ |
|
||||||
function onClose(ConnectionInterface $conn); |
|
||||||
|
|
||||||
/** |
|
||||||
* If there is an error with one of the sockets, or somewhere in the application where an Exception is thrown, |
|
||||||
* the Exception is sent back down the stack, handled by the Server and bubbled back up the application through this method |
|
||||||
* @param ConnectionInterface $conn |
|
||||||
* @param \Exception $e |
|
||||||
* @throws \Exception |
|
||||||
*/ |
|
||||||
function onError(ConnectionInterface $conn, \Exception $e); |
|
||||||
} |
|
@ -1,26 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet; |
|
||||||
|
|
||||||
/** |
|
||||||
* The version of Ratchet being used |
|
||||||
* @var string |
|
||||||
*/ |
|
||||||
const VERSION = 'Ratchet/0.4'; |
|
||||||
|
|
||||||
/** |
|
||||||
* A proxy object representing a connection to the application |
|
||||||
* This acts as a container to store data (in memory) about the connection |
|
||||||
*/ |
|
||||||
interface ConnectionInterface { |
|
||||||
/** |
|
||||||
* Send data to the connection |
|
||||||
* @param string $data |
|
||||||
* @return \Ratchet\ConnectionInterface |
|
||||||
*/ |
|
||||||
function send($data); |
|
||||||
|
|
||||||
/** |
|
||||||
* Close the connection |
|
||||||
*/ |
|
||||||
function close(); |
|
||||||
} |
|
@ -1,22 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Http; |
|
||||||
use Ratchet\ConnectionInterface; |
|
||||||
use GuzzleHttp\Psr7 as gPsr; |
|
||||||
use GuzzleHttp\Psr7\Response; |
|
||||||
|
|
||||||
trait CloseResponseTrait { |
|
||||||
/** |
|
||||||
* Close a connection with an HTTP response |
|
||||||
* @param \Ratchet\ConnectionInterface $conn |
|
||||||
* @param int $code HTTP status code |
|
||||||
* @return null |
|
||||||
*/ |
|
||||||
private function close(ConnectionInterface $conn, $code = 400, array $additional_headers = []) { |
|
||||||
$response = new Response($code, array_merge([ |
|
||||||
'X-Powered-By' => \Ratchet\VERSION |
|
||||||
], $additional_headers)); |
|
||||||
|
|
||||||
$conn->send(gPsr\str($response)); |
|
||||||
$conn->close(); |
|
||||||
} |
|
||||||
} |
|
@ -1,76 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Http; |
|
||||||
use Ratchet\MessageInterface; |
|
||||||
use Ratchet\ConnectionInterface; |
|
||||||
use GuzzleHttp\Psr7 as gPsr; |
|
||||||
|
|
||||||
/** |
|
||||||
* This class receives streaming data from a client request |
|
||||||
* and parses HTTP headers, returning a PSR-7 Request object |
|
||||||
* once it's been buffered |
|
||||||
*/ |
|
||||||
class HttpRequestParser implements MessageInterface { |
|
||||||
const EOM = "\r\n\r\n"; |
|
||||||
|
|
||||||
/** |
|
||||||
* The maximum number of bytes the request can be |
|
||||||
* This is a security measure to prevent attacks |
|
||||||
* @var int |
|
||||||
*/ |
|
||||||
public $maxSize = 4096; |
|
||||||
|
|
||||||
/** |
|
||||||
* @param \Ratchet\ConnectionInterface $context |
|
||||||
* @param string $data Data stream to buffer |
|
||||||
* @return \Psr\Http\Message\RequestInterface |
|
||||||
* @throws \OverflowException If the message buffer has become too large |
|
||||||
*/ |
|
||||||
public function onMessage(ConnectionInterface $context, $data) { |
|
||||||
if (!isset($context->httpBuffer)) { |
|
||||||
$context->httpBuffer = ''; |
|
||||||
} |
|
||||||
|
|
||||||
$context->httpBuffer .= $data; |
|
||||||
|
|
||||||
if (strlen($context->httpBuffer) > (int)$this->maxSize) { |
|
||||||
throw new \OverflowException("Maximum buffer size of {$this->maxSize} exceeded parsing HTTP header"); |
|
||||||
} |
|
||||||
|
|
||||||
if ($this->isEom($context->httpBuffer)) { |
|
||||||
$request = $this->parse($context->httpBuffer); |
|
||||||
|
|
||||||
unset($context->httpBuffer); |
|
||||||
|
|
||||||
return $request; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Determine if the message has been buffered as per the HTTP specification |
|
||||||
* @param string $message |
|
||||||
* @return boolean |
|
||||||
*/ |
|
||||||
public function isEom($message) { |
|
||||||
return (boolean)strpos($message, static::EOM); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @param string $headers |
|
||||||
* @return \Psr\Http\Message\RequestInterface |
|
||||||
*/ |
|
||||||
public function parse($headers) { |
|
||||||
if (function_exists('http_parse_message')) { |
|
||||||
$parts = http_parse_message($headers); |
|
||||||
|
|
||||||
return new gPsr\Request( |
|
||||||
$parts->requestMethod |
|
||||||
, $parts->requestUrl |
|
||||||
, $parts->headers |
|
||||||
, null |
|
||||||
, $parts->httpVersion |
|
||||||
); |
|
||||||
} else { |
|
||||||
return gPsr\parse_request($headers); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,76 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Http; |
|
||||||
use Ratchet\MessageComponentInterface; |
|
||||||
use Ratchet\ConnectionInterface; |
|
||||||
|
|
||||||
class HttpServer implements MessageComponentInterface { |
|
||||||
use CloseResponseTrait; |
|
||||||
|
|
||||||
/** |
|
||||||
* Buffers incoming HTTP requests returning a Guzzle Request when coalesced |
|
||||||
* @var HttpRequestParser |
|
||||||
* @note May not expose this in the future, may do through facade methods |
|
||||||
*/ |
|
||||||
protected $_reqParser; |
|
||||||
|
|
||||||
/** |
|
||||||
* @var \Ratchet\Http\HttpServerInterface |
|
||||||
*/ |
|
||||||
protected $_httpServer; |
|
||||||
|
|
||||||
/** |
|
||||||
* @param HttpServerInterface |
|
||||||
*/ |
|
||||||
public function __construct(HttpServerInterface $component) { |
|
||||||
$this->_httpServer = $component; |
|
||||||
$this->_reqParser = new HttpRequestParser; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function onOpen(ConnectionInterface $conn) { |
|
||||||
$conn->httpHeadersReceived = false; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function onMessage(ConnectionInterface $from, $msg) { |
|
||||||
if (true !== $from->httpHeadersReceived) { |
|
||||||
try { |
|
||||||
if (null === ($request = $this->_reqParser->onMessage($from, $msg))) { |
|
||||||
return; |
|
||||||
} |
|
||||||
} catch (\OverflowException $oe) { |
|
||||||
return $this->close($from, 413); |
|
||||||
} |
|
||||||
|
|
||||||
$from->httpHeadersReceived = true; |
|
||||||
|
|
||||||
return $this->_httpServer->onOpen($from, $request); |
|
||||||
} |
|
||||||
|
|
||||||
$this->_httpServer->onMessage($from, $msg); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function onClose(ConnectionInterface $conn) { |
|
||||||
if ($conn->httpHeadersReceived) { |
|
||||||
$this->_httpServer->onClose($conn); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function onError(ConnectionInterface $conn, \Exception $e) { |
|
||||||
if ($conn->httpHeadersReceived) { |
|
||||||
$this->_httpServer->onError($conn, $e); |
|
||||||
} else { |
|
||||||
$this->close($conn, 500); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,14 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Http; |
|
||||||
use Ratchet\MessageComponentInterface; |
|
||||||
use Ratchet\ConnectionInterface; |
|
||||||
use Psr\Http\Message\RequestInterface; |
|
||||||
|
|
||||||
interface HttpServerInterface extends MessageComponentInterface { |
|
||||||
/** |
|
||||||
* @param \Ratchet\ConnectionInterface $conn |
|
||||||
* @param \Psr\Http\Message\RequestInterface $request null is default because PHP won't let me overload; don't pass null!!! |
|
||||||
* @throws \UnexpectedValueException if a RequestInterface is not passed |
|
||||||
*/ |
|
||||||
public function onOpen(ConnectionInterface $conn, RequestInterface $request = null); |
|
||||||
} |
|
@ -1,65 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Http; |
|
||||||
use Ratchet\ConnectionInterface; |
|
||||||
use Ratchet\MessageComponentInterface; |
|
||||||
use Psr\Http\Message\RequestInterface; |
|
||||||
|
|
||||||
/** |
|
||||||
* A middleware to ensure JavaScript clients connecting are from the expected domain. |
|
||||||
* This protects other websites from open WebSocket connections to your application. |
|
||||||
* Note: This can be spoofed from non-web browser clients |
|
||||||
*/ |
|
||||||
class OriginCheck implements HttpServerInterface { |
|
||||||
use CloseResponseTrait; |
|
||||||
|
|
||||||
/** |
|
||||||
* @var \Ratchet\MessageComponentInterface |
|
||||||
*/ |
|
||||||
protected $_component; |
|
||||||
|
|
||||||
public $allowedOrigins = []; |
|
||||||
|
|
||||||
/** |
|
||||||
* @param MessageComponentInterface $component Component/Application to decorate |
|
||||||
* @param array $allowed An array of allowed domains that are allowed to connect from |
|
||||||
*/ |
|
||||||
public function __construct(MessageComponentInterface $component, array $allowed = []) { |
|
||||||
$this->_component = $component; |
|
||||||
$this->allowedOrigins += $allowed; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function onOpen(ConnectionInterface $conn, RequestInterface $request = null) { |
|
||||||
$header = (string)$request->getHeader('Origin')[0]; |
|
||||||
$origin = parse_url($header, PHP_URL_HOST) ?: $header; |
|
||||||
|
|
||||||
if (!in_array($origin, $this->allowedOrigins)) { |
|
||||||
return $this->close($conn, 403); |
|
||||||
} |
|
||||||
|
|
||||||
return $this->_component->onOpen($conn, $request); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
function onMessage(ConnectionInterface $from, $msg) { |
|
||||||
return $this->_component->onMessage($from, $msg); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
function onClose(ConnectionInterface $conn) { |
|
||||||
return $this->_component->onClose($conn); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
function onError(ConnectionInterface $conn, \Exception $e) { |
|
||||||
return $this->_component->onError($conn, $e); |
|
||||||
} |
|
||||||
} |
|
@ -1,91 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Http; |
|
||||||
use Ratchet\ConnectionInterface; |
|
||||||
use Psr\Http\Message\RequestInterface; |
|
||||||
use Symfony\Component\Routing\Matcher\UrlMatcherInterface; |
|
||||||
use Symfony\Component\Routing\Exception\MethodNotAllowedException; |
|
||||||
use Symfony\Component\Routing\Exception\ResourceNotFoundException; |
|
||||||
use GuzzleHttp\Psr7 as gPsr; |
|
||||||
|
|
||||||
class Router implements HttpServerInterface { |
|
||||||
use CloseResponseTrait; |
|
||||||
|
|
||||||
/** |
|
||||||
* @var \Symfony\Component\Routing\Matcher\UrlMatcherInterface |
|
||||||
*/ |
|
||||||
protected $_matcher; |
|
||||||
|
|
||||||
public function __construct(UrlMatcherInterface $matcher) { |
|
||||||
$this->_matcher = $matcher; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
* @throws \UnexpectedValueException If a controller is not \Ratchet\Http\HttpServerInterface |
|
||||||
*/ |
|
||||||
public function onOpen(ConnectionInterface $conn, RequestInterface $request = null) { |
|
||||||
if (null === $request) { |
|
||||||
throw new \UnexpectedValueException('$request can not be null'); |
|
||||||
} |
|
||||||
|
|
||||||
$uri = $request->getUri(); |
|
||||||
|
|
||||||
$context = $this->_matcher->getContext(); |
|
||||||
$context->setMethod($request->getMethod()); |
|
||||||
$context->setHost($uri->getHost()); |
|
||||||
|
|
||||||
try { |
|
||||||
$route = $this->_matcher->match($uri->getPath()); |
|
||||||
} catch (MethodNotAllowedException $nae) { |
|
||||||
return $this->close($conn, 403); |
|
||||||
} catch (ResourceNotFoundException $nfe) { |
|
||||||
return $this->close($conn, 404); |
|
||||||
} |
|
||||||
|
|
||||||
if (is_string($route['_controller']) && class_exists($route['_controller'])) { |
|
||||||
$route['_controller'] = new $route['_controller']; |
|
||||||
} |
|
||||||
|
|
||||||
if (!($route['_controller'] instanceof HttpServerInterface)) { |
|
||||||
throw new \UnexpectedValueException('All routes must implement Ratchet\Http\HttpServerInterface'); |
|
||||||
} |
|
||||||
|
|
||||||
$parameters = []; |
|
||||||
foreach($route as $key => $value) { |
|
||||||
if ((is_string($key)) && ('_' !== substr($key, 0, 1))) { |
|
||||||
$parameters[$key] = $value; |
|
||||||
} |
|
||||||
} |
|
||||||
$parameters = array_merge($parameters, gPsr\parse_query($uri->getQuery() ?: '')); |
|
||||||
|
|
||||||
$request = $request->withUri($uri->withQuery(gPsr\build_query($parameters))); |
|
||||||
|
|
||||||
$conn->controller = $route['_controller']; |
|
||||||
$conn->controller->onOpen($conn, $request); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
function onMessage(ConnectionInterface $from, $msg) { |
|
||||||
$from->controller->onMessage($from, $msg); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
function onClose(ConnectionInterface $conn) { |
|
||||||
if (isset($conn->controller)) { |
|
||||||
$conn->controller->onClose($conn); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
function onError(ConnectionInterface $conn, \Exception $e) { |
|
||||||
if (isset($conn->controller)) { |
|
||||||
$conn->controller->onError($conn, $e); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,5 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet; |
|
||||||
|
|
||||||
interface MessageComponentInterface extends ComponentInterface, MessageInterface { |
|
||||||
} |
|
@ -1,12 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet; |
|
||||||
|
|
||||||
interface MessageInterface { |
|
||||||
/** |
|
||||||
* Triggered when a client sends data through the socket |
|
||||||
* @param \Ratchet\ConnectionInterface $from The socket/connection that sent the message to your application |
|
||||||
* @param string $msg The message received |
|
||||||
* @throws \Exception |
|
||||||
*/ |
|
||||||
function onMessage(ConnectionInterface $from, $msg); |
|
||||||
} |
|
@ -1,23 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Server; |
|
||||||
use Ratchet\MessageComponentInterface; |
|
||||||
use Ratchet\ConnectionInterface; |
|
||||||
|
|
||||||
/** |
|
||||||
* A simple Ratchet application that will reply to all messages with the message it received |
|
||||||
*/ |
|
||||||
class EchoServer implements MessageComponentInterface { |
|
||||||
public function onOpen(ConnectionInterface $conn) { |
|
||||||
} |
|
||||||
|
|
||||||
public function onMessage(ConnectionInterface $from, $msg) { |
|
||||||
$from->send($msg); |
|
||||||
} |
|
||||||
|
|
||||||
public function onClose(ConnectionInterface $conn) { |
|
||||||
} |
|
||||||
|
|
||||||
public function onError(ConnectionInterface $conn, \Exception $e) { |
|
||||||
$conn->close(); |
|
||||||
} |
|
||||||
} |
|
@ -1,200 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Server; |
|
||||||
use Ratchet\MessageComponentInterface; |
|
||||||
use Ratchet\ConnectionInterface; |
|
||||||
|
|
||||||
/** |
|
||||||
* An app to go on a server stack to pass a policy file to a Flash socket |
|
||||||
* Useful if you're using Flash as a WebSocket polyfill on IE |
|
||||||
* Be sure to run your server instance on port 843 |
|
||||||
* By default this lets accepts everything, make sure you tighten the rules up for production |
|
||||||
* @final |
|
||||||
* @link http://www.adobe.com/devnet/articles/crossdomain_policy_file_spec.html |
|
||||||
* @link http://learn.adobe.com/wiki/download/attachments/64389123/CrossDomain_PolicyFile_Specification.pdf?version=1 |
|
||||||
* @link view-source:http://www.adobe.com/xml/schemas/PolicyFileSocket.xsd |
|
||||||
*/ |
|
||||||
class FlashPolicy implements MessageComponentInterface { |
|
||||||
|
|
||||||
/** |
|
||||||
* Contains the root policy node |
|
||||||
* @var string |
|
||||||
*/ |
|
||||||
protected $_policy = '<?xml version="1.0"?><!DOCTYPE cross-domain-policy SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd"><cross-domain-policy></cross-domain-policy>'; |
|
||||||
|
|
||||||
/** |
|
||||||
* Stores an array of allowed domains and their ports |
|
||||||
* @var array |
|
||||||
*/ |
|
||||||
protected $_access = array(); |
|
||||||
|
|
||||||
/** |
|
||||||
* @var string |
|
||||||
*/ |
|
||||||
protected $_siteControl = ''; |
|
||||||
|
|
||||||
/** |
|
||||||
* @var string |
|
||||||
*/ |
|
||||||
protected $_cache = ''; |
|
||||||
|
|
||||||
/** |
|
||||||
* @var string |
|
||||||
*/ |
|
||||||
protected $_cacheValid = false; |
|
||||||
|
|
||||||
/** |
|
||||||
* Add a domain to an allowed access list. |
|
||||||
* |
|
||||||
* @param string $domain Specifies a requesting domain to be granted access. Both named domains and IP |
|
||||||
* addresses are acceptable values. Subdomains are considered different domains. A wildcard (*) can |
|
||||||
* be used to match all domains when used alone, or multiple domains (subdomains) when used as a |
|
||||||
* prefix for an explicit, second-level domain name separated with a dot (.) |
|
||||||
* @param string $ports A comma-separated list of ports or range of ports that a socket connection |
|
||||||
* is allowed to connect to. A range of ports is specified through a dash (-) between two port numbers. |
|
||||||
* Ranges can be used with individual ports when separated with a comma. A single wildcard (*) can |
|
||||||
* be used to allow all ports. |
|
||||||
* @param bool $secure |
|
||||||
* @throws \UnexpectedValueException |
|
||||||
* @return FlashPolicy |
|
||||||
*/ |
|
||||||
public function addAllowedAccess($domain, $ports = '*', $secure = false) { |
|
||||||
if (!$this->validateDomain($domain)) { |
|
||||||
throw new \UnexpectedValueException('Invalid domain'); |
|
||||||
} |
|
||||||
|
|
||||||
if (!$this->validatePorts($ports)) { |
|
||||||
throw new \UnexpectedValueException('Invalid Port'); |
|
||||||
} |
|
||||||
|
|
||||||
$this->_access[] = array($domain, $ports, (boolean)$secure); |
|
||||||
$this->_cacheValid = false; |
|
||||||
|
|
||||||
return $this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Removes all domains from the allowed access list. |
|
||||||
* |
|
||||||
* @return \Ratchet\Server\FlashPolicy |
|
||||||
*/ |
|
||||||
public function clearAllowedAccess() { |
|
||||||
$this->_access = array(); |
|
||||||
$this->_cacheValid = false; |
|
||||||
|
|
||||||
return $this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* site-control defines the meta-policy for the current domain. A meta-policy specifies acceptable |
|
||||||
* domain policy files other than the master policy file located in the target domain's root and named |
|
||||||
* crossdomain.xml. |
|
||||||
* |
|
||||||
* @param string $permittedCrossDomainPolicies |
|
||||||
* @throws \UnexpectedValueException |
|
||||||
* @return FlashPolicy |
|
||||||
*/ |
|
||||||
public function setSiteControl($permittedCrossDomainPolicies = 'all') { |
|
||||||
if (!$this->validateSiteControl($permittedCrossDomainPolicies)) { |
|
||||||
throw new \UnexpectedValueException('Invalid site control set'); |
|
||||||
} |
|
||||||
|
|
||||||
$this->_siteControl = $permittedCrossDomainPolicies; |
|
||||||
$this->_cacheValid = false; |
|
||||||
|
|
||||||
return $this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function onOpen(ConnectionInterface $conn) { |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function onMessage(ConnectionInterface $from, $msg) { |
|
||||||
if (!$this->_cacheValid) { |
|
||||||
$this->_cache = $this->renderPolicy()->asXML(); |
|
||||||
$this->_cacheValid = true; |
|
||||||
} |
|
||||||
|
|
||||||
$from->send($this->_cache . "\0"); |
|
||||||
$from->close(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function onClose(ConnectionInterface $conn) { |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function onError(ConnectionInterface $conn, \Exception $e) { |
|
||||||
$conn->close(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Builds the crossdomain file based on the template policy |
|
||||||
* |
|
||||||
* @throws \UnexpectedValueException |
|
||||||
* @return \SimpleXMLElement |
|
||||||
*/ |
|
||||||
public function renderPolicy() { |
|
||||||
$policy = new \SimpleXMLElement($this->_policy); |
|
||||||
|
|
||||||
$siteControl = $policy->addChild('site-control'); |
|
||||||
|
|
||||||
if ($this->_siteControl == '') { |
|
||||||
$this->setSiteControl(); |
|
||||||
} |
|
||||||
|
|
||||||
$siteControl->addAttribute('permitted-cross-domain-policies', $this->_siteControl); |
|
||||||
|
|
||||||
if (empty($this->_access)) { |
|
||||||
throw new \UnexpectedValueException('You must add a domain through addAllowedAccess()'); |
|
||||||
} |
|
||||||
|
|
||||||
foreach ($this->_access as $access) { |
|
||||||
$tmp = $policy->addChild('allow-access-from'); |
|
||||||
$tmp->addAttribute('domain', $access[0]); |
|
||||||
$tmp->addAttribute('to-ports', $access[1]); |
|
||||||
$tmp->addAttribute('secure', ($access[2] === true) ? 'true' : 'false'); |
|
||||||
} |
|
||||||
|
|
||||||
return $policy; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Make sure the proper site control was passed |
|
||||||
* |
|
||||||
* @param string $permittedCrossDomainPolicies |
|
||||||
* @return bool |
|
||||||
*/ |
|
||||||
public function validateSiteControl($permittedCrossDomainPolicies) { |
|
||||||
//'by-content-type' and 'by-ftp-filename' are not available for sockets |
|
||||||
return (bool)in_array($permittedCrossDomainPolicies, array('none', 'master-only', 'all')); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Validate for proper domains (wildcards allowed) |
|
||||||
* |
|
||||||
* @param string $domain |
|
||||||
* @return bool |
|
||||||
*/ |
|
||||||
public function validateDomain($domain) { |
|
||||||
return (bool)preg_match("/^((http(s)?:\/\/)?([a-z0-9-_]+\.|\*\.)*([a-z0-9-_\.]+)|\*)$/i", $domain); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Make sure valid ports were passed |
|
||||||
* |
|
||||||
* @param string $port |
|
||||||
* @return bool |
|
||||||
*/ |
|
||||||
public function validatePorts($port) { |
|
||||||
return (bool)preg_match('/^(\*|(\d+[,-]?)*\d+)$/', $port); |
|
||||||
} |
|
||||||
} |
|
@ -1,38 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Server; |
|
||||||
use Ratchet\ConnectionInterface; |
|
||||||
use React\Socket\ConnectionInterface as ReactConn; |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
class IoConnection implements ConnectionInterface { |
|
||||||
/** |
|
||||||
* @var \React\Socket\ConnectionInterface |
|
||||||
*/ |
|
||||||
protected $conn; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* @param \React\Socket\ConnectionInterface $conn |
|
||||||
*/ |
|
||||||
public function __construct(ReactConn $conn) { |
|
||||||
$this->conn = $conn; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function send($data) { |
|
||||||
$this->conn->write($data); |
|
||||||
|
|
||||||
return $this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function close() { |
|
||||||
$this->conn->end(); |
|
||||||
} |
|
||||||
} |
|
@ -1,141 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Server; |
|
||||||
use Ratchet\MessageComponentInterface; |
|
||||||
use React\EventLoop\LoopInterface; |
|
||||||
use React\Socket\ServerInterface; |
|
||||||
use React\EventLoop\Factory as LoopFactory; |
|
||||||
use React\Socket\Server as Reactor; |
|
||||||
|
|
||||||
/** |
|
||||||
* Creates an open-ended socket to listen on a port for incoming connections. |
|
||||||
* Events are delegated through this to attached applications |
|
||||||
*/ |
|
||||||
class IoServer { |
|
||||||
/** |
|
||||||
* @var \React\EventLoop\LoopInterface |
|
||||||
*/ |
|
||||||
public $loop; |
|
||||||
|
|
||||||
/** |
|
||||||
* @var \Ratchet\MessageComponentInterface |
|
||||||
*/ |
|
||||||
public $app; |
|
||||||
|
|
||||||
/** |
|
||||||
* Array of React event handlers |
|
||||||
* @var \SplFixedArray |
|
||||||
*/ |
|
||||||
protected $handlers; |
|
||||||
|
|
||||||
/** |
|
||||||
* The socket server the Ratchet Application is run off of |
|
||||||
* @var \React\Socket\ServerInterface |
|
||||||
*/ |
|
||||||
public $socket; |
|
||||||
|
|
||||||
/** |
|
||||||
* @param \Ratchet\MessageComponentInterface $app The Ratchet application stack to host |
|
||||||
* @param \React\Socket\ServerInterface $socket The React socket server to run the Ratchet application off of |
|
||||||
* @param \React\EventLoop\LoopInterface|null $loop The React looper to run the Ratchet application off of |
|
||||||
*/ |
|
||||||
public function __construct(MessageComponentInterface $app, ServerInterface $socket, LoopInterface $loop = null) { |
|
||||||
if (false === strpos(PHP_VERSION, "hiphop")) { |
|
||||||
gc_enable(); |
|
||||||
} |
|
||||||
|
|
||||||
set_time_limit(0); |
|
||||||
ob_implicit_flush(); |
|
||||||
|
|
||||||
$this->loop = $loop; |
|
||||||
$this->app = $app; |
|
||||||
$this->socket = $socket; |
|
||||||
|
|
||||||
$socket->on('connection', array($this, 'handleConnect')); |
|
||||||
|
|
||||||
$this->handlers = new \SplFixedArray(3); |
|
||||||
$this->handlers[0] = array($this, 'handleData'); |
|
||||||
$this->handlers[1] = array($this, 'handleEnd'); |
|
||||||
$this->handlers[2] = array($this, 'handleError'); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @param \Ratchet\MessageComponentInterface $component The application that I/O will call when events are received |
|
||||||
* @param int $port The port to server sockets on |
|
||||||
* @param string $address The address to receive sockets on (0.0.0.0 means receive connections from any) |
|
||||||
* @return IoServer |
|
||||||
*/ |
|
||||||
public static function factory(MessageComponentInterface $component, $port = 80, $address = '0.0.0.0') { |
|
||||||
$loop = LoopFactory::create(); |
|
||||||
$socket = new Reactor($loop); |
|
||||||
$socket->listen($port, $address); |
|
||||||
|
|
||||||
return new static($component, $socket, $loop); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Run the application by entering the event loop |
|
||||||
* @throws \RuntimeException If a loop was not previously specified |
|
||||||
*/ |
|
||||||
public function run() { |
|
||||||
if (null === $this->loop) { |
|
||||||
throw new \RuntimeException("A React Loop was not provided during instantiation"); |
|
||||||
} |
|
||||||
|
|
||||||
// @codeCoverageIgnoreStart |
|
||||||
$this->loop->run(); |
|
||||||
// @codeCoverageIgnoreEnd |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Triggered when a new connection is received from React |
|
||||||
* @param \React\Socket\ConnectionInterface $conn |
|
||||||
*/ |
|
||||||
public function handleConnect($conn) { |
|
||||||
$conn->decor = new IoConnection($conn); |
|
||||||
|
|
||||||
$conn->decor->resourceId = (int)$conn->stream; |
|
||||||
$conn->decor->remoteAddress = $conn->getRemoteAddress(); |
|
||||||
|
|
||||||
$this->app->onOpen($conn->decor); |
|
||||||
|
|
||||||
$conn->on('data', $this->handlers[0]); |
|
||||||
$conn->on('end', $this->handlers[1]); |
|
||||||
$conn->on('error', $this->handlers[2]); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Data has been received from React |
|
||||||
* @param string $data |
|
||||||
* @param \React\Socket\ConnectionInterface $conn |
|
||||||
*/ |
|
||||||
public function handleData($data, $conn) { |
|
||||||
try { |
|
||||||
$this->app->onMessage($conn->decor, $data); |
|
||||||
} catch (\Exception $e) { |
|
||||||
$this->handleError($e, $conn); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* A connection has been closed by React |
|
||||||
* @param \React\Socket\ConnectionInterface $conn |
|
||||||
*/ |
|
||||||
public function handleEnd($conn) { |
|
||||||
try { |
|
||||||
$this->app->onClose($conn->decor); |
|
||||||
} catch (\Exception $e) { |
|
||||||
$this->handleError($e, $conn); |
|
||||||
} |
|
||||||
|
|
||||||
unset($conn->decor); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* An error has occurred, let the listening application know |
|
||||||
* @param \Exception $e |
|
||||||
* @param \React\Socket\ConnectionInterface $conn |
|
||||||
*/ |
|
||||||
public function handleError(\Exception $e, $conn) { |
|
||||||
$this->app->onError($conn->decor, $e); |
|
||||||
} |
|
||||||
} |
|
@ -1,111 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Server; |
|
||||||
use Ratchet\MessageComponentInterface; |
|
||||||
use Ratchet\ConnectionInterface; |
|
||||||
|
|
||||||
class IpBlackList implements MessageComponentInterface { |
|
||||||
/** |
|
||||||
* @var array |
|
||||||
*/ |
|
||||||
protected $_blacklist = array(); |
|
||||||
|
|
||||||
/** |
|
||||||
* @var \Ratchet\MessageComponentInterface |
|
||||||
*/ |
|
||||||
protected $_decorating; |
|
||||||
|
|
||||||
/** |
|
||||||
* @param \Ratchet\MessageComponentInterface $component |
|
||||||
*/ |
|
||||||
public function __construct(MessageComponentInterface $component) { |
|
||||||
$this->_decorating = $component; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Add an address to the blacklist that will not be allowed to connect to your application |
|
||||||
* @param string $ip IP address to block from connecting to your application |
|
||||||
* @return IpBlackList |
|
||||||
*/ |
|
||||||
public function blockAddress($ip) { |
|
||||||
$this->_blacklist[$ip] = true; |
|
||||||
|
|
||||||
return $this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Unblock an address so they can access your application again |
|
||||||
* @param string $ip IP address to unblock from connecting to your application |
|
||||||
* @return IpBlackList |
|
||||||
*/ |
|
||||||
public function unblockAddress($ip) { |
|
||||||
if (isset($this->_blacklist[$this->filterAddress($ip)])) { |
|
||||||
unset($this->_blacklist[$this->filterAddress($ip)]); |
|
||||||
} |
|
||||||
|
|
||||||
return $this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @param string $address |
|
||||||
* @return bool |
|
||||||
*/ |
|
||||||
public function isBlocked($address) { |
|
||||||
return (isset($this->_blacklist[$this->filterAddress($address)])); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Get an array of all the addresses blocked |
|
||||||
* @return array |
|
||||||
*/ |
|
||||||
public function getBlockedAddresses() { |
|
||||||
return array_keys($this->_blacklist); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @param string $address |
|
||||||
* @return string |
|
||||||
*/ |
|
||||||
public function filterAddress($address) { |
|
||||||
if (strstr($address, ':') && substr_count($address, '.') == 3) { |
|
||||||
list($address, $port) = explode(':', $address); |
|
||||||
} |
|
||||||
|
|
||||||
return $address; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
function onOpen(ConnectionInterface $conn) { |
|
||||||
if ($this->isBlocked($conn->remoteAddress)) { |
|
||||||
return $conn->close(); |
|
||||||
} |
|
||||||
|
|
||||||
return $this->_decorating->onOpen($conn); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
function onMessage(ConnectionInterface $from, $msg) { |
|
||||||
return $this->_decorating->onMessage($from, $msg); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
function onClose(ConnectionInterface $conn) { |
|
||||||
if (!$this->isBlocked($conn->remoteAddress)) { |
|
||||||
$this->_decorating->onClose($conn); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
function onError(ConnectionInterface $conn, \Exception $e) { |
|
||||||
if (!$this->isBlocked($conn->remoteAddress)) { |
|
||||||
$this->_decorating->onError($conn, $e); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,16 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Session\Serialize; |
|
||||||
|
|
||||||
interface HandlerInterface { |
|
||||||
/** |
|
||||||
* @param array |
|
||||||
* @return string |
|
||||||
*/ |
|
||||||
function serialize(array $data); |
|
||||||
|
|
||||||
/** |
|
||||||
* @param string |
|
||||||
* @return array |
|
||||||
*/ |
|
||||||
function unserialize($raw); |
|
||||||
} |
|
@ -1,33 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Session\Serialize; |
|
||||||
|
|
||||||
class PhpBinaryHandler implements HandlerInterface { |
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
function serialize(array $data) { |
|
||||||
throw new \RuntimeException("Serialize PhpHandler:serialize code not written yet, write me!"); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
* @link http://ca2.php.net/manual/en/function.session-decode.php#108037 Code from this comment on php.net |
|
||||||
*/ |
|
||||||
public function unserialize($raw) { |
|
||||||
$returnData = array(); |
|
||||||
$offset = 0; |
|
||||||
|
|
||||||
while ($offset < strlen($raw)) { |
|
||||||
$num = ord($raw[$offset]); |
|
||||||
$offset += 1; |
|
||||||
$varname = substr($raw, $offset, $num); |
|
||||||
$offset += $num; |
|
||||||
$data = unserialize(substr($raw, $offset)); |
|
||||||
|
|
||||||
$returnData[$varname] = $data; |
|
||||||
$offset += strlen(serialize($data)); |
|
||||||
} |
|
||||||
|
|
||||||
return $returnData; |
|
||||||
} |
|
||||||
} |
|
@ -1,38 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Session\Serialize; |
|
||||||
|
|
||||||
class PhpHandler implements HandlerInterface { |
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
function serialize(array $data) { |
|
||||||
throw new \RuntimeException("Serialize PhpHandler:serialize code not written yet, write me!"); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
* @link http://ca2.php.net/manual/en/function.session-decode.php#108037 Code from this comment on php.net |
|
||||||
* @throws \UnexpectedValueException If there is a problem parsing the data |
|
||||||
*/ |
|
||||||
public function unserialize($raw) { |
|
||||||
$returnData = array(); |
|
||||||
$offset = 0; |
|
||||||
|
|
||||||
while ($offset < strlen($raw)) { |
|
||||||
if (!strstr(substr($raw, $offset), "|")) { |
|
||||||
throw new \UnexpectedValueException("invalid data, remaining: " . substr($raw, $offset)); |
|
||||||
} |
|
||||||
|
|
||||||
$pos = strpos($raw, "|", $offset); |
|
||||||
$num = $pos - $offset; |
|
||||||
$varname = substr($raw, $offset, $num); |
|
||||||
$offset += $num + 1; |
|
||||||
$data = unserialize(substr($raw, $offset)); |
|
||||||
|
|
||||||
$returnData[$varname] = $data; |
|
||||||
$offset += strlen(serialize($data)); |
|
||||||
} |
|
||||||
|
|
||||||
return $returnData; |
|
||||||
} |
|
||||||
} |
|
@ -1,243 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Session; |
|
||||||
use Ratchet\ConnectionInterface; |
|
||||||
use Ratchet\Http\HttpServerInterface; |
|
||||||
use Psr\Http\Message\RequestInterface; |
|
||||||
use Ratchet\Session\Storage\VirtualSessionStorage; |
|
||||||
use Ratchet\Session\Serialize\HandlerInterface; |
|
||||||
use Symfony\Component\HttpFoundation\Session\Session; |
|
||||||
use Symfony\Component\HttpFoundation\Session\Storage\Handler\NullSessionHandler; |
|
||||||
|
|
||||||
/** |
|
||||||
* This component will allow access to session data from your website for each user connected |
|
||||||
* Symfony HttpFoundation is required for this component to work |
|
||||||
* Your website must also use Symfony HttpFoundation Sessions to read your sites session data |
|
||||||
* If your are not using at least PHP 5.4 you must include a SessionHandlerInterface stub (is included in Symfony HttpFoundation, loaded w/ composer) |
|
||||||
*/ |
|
||||||
class SessionProvider implements HttpServerInterface { |
|
||||||
/** |
|
||||||
* @var \Ratchet\MessageComponentInterface |
|
||||||
*/ |
|
||||||
protected $_app; |
|
||||||
|
|
||||||
/** |
|
||||||
* Selected handler storage assigned by the developer |
|
||||||
* @var \SessionHandlerInterface |
|
||||||
*/ |
|
||||||
protected $_handler; |
|
||||||
|
|
||||||
/** |
|
||||||
* Null storage handler if no previous session was found |
|
||||||
* @var \SessionHandlerInterface |
|
||||||
*/ |
|
||||||
protected $_null; |
|
||||||
|
|
||||||
/** |
|
||||||
* @var \Ratchet\Session\Serialize\HandlerInterface |
|
||||||
*/ |
|
||||||
protected $_serializer; |
|
||||||
|
|
||||||
/** |
|
||||||
* @param \Ratchet\Http\HttpServerInterface $app |
|
||||||
* @param \SessionHandlerInterface $handler |
|
||||||
* @param array $options |
|
||||||
* @param \Ratchet\Session\Serialize\HandlerInterface $serializer |
|
||||||
* @throws \RuntimeException |
|
||||||
*/ |
|
||||||
public function __construct(HttpServerInterface $app, \SessionHandlerInterface $handler, array $options = array(), HandlerInterface $serializer = null) { |
|
||||||
$this->_app = $app; |
|
||||||
$this->_handler = $handler; |
|
||||||
$this->_null = new NullSessionHandler; |
|
||||||
|
|
||||||
ini_set('session.auto_start', 0); |
|
||||||
ini_set('session.cache_limiter', ''); |
|
||||||
ini_set('session.use_cookies', 0); |
|
||||||
|
|
||||||
$this->setOptions($options); |
|
||||||
|
|
||||||
if (null === $serializer) { |
|
||||||
$serialClass = __NAMESPACE__ . "\\Serialize\\{$this->toClassCase(ini_get('session.serialize_handler'))}Handler"; // awesome/terrible hack, eh? |
|
||||||
if (!class_exists($serialClass)) { |
|
||||||
throw new \RuntimeException('Unable to parse session serialize handler'); |
|
||||||
} |
|
||||||
|
|
||||||
$serializer = new $serialClass; |
|
||||||
} |
|
||||||
|
|
||||||
$this->_serializer = $serializer; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function onOpen(ConnectionInterface $conn, RequestInterface $request = null) { |
|
||||||
$sessionName = ini_get('session.name'); |
|
||||||
|
|
||||||
$id = array_reduce($request->getHeader('Cookie'), function($accumulator, $cookie) use ($sessionName) { |
|
||||||
if ($accumulator) { |
|
||||||
return $accumulator; |
|
||||||
} |
|
||||||
|
|
||||||
$crumbs = $this->parseCookie($cookie); |
|
||||||
|
|
||||||
return isset($crumbs['cookies'][$sessionName]) ? $crumbs['cookies'][$sessionName] : false; |
|
||||||
}, false); |
|
||||||
|
|
||||||
if (null === $request || false === $id) { |
|
||||||
$saveHandler = $this->_null; |
|
||||||
$id = ''; |
|
||||||
} else { |
|
||||||
$saveHandler = $this->_handler; |
|
||||||
} |
|
||||||
|
|
||||||
$conn->Session = new Session(new VirtualSessionStorage($saveHandler, $id, $this->_serializer)); |
|
||||||
|
|
||||||
if (ini_get('session.auto_start')) { |
|
||||||
$conn->Session->start(); |
|
||||||
} |
|
||||||
|
|
||||||
return $this->_app->onOpen($conn, $request); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
function onMessage(ConnectionInterface $from, $msg) { |
|
||||||
return $this->_app->onMessage($from, $msg); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
function onClose(ConnectionInterface $conn) { |
|
||||||
// "close" session for Connection |
|
||||||
|
|
||||||
return $this->_app->onClose($conn); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
function onError(ConnectionInterface $conn, \Exception $e) { |
|
||||||
return $this->_app->onError($conn, $e); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Set all the php session. ini options |
|
||||||
* © Symfony |
|
||||||
* @param array $options |
|
||||||
* @return array |
|
||||||
*/ |
|
||||||
protected function setOptions(array $options) { |
|
||||||
$all = array( |
|
||||||
'auto_start', 'cache_limiter', 'cookie_domain', 'cookie_httponly', |
|
||||||
'cookie_lifetime', 'cookie_path', 'cookie_secure', |
|
||||||
'entropy_file', 'entropy_length', 'gc_divisor', |
|
||||||
'gc_maxlifetime', 'gc_probability', 'hash_bits_per_character', |
|
||||||
'hash_function', 'name', 'referer_check', |
|
||||||
'serialize_handler', 'use_cookies', |
|
||||||
'use_only_cookies', 'use_trans_sid', 'upload_progress.enabled', |
|
||||||
'upload_progress.cleanup', 'upload_progress.prefix', 'upload_progress.name', |
|
||||||
'upload_progress.freq', 'upload_progress.min-freq', 'url_rewriter.tags' |
|
||||||
); |
|
||||||
|
|
||||||
foreach ($all as $key) { |
|
||||||
if (!array_key_exists($key, $options)) { |
|
||||||
$options[$key] = ini_get("session.{$key}"); |
|
||||||
} else { |
|
||||||
ini_set("session.{$key}", $options[$key]); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return $options; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @param string $langDef Input to convert |
|
||||||
* @return string |
|
||||||
*/ |
|
||||||
protected function toClassCase($langDef) { |
|
||||||
return str_replace(' ', '', ucwords(str_replace('_', ' ', $langDef))); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Taken from Guzzle3 |
|
||||||
*/ |
|
||||||
private static $cookieParts = array( |
|
||||||
'domain' => 'Domain', |
|
||||||
'path' => 'Path', |
|
||||||
'max_age' => 'Max-Age', |
|
||||||
'expires' => 'Expires', |
|
||||||
'version' => 'Version', |
|
||||||
'secure' => 'Secure', |
|
||||||
'port' => 'Port', |
|
||||||
'discard' => 'Discard', |
|
||||||
'comment' => 'Comment', |
|
||||||
'comment_url' => 'Comment-Url', |
|
||||||
'http_only' => 'HttpOnly' |
|
||||||
); |
|
||||||
|
|
||||||
/** |
|
||||||
* Taken from Guzzle3 |
|
||||||
*/ |
|
||||||
private function parseCookie($cookie, $host = null, $path = null, $decode = false) { |
|
||||||
// Explode the cookie string using a series of semicolons |
|
||||||
$pieces = array_filter(array_map('trim', explode(';', $cookie))); |
|
||||||
|
|
||||||
// The name of the cookie (first kvp) must include an equal sign. |
|
||||||
if (empty($pieces) || !strpos($pieces[0], '=')) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
// Create the default return array |
|
||||||
$data = array_merge(array_fill_keys(array_keys(self::$cookieParts), null), array( |
|
||||||
'cookies' => array(), |
|
||||||
'data' => array(), |
|
||||||
'path' => $path ?: '/', |
|
||||||
'http_only' => false, |
|
||||||
'discard' => false, |
|
||||||
'domain' => $host |
|
||||||
)); |
|
||||||
$foundNonCookies = 0; |
|
||||||
|
|
||||||
// Add the cookie pieces into the parsed data array |
|
||||||
foreach ($pieces as $part) { |
|
||||||
|
|
||||||
$cookieParts = explode('=', $part, 2); |
|
||||||
$key = trim($cookieParts[0]); |
|
||||||
|
|
||||||
if (count($cookieParts) == 1) { |
|
||||||
// Can be a single value (e.g. secure, httpOnly) |
|
||||||
$value = true; |
|
||||||
} else { |
|
||||||
// Be sure to strip wrapping quotes |
|
||||||
$value = trim($cookieParts[1], " \n\r\t\0\x0B\""); |
|
||||||
if ($decode) { |
|
||||||
$value = urldecode($value); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Only check for non-cookies when cookies have been found |
|
||||||
if (!empty($data['cookies'])) { |
|
||||||
foreach (self::$cookieParts as $mapValue => $search) { |
|
||||||
if (!strcasecmp($search, $key)) { |
|
||||||
$data[$mapValue] = $mapValue == 'port' ? array_map('trim', explode(',', $value)) : $value; |
|
||||||
$foundNonCookies++; |
|
||||||
continue 2; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// If cookies have not yet been retrieved, or this value was not found in the pieces array, treat it as a |
|
||||||
// cookie. IF non-cookies have been parsed, then this isn't a cookie, it's cookie data. Cookies then data. |
|
||||||
$data[$foundNonCookies ? 'data' : 'cookies'][$key] = $value; |
|
||||||
} |
|
||||||
|
|
||||||
// Calculate the expires date |
|
||||||
if (!$data['expires'] && $data['max_age']) { |
|
||||||
$data['expires'] = time() + (int) $data['max_age']; |
|
||||||
} |
|
||||||
|
|
||||||
return $data; |
|
||||||
} |
|
||||||
} |
|
@ -1,54 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Session\Storage\Proxy; |
|
||||||
use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy; |
|
||||||
|
|
||||||
class VirtualProxy extends SessionHandlerProxy { |
|
||||||
/** |
|
||||||
* @var string |
|
||||||
*/ |
|
||||||
protected $_sessionId; |
|
||||||
|
|
||||||
/** |
|
||||||
* @var string |
|
||||||
*/ |
|
||||||
protected $_sessionName; |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function __construct(\SessionHandlerInterface $handler) { |
|
||||||
parent::__construct($handler); |
|
||||||
|
|
||||||
$this->saveHandlerName = 'user'; |
|
||||||
$this->_sessionName = ini_get('session.name'); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function getId() { |
|
||||||
return $this->_sessionId; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function setId($id) { |
|
||||||
$this->_sessionId = $id; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function getName() { |
|
||||||
return $this->_sessionName; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* DO NOT CALL THIS METHOD |
|
||||||
* @internal |
|
||||||
*/ |
|
||||||
public function setName($name) { |
|
||||||
throw new \RuntimeException("Can not change session name in VirtualProxy"); |
|
||||||
} |
|
||||||
} |
|
@ -1,88 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Session\Storage; |
|
||||||
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; |
|
||||||
use Ratchet\Session\Storage\Proxy\VirtualProxy; |
|
||||||
use Ratchet\Session\Serialize\HandlerInterface; |
|
||||||
|
|
||||||
class VirtualSessionStorage extends NativeSessionStorage { |
|
||||||
/** |
|
||||||
* @var \Ratchet\Session\Serialize\HandlerInterface |
|
||||||
*/ |
|
||||||
protected $_serializer; |
|
||||||
|
|
||||||
/** |
|
||||||
* @param \SessionHandlerInterface $handler |
|
||||||
* @param string $sessionId The ID of the session to retrieve |
|
||||||
* @param \Ratchet\Session\Serialize\HandlerInterface $serializer |
|
||||||
*/ |
|
||||||
public function __construct(\SessionHandlerInterface $handler, $sessionId, HandlerInterface $serializer) { |
|
||||||
$this->setSaveHandler($handler); |
|
||||||
$this->saveHandler->setId($sessionId); |
|
||||||
$this->_serializer = $serializer; |
|
||||||
$this->setMetadataBag(null); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function start() { |
|
||||||
if ($this->started && !$this->closed) { |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
// You have to call Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler::open() to use |
|
||||||
// pdo_sqlite (and possible pdo_*) as session storage, if you are using a DSN string instead of a \PDO object |
|
||||||
// in the constructor. The method arguments are filled with the values, which are also used by the symfony |
|
||||||
// framework in this case. This must not be the best choice, but it works. |
|
||||||
$this->saveHandler->open(session_save_path(), session_name()); |
|
||||||
|
|
||||||
$rawData = $this->saveHandler->read($this->saveHandler->getId()); |
|
||||||
$sessionData = $this->_serializer->unserialize($rawData); |
|
||||||
|
|
||||||
$this->loadSession($sessionData); |
|
||||||
|
|
||||||
if (!$this->saveHandler->isWrapper() && !$this->saveHandler->isSessionHandlerInterface()) { |
|
||||||
$this->saveHandler->setActive(false); |
|
||||||
} |
|
||||||
|
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function regenerate($destroy = false, $lifetime = null) { |
|
||||||
// .. ? |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function save() { |
|
||||||
// get the data from the bags? |
|
||||||
// serialize the data |
|
||||||
// save the data using the saveHandler |
|
||||||
// $this->saveHandler->write($this->saveHandler->getId(), |
|
||||||
|
|
||||||
if (!$this->saveHandler->isWrapper() && !$this->getSaveHandler()->isSessionHandlerInterface()) { |
|
||||||
$this->saveHandler->setActive(false); |
|
||||||
} |
|
||||||
|
|
||||||
$this->closed = true; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function setSaveHandler($saveHandler = null) { |
|
||||||
if (!($saveHandler instanceof \SessionHandlerInterface)) { |
|
||||||
throw new \InvalidArgumentException('Handler must be instance of SessionHandlerInterface'); |
|
||||||
} |
|
||||||
|
|
||||||
if (!($saveHandler instanceof VirtualProxy)) { |
|
||||||
$saveHandler = new VirtualProxy($saveHandler); |
|
||||||
} |
|
||||||
|
|
||||||
$this->saveHandler = $saveHandler; |
|
||||||
} |
|
||||||
} |
|
@ -1,5 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Wamp; |
|
||||||
|
|
||||||
class Exception extends \Exception { |
|
||||||
} |
|
@ -1,31 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Wamp; |
|
||||||
|
|
||||||
class JsonException extends Exception { |
|
||||||
public function __construct() { |
|
||||||
$code = json_last_error(); |
|
||||||
|
|
||||||
switch ($code) { |
|
||||||
case JSON_ERROR_DEPTH: |
|
||||||
$msg = 'Maximum stack depth exceeded'; |
|
||||||
break; |
|
||||||
case JSON_ERROR_STATE_MISMATCH: |
|
||||||
$msg = 'Underflow or the modes mismatch'; |
|
||||||
break; |
|
||||||
case JSON_ERROR_CTRL_CHAR: |
|
||||||
$msg = 'Unexpected control character found'; |
|
||||||
break; |
|
||||||
case JSON_ERROR_SYNTAX: |
|
||||||
$msg = 'Syntax error, malformed JSON'; |
|
||||||
break; |
|
||||||
case JSON_ERROR_UTF8: |
|
||||||
$msg = 'Malformed UTF-8 characters, possibly incorrectly encoded'; |
|
||||||
break; |
|
||||||
default: |
|
||||||
$msg = 'Unknown error'; |
|
||||||
break; |
|
||||||
} |
|
||||||
|
|
||||||
parent::__construct($msg, $code); |
|
||||||
} |
|
||||||
} |
|
@ -1,157 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Wamp; |
|
||||||
use Ratchet\MessageComponentInterface; |
|
||||||
use Ratchet\WebSocket\WsServerInterface; |
|
||||||
use Ratchet\ConnectionInterface; |
|
||||||
|
|
||||||
/** |
|
||||||
* WebSocket Application Messaging Protocol |
|
||||||
* |
|
||||||
* @link http://wamp.ws/spec |
|
||||||
* @link https://github.com/oberstet/AutobahnJS |
|
||||||
* |
|
||||||
* +--------------+----+------------------+ |
|
||||||
* | Message Type | ID | DIRECTION | |
|
||||||
* |--------------+----+------------------+ |
|
||||||
* | WELCOME | 0 | Server-to-Client | |
|
||||||
* | PREFIX | 1 | Bi-Directional | |
|
||||||
* | CALL | 2 | Client-to-Server | |
|
||||||
* | CALL RESULT | 3 | Server-to-Client | |
|
||||||
* | CALL ERROR | 4 | Server-to-Client | |
|
||||||
* | SUBSCRIBE | 5 | Client-to-Server | |
|
||||||
* | UNSUBSCRIBE | 6 | Client-to-Server | |
|
||||||
* | PUBLISH | 7 | Client-to-Server | |
|
||||||
* | EVENT | 8 | Server-to-Client | |
|
||||||
* +--------------+----+------------------+ |
|
||||||
*/ |
|
||||||
class ServerProtocol implements MessageComponentInterface, WsServerInterface { |
|
||||||
const MSG_WELCOME = 0; |
|
||||||
const MSG_PREFIX = 1; |
|
||||||
const MSG_CALL = 2; |
|
||||||
const MSG_CALL_RESULT = 3; |
|
||||||
const MSG_CALL_ERROR = 4; |
|
||||||
const MSG_SUBSCRIBE = 5; |
|
||||||
const MSG_UNSUBSCRIBE = 6; |
|
||||||
const MSG_PUBLISH = 7; |
|
||||||
const MSG_EVENT = 8; |
|
||||||
|
|
||||||
/** |
|
||||||
* @var WampServerInterface |
|
||||||
*/ |
|
||||||
protected $_decorating; |
|
||||||
|
|
||||||
/** |
|
||||||
* @var \SplObjectStorage |
|
||||||
*/ |
|
||||||
protected $connections; |
|
||||||
|
|
||||||
/** |
|
||||||
* @param WampServerInterface $serverComponent An class to propagate calls through |
|
||||||
*/ |
|
||||||
public function __construct(WampServerInterface $serverComponent) { |
|
||||||
$this->_decorating = $serverComponent; |
|
||||||
$this->connections = new \SplObjectStorage; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function getSubProtocols() { |
|
||||||
if ($this->_decorating instanceof WsServerInterface) { |
|
||||||
$subs = $this->_decorating->getSubProtocols(); |
|
||||||
$subs[] = 'wamp'; |
|
||||||
|
|
||||||
return $subs; |
|
||||||
} else { |
|
||||||
return array('wamp'); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function onOpen(ConnectionInterface $conn) { |
|
||||||
$decor = new WampConnection($conn); |
|
||||||
$this->connections->attach($conn, $decor); |
|
||||||
|
|
||||||
$this->_decorating->onOpen($decor); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
* @throws \Ratchet\Wamp\Exception |
|
||||||
* @throws \Ratchet\Wamp\JsonException |
|
||||||
*/ |
|
||||||
public function onMessage(ConnectionInterface $from, $msg) { |
|
||||||
$from = $this->connections[$from]; |
|
||||||
|
|
||||||
if (null === ($json = @json_decode($msg, true))) { |
|
||||||
throw new JsonException; |
|
||||||
} |
|
||||||
|
|
||||||
if (!is_array($json) || $json !== array_values($json)) { |
|
||||||
throw new Exception("Invalid WAMP message format"); |
|
||||||
} |
|
||||||
|
|
||||||
switch ($json[0]) { |
|
||||||
case static::MSG_PREFIX: |
|
||||||
$from->WAMP->prefixes[$json[1]] = $json[2]; |
|
||||||
break; |
|
||||||
|
|
||||||
case static::MSG_CALL: |
|
||||||
array_shift($json); |
|
||||||
$callID = array_shift($json); |
|
||||||
$procURI = array_shift($json); |
|
||||||
|
|
||||||
if (count($json) == 1 && is_array($json[0])) { |
|
||||||
$json = $json[0]; |
|
||||||
} |
|
||||||
|
|
||||||
$this->_decorating->onCall($from, $callID, $from->getUri($procURI), $json); |
|
||||||
break; |
|
||||||
|
|
||||||
case static::MSG_SUBSCRIBE: |
|
||||||
$this->_decorating->onSubscribe($from, $from->getUri($json[1])); |
|
||||||
break; |
|
||||||
|
|
||||||
case static::MSG_UNSUBSCRIBE: |
|
||||||
$this->_decorating->onUnSubscribe($from, $from->getUri($json[1])); |
|
||||||
break; |
|
||||||
|
|
||||||
case static::MSG_PUBLISH: |
|
||||||
$exclude = (array_key_exists(3, $json) ? $json[3] : null); |
|
||||||
if (!is_array($exclude)) { |
|
||||||
if (true === (boolean)$exclude) { |
|
||||||
$exclude = array($from->WAMP->sessionId); |
|
||||||
} else { |
|
||||||
$exclude = array(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
$eligible = (array_key_exists(4, $json) ? $json[4] : array()); |
|
||||||
|
|
||||||
$this->_decorating->onPublish($from, $from->getUri($json[1]), $json[2], $exclude, $eligible); |
|
||||||
break; |
|
||||||
|
|
||||||
default: |
|
||||||
throw new Exception('Invalid WAMP message type'); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function onClose(ConnectionInterface $conn) { |
|
||||||
$decor = $this->connections[$conn]; |
|
||||||
$this->connections->detach($conn); |
|
||||||
|
|
||||||
$this->_decorating->onClose($decor); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function onError(ConnectionInterface $conn, \Exception $e) { |
|
||||||
return $this->_decorating->onError($this->connections[$conn], $e); |
|
||||||
} |
|
||||||
} |
|
@ -1,106 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Wamp; |
|
||||||
use Ratchet\ConnectionInterface; |
|
||||||
|
|
||||||
/** |
|
||||||
* A topic/channel containing connections that have subscribed to it |
|
||||||
*/ |
|
||||||
class Topic implements \IteratorAggregate, \Countable { |
|
||||||
/** |
|
||||||
* If true the TopicManager will destroy this object if it's ever empty of connections |
|
||||||
* @deprecated in v0.4 |
|
||||||
* @type bool |
|
||||||
*/ |
|
||||||
public $autoDelete = false; |
|
||||||
|
|
||||||
private $id; |
|
||||||
|
|
||||||
private $subscribers; |
|
||||||
|
|
||||||
/** |
|
||||||
* @param string $topicId Unique ID for this object |
|
||||||
*/ |
|
||||||
public function __construct($topicId) { |
|
||||||
$this->id = $topicId; |
|
||||||
$this->subscribers = new \SplObjectStorage; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @return string |
|
||||||
*/ |
|
||||||
public function getId() { |
|
||||||
return $this->id; |
|
||||||
} |
|
||||||
|
|
||||||
public function __toString() { |
|
||||||
return $this->getId(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Send a message to all the connections in this topic |
|
||||||
* @param string $msg Payload to publish |
|
||||||
* @param array $exclude A list of session IDs the message should be excluded from (blacklist) |
|
||||||
* @param array $eligible A list of session Ids the message should be send to (whitelist) |
|
||||||
* @return Topic The same Topic object to chain |
|
||||||
*/ |
|
||||||
public function broadcast($msg, array $exclude = array(), array $eligible = array()) { |
|
||||||
$useEligible = (bool)count($eligible); |
|
||||||
foreach ($this->subscribers as $client) { |
|
||||||
if (in_array($client->WAMP->sessionId, $exclude)) { |
|
||||||
continue; |
|
||||||
} |
|
||||||
|
|
||||||
if ($useEligible && !in_array($client->WAMP->sessionId, $eligible)) { |
|
||||||
continue; |
|
||||||
} |
|
||||||
|
|
||||||
$client->event($this->id, $msg); |
|
||||||
} |
|
||||||
|
|
||||||
return $this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @param WampConnection $conn |
|
||||||
* @return boolean |
|
||||||
*/ |
|
||||||
public function has(ConnectionInterface $conn) { |
|
||||||
return $this->subscribers->contains($conn); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @param WampConnection $conn |
|
||||||
* @return Topic |
|
||||||
*/ |
|
||||||
public function add(ConnectionInterface $conn) { |
|
||||||
$this->subscribers->attach($conn); |
|
||||||
|
|
||||||
return $this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @param WampConnection $conn |
|
||||||
* @return Topic |
|
||||||
*/ |
|
||||||
public function remove(ConnectionInterface $conn) { |
|
||||||
if ($this->subscribers->contains($conn)) { |
|
||||||
$this->subscribers->detach($conn); |
|
||||||
} |
|
||||||
|
|
||||||
return $this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function getIterator() { |
|
||||||
return $this->subscribers; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function count() { |
|
||||||
return $this->subscribers->count(); |
|
||||||
} |
|
||||||
} |
|
@ -1,125 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Wamp; |
|
||||||
use Ratchet\ConnectionInterface; |
|
||||||
use Ratchet\WebSocket\WsServerInterface; |
|
||||||
|
|
||||||
class TopicManager implements WsServerInterface, WampServerInterface { |
|
||||||
/** |
|
||||||
* @var WampServerInterface |
|
||||||
*/ |
|
||||||
protected $app; |
|
||||||
|
|
||||||
/** |
|
||||||
* @var array |
|
||||||
*/ |
|
||||||
protected $topicLookup = array(); |
|
||||||
|
|
||||||
public function __construct(WampServerInterface $app) { |
|
||||||
$this->app = $app; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function onOpen(ConnectionInterface $conn) { |
|
||||||
$conn->WAMP->subscriptions = new \SplObjectStorage; |
|
||||||
$this->app->onOpen($conn); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function onCall(ConnectionInterface $conn, $id, $topic, array $params) { |
|
||||||
$this->app->onCall($conn, $id, $this->getTopic($topic), $params); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function onSubscribe(ConnectionInterface $conn, $topic) { |
|
||||||
$topicObj = $this->getTopic($topic); |
|
||||||
|
|
||||||
if ($conn->WAMP->subscriptions->contains($topicObj)) { |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
$this->topicLookup[$topic]->add($conn); |
|
||||||
$conn->WAMP->subscriptions->attach($topicObj); |
|
||||||
$this->app->onSubscribe($conn, $topicObj); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function onUnsubscribe(ConnectionInterface $conn, $topic) { |
|
||||||
$topicObj = $this->getTopic($topic); |
|
||||||
|
|
||||||
if (!$conn->WAMP->subscriptions->contains($topicObj)) { |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
$this->cleanTopic($topicObj, $conn); |
|
||||||
|
|
||||||
$this->app->onUnsubscribe($conn, $topicObj); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function onPublish(ConnectionInterface $conn, $topic, $event, array $exclude, array $eligible) { |
|
||||||
$this->app->onPublish($conn, $this->getTopic($topic), $event, $exclude, $eligible); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function onClose(ConnectionInterface $conn) { |
|
||||||
$this->app->onClose($conn); |
|
||||||
|
|
||||||
foreach ($this->topicLookup as $topic) { |
|
||||||
$this->cleanTopic($topic, $conn); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function onError(ConnectionInterface $conn, \Exception $e) { |
|
||||||
$this->app->onError($conn, $e); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function getSubProtocols() { |
|
||||||
if ($this->app instanceof WsServerInterface) { |
|
||||||
return $this->app->getSubProtocols(); |
|
||||||
} |
|
||||||
|
|
||||||
return array(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @param string |
|
||||||
* @return Topic |
|
||||||
*/ |
|
||||||
protected function getTopic($topic) { |
|
||||||
if (!array_key_exists($topic, $this->topicLookup)) { |
|
||||||
$this->topicLookup[$topic] = new Topic($topic); |
|
||||||
} |
|
||||||
|
|
||||||
return $this->topicLookup[$topic]; |
|
||||||
} |
|
||||||
|
|
||||||
protected function cleanTopic(Topic $topic, ConnectionInterface $conn) { |
|
||||||
if ($conn->WAMP->subscriptions->contains($topic)) { |
|
||||||
$conn->WAMP->subscriptions->detach($topic); |
|
||||||
} |
|
||||||
|
|
||||||
$this->topicLookup[$topic->getId()]->remove($conn); |
|
||||||
|
|
||||||
if ($topic->autoDelete && 0 === $topic->count()) { |
|
||||||
unset($this->topicLookup[$topic->getId()]); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,115 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Wamp; |
|
||||||
use Ratchet\ConnectionInterface; |
|
||||||
use Ratchet\AbstractConnectionDecorator; |
|
||||||
use Ratchet\Wamp\ServerProtocol as WAMP; |
|
||||||
|
|
||||||
/** |
|
||||||
* A ConnectionInterface object wrapper that is passed to your WAMP application |
|
||||||
* representing a client. Methods on this Connection are therefore different. |
|
||||||
* @property \stdClass $WAMP |
|
||||||
*/ |
|
||||||
class WampConnection extends AbstractConnectionDecorator { |
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function __construct(ConnectionInterface $conn) { |
|
||||||
parent::__construct($conn); |
|
||||||
|
|
||||||
$this->WAMP = new \StdClass; |
|
||||||
$this->WAMP->sessionId = str_replace('.', '', uniqid(mt_rand(), true)); |
|
||||||
$this->WAMP->prefixes = array(); |
|
||||||
|
|
||||||
$this->send(json_encode(array(WAMP::MSG_WELCOME, $this->WAMP->sessionId, 1, \Ratchet\VERSION))); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Successfully respond to a call made by the client |
|
||||||
* @param string $id The unique ID given by the client to respond to |
|
||||||
* @param array $data an object or array |
|
||||||
* @return WampConnection |
|
||||||
*/ |
|
||||||
public function callResult($id, $data = array()) { |
|
||||||
return $this->send(json_encode(array(WAMP::MSG_CALL_RESULT, $id, $data))); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Respond with an error to a client call |
|
||||||
* @param string $id The unique ID given by the client to respond to |
|
||||||
* @param string $errorUri The URI given to identify the specific error |
|
||||||
* @param string $desc A developer-oriented description of the error |
|
||||||
* @param string $details An optional human readable detail message to send back |
|
||||||
* @return WampConnection |
|
||||||
*/ |
|
||||||
public function callError($id, $errorUri, $desc = '', $details = null) { |
|
||||||
if ($errorUri instanceof Topic) { |
|
||||||
$errorUri = (string)$errorUri; |
|
||||||
} |
|
||||||
|
|
||||||
$data = array(WAMP::MSG_CALL_ERROR, $id, $errorUri, $desc); |
|
||||||
|
|
||||||
if (null !== $details) { |
|
||||||
$data[] = $details; |
|
||||||
} |
|
||||||
|
|
||||||
return $this->send(json_encode($data)); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @param string $topic The topic to broadcast to |
|
||||||
* @param mixed $msg Data to send with the event. Anything that is json'able |
|
||||||
* @return WampConnection |
|
||||||
*/ |
|
||||||
public function event($topic, $msg) { |
|
||||||
return $this->send(json_encode(array(WAMP::MSG_EVENT, (string)$topic, $msg))); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @param string $curie |
|
||||||
* @param string $uri |
|
||||||
* @return WampConnection |
|
||||||
*/ |
|
||||||
public function prefix($curie, $uri) { |
|
||||||
$this->WAMP->prefixes[$curie] = (string)$uri; |
|
||||||
|
|
||||||
return $this->send(json_encode(array(WAMP::MSG_PREFIX, $curie, (string)$uri))); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Get the full request URI from the connection object if a prefix has been established for it |
|
||||||
* @param string $uri |
|
||||||
* @return string |
|
||||||
*/ |
|
||||||
public function getUri($uri) { |
|
||||||
$curieSeperator = ':'; |
|
||||||
|
|
||||||
if (preg_match('/http(s*)\:\/\//', $uri) == false) { |
|
||||||
if (strpos($uri, $curieSeperator) !== false) { |
|
||||||
list($prefix, $action) = explode($curieSeperator, $uri); |
|
||||||
|
|
||||||
if(isset($this->WAMP->prefixes[$prefix]) === true){ |
|
||||||
return $this->WAMP->prefixes[$prefix] . '#' . $action; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return $uri; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @internal |
|
||||||
*/ |
|
||||||
public function send($data) { |
|
||||||
$this->getConnection()->send($data); |
|
||||||
|
|
||||||
return $this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function close($opt = null) { |
|
||||||
$this->getConnection()->close($opt); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,67 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Wamp; |
|
||||||
use Ratchet\MessageComponentInterface; |
|
||||||
use Ratchet\WebSocket\WsServerInterface; |
|
||||||
use Ratchet\ConnectionInterface; |
|
||||||
|
|
||||||
/** |
|
||||||
* Enable support for the official WAMP sub-protocol in your application |
|
||||||
* WAMP allows for Pub/Sub and RPC |
|
||||||
* @link http://wamp.ws The WAMP specification |
|
||||||
* @link https://github.com/oberstet/AutobahnJS Souce for client side library |
|
||||||
* @link http://autobahn.s3.amazonaws.com/js/autobahn.min.js Minified client side library |
|
||||||
*/ |
|
||||||
class WampServer implements MessageComponentInterface, WsServerInterface { |
|
||||||
/** |
|
||||||
* @var ServerProtocol |
|
||||||
*/ |
|
||||||
protected $wampProtocol; |
|
||||||
|
|
||||||
/** |
|
||||||
* This class just makes it 1 step easier to use Topic objects in WAMP |
|
||||||
* If you're looking at the source code, look in the __construct of this |
|
||||||
* class and use that to make your application instead of using this |
|
||||||
*/ |
|
||||||
public function __construct(WampServerInterface $app) { |
|
||||||
$this->wampProtocol = new ServerProtocol(new TopicManager($app)); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function onOpen(ConnectionInterface $conn) { |
|
||||||
$this->wampProtocol->onOpen($conn); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function onMessage(ConnectionInterface $conn, $msg) { |
|
||||||
try { |
|
||||||
$this->wampProtocol->onMessage($conn, $msg); |
|
||||||
} catch (Exception $we) { |
|
||||||
$conn->close(1007); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function onClose(ConnectionInterface $conn) { |
|
||||||
$this->wampProtocol->onClose($conn); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function onError(ConnectionInterface $conn, \Exception $e) { |
|
||||||
$this->wampProtocol->onError($conn, $e); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function getSubProtocols() { |
|
||||||
return $this->wampProtocol->getSubProtocols(); |
|
||||||
} |
|
||||||
} |
|
@ -1,43 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Wamp; |
|
||||||
use Ratchet\ComponentInterface; |
|
||||||
use Ratchet\ConnectionInterface; |
|
||||||
|
|
||||||
/** |
|
||||||
* An extension of Ratchet\ComponentInterface to server a WAMP application |
|
||||||
* onMessage is replaced by various types of messages for this protocol (pub/sub or rpc) |
|
||||||
*/ |
|
||||||
interface WampServerInterface extends ComponentInterface { |
|
||||||
/** |
|
||||||
* An RPC call has been received |
|
||||||
* @param \Ratchet\ConnectionInterface $conn |
|
||||||
* @param string $id The unique ID of the RPC, required to respond to |
|
||||||
* @param string|Topic $topic The topic to execute the call against |
|
||||||
* @param array $params Call parameters received from the client |
|
||||||
*/ |
|
||||||
function onCall(ConnectionInterface $conn, $id, $topic, array $params); |
|
||||||
|
|
||||||
/** |
|
||||||
* A request to subscribe to a topic has been made |
|
||||||
* @param \Ratchet\ConnectionInterface $conn |
|
||||||
* @param string|Topic $topic The topic to subscribe to |
|
||||||
*/ |
|
||||||
function onSubscribe(ConnectionInterface $conn, $topic); |
|
||||||
|
|
||||||
/** |
|
||||||
* A request to unsubscribe from a topic has been made |
|
||||||
* @param \Ratchet\ConnectionInterface $conn |
|
||||||
* @param string|Topic $topic The topic to unsubscribe from |
|
||||||
*/ |
|
||||||
function onUnSubscribe(ConnectionInterface $conn, $topic); |
|
||||||
|
|
||||||
/** |
|
||||||
* A client is attempting to publish content to a subscribed connections on a URI |
|
||||||
* @param \Ratchet\ConnectionInterface $conn |
|
||||||
* @param string|Topic $topic The topic the user has attempted to publish to |
|
||||||
* @param string $event Payload of the publish |
|
||||||
* @param array $exclude A list of session IDs the message should be excluded from (blacklist) |
|
||||||
* @param array $eligible A list of session Ids the message should be send to (whitelist) |
|
||||||
*/ |
|
||||||
function onPublish(ConnectionInterface $conn, $topic, $event, array $exclude, array $eligible); |
|
||||||
} |
|
@ -1,20 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\WebSocket; |
|
||||||
use Ratchet\RFC6455\Messaging\MessageBuffer; |
|
||||||
|
|
||||||
class ConnContext { |
|
||||||
/** |
|
||||||
* @var \Ratchet\WebSocket\WsConnection |
|
||||||
*/ |
|
||||||
public $connection; |
|
||||||
|
|
||||||
/** |
|
||||||
* @var \Ratchet\RFC6455\Messaging\MessageBuffer; |
|
||||||
*/ |
|
||||||
public $buffer; |
|
||||||
|
|
||||||
public function __construct(WsConnection $conn, MessageBuffer $buffer) { |
|
||||||
$this->connection = $conn; |
|
||||||
$this->buffer = $buffer; |
|
||||||
} |
|
||||||
} |
|
@ -1,8 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\WebSocket; |
|
||||||
use Ratchet\ConnectionInterface; |
|
||||||
use Ratchet\RFC6455\Messaging\MessageInterface; |
|
||||||
|
|
||||||
interface MessageCallableInterface { |
|
||||||
public function onMessage(ConnectionInterface $conn, MessageInterface $msg); |
|
||||||
} |
|
@ -1,6 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\WebSocket; |
|
||||||
use Ratchet\ComponentInterface; |
|
||||||
|
|
||||||
interface MessageComponentInterface extends ComponentInterface, MessageCallableInterface { |
|
||||||
} |
|
@ -1,45 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\WebSocket; |
|
||||||
use Ratchet\AbstractConnectionDecorator; |
|
||||||
use Ratchet\RFC6455\Messaging\DataInterface; |
|
||||||
use Ratchet\RFC6455\Messaging\Frame; |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
* @property \StdClass $WebSocket |
|
||||||
*/ |
|
||||||
class WsConnection extends AbstractConnectionDecorator { |
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function send($msg) { |
|
||||||
if (!$this->WebSocket->closing) { |
|
||||||
if (!($msg instanceof DataInterface)) { |
|
||||||
$msg = new Frame($msg); |
|
||||||
} |
|
||||||
|
|
||||||
$this->getConnection()->send($msg->getContents()); |
|
||||||
} |
|
||||||
|
|
||||||
return $this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @param int|\Ratchet\RFC6455\Messaging\DataInterface |
|
||||||
*/ |
|
||||||
public function close($code = 1000) { |
|
||||||
if ($this->WebSocket->closing) { |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
if ($code instanceof DataInterface) { |
|
||||||
$this->send($code); |
|
||||||
} else { |
|
||||||
$this->send(new Frame(pack('n', $code), true, Frame::OP_CLOSE)); |
|
||||||
} |
|
||||||
|
|
||||||
$this->getConnection()->close(); |
|
||||||
|
|
||||||
$this->WebSocket->closing = true; |
|
||||||
} |
|
||||||
} |
|
@ -1,221 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\WebSocket; |
|
||||||
use Ratchet\ComponentInterface; |
|
||||||
use Ratchet\ConnectionInterface; |
|
||||||
use Ratchet\MessageComponentInterface as DataComponentInterface; |
|
||||||
use Ratchet\Http\HttpServerInterface; |
|
||||||
use Ratchet\Http\CloseResponseTrait; |
|
||||||
use Psr\Http\Message\RequestInterface; |
|
||||||
use Ratchet\RFC6455\Messaging\MessageInterface; |
|
||||||
use Ratchet\RFC6455\Messaging\FrameInterface; |
|
||||||
use Ratchet\RFC6455\Messaging\Frame; |
|
||||||
use Ratchet\RFC6455\Messaging\MessageBuffer; |
|
||||||
use Ratchet\RFC6455\Messaging\CloseFrameChecker; |
|
||||||
use Ratchet\RFC6455\Handshake\ServerNegotiator; |
|
||||||
use Ratchet\RFC6455\Handshake\RequestVerifier; |
|
||||||
use React\EventLoop\LoopInterface; |
|
||||||
use GuzzleHttp\Psr7 as gPsr; |
|
||||||
|
|
||||||
/** |
|
||||||
* The adapter to handle WebSocket requests/responses |
|
||||||
* This is a mediator between the Server and your application to handle real-time messaging through a web browser |
|
||||||
* @link http://ca.php.net/manual/en/ref.http.php |
|
||||||
* @link http://dev.w3.org/html5/websockets/ |
|
||||||
*/ |
|
||||||
class WsServer implements HttpServerInterface { |
|
||||||
use CloseResponseTrait; |
|
||||||
|
|
||||||
/** |
|
||||||
* Decorated component |
|
||||||
* @var \Ratchet\ComponentInterface |
|
||||||
*/ |
|
||||||
private $delegate; |
|
||||||
|
|
||||||
/** |
|
||||||
* @var \SplObjectStorage |
|
||||||
*/ |
|
||||||
protected $connections; |
|
||||||
|
|
||||||
/** |
|
||||||
* @var \Ratchet\RFC6455\Messaging\CloseFrameChecker |
|
||||||
*/ |
|
||||||
private $closeFrameChecker; |
|
||||||
|
|
||||||
/** |
|
||||||
* @var \Ratchet\RFC6455\Handshake\ServerNegotiator |
|
||||||
*/ |
|
||||||
private $handshakeNegotiator; |
|
||||||
|
|
||||||
/** |
|
||||||
* @var \Closure |
|
||||||
*/ |
|
||||||
private $ueFlowFactory; |
|
||||||
|
|
||||||
/** |
|
||||||
* @var \Closure |
|
||||||
*/ |
|
||||||
private $pongReceiver; |
|
||||||
|
|
||||||
/** |
|
||||||
* @var \Closure |
|
||||||
*/ |
|
||||||
private $msgCb; |
|
||||||
|
|
||||||
/** |
|
||||||
* @param \Ratchet\WebSocket\MessageComponentInterface|\Ratchet\MessageComponentInterface $component Your application to run with WebSockets |
|
||||||
* @note If you want to enable sub-protocols have your component implement WsServerInterface as well |
|
||||||
*/ |
|
||||||
public function __construct(ComponentInterface $component) { |
|
||||||
if ($component instanceof MessageComponentInterface) { |
|
||||||
$this->msgCb = function(ConnectionInterface $conn, MessageInterface $msg) { |
|
||||||
$this->delegate->onMessage($conn, $msg); |
|
||||||
}; |
|
||||||
} elseif ($component instanceof DataComponentInterface) { |
|
||||||
$this->msgCb = function(ConnectionInterface $conn, MessageInterface $msg) { |
|
||||||
$this->delegate->onMessage($conn, $msg->getPayload()); |
|
||||||
}; |
|
||||||
} else { |
|
||||||
throw new \UnexpectedValueException('Expected instance of \Ratchet\WebSocket\MessageComponentInterface or \Ratchet\MessageComponentInterface'); |
|
||||||
} |
|
||||||
|
|
||||||
$this->delegate = $component; |
|
||||||
$this->connections = new \SplObjectStorage; |
|
||||||
|
|
||||||
$this->closeFrameChecker = new CloseFrameChecker; |
|
||||||
$this->handshakeNegotiator = new ServerNegotiator(new RequestVerifier); |
|
||||||
$this->handshakeNegotiator->setStrictSubProtocolCheck(true); |
|
||||||
|
|
||||||
if ($component instanceof WsServerInterface) { |
|
||||||
$this->handshakeNegotiator->setSupportedSubProtocols($component->getSubProtocols()); |
|
||||||
} |
|
||||||
|
|
||||||
$this->pongReceiver = function() {}; |
|
||||||
|
|
||||||
$reusableUnderflowException = new \UnderflowException; |
|
||||||
$this->ueFlowFactory = function() use ($reusableUnderflowException) { |
|
||||||
return $reusableUnderflowException; |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function onOpen(ConnectionInterface $conn, RequestInterface $request = null) { |
|
||||||
if (null === $request) { |
|
||||||
throw new \UnexpectedValueException('$request can not be null'); |
|
||||||
} |
|
||||||
|
|
||||||
$conn->httpRequest = $request; |
|
||||||
|
|
||||||
$conn->WebSocket = new \StdClass; |
|
||||||
$conn->WebSocket->closing = false; |
|
||||||
|
|
||||||
$response = $this->handshakeNegotiator->handshake($request)->withHeader('X-Powered-By', \Ratchet\VERSION); |
|
||||||
|
|
||||||
$conn->send(gPsr\str($response)); |
|
||||||
|
|
||||||
if (101 !== $response->getStatusCode()) { |
|
||||||
return $conn->close(); |
|
||||||
} |
|
||||||
|
|
||||||
$wsConn = new WsConnection($conn); |
|
||||||
|
|
||||||
$streamer = new MessageBuffer( |
|
||||||
$this->closeFrameChecker, |
|
||||||
function(MessageInterface $msg) use ($wsConn) { |
|
||||||
$cb = $this->msgCb; |
|
||||||
$cb($wsConn, $msg); |
|
||||||
}, |
|
||||||
function(FrameInterface $frame) use ($wsConn) { |
|
||||||
$this->onControlFrame($frame, $wsConn); |
|
||||||
}, |
|
||||||
true, |
|
||||||
$this->ueFlowFactory |
|
||||||
); |
|
||||||
|
|
||||||
$this->connections->attach($conn, new ConnContext($wsConn, $streamer)); |
|
||||||
|
|
||||||
return $this->delegate->onOpen($wsConn); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function onMessage(ConnectionInterface $from, $msg) { |
|
||||||
if ($from->WebSocket->closing) { |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
$this->connections[$from]->buffer->onData($msg); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function onClose(ConnectionInterface $conn) { |
|
||||||
if ($this->connections->contains($conn)) { |
|
||||||
$context = $this->connections[$conn]; |
|
||||||
$this->connections->detach($conn); |
|
||||||
|
|
||||||
$this->delegate->onClose($context->connection); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* {@inheritdoc} |
|
||||||
*/ |
|
||||||
public function onError(ConnectionInterface $conn, \Exception $e) { |
|
||||||
if ($this->connections->contains($conn)) { |
|
||||||
$this->delegate->onError($this->connections[$conn]->connection, $e); |
|
||||||
} else { |
|
||||||
$conn->close(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public function onControlFrame(FrameInterface $frame, WsConnection $conn) { |
|
||||||
switch ($frame->getOpCode()) { |
|
||||||
case Frame::OP_CLOSE: |
|
||||||
$conn->close($frame); |
|
||||||
break; |
|
||||||
case Frame::OP_PING: |
|
||||||
$conn->send(new Frame($frame->getPayload(), true, Frame::OP_PONG)); |
|
||||||
break; |
|
||||||
case Frame::OP_PONG: |
|
||||||
$pongReceiver = $this->pongReceiver; |
|
||||||
$pongReceiver($frame, $conn); |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public function setStrictSubProtocolCheck($enable) { |
|
||||||
$this->handshakeNegotiator->setStrictSubProtocolCheck($enable); |
|
||||||
} |
|
||||||
|
|
||||||
public function enableKeepAlive(LoopInterface $loop, $interval = 30) { |
|
||||||
$lastPing = new Frame(uniqid(), true, Frame::OP_PING); |
|
||||||
$pingedConnections = new \SplObjectStorage; |
|
||||||
$splClearer = new \SplObjectStorage; |
|
||||||
|
|
||||||
$this->pongReceiver = function(FrameInterface $frame, $wsConn) use ($pingedConnections, &$lastPing) { |
|
||||||
if ($frame->getPayload() === $lastPing->getPayload()) { |
|
||||||
$pingedConnections->detach($wsConn); |
|
||||||
} |
|
||||||
}; |
|
||||||
|
|
||||||
$loop->addPeriodicTimer((int)$interval, function() use ($pingedConnections, &$lastPing, $splClearer) { |
|
||||||
foreach ($pingedConnections as $wsConn) { |
|
||||||
$wsConn->close(); |
|
||||||
} |
|
||||||
$pingedConnections->removeAllExcept($splClearer); |
|
||||||
|
|
||||||
$lastPing = new Frame(uniqid(), true, Frame::OP_PING); |
|
||||||
|
|
||||||
foreach ($this->connections as $key => $conn) { |
|
||||||
$wsConn = $this->connections[$conn]->connection; |
|
||||||
|
|
||||||
$wsConn->send($lastPing); |
|
||||||
$pingedConnections->attach($wsConn); |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
} |
|
@ -1,14 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\WebSocket; |
|
||||||
|
|
||||||
/** |
|
||||||
* WebSocket Server Interface |
|
||||||
*/ |
|
||||||
interface WsServerInterface { |
|
||||||
/** |
|
||||||
* If any component in a stack supports a WebSocket sub-protocol return each supported in an array |
|
||||||
* @return array |
|
||||||
* @todo This method may be removed in future version (note that will not break code, just make some code obsolete) |
|
||||||
*/ |
|
||||||
function getSubProtocols(); |
|
||||||
} |
|
@ -1,38 +0,0 @@ |
|||||||
<?php |
|
||||||
use Ratchet\ConnectionInterface; |
|
||||||
|
|
||||||
require dirname(dirname(dirname(__DIR__))) . '/vendor/autoload.php'; |
|
||||||
|
|
||||||
class BinaryEcho implements \Ratchet\WebSocket\MessageComponentInterface { |
|
||||||
public function onMessage(ConnectionInterface $from, \Ratchet\RFC6455\Messaging\MessageInterface $msg) { |
|
||||||
$from->send($msg); |
|
||||||
} |
|
||||||
|
|
||||||
public function onOpen(ConnectionInterface $conn) { |
|
||||||
} |
|
||||||
|
|
||||||
public function onClose(ConnectionInterface $conn) { |
|
||||||
} |
|
||||||
|
|
||||||
public function onError(ConnectionInterface $conn, \Exception $e) { |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
$port = $argc > 1 ? $argv[1] : 8000; |
|
||||||
$impl = sprintf('React\EventLoop\%sLoop', $argc > 2 ? $argv[2] : 'StreamSelect'); |
|
||||||
|
|
||||||
$loop = new $impl; |
|
||||||
$sock = new React\Socket\Server($loop); |
|
||||||
|
|
||||||
$wsServer = new Ratchet\WebSocket\WsServer(new BinaryEcho); |
|
||||||
// This is enabled to test https://github.com/ratchetphp/Ratchet/issues/430 |
|
||||||
// The time is left at 10 minutes so that it will not try to every ping anything |
|
||||||
// This causes the Ratchet server to crash on test 2.7 |
|
||||||
$wsServer->enableKeepAlive($loop, 600); |
|
||||||
|
|
||||||
$app = new Ratchet\Http\HttpServer($wsServer); |
|
||||||
|
|
||||||
$sock->listen($port, '0.0.0.0'); |
|
||||||
|
|
||||||
$server = new Ratchet\Server\IoServer($app, $sock, $loop); |
|
||||||
$server->run(); |
|
@ -1,15 +0,0 @@ |
|||||||
{ |
|
||||||
"options": {"failByDrop": false} |
|
||||||
, "outdir": "reports/ab" |
|
||||||
|
|
||||||
, "servers": [ |
|
||||||
{"agent": "Ratchet/0.4 libevent", "url": "ws://localhost:8001", "options": {"version": 18}} |
|
||||||
, {"agent": "Ratchet/0.4 libev", "url": "ws://localhost:8004", "options": {"version": 18}} |
|
||||||
, {"agent": "Ratchet/0.4 streams", "url": "ws://localhost:8002", "options": {"version": 18}} |
|
||||||
, {"agent": "AutobahnTestSuite/0.5.9", "url": "ws://localhost:8000", "options": {"version": 18}} |
|
||||||
] |
|
||||||
|
|
||||||
, "cases": ["*"] |
|
||||||
, "exclude-cases": [] |
|
||||||
, "exclude-agent-cases": {} |
|
||||||
} |
|
@ -1,12 +0,0 @@ |
|||||||
{ |
|
||||||
"options": {"failByDrop": false} |
|
||||||
, "outdir": "reports/profile" |
|
||||||
|
|
||||||
, "servers": [ |
|
||||||
{"agent": "Ratchet", "url": "ws://localhost:8000", "options": {"version": 18}} |
|
||||||
] |
|
||||||
|
|
||||||
, "cases": ["9.7.4"] |
|
||||||
, "exclude-cases": ["1.2.*", "2.3", "2.4", "2.6", "9.2.*", "9.4.*", "9.6.*", "9.8.*"] |
|
||||||
, "exclude-agent-cases": {} |
|
||||||
} |
|
@ -1,12 +0,0 @@ |
|||||||
{ |
|
||||||
"options": {"failByDrop": false} |
|
||||||
, "outdir": "reports/rfc" |
|
||||||
|
|
||||||
, "servers": [ |
|
||||||
{"agent": "Ratchet", "url": "ws://localhost:8000", "options": {"version": 18}} |
|
||||||
] |
|
||||||
|
|
||||||
, "cases": ["*"] |
|
||||||
, "exclude-cases": [] |
|
||||||
, "exclude-agent-cases": {} |
|
||||||
} |
|
@ -1,4 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
$loader = require __DIR__ . '/../vendor/autoload.php'; |
|
||||||
$loader->addPsr4('Ratchet\\', __DIR__ . '/helpers/Ratchet'); |
|
@ -1,50 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet; |
|
||||||
|
|
||||||
abstract class AbstractMessageComponentTestCase extends \PHPUnit_Framework_TestCase { |
|
||||||
protected $_app; |
|
||||||
protected $_serv; |
|
||||||
protected $_conn; |
|
||||||
|
|
||||||
abstract public function getConnectionClassString(); |
|
||||||
abstract public function getDecoratorClassString(); |
|
||||||
abstract public function getComponentClassString(); |
|
||||||
|
|
||||||
public function setUp() { |
|
||||||
$this->_app = $this->getMock($this->getComponentClassString()); |
|
||||||
$decorator = $this->getDecoratorClassString(); |
|
||||||
$this->_serv = new $decorator($this->_app); |
|
||||||
$this->_conn = $this->getMock('\Ratchet\ConnectionInterface'); |
|
||||||
|
|
||||||
$this->doOpen($this->_conn); |
|
||||||
} |
|
||||||
|
|
||||||
protected function doOpen($conn) { |
|
||||||
$this->_serv->onOpen($conn); |
|
||||||
} |
|
||||||
|
|
||||||
public function isExpectedConnection() { |
|
||||||
return new \PHPUnit_Framework_Constraint_IsInstanceOf($this->getConnectionClassString()); |
|
||||||
} |
|
||||||
|
|
||||||
public function testOpen() { |
|
||||||
$this->_app->expects($this->once())->method('onOpen')->with($this->isExpectedConnection()); |
|
||||||
$this->doOpen($this->getMock('\Ratchet\ConnectionInterface')); |
|
||||||
} |
|
||||||
|
|
||||||
public function testOnClose() { |
|
||||||
$this->_app->expects($this->once())->method('onClose')->with($this->isExpectedConnection()); |
|
||||||
$this->_serv->onClose($this->_conn); |
|
||||||
} |
|
||||||
|
|
||||||
public function testOnError() { |
|
||||||
$e = new \Exception('Whoops!'); |
|
||||||
$this->_app->expects($this->once())->method('onError')->with($this->isExpectedConnection(), $e); |
|
||||||
$this->_serv->onError($this->_conn, $e); |
|
||||||
} |
|
||||||
|
|
||||||
public function passthroughMessageTest($value) { |
|
||||||
$this->_app->expects($this->once())->method('onMessage')->with($this->isExpectedConnection(), $value); |
|
||||||
$this->_serv->onMessage($this->_conn, $value); |
|
||||||
} |
|
||||||
} |
|
@ -1,35 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Mock; |
|
||||||
use Ratchet\MessageComponentInterface; |
|
||||||
use Ratchet\WebSocket\WsServerInterface; |
|
||||||
use Ratchet\ConnectionInterface; |
|
||||||
|
|
||||||
class Component implements MessageComponentInterface, WsServerInterface { |
|
||||||
public $last = array(); |
|
||||||
|
|
||||||
public $protocols = array(); |
|
||||||
|
|
||||||
public function __construct(ComponentInterface $app = null) { |
|
||||||
$this->last[__FUNCTION__] = func_get_args(); |
|
||||||
} |
|
||||||
|
|
||||||
public function onOpen(ConnectionInterface $conn) { |
|
||||||
$this->last[__FUNCTION__] = func_get_args(); |
|
||||||
} |
|
||||||
|
|
||||||
public function onMessage(ConnectionInterface $from, $msg) { |
|
||||||
$this->last[__FUNCTION__] = func_get_args(); |
|
||||||
} |
|
||||||
|
|
||||||
public function onClose(ConnectionInterface $conn) { |
|
||||||
$this->last[__FUNCTION__] = func_get_args(); |
|
||||||
} |
|
||||||
|
|
||||||
public function onError(ConnectionInterface $conn, \Exception $e) { |
|
||||||
$this->last[__FUNCTION__] = func_get_args(); |
|
||||||
} |
|
||||||
|
|
||||||
public function getSubProtocols() { |
|
||||||
return $this->protocols; |
|
||||||
} |
|
||||||
} |
|
@ -1,20 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Mock; |
|
||||||
use Ratchet\ConnectionInterface; |
|
||||||
|
|
||||||
class Connection implements ConnectionInterface { |
|
||||||
public $last = array( |
|
||||||
'send' => '' |
|
||||||
, 'close' => false |
|
||||||
); |
|
||||||
|
|
||||||
public $remoteAddress = '127.0.0.1'; |
|
||||||
|
|
||||||
public function send($data) { |
|
||||||
$this->last[__FUNCTION__] = $data; |
|
||||||
} |
|
||||||
|
|
||||||
public function close() { |
|
||||||
$this->last[__FUNCTION__] = true; |
|
||||||
} |
|
||||||
} |
|
@ -1,22 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Mock; |
|
||||||
use Ratchet\AbstractConnectionDecorator; |
|
||||||
|
|
||||||
class ConnectionDecorator extends AbstractConnectionDecorator { |
|
||||||
public $last = array( |
|
||||||
'write' => '' |
|
||||||
, 'end' => false |
|
||||||
); |
|
||||||
|
|
||||||
public function send($data) { |
|
||||||
$this->last[__FUNCTION__] = $data; |
|
||||||
|
|
||||||
$this->getConnection()->send($data); |
|
||||||
} |
|
||||||
|
|
||||||
public function close() { |
|
||||||
$this->last[__FUNCTION__] = true; |
|
||||||
|
|
||||||
$this->getConnection()->close(); |
|
||||||
} |
|
||||||
} |
|
@ -1,43 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Mock; |
|
||||||
use Ratchet\Wamp\WampServerInterface; |
|
||||||
use Ratchet\WebSocket\WsServerInterface; |
|
||||||
use Ratchet\ConnectionInterface; |
|
||||||
|
|
||||||
class WampComponent implements WampServerInterface, WsServerInterface { |
|
||||||
public $last = array(); |
|
||||||
|
|
||||||
public $protocols = array(); |
|
||||||
|
|
||||||
public function getSubProtocols() { |
|
||||||
return $this->protocols; |
|
||||||
} |
|
||||||
|
|
||||||
public function onCall(ConnectionInterface $conn, $id, $procURI, array $params) { |
|
||||||
$this->last[__FUNCTION__] = func_get_args(); |
|
||||||
} |
|
||||||
|
|
||||||
public function onSubscribe(ConnectionInterface $conn, $topic) { |
|
||||||
$this->last[__FUNCTION__] = func_get_args(); |
|
||||||
} |
|
||||||
|
|
||||||
public function onUnSubscribe(ConnectionInterface $conn, $topic) { |
|
||||||
$this->last[__FUNCTION__] = func_get_args(); |
|
||||||
} |
|
||||||
|
|
||||||
public function onPublish(ConnectionInterface $conn, $topic, $event, array $exclude, array $eligible) { |
|
||||||
$this->last[__FUNCTION__] = func_get_args(); |
|
||||||
} |
|
||||||
|
|
||||||
public function onOpen(ConnectionInterface $conn) { |
|
||||||
$this->last[__FUNCTION__] = func_get_args(); |
|
||||||
} |
|
||||||
|
|
||||||
public function onClose(ConnectionInterface $conn) { |
|
||||||
$this->last[__FUNCTION__] = func_get_args(); |
|
||||||
} |
|
||||||
|
|
||||||
public function onError(ConnectionInterface $conn, \Exception $e) { |
|
||||||
$this->last[__FUNCTION__] = func_get_args(); |
|
||||||
} |
|
||||||
} |
|
@ -1,28 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet; |
|
||||||
use Ratchet\ConnectionInterface; |
|
||||||
use Ratchet\MessageComponentInterface; |
|
||||||
use Ratchet\WebSocket\WsServerInterface; |
|
||||||
use Ratchet\Wamp\WampServerInterface; |
|
||||||
|
|
||||||
class NullComponent implements MessageComponentInterface, WsServerInterface, WampServerInterface { |
|
||||||
public function onOpen(ConnectionInterface $conn) {} |
|
||||||
|
|
||||||
public function onMessage(ConnectionInterface $conn, $msg) {} |
|
||||||
|
|
||||||
public function onClose(ConnectionInterface $conn) {} |
|
||||||
|
|
||||||
public function onError(ConnectionInterface $conn, \Exception $e) {} |
|
||||||
|
|
||||||
public function onCall(ConnectionInterface $conn, $id, $topic, array $params) {} |
|
||||||
|
|
||||||
public function onSubscribe(ConnectionInterface $conn, $topic) {} |
|
||||||
|
|
||||||
public function onUnSubscribe(ConnectionInterface $conn, $topic) {} |
|
||||||
|
|
||||||
public function onPublish(ConnectionInterface $conn, $topic, $event, array $exclude = array(), array $eligible = array()) {} |
|
||||||
|
|
||||||
public function getSubProtocols() { |
|
||||||
return array(); |
|
||||||
} |
|
||||||
} |
|
@ -1,7 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Wamp\Stub; |
|
||||||
use Ratchet\WebSocket\WsServerInterface; |
|
||||||
use Ratchet\Wamp\WampServerInterface; |
|
||||||
|
|
||||||
interface WsWampServerInterface extends WsServerInterface, WampServerInterface { |
|
||||||
} |
|
@ -1,7 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\WebSocket\Stub; |
|
||||||
use Ratchet\MessageComponentInterface; |
|
||||||
use Ratchet\WebSocket\WsServerInterface; |
|
||||||
|
|
||||||
interface WsMessageComponentInterface extends MessageComponentInterface, WsServerInterface { |
|
||||||
} |
|
@ -1,147 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet; |
|
||||||
use Ratchet\Mock\ConnectionDecorator; |
|
||||||
|
|
||||||
/** |
|
||||||
* @covers Ratchet\AbstractConnectionDecorator |
|
||||||
* @covers Ratchet\ConnectionInterface |
|
||||||
*/ |
|
||||||
class AbstractConnectionDecoratorTest extends \PHPUnit_Framework_TestCase { |
|
||||||
protected $mock; |
|
||||||
protected $l1; |
|
||||||
protected $l2; |
|
||||||
|
|
||||||
public function setUp() { |
|
||||||
$this->mock = $this->getMock('\Ratchet\ConnectionInterface'); |
|
||||||
$this->l1 = new ConnectionDecorator($this->mock); |
|
||||||
$this->l2 = new ConnectionDecorator($this->l1); |
|
||||||
} |
|
||||||
|
|
||||||
public function testGet() { |
|
||||||
$var = 'hello'; |
|
||||||
$val = 'world'; |
|
||||||
|
|
||||||
$this->mock->$var = $val; |
|
||||||
|
|
||||||
$this->assertEquals($val, $this->l1->$var); |
|
||||||
$this->assertEquals($val, $this->l2->$var); |
|
||||||
} |
|
||||||
|
|
||||||
public function testSet() { |
|
||||||
$var = 'Chris'; |
|
||||||
$val = 'Boden'; |
|
||||||
|
|
||||||
$this->l1->$var = $val; |
|
||||||
|
|
||||||
$this->assertEquals($val, $this->mock->$var); |
|
||||||
} |
|
||||||
|
|
||||||
public function testSetLevel2() { |
|
||||||
$var = 'Try'; |
|
||||||
$val = 'Again'; |
|
||||||
|
|
||||||
$this->l2->$var = $val; |
|
||||||
|
|
||||||
$this->assertEquals($val, $this->mock->$var); |
|
||||||
} |
|
||||||
|
|
||||||
public function testIsSetTrue() { |
|
||||||
$var = 'PHP'; |
|
||||||
$val = 'Ratchet'; |
|
||||||
|
|
||||||
$this->mock->$var = $val; |
|
||||||
|
|
||||||
$this->assertTrue(isset($this->l1->$var)); |
|
||||||
$this->assertTrue(isset($this->l2->$var)); |
|
||||||
} |
|
||||||
|
|
||||||
public function testIsSetFalse() { |
|
||||||
$var = 'herp'; |
|
||||||
$val = 'derp'; |
|
||||||
|
|
||||||
$this->assertFalse(isset($this->l1->$var)); |
|
||||||
$this->assertFalse(isset($this->l2->$var)); |
|
||||||
} |
|
||||||
|
|
||||||
public function testUnset() { |
|
||||||
$var = 'Flying'; |
|
||||||
$val = 'Monkey'; |
|
||||||
|
|
||||||
$this->mock->$var = $val; |
|
||||||
unset($this->l1->$var); |
|
||||||
|
|
||||||
$this->assertFalse(isset($this->mock->$var)); |
|
||||||
} |
|
||||||
|
|
||||||
public function testUnsetLevel2() { |
|
||||||
$var = 'Flying'; |
|
||||||
$val = 'Monkey'; |
|
||||||
|
|
||||||
$this->mock->$var = $val; |
|
||||||
unset($this->l2->$var); |
|
||||||
|
|
||||||
$this->assertFalse(isset($this->mock->$var)); |
|
||||||
} |
|
||||||
|
|
||||||
public function testGetConnection() { |
|
||||||
$class = new \ReflectionClass('\\Ratchet\\AbstractConnectionDecorator'); |
|
||||||
$method = $class->getMethod('getConnection'); |
|
||||||
$method->setAccessible(true); |
|
||||||
|
|
||||||
$conn = $method->invokeArgs($this->l1, array()); |
|
||||||
|
|
||||||
$this->assertSame($this->mock, $conn); |
|
||||||
} |
|
||||||
|
|
||||||
public function testGetConnectionLevel2() { |
|
||||||
$class = new \ReflectionClass('\\Ratchet\\AbstractConnectionDecorator'); |
|
||||||
$method = $class->getMethod('getConnection'); |
|
||||||
$method->setAccessible(true); |
|
||||||
|
|
||||||
$conn = $method->invokeArgs($this->l2, array()); |
|
||||||
|
|
||||||
$this->assertSame($this->l1, $conn); |
|
||||||
} |
|
||||||
|
|
||||||
public function testWrapperCanStoreSelfInDecorator() { |
|
||||||
$this->mock->decorator = $this->l1; |
|
||||||
|
|
||||||
$this->assertSame($this->l1, $this->l2->decorator); |
|
||||||
} |
|
||||||
|
|
||||||
public function testDecoratorRecursion() { |
|
||||||
$this->mock->decorator = new \stdClass; |
|
||||||
$this->mock->decorator->conn = $this->l1; |
|
||||||
|
|
||||||
$this->assertSame($this->l1, $this->mock->decorator->conn); |
|
||||||
$this->assertSame($this->l1, $this->l1->decorator->conn); |
|
||||||
$this->assertSame($this->l1, $this->l2->decorator->conn); |
|
||||||
} |
|
||||||
|
|
||||||
public function testDecoratorRecursionLevel2() { |
|
||||||
$this->mock->decorator = new \stdClass; |
|
||||||
$this->mock->decorator->conn = $this->l2; |
|
||||||
|
|
||||||
$this->assertSame($this->l2, $this->mock->decorator->conn); |
|
||||||
$this->assertSame($this->l2, $this->l1->decorator->conn); |
|
||||||
$this->assertSame($this->l2, $this->l2->decorator->conn); |
|
||||||
|
|
||||||
// just for fun |
|
||||||
$this->assertSame($this->l2, $this->l2->decorator->conn->decorator->conn->decorator->conn); |
|
||||||
} |
|
||||||
|
|
||||||
public function testWarningGettingNothing() { |
|
||||||
$this->setExpectedException('PHPUnit_Framework_Error'); |
|
||||||
$var = $this->mock->nonExistant; |
|
||||||
} |
|
||||||
|
|
||||||
public function testWarningGettingNothingLevel1() { |
|
||||||
$this->setExpectedException('PHPUnit_Framework_Error'); |
|
||||||
$var = $this->l1->nonExistant; |
|
||||||
} |
|
||||||
|
|
||||||
public function testWarningGettingNothingLevel2() { |
|
||||||
$this->setExpectedException('PHPUnit_Framework_Error'); |
|
||||||
$var = $this->l2->nonExistant; |
|
||||||
} |
|
||||||
} |
|
@ -1,50 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Http; |
|
||||||
|
|
||||||
/** |
|
||||||
* @covers Ratchet\Http\HttpRequestParser |
|
||||||
*/ |
|
||||||
class HttpRequestParserTest extends \PHPUnit_Framework_TestCase { |
|
||||||
protected $parser; |
|
||||||
|
|
||||||
public function setUp() { |
|
||||||
$this->parser = new HttpRequestParser; |
|
||||||
} |
|
||||||
|
|
||||||
public function headersProvider() { |
|
||||||
return array( |
|
||||||
array(false, "GET / HTTP/1.1\r\nHost: socketo.me\r\n") |
|
||||||
, array(true, "GET / HTTP/1.1\r\nHost: socketo.me\r\n\r\n") |
|
||||||
, array(true, "GET / HTTP/1.1\r\nHost: socketo.me\r\n\r\n1") |
|
||||||
, array(true, "GET / HTTP/1.1\r\nHost: socketo.me\r\n\r\nHixie✖") |
|
||||||
, array(true, "GET / HTTP/1.1\r\nHost: socketo.me\r\n\r\nHixie✖\r\n\r\n") |
|
||||||
, array(true, "GET / HTTP/1.1\r\nHost: socketo.me\r\n\r\nHixie\r\n") |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @dataProvider headersProvider |
|
||||||
*/ |
|
||||||
public function testIsEom($expected, $message) { |
|
||||||
$this->assertEquals($expected, $this->parser->isEom($message)); |
|
||||||
} |
|
||||||
|
|
||||||
public function testBufferOverflowResponse() { |
|
||||||
$conn = $this->getMock('\Ratchet\ConnectionInterface'); |
|
||||||
|
|
||||||
$this->parser->maxSize = 20; |
|
||||||
|
|
||||||
$this->assertNull($this->parser->onMessage($conn, "GET / HTTP/1.1\r\n")); |
|
||||||
|
|
||||||
$this->setExpectedException('OverflowException'); |
|
||||||
|
|
||||||
$this->parser->onMessage($conn, "Header-Is: Too Big"); |
|
||||||
} |
|
||||||
|
|
||||||
public function testReturnTypeIsRequest() { |
|
||||||
$conn = $this->getMock('\Ratchet\ConnectionInterface'); |
|
||||||
$return = $this->parser->onMessage($conn, "GET / HTTP/1.1\r\nHost: socketo.me\r\n\r\n"); |
|
||||||
|
|
||||||
$this->assertInstanceOf('\Psr\Http\Message\RequestInterface', $return); |
|
||||||
} |
|
||||||
} |
|
@ -1,64 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Http; |
|
||||||
use Ratchet\AbstractMessageComponentTestCase; |
|
||||||
|
|
||||||
/** |
|
||||||
* @covers Ratchet\Http\HttpServer |
|
||||||
*/ |
|
||||||
class HttpServerTest extends AbstractMessageComponentTestCase { |
|
||||||
public function setUp() { |
|
||||||
parent::setUp(); |
|
||||||
$this->_conn->httpHeadersReceived = true; |
|
||||||
} |
|
||||||
|
|
||||||
public function getConnectionClassString() { |
|
||||||
return '\Ratchet\ConnectionInterface'; |
|
||||||
} |
|
||||||
|
|
||||||
public function getDecoratorClassString() { |
|
||||||
return '\Ratchet\Http\HttpServer'; |
|
||||||
} |
|
||||||
|
|
||||||
public function getComponentClassString() { |
|
||||||
return '\Ratchet\Http\HttpServerInterface'; |
|
||||||
} |
|
||||||
|
|
||||||
public function testOpen() { |
|
||||||
$headers = "GET / HTTP/1.1\r\nHost: socketo.me\r\n\r\n"; |
|
||||||
|
|
||||||
$this->_conn->httpHeadersReceived = false; |
|
||||||
$this->_app->expects($this->once())->method('onOpen')->with($this->isExpectedConnection()); |
|
||||||
$this->_serv->onMessage($this->_conn, $headers); |
|
||||||
} |
|
||||||
|
|
||||||
public function testOnMessageAfterHeaders() { |
|
||||||
$headers = "GET / HTTP/1.1\r\nHost: socketo.me\r\n\r\n"; |
|
||||||
$this->_conn->httpHeadersReceived = false; |
|
||||||
$this->_serv->onMessage($this->_conn, $headers); |
|
||||||
|
|
||||||
$message = "Hello World!"; |
|
||||||
$this->_app->expects($this->once())->method('onMessage')->with($this->isExpectedConnection(), $message); |
|
||||||
$this->_serv->onMessage($this->_conn, $message); |
|
||||||
} |
|
||||||
|
|
||||||
public function testBufferOverflow() { |
|
||||||
$this->_conn->expects($this->once())->method('close'); |
|
||||||
$this->_conn->httpHeadersReceived = false; |
|
||||||
|
|
||||||
$this->_serv->onMessage($this->_conn, str_repeat('a', 5000)); |
|
||||||
} |
|
||||||
|
|
||||||
public function testCloseIfNotEstablished() { |
|
||||||
$this->_conn->httpHeadersReceived = false; |
|
||||||
$this->_conn->expects($this->once())->method('close'); |
|
||||||
$this->_serv->onError($this->_conn, new \Exception('Whoops!')); |
|
||||||
} |
|
||||||
|
|
||||||
public function testBufferHeaders() { |
|
||||||
$this->_conn->httpHeadersReceived = false; |
|
||||||
$this->_app->expects($this->never())->method('onOpen'); |
|
||||||
$this->_app->expects($this->never())->method('onMessage'); |
|
||||||
|
|
||||||
$this->_serv->onMessage($this->_conn, "GET / HTTP/1.1"); |
|
||||||
} |
|
||||||
} |
|
@ -1,46 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Http; |
|
||||||
use Ratchet\AbstractMessageComponentTestCase; |
|
||||||
|
|
||||||
/** |
|
||||||
* @covers Ratchet\Http\OriginCheck |
|
||||||
*/ |
|
||||||
class OriginCheckTest extends AbstractMessageComponentTestCase { |
|
||||||
protected $_reqStub; |
|
||||||
|
|
||||||
public function setUp() { |
|
||||||
$this->_reqStub = $this->getMock('Psr\Http\Message\RequestInterface'); |
|
||||||
$this->_reqStub->expects($this->any())->method('getHeader')->will($this->returnValue(['localhost'])); |
|
||||||
|
|
||||||
parent::setUp(); |
|
||||||
|
|
||||||
$this->_serv->allowedOrigins[] = 'localhost'; |
|
||||||
} |
|
||||||
|
|
||||||
protected function doOpen($conn) { |
|
||||||
$this->_serv->onOpen($conn, $this->_reqStub); |
|
||||||
} |
|
||||||
|
|
||||||
public function getConnectionClassString() { |
|
||||||
return '\Ratchet\ConnectionInterface'; |
|
||||||
} |
|
||||||
|
|
||||||
public function getDecoratorClassString() { |
|
||||||
return '\Ratchet\Http\OriginCheck'; |
|
||||||
} |
|
||||||
|
|
||||||
public function getComponentClassString() { |
|
||||||
return '\Ratchet\Http\HttpServerInterface'; |
|
||||||
} |
|
||||||
|
|
||||||
public function testCloseOnNonMatchingOrigin() { |
|
||||||
$this->_serv->allowedOrigins = ['socketo.me']; |
|
||||||
$this->_conn->expects($this->once())->method('close'); |
|
||||||
|
|
||||||
$this->_serv->onOpen($this->_conn, $this->_reqStub); |
|
||||||
} |
|
||||||
|
|
||||||
public function testOnMessage() { |
|
||||||
$this->passthroughMessageTest('Hello World!'); |
|
||||||
} |
|
||||||
} |
|
@ -1,143 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Http; |
|
||||||
use Ratchet\WebSocket\WsServerInterface; |
|
||||||
use Symfony\Component\Routing\Exception\ResourceNotFoundException; |
|
||||||
use Symfony\Component\Routing\Matcher\UrlMatcherInterface; |
|
||||||
|
|
||||||
/** |
|
||||||
* @covers Ratchet\Http\Router |
|
||||||
*/ |
|
||||||
class RouterTest extends \PHPUnit_Framework_TestCase { |
|
||||||
protected $_router; |
|
||||||
protected $_matcher; |
|
||||||
protected $_conn; |
|
||||||
protected $_uri; |
|
||||||
protected $_req; |
|
||||||
|
|
||||||
public function setUp() { |
|
||||||
$this->_conn = $this->getMock('\Ratchet\ConnectionInterface'); |
|
||||||
$this->_uri = $this->getMock('Psr\Http\Message\UriInterface'); |
|
||||||
$this->_req = $this->getMock('\Psr\Http\Message\RequestInterface'); |
|
||||||
$this->_req |
|
||||||
->expects($this->any()) |
|
||||||
->method('getUri') |
|
||||||
->will($this->returnValue($this->_uri)); |
|
||||||
$this->_matcher = $this->getMock('Symfony\Component\Routing\Matcher\UrlMatcherInterface'); |
|
||||||
$this->_matcher |
|
||||||
->expects($this->any()) |
|
||||||
->method('getContext') |
|
||||||
->will($this->returnValue($this->getMock('Symfony\Component\Routing\RequestContext'))); |
|
||||||
$this->_router = new Router($this->_matcher); |
|
||||||
|
|
||||||
$this->_uri->expects($this->any())->method('getPath')->will($this->returnValue('ws://doesnt.matter/')); |
|
||||||
$this->_uri->expects($this->any())->method('withQuery')->with($this->callback(function($val) { |
|
||||||
$this->setResult($val); |
|
||||||
|
|
||||||
return true; |
|
||||||
}))->will($this->returnSelf()); |
|
||||||
$this->_uri->expects($this->any())->method('getQuery')->will($this->returnCallback([$this, 'getResult'])); |
|
||||||
$this->_req->expects($this->any())->method('withUri')->will($this->returnSelf()); |
|
||||||
} |
|
||||||
|
|
||||||
public function testFourOhFour() { |
|
||||||
$this->_conn->expects($this->once())->method('close'); |
|
||||||
|
|
||||||
$nope = new ResourceNotFoundException; |
|
||||||
$this->_matcher->expects($this->any())->method('match')->will($this->throwException($nope)); |
|
||||||
|
|
||||||
$this->_router->onOpen($this->_conn, $this->_req); |
|
||||||
} |
|
||||||
|
|
||||||
public function testNullRequest() { |
|
||||||
$this->setExpectedException('\UnexpectedValueException'); |
|
||||||
$this->_router->onOpen($this->_conn); |
|
||||||
} |
|
||||||
|
|
||||||
public function testControllerIsMessageComponentInterface() { |
|
||||||
$this->setExpectedException('\UnexpectedValueException'); |
|
||||||
$this->_matcher->expects($this->any())->method('match')->will($this->returnValue(array('_controller' => new \StdClass))); |
|
||||||
$this->_router->onOpen($this->_conn, $this->_req); |
|
||||||
} |
|
||||||
|
|
||||||
public function testControllerOnOpen() { |
|
||||||
$controller = $this->getMockBuilder('\Ratchet\WebSocket\WsServer')->disableOriginalConstructor()->getMock(); |
|
||||||
$this->_matcher->expects($this->any())->method('match')->will($this->returnValue(array('_controller' => $controller))); |
|
||||||
$this->_router->onOpen($this->_conn, $this->_req); |
|
||||||
|
|
||||||
$expectedConn = new \PHPUnit_Framework_Constraint_IsInstanceOf('\Ratchet\ConnectionInterface'); |
|
||||||
$controller->expects($this->once())->method('onOpen')->with($expectedConn, $this->_req); |
|
||||||
|
|
||||||
$this->_matcher->expects($this->any())->method('match')->will($this->returnValue(array('_controller' => $controller))); |
|
||||||
$this->_router->onOpen($this->_conn, $this->_req); |
|
||||||
} |
|
||||||
|
|
||||||
public function testControllerOnMessageBubbles() { |
|
||||||
$message = "The greatest trick the Devil ever pulled was convincing the world he didn't exist"; |
|
||||||
$controller = $this->getMockBuilder('\Ratchet\WebSocket\WsServer')->disableOriginalConstructor()->getMock(); |
|
||||||
$controller->expects($this->once())->method('onMessage')->with($this->_conn, $message); |
|
||||||
|
|
||||||
$this->_conn->controller = $controller; |
|
||||||
|
|
||||||
$this->_router->onMessage($this->_conn, $message); |
|
||||||
} |
|
||||||
|
|
||||||
public function testControllerOnCloseBubbles() { |
|
||||||
$controller = $this->getMockBuilder('\Ratchet\WebSocket\WsServer')->disableOriginalConstructor()->getMock(); |
|
||||||
$controller->expects($this->once())->method('onClose')->with($this->_conn); |
|
||||||
|
|
||||||
$this->_conn->controller = $controller; |
|
||||||
|
|
||||||
$this->_router->onClose($this->_conn); |
|
||||||
} |
|
||||||
|
|
||||||
public function testControllerOnErrorBubbles() { |
|
||||||
$e= new \Exception('One cannot be betrayed if one has no exceptions'); |
|
||||||
$controller = $this->getMockBuilder('\Ratchet\WebSocket\WsServer')->disableOriginalConstructor()->getMock(); |
|
||||||
$controller->expects($this->once())->method('onError')->with($this->_conn, $e); |
|
||||||
|
|
||||||
$this->_conn->controller = $controller; |
|
||||||
|
|
||||||
$this->_router->onError($this->_conn, $e); |
|
||||||
} |
|
||||||
|
|
||||||
public function testRouterGeneratesRouteParameters() { |
|
||||||
/** @var $controller WsServerInterface */ |
|
||||||
$controller = $this->getMockBuilder('\Ratchet\WebSocket\WsServer')->disableOriginalConstructor()->getMock(); |
|
||||||
/** @var $matcher UrlMatcherInterface */ |
|
||||||
$this->_matcher->expects($this->any())->method('match')->will( |
|
||||||
$this->returnValue(['_controller' => $controller, 'foo' => 'bar', 'baz' => 'qux']) |
|
||||||
); |
|
||||||
$conn = $this->getMock('Ratchet\Mock\Connection'); |
|
||||||
|
|
||||||
$router = new Router($this->_matcher); |
|
||||||
|
|
||||||
$router->onOpen($conn, $this->_req); |
|
||||||
|
|
||||||
$this->assertEquals('foo=bar&baz=qux', $this->_req->getUri()->getQuery()); |
|
||||||
} |
|
||||||
|
|
||||||
public function testQueryParams() { |
|
||||||
$controller = $this->getMockBuilder('\Ratchet\WebSocket\WsServer')->disableOriginalConstructor()->getMock(); |
|
||||||
$this->_matcher->expects($this->any())->method('match')->will( |
|
||||||
$this->returnValue(['_controller' => $controller, 'foo' => 'bar', 'baz' => 'qux']) |
|
||||||
); |
|
||||||
|
|
||||||
$conn = $this->getMock('Ratchet\Mock\Connection'); |
|
||||||
$request = $this->getMock('Psr\Http\Message\RequestInterface'); |
|
||||||
$uri = new \GuzzleHttp\Psr7\Uri('ws://doesnt.matter/endpoint?hello=world&foo=nope'); |
|
||||||
|
|
||||||
$request->expects($this->any())->method('getUri')->will($this->returnCallback(function() use (&$uri) { |
|
||||||
return $uri; |
|
||||||
})); |
|
||||||
$request->expects($this->any())->method('withUri')->with($this->callback(function($url) use (&$uri) { |
|
||||||
$uri = $url; |
|
||||||
|
|
||||||
return true; |
|
||||||
}))->will($this->returnSelf()); |
|
||||||
|
|
||||||
$router = new Router($this->_matcher); |
|
||||||
$router->onOpen($conn, $request); |
|
||||||
|
|
||||||
$this->assertEquals('foo=nope&baz=qux&hello=world', $request->getUri()->getQuery()); |
|
||||||
} |
|
||||||
} |
|
@ -1,26 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Server; |
|
||||||
use Ratchet\Server\EchoServer; |
|
||||||
|
|
||||||
class EchoServerTest extends \PHPUnit_Framework_TestCase { |
|
||||||
protected $_conn; |
|
||||||
protected $_comp; |
|
||||||
|
|
||||||
public function setUp() { |
|
||||||
$this->_conn = $this->getMock('\Ratchet\ConnectionInterface'); |
|
||||||
$this->_comp = new EchoServer; |
|
||||||
} |
|
||||||
|
|
||||||
public function testMessageEchod() { |
|
||||||
$message = 'Tillsonburg, my back still aches when I hear that word.'; |
|
||||||
$this->_conn->expects($this->once())->method('send')->with($message); |
|
||||||
$this->_comp->onMessage($this->_conn, $message); |
|
||||||
} |
|
||||||
|
|
||||||
public function testErrorClosesConnection() { |
|
||||||
ob_start(); |
|
||||||
$this->_conn->expects($this->once())->method('close'); |
|
||||||
$this->_comp->onError($this->_conn, new \Exception); |
|
||||||
ob_end_clean(); |
|
||||||
} |
|
||||||
} |
|
@ -1,152 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Application\Server; |
|
||||||
use Ratchet\Server\FlashPolicy; |
|
||||||
|
|
||||||
/** |
|
||||||
* @covers Ratchet\Server\FlashPolicy |
|
||||||
*/ |
|
||||||
class FlashPolicyTest extends \PHPUnit_Framework_TestCase { |
|
||||||
|
|
||||||
protected $_policy; |
|
||||||
|
|
||||||
public function setUp() { |
|
||||||
$this->_policy = new FlashPolicy(); |
|
||||||
} |
|
||||||
|
|
||||||
public function testPolicyRender() { |
|
||||||
$this->_policy->setSiteControl('all'); |
|
||||||
$this->_policy->addAllowedAccess('example.com', '*'); |
|
||||||
$this->_policy->addAllowedAccess('dev.example.com', '*'); |
|
||||||
|
|
||||||
$this->assertInstanceOf('SimpleXMLElement', $this->_policy->renderPolicy()); |
|
||||||
} |
|
||||||
|
|
||||||
public function testInvalidPolicyReader() { |
|
||||||
$this->setExpectedException('UnexpectedValueException'); |
|
||||||
$this->_policy->renderPolicy(); |
|
||||||
} |
|
||||||
|
|
||||||
public function testInvalidDomainPolicyReader() { |
|
||||||
$this->setExpectedException('UnexpectedValueException'); |
|
||||||
$this->_policy->setSiteControl('all'); |
|
||||||
$this->_policy->addAllowedAccess('dev.example.*', '*'); |
|
||||||
$this->_policy->renderPolicy(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @dataProvider siteControl |
|
||||||
*/ |
|
||||||
public function testSiteControlValidation($accept, $permittedCrossDomainPolicies) { |
|
||||||
$this->assertEquals($accept, $this->_policy->validateSiteControl($permittedCrossDomainPolicies)); |
|
||||||
} |
|
||||||
|
|
||||||
public static function siteControl() { |
|
||||||
return array( |
|
||||||
array(true, 'all') |
|
||||||
, array(true, 'none') |
|
||||||
, array(true, 'master-only') |
|
||||||
, array(false, 'by-content-type') |
|
||||||
, array(false, 'by-ftp-filename') |
|
||||||
, array(false, '') |
|
||||||
, array(false, 'all ') |
|
||||||
, array(false, 'asdf') |
|
||||||
, array(false, '@893830') |
|
||||||
, array(false, '*') |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @dataProvider URI |
|
||||||
*/ |
|
||||||
public function testDomainValidation($accept, $domain) { |
|
||||||
$this->assertEquals($accept, $this->_policy->validateDomain($domain)); |
|
||||||
} |
|
||||||
|
|
||||||
public static function URI() { |
|
||||||
return array( |
|
||||||
array(true, '*') |
|
||||||
, array(true, 'example.com') |
|
||||||
, array(true, 'exam-ple.com') |
|
||||||
, array(true, '*.example.com') |
|
||||||
, array(true, 'www.example.com') |
|
||||||
, array(true, 'dev.dev.example.com') |
|
||||||
, array(true, 'http://example.com') |
|
||||||
, array(true, 'https://example.com') |
|
||||||
, array(true, 'http://*.example.com') |
|
||||||
, array(false, 'exam*ple.com') |
|
||||||
, array(true, '127.0.255.1') |
|
||||||
, array(true, 'localhost') |
|
||||||
, array(false, 'www.example.*') |
|
||||||
, array(false, 'www.exa*le.com') |
|
||||||
, array(false, 'www.example.*com') |
|
||||||
, array(false, '*.example.*') |
|
||||||
, array(false, 'gasldf*$#a0sdf0a8sdf') |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @dataProvider ports |
|
||||||
*/ |
|
||||||
public function testPortValidation($accept, $ports) { |
|
||||||
$this->assertEquals($accept, $this->_policy->validatePorts($ports)); |
|
||||||
} |
|
||||||
|
|
||||||
public static function ports() { |
|
||||||
return array( |
|
||||||
array(true, '*') |
|
||||||
, array(true, '80') |
|
||||||
, array(true, '80,443') |
|
||||||
, array(true, '507,516-523') |
|
||||||
, array(true, '507,516-523,333') |
|
||||||
, array(true, '507,516-523,507,516-523') |
|
||||||
, array(false, '516-') |
|
||||||
, array(true, '516-523,11') |
|
||||||
, array(false, '516,-523,11') |
|
||||||
, array(false, 'example') |
|
||||||
, array(false, 'asdf,123') |
|
||||||
, array(false, '--') |
|
||||||
, array(false, ',,,') |
|
||||||
, array(false, '838*') |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
public function testAddAllowedAccessOnlyAcceptsValidPorts() { |
|
||||||
$this->setExpectedException('UnexpectedValueException'); |
|
||||||
|
|
||||||
$this->_policy->addAllowedAccess('*', 'nope'); |
|
||||||
} |
|
||||||
|
|
||||||
public function testSetSiteControlThrowsException() { |
|
||||||
$this->setExpectedException('UnexpectedValueException'); |
|
||||||
|
|
||||||
$this->_policy->setSiteControl('nope'); |
|
||||||
} |
|
||||||
|
|
||||||
public function testErrorClosesConnection() { |
|
||||||
$conn = $this->getMock('\\Ratchet\\ConnectionInterface'); |
|
||||||
$conn->expects($this->once())->method('close'); |
|
||||||
|
|
||||||
$this->_policy->onError($conn, new \Exception); |
|
||||||
} |
|
||||||
|
|
||||||
public function testOnMessageSendsString() { |
|
||||||
$this->_policy->addAllowedAccess('*', '*'); |
|
||||||
|
|
||||||
$conn = $this->getMock('\\Ratchet\\ConnectionInterface'); |
|
||||||
$conn->expects($this->once())->method('send')->with($this->isType('string')); |
|
||||||
|
|
||||||
$this->_policy->onMessage($conn, ' '); |
|
||||||
} |
|
||||||
|
|
||||||
public function testOnOpenExists() { |
|
||||||
$this->assertTrue(method_exists($this->_policy, 'onOpen')); |
|
||||||
$conn = $this->getMock('\Ratchet\ConnectionInterface'); |
|
||||||
$this->_policy->onOpen($conn); |
|
||||||
} |
|
||||||
|
|
||||||
public function testOnCloseExists() { |
|
||||||
$this->assertTrue(method_exists($this->_policy, 'onClose')); |
|
||||||
$conn = $this->getMock('\Ratchet\ConnectionInterface'); |
|
||||||
$this->_policy->onClose($conn); |
|
||||||
} |
|
||||||
} |
|
@ -1,32 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Application\Server; |
|
||||||
use Ratchet\Server\IoConnection; |
|
||||||
|
|
||||||
/** |
|
||||||
* @covers Ratchet\Server\IoConnection |
|
||||||
*/ |
|
||||||
class IoConnectionTest extends \PHPUnit_Framework_TestCase { |
|
||||||
protected $sock; |
|
||||||
protected $conn; |
|
||||||
|
|
||||||
public function setUp() { |
|
||||||
$this->sock = $this->getMock('\\React\\Socket\\ConnectionInterface'); |
|
||||||
$this->conn = new IoConnection($this->sock); |
|
||||||
} |
|
||||||
|
|
||||||
public function testCloseBubbles() { |
|
||||||
$this->sock->expects($this->once())->method('end'); |
|
||||||
$this->conn->close(); |
|
||||||
} |
|
||||||
|
|
||||||
public function testSendBubbles() { |
|
||||||
$msg = '6 hour rides are productive'; |
|
||||||
|
|
||||||
$this->sock->expects($this->once())->method('write')->with($msg); |
|
||||||
$this->conn->send($msg); |
|
||||||
} |
|
||||||
|
|
||||||
public function testSendReturnsSelf() { |
|
||||||
$this->assertSame($this->conn, $this->conn->send('fluent interface')); |
|
||||||
} |
|
||||||
} |
|
@ -1,118 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Server; |
|
||||||
use Ratchet\Server\IoServer; |
|
||||||
use React\EventLoop\StreamSelectLoop; |
|
||||||
use React\Socket\Server; |
|
||||||
|
|
||||||
/** |
|
||||||
* @covers Ratchet\Server\IoServer |
|
||||||
*/ |
|
||||||
class IoServerTest extends \PHPUnit_Framework_TestCase { |
|
||||||
protected $server; |
|
||||||
|
|
||||||
protected $app; |
|
||||||
|
|
||||||
protected $port; |
|
||||||
|
|
||||||
protected $reactor; |
|
||||||
|
|
||||||
public function setUp() { |
|
||||||
$this->app = $this->getMock('\\Ratchet\\MessageComponentInterface'); |
|
||||||
|
|
||||||
$loop = new StreamSelectLoop; |
|
||||||
$this->reactor = new Server($loop); |
|
||||||
$this->reactor->listen(0); |
|
||||||
|
|
||||||
$this->port = $this->reactor->getPort(); |
|
||||||
$this->server = new IoServer($this->app, $this->reactor, $loop); |
|
||||||
} |
|
||||||
|
|
||||||
public function testOnOpen() { |
|
||||||
$this->app->expects($this->once())->method('onOpen')->with($this->isInstanceOf('\\Ratchet\\ConnectionInterface')); |
|
||||||
|
|
||||||
$client = stream_socket_client("tcp://localhost:{$this->port}"); |
|
||||||
|
|
||||||
$this->server->loop->tick(); |
|
||||||
|
|
||||||
//$this->assertTrue(is_string($this->app->last['onOpen'][0]->remoteAddress)); |
|
||||||
//$this->assertTrue(is_int($this->app->last['onOpen'][0]->resourceId)); |
|
||||||
} |
|
||||||
|
|
||||||
public function testOnData() { |
|
||||||
$msg = 'Hello World!'; |
|
||||||
|
|
||||||
$this->app->expects($this->once())->method('onMessage')->with( |
|
||||||
$this->isInstanceOf('\\Ratchet\\ConnectionInterface') |
|
||||||
, $msg |
|
||||||
); |
|
||||||
|
|
||||||
$client = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); |
|
||||||
socket_set_option($client, SOL_SOCKET, SO_REUSEADDR, 1); |
|
||||||
socket_set_option($client, SOL_SOCKET, SO_SNDBUF, 4096); |
|
||||||
socket_set_block($client); |
|
||||||
socket_connect($client, 'localhost', $this->port); |
|
||||||
|
|
||||||
$this->server->loop->tick(); |
|
||||||
|
|
||||||
socket_write($client, $msg); |
|
||||||
$this->server->loop->tick(); |
|
||||||
|
|
||||||
socket_shutdown($client, 1); |
|
||||||
socket_shutdown($client, 0); |
|
||||||
socket_close($client); |
|
||||||
|
|
||||||
$this->server->loop->tick(); |
|
||||||
} |
|
||||||
|
|
||||||
public function testOnClose() { |
|
||||||
$this->app->expects($this->once())->method('onClose')->with($this->isInstanceOf('\\Ratchet\\ConnectionInterface')); |
|
||||||
|
|
||||||
$client = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); |
|
||||||
socket_set_option($client, SOL_SOCKET, SO_REUSEADDR, 1); |
|
||||||
socket_set_option($client, SOL_SOCKET, SO_SNDBUF, 4096); |
|
||||||
socket_set_block($client); |
|
||||||
socket_connect($client, 'localhost', $this->port); |
|
||||||
|
|
||||||
$this->server->loop->tick(); |
|
||||||
|
|
||||||
socket_shutdown($client, 1); |
|
||||||
socket_shutdown($client, 0); |
|
||||||
socket_close($client); |
|
||||||
|
|
||||||
$this->server->loop->tick(); |
|
||||||
} |
|
||||||
|
|
||||||
public function testFactory() { |
|
||||||
$this->assertInstanceOf('\\Ratchet\\Server\\IoServer', IoServer::factory($this->app, 0)); |
|
||||||
} |
|
||||||
|
|
||||||
public function testNoLoopProvidedError() { |
|
||||||
$this->setExpectedException('RuntimeException'); |
|
||||||
|
|
||||||
$io = new IoServer($this->app, $this->reactor); |
|
||||||
$io->run(); |
|
||||||
} |
|
||||||
|
|
||||||
public function testOnErrorPassesException() { |
|
||||||
$conn = $this->getMock('\\React\\Socket\\ConnectionInterface'); |
|
||||||
$conn->decor = $this->getMock('\\Ratchet\\ConnectionInterface'); |
|
||||||
$err = new \Exception("Nope"); |
|
||||||
|
|
||||||
$this->app->expects($this->once())->method('onError')->with($conn->decor, $err); |
|
||||||
|
|
||||||
$this->server->handleError($err, $conn); |
|
||||||
} |
|
||||||
|
|
||||||
public function onErrorCalledWhenExceptionThrown() { |
|
||||||
$this->markTestIncomplete("Need to learn how to throw an exception from a mock"); |
|
||||||
|
|
||||||
$conn = $this->getMock('\\React\\Socket\\ConnectionInterface'); |
|
||||||
$this->server->handleConnect($conn); |
|
||||||
|
|
||||||
$e = new \Exception; |
|
||||||
$this->app->expects($this->once())->method('onMessage')->with($this->isInstanceOf('\\Ratchet\\ConnectionInterface'), 'f')->will($e); |
|
||||||
$this->app->expects($this->once())->method('onError')->with($this->instanceOf('\\Ratchet\\ConnectionInterface', $e)); |
|
||||||
|
|
||||||
$this->server->handleData('f', $conn); |
|
||||||
} |
|
||||||
} |
|
@ -1,125 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Server; |
|
||||||
use Ratchet\Server\IpBlackList; |
|
||||||
|
|
||||||
/** |
|
||||||
* @covers Ratchet\Server\IpBlackList |
|
||||||
*/ |
|
||||||
class IpBlackListTest extends \PHPUnit_Framework_TestCase { |
|
||||||
protected $blocker; |
|
||||||
protected $mock; |
|
||||||
|
|
||||||
public function setUp() { |
|
||||||
$this->mock = $this->getMock('\\Ratchet\\MessageComponentInterface'); |
|
||||||
$this->blocker = new IpBlackList($this->mock); |
|
||||||
} |
|
||||||
|
|
||||||
public function testOnOpen() { |
|
||||||
$this->mock->expects($this->exactly(3))->method('onOpen'); |
|
||||||
|
|
||||||
$conn1 = $this->newConn(); |
|
||||||
$conn2 = $this->newConn(); |
|
||||||
$conn3 = $this->newConn(); |
|
||||||
|
|
||||||
$this->blocker->onOpen($conn1); |
|
||||||
$this->blocker->onOpen($conn3); |
|
||||||
$this->blocker->onOpen($conn2); |
|
||||||
} |
|
||||||
|
|
||||||
public function testBlockDoesNotTriggerOnOpen() { |
|
||||||
$conn = $this->newConn(); |
|
||||||
|
|
||||||
$this->blocker->blockAddress($conn->remoteAddress); |
|
||||||
|
|
||||||
$this->mock->expects($this->never())->method('onOpen'); |
|
||||||
|
|
||||||
$ret = $this->blocker->onOpen($conn); |
|
||||||
} |
|
||||||
|
|
||||||
public function testBlockDoesNotTriggerOnClose() { |
|
||||||
$conn = $this->newConn(); |
|
||||||
|
|
||||||
$this->blocker->blockAddress($conn->remoteAddress); |
|
||||||
|
|
||||||
$this->mock->expects($this->never())->method('onClose'); |
|
||||||
|
|
||||||
$ret = $this->blocker->onOpen($conn); |
|
||||||
} |
|
||||||
|
|
||||||
public function testOnMessageDecoration() { |
|
||||||
$conn = $this->newConn(); |
|
||||||
$msg = 'Hello not being blocked'; |
|
||||||
|
|
||||||
$this->mock->expects($this->once())->method('onMessage')->with($conn, $msg); |
|
||||||
|
|
||||||
$this->blocker->onMessage($conn, $msg); |
|
||||||
} |
|
||||||
|
|
||||||
public function testOnCloseDecoration() { |
|
||||||
$conn = $this->newConn(); |
|
||||||
|
|
||||||
$this->mock->expects($this->once())->method('onClose')->with($conn); |
|
||||||
|
|
||||||
$this->blocker->onClose($conn); |
|
||||||
} |
|
||||||
|
|
||||||
public function testBlockClosesConnection() { |
|
||||||
$conn = $this->newConn(); |
|
||||||
$this->blocker->blockAddress($conn->remoteAddress); |
|
||||||
|
|
||||||
$conn->expects($this->once())->method('close'); |
|
||||||
|
|
||||||
$this->blocker->onOpen($conn); |
|
||||||
} |
|
||||||
|
|
||||||
public function testAddAndRemoveWithFluentInterfaces() { |
|
||||||
$blockOne = '127.0.0.1'; |
|
||||||
$blockTwo = '192.168.1.1'; |
|
||||||
$unblock = '75.119.207.140'; |
|
||||||
|
|
||||||
$this->blocker |
|
||||||
->blockAddress($unblock) |
|
||||||
->blockAddress($blockOne) |
|
||||||
->unblockAddress($unblock) |
|
||||||
->blockAddress($blockTwo) |
|
||||||
; |
|
||||||
|
|
||||||
$this->assertEquals(array($blockOne, $blockTwo), $this->blocker->getBlockedAddresses()); |
|
||||||
} |
|
||||||
|
|
||||||
public function testDecoratorPassesErrors() { |
|
||||||
$conn = $this->newConn(); |
|
||||||
$e = new \Exception('I threw an error'); |
|
||||||
|
|
||||||
$this->mock->expects($this->once())->method('onError')->with($conn, $e); |
|
||||||
|
|
||||||
$this->blocker->onError($conn, $e); |
|
||||||
} |
|
||||||
|
|
||||||
public function addressProvider() { |
|
||||||
return array( |
|
||||||
array('127.0.0.1', '127.0.0.1') |
|
||||||
, array('localhost', 'localhost') |
|
||||||
, array('fe80::1%lo0', 'fe80::1%lo0') |
|
||||||
, array('127.0.0.1', '127.0.0.1:6392') |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @dataProvider addressProvider |
|
||||||
*/ |
|
||||||
public function testFilterAddress($expected, $input) { |
|
||||||
$this->assertEquals($expected, $this->blocker->filterAddress($input)); |
|
||||||
} |
|
||||||
|
|
||||||
public function testUnblockingSilentlyFails() { |
|
||||||
$this->assertInstanceOf('\\Ratchet\\Server\\IpBlackList', $this->blocker->unblockAddress('localhost')); |
|
||||||
} |
|
||||||
|
|
||||||
protected function newConn() { |
|
||||||
$conn = $this->getMock('\\Ratchet\\ConnectionInterface'); |
|
||||||
$conn->remoteAddress = '127.0.0.1'; |
|
||||||
|
|
||||||
return $conn; |
|
||||||
} |
|
||||||
} |
|
@ -1,36 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Session\Serialize; |
|
||||||
use Ratchet\Session\Serialize\PhpHandler; |
|
||||||
|
|
||||||
/** |
|
||||||
* @covers Ratchet\Session\Serialize\PhpHandler |
|
||||||
*/ |
|
||||||
class PhpHandlerTest extends \PHPUnit_Framework_TestCase { |
|
||||||
protected $_handler; |
|
||||||
|
|
||||||
public function setUp() { |
|
||||||
$this->_handler = new PhpHandler; |
|
||||||
} |
|
||||||
|
|
||||||
public function serializedProvider() { |
|
||||||
return array( |
|
||||||
array( |
|
||||||
'_sf2_attributes|a:2:{s:5:"hello";s:5:"world";s:4:"last";i:1332872102;}_sf2_flashes|a:0:{}' |
|
||||||
, array( |
|
||||||
'_sf2_attributes' => array( |
|
||||||
'hello' => 'world' |
|
||||||
, 'last' => 1332872102 |
|
||||||
) |
|
||||||
, '_sf2_flashes' => array() |
|
||||||
) |
|
||||||
) |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @dataProvider serializedProvider |
|
||||||
*/ |
|
||||||
public function testUnserialize($in, $expected) { |
|
||||||
$this->assertEquals($expected, $this->_handler->unserialize($in)); |
|
||||||
} |
|
||||||
} |
|
@ -1,124 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Session; |
|
||||||
use Ratchet\AbstractMessageComponentTestCase; |
|
||||||
use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler; |
|
||||||
use Symfony\Component\HttpFoundation\Session\Storage\Handler\NullSessionHandler; |
|
||||||
|
|
||||||
/** |
|
||||||
* @covers Ratchet\Session\SessionProvider |
|
||||||
* @covers Ratchet\Session\Storage\VirtualSessionStorage |
|
||||||
* @covers Ratchet\Session\Storage\Proxy\VirtualProxy |
|
||||||
*/ |
|
||||||
class SessionProviderTest extends AbstractMessageComponentTestCase { |
|
||||||
public function setUp() { |
|
||||||
if (!class_exists('Symfony\Component\HttpFoundation\Session\Session')) { |
|
||||||
return $this->markTestSkipped('Dependency of Symfony HttpFoundation failed'); |
|
||||||
} |
|
||||||
|
|
||||||
parent::setUp(); |
|
||||||
$this->_serv = new SessionProvider($this->_app, new NullSessionHandler); |
|
||||||
} |
|
||||||
|
|
||||||
public function tearDown() { |
|
||||||
ini_set('session.serialize_handler', 'php'); |
|
||||||
} |
|
||||||
|
|
||||||
public function getConnectionClassString() { |
|
||||||
return '\Ratchet\ConnectionInterface'; |
|
||||||
} |
|
||||||
|
|
||||||
public function getDecoratorClassString() { |
|
||||||
return '\Ratchet\NullComponent'; |
|
||||||
} |
|
||||||
|
|
||||||
public function getComponentClassString() { |
|
||||||
return '\Ratchet\Http\HttpServerInterface'; |
|
||||||
} |
|
||||||
|
|
||||||
public function classCaseProvider() { |
|
||||||
return array( |
|
||||||
array('php', 'Php') |
|
||||||
, array('php_binary', 'PhpBinary') |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @dataProvider classCaseProvider |
|
||||||
*/ |
|
||||||
public function testToClassCase($in, $out) { |
|
||||||
$ref = new \ReflectionClass('\\Ratchet\\Session\\SessionProvider'); |
|
||||||
$method = $ref->getMethod('toClassCase'); |
|
||||||
$method->setAccessible(true); |
|
||||||
|
|
||||||
$component = new SessionProvider($this->getMock($this->getComponentClassString()), $this->getMock('\SessionHandlerInterface')); |
|
||||||
$this->assertEquals($out, $method->invokeArgs($component, array($in))); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* I think I have severely butchered this test...it's not so much of a unit test as it is a full-fledged component test |
|
||||||
*/ |
|
||||||
public function testConnectionValueFromPdo() { |
|
||||||
if (!extension_loaded('PDO') || !extension_loaded('pdo_sqlite')) { |
|
||||||
return $this->markTestSkipped('Session test requires PDO and pdo_sqlite'); |
|
||||||
} |
|
||||||
|
|
||||||
$sessionId = md5('testSession'); |
|
||||||
|
|
||||||
$dbOptions = array( |
|
||||||
'db_table' => 'sessions' |
|
||||||
, 'db_id_col' => 'sess_id' |
|
||||||
, 'db_data_col' => 'sess_data' |
|
||||||
, 'db_time_col' => 'sess_time' |
|
||||||
, 'db_lifetime_col' => 'sess_lifetime' |
|
||||||
); |
|
||||||
|
|
||||||
$pdo = new \PDO("sqlite::memory:"); |
|
||||||
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); |
|
||||||
$pdo->exec(vsprintf("CREATE TABLE %s (%s TEXT NOT NULL PRIMARY KEY, %s BLOB NOT NULL, %s INTEGER NOT NULL, %s INTEGER)", $dbOptions)); |
|
||||||
|
|
||||||
$pdoHandler = new PdoSessionHandler($pdo, $dbOptions); |
|
||||||
$pdoHandler->write($sessionId, '_sf2_attributes|a:2:{s:5:"hello";s:5:"world";s:4:"last";i:1332872102;}_sf2_flashes|a:0:{}'); |
|
||||||
|
|
||||||
$component = new SessionProvider($this->getMock($this->getComponentClassString()), $pdoHandler, array('auto_start' => 1)); |
|
||||||
$connection = $this->getMock('Ratchet\\ConnectionInterface'); |
|
||||||
|
|
||||||
$headers = $this->getMock('Psr\Http\Message\RequestInterface'); |
|
||||||
$headers->expects($this->once())->method('getHeader')->will($this->returnValue([ini_get('session.name') . "={$sessionId};"])); |
|
||||||
|
|
||||||
$component->onOpen($connection, $headers); |
|
||||||
|
|
||||||
$this->assertEquals('world', $connection->Session->get('hello')); |
|
||||||
} |
|
||||||
|
|
||||||
protected function newConn() { |
|
||||||
$conn = $this->getMock('Ratchet\ConnectionInterface'); |
|
||||||
|
|
||||||
$headers = $this->getMock('Psr\Http\Message\Request', array('getCookie'), array('POST', '/', array())); |
|
||||||
$headers->expects($this->once())->method('getCookie', array(ini_get('session.name')))->will($this->returnValue(null)); |
|
||||||
|
|
||||||
return $conn; |
|
||||||
} |
|
||||||
|
|
||||||
public function testOnMessageDecorator() { |
|
||||||
$message = "Database calls are usually blocking :("; |
|
||||||
$this->_app->expects($this->once())->method('onMessage')->with($this->isExpectedConnection(), $message); |
|
||||||
$this->_serv->onMessage($this->_conn, $message); |
|
||||||
} |
|
||||||
|
|
||||||
public function testRejectInvalidSeralizers() { |
|
||||||
if (!function_exists('wddx_serialize_value')) { |
|
||||||
$this->markTestSkipped(); |
|
||||||
} |
|
||||||
|
|
||||||
ini_set('session.serialize_handler', 'wddx'); |
|
||||||
$this->setExpectedException('\RuntimeException'); |
|
||||||
new SessionProvider($this->getMock($this->getComponentClassString()), $this->getMock('\SessionHandlerInterface')); |
|
||||||
} |
|
||||||
|
|
||||||
protected function doOpen($conn) { |
|
||||||
$request = $this->getMock('Psr\Http\Message\RequestInterface'); |
|
||||||
$request->expects($this->any())->method('getHeader')->will($this->returnValue([])); |
|
||||||
|
|
||||||
$this->_serv->onOpen($conn, $request); |
|
||||||
} |
|
||||||
} |
|
@ -1,53 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Session\Storage; |
|
||||||
use Ratchet\Session\Serialize\PhpHandler; |
|
||||||
use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag; |
|
||||||
use Symfony\Component\HttpFoundation\Session\Flash\FlashBag; |
|
||||||
use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler; |
|
||||||
|
|
||||||
class VirtualSessionStoragePDOTest extends \PHPUnit_Framework_TestCase { |
|
||||||
/** |
|
||||||
* @var VirtualSessionStorage |
|
||||||
*/ |
|
||||||
protected $_virtualSessionStorage; |
|
||||||
|
|
||||||
protected $_pathToDB; |
|
||||||
|
|
||||||
public function setUp() { |
|
||||||
if (!extension_loaded('PDO') || !extension_loaded('pdo_sqlite')) { |
|
||||||
return $this->markTestSkipped('Session test requires PDO and pdo_sqlite'); |
|
||||||
} |
|
||||||
|
|
||||||
$schema = <<<SQL |
|
||||||
CREATE TABLE `sessions` ( |
|
||||||
`sess_id` VARBINARY(128) NOT NULL PRIMARY KEY, |
|
||||||
`sess_data` BLOB NOT NULL, |
|
||||||
`sess_time` INTEGER UNSIGNED NOT NULL, |
|
||||||
`sess_lifetime` MEDIUMINT NOT NULL |
|
||||||
); |
|
||||||
SQL; |
|
||||||
$this->_pathToDB = tempnam(sys_get_temp_dir(), 'SQ3');; |
|
||||||
$dsn = 'sqlite:' . $this->_pathToDB; |
|
||||||
|
|
||||||
$pdo = new \PDO($dsn); |
|
||||||
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); |
|
||||||
$pdo->exec($schema); |
|
||||||
$pdo = null; |
|
||||||
|
|
||||||
$sessionHandler = new PdoSessionHandler($dsn); |
|
||||||
$serializer = new PhpHandler(); |
|
||||||
$this->_virtualSessionStorage = new VirtualSessionStorage($sessionHandler, 'foobar', $serializer); |
|
||||||
$this->_virtualSessionStorage->registerBag(new FlashBag()); |
|
||||||
$this->_virtualSessionStorage->registerBag(new AttributeBag()); |
|
||||||
} |
|
||||||
|
|
||||||
public function tearDown() { |
|
||||||
unlink($this->_pathToDB); |
|
||||||
} |
|
||||||
|
|
||||||
public function testStartWithDSN() { |
|
||||||
$this->_virtualSessionStorage->start(); |
|
||||||
|
|
||||||
$this->assertTrue($this->_virtualSessionStorage->isStarted()); |
|
||||||
} |
|
||||||
} |
|
@ -1,268 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Wamp; |
|
||||||
use Ratchet\Mock\Connection; |
|
||||||
use Ratchet\Mock\WampComponent as TestComponent; |
|
||||||
|
|
||||||
/** |
|
||||||
* @covers Ratchet\Wamp\ServerProtocol |
|
||||||
* @covers Ratchet\Wamp\WampServerInterface |
|
||||||
* @covers Ratchet\Wamp\WampConnection |
|
||||||
*/ |
|
||||||
class ServerProtocolTest extends \PHPUnit_Framework_TestCase { |
|
||||||
protected $_comp; |
|
||||||
|
|
||||||
protected $_app; |
|
||||||
|
|
||||||
public function setUp() { |
|
||||||
$this->_app = new TestComponent; |
|
||||||
$this->_comp = new ServerProtocol($this->_app); |
|
||||||
} |
|
||||||
|
|
||||||
protected function newConn() { |
|
||||||
return new Connection; |
|
||||||
} |
|
||||||
|
|
||||||
public function invalidMessageProvider() { |
|
||||||
return array( |
|
||||||
array(0) |
|
||||||
, array(3) |
|
||||||
, array(4) |
|
||||||
, array(8) |
|
||||||
, array(9) |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @dataProvider invalidMessageProvider |
|
||||||
*/ |
|
||||||
public function testInvalidMessages($type) { |
|
||||||
$this->setExpectedException('\Ratchet\Wamp\Exception'); |
|
||||||
|
|
||||||
$conn = $this->newConn(); |
|
||||||
$this->_comp->onOpen($conn); |
|
||||||
$this->_comp->onMessage($conn, json_encode(array($type))); |
|
||||||
} |
|
||||||
|
|
||||||
public function testWelcomeMessage() { |
|
||||||
$conn = $this->newConn(); |
|
||||||
|
|
||||||
$this->_comp->onOpen($conn); |
|
||||||
|
|
||||||
$message = $conn->last['send']; |
|
||||||
$json = json_decode($message); |
|
||||||
|
|
||||||
$this->assertEquals(4, count($json)); |
|
||||||
$this->assertEquals(0, $json[0]); |
|
||||||
$this->assertTrue(is_string($json[1])); |
|
||||||
$this->assertEquals(1, $json[2]); |
|
||||||
} |
|
||||||
|
|
||||||
public function testSubscribe() { |
|
||||||
$uri = 'http://example.com'; |
|
||||||
$clientMessage = array(5, $uri); |
|
||||||
|
|
||||||
$conn = $this->newConn(); |
|
||||||
|
|
||||||
$this->_comp->onOpen($conn); |
|
||||||
$this->_comp->onMessage($conn, json_encode($clientMessage)); |
|
||||||
|
|
||||||
$this->assertEquals($uri, $this->_app->last['onSubscribe'][1]); |
|
||||||
} |
|
||||||
|
|
||||||
public function testUnSubscribe() { |
|
||||||
$uri = 'http://example.com/endpoint'; |
|
||||||
$clientMessage = array(6, $uri); |
|
||||||
|
|
||||||
$conn = $this->newConn(); |
|
||||||
|
|
||||||
$this->_comp->onOpen($conn); |
|
||||||
$this->_comp->onMessage($conn, json_encode($clientMessage)); |
|
||||||
|
|
||||||
$this->assertEquals($uri, $this->_app->last['onUnSubscribe'][1]); |
|
||||||
} |
|
||||||
|
|
||||||
public function callProvider() { |
|
||||||
return array( |
|
||||||
array(2, 'a', 'b') |
|
||||||
, array(2, array('a', 'b')) |
|
||||||
, array(1, 'one') |
|
||||||
, array(3, 'one', 'two', 'three') |
|
||||||
, array(3, array('un', 'deux', 'trois')) |
|
||||||
, array(2, 'hi', array('hello', 'world')) |
|
||||||
, array(2, array('hello', 'world'), 'hi') |
|
||||||
, array(2, array('hello' => 'world', 'herp' => 'derp')) |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @dataProvider callProvider |
|
||||||
*/ |
|
||||||
public function testCall() { |
|
||||||
$args = func_get_args(); |
|
||||||
$paramNum = array_shift($args); |
|
||||||
|
|
||||||
$uri = 'http://example.com/endpoint/' . rand(1, 100); |
|
||||||
$id = uniqid(); |
|
||||||
$clientMessage = array_merge(array(2, $id, $uri), $args); |
|
||||||
|
|
||||||
$conn = $this->newConn(); |
|
||||||
|
|
||||||
$this->_comp->onOpen($conn); |
|
||||||
$this->_comp->onMessage($conn, json_encode($clientMessage)); |
|
||||||
|
|
||||||
$this->assertEquals($id, $this->_app->last['onCall'][1]); |
|
||||||
$this->assertEquals($uri, $this->_app->last['onCall'][2]); |
|
||||||
|
|
||||||
$this->assertEquals($paramNum, count($this->_app->last['onCall'][3])); |
|
||||||
} |
|
||||||
|
|
||||||
public function testPublish() { |
|
||||||
$conn = $this->newConn(); |
|
||||||
|
|
||||||
$topic = 'pubsubhubbub'; |
|
||||||
$event = 'Here I am, publishing data'; |
|
||||||
|
|
||||||
$clientMessage = array(7, $topic, $event); |
|
||||||
|
|
||||||
$this->_comp->onOpen($conn); |
|
||||||
$this->_comp->onMessage($conn, json_encode($clientMessage)); |
|
||||||
|
|
||||||
$this->assertEquals($topic, $this->_app->last['onPublish'][1]); |
|
||||||
$this->assertEquals($event, $this->_app->last['onPublish'][2]); |
|
||||||
$this->assertEquals(array(), $this->_app->last['onPublish'][3]); |
|
||||||
$this->assertEquals(array(), $this->_app->last['onPublish'][4]); |
|
||||||
} |
|
||||||
|
|
||||||
public function testPublishAndExcludeMe() { |
|
||||||
$conn = $this->newConn(); |
|
||||||
|
|
||||||
$this->_comp->onOpen($conn); |
|
||||||
$this->_comp->onMessage($conn, json_encode(array(7, 'topic', 'event', true))); |
|
||||||
|
|
||||||
$this->assertEquals($conn->WAMP->sessionId, $this->_app->last['onPublish'][3][0]); |
|
||||||
} |
|
||||||
|
|
||||||
public function testPublishAndEligible() { |
|
||||||
$conn = $this->newConn(); |
|
||||||
|
|
||||||
$buddy = uniqid(); |
|
||||||
$friend = uniqid(); |
|
||||||
|
|
||||||
$this->_comp->onOpen($conn); |
|
||||||
$this->_comp->onMessage($conn, json_encode(array(7, 'topic', 'event', false, array($buddy, $friend)))); |
|
||||||
|
|
||||||
$this->assertEquals(array(), $this->_app->last['onPublish'][3]); |
|
||||||
$this->assertEquals(2, count($this->_app->last['onPublish'][4])); |
|
||||||
} |
|
||||||
|
|
||||||
public function eventProvider() { |
|
||||||
return array( |
|
||||||
array('http://example.com', array('one', 'two')) |
|
||||||
, array('curie', array(array('hello' => 'world', 'herp' => 'derp'))) |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @dataProvider eventProvider |
|
||||||
*/ |
|
||||||
public function testEvent($topic, $payload) { |
|
||||||
$conn = new WampConnection($this->newConn()); |
|
||||||
$conn->event($topic, $payload); |
|
||||||
|
|
||||||
$eventString = $conn->last['send']; |
|
||||||
|
|
||||||
$this->assertSame(array(8, $topic, $payload), json_decode($eventString, true)); |
|
||||||
} |
|
||||||
|
|
||||||
public function testOnClosePropagation() { |
|
||||||
$conn = new Connection; |
|
||||||
|
|
||||||
$this->_comp->onOpen($conn); |
|
||||||
$this->_comp->onClose($conn); |
|
||||||
|
|
||||||
$class = new \ReflectionClass('\\Ratchet\\Wamp\\WampConnection'); |
|
||||||
$method = $class->getMethod('getConnection'); |
|
||||||
$method->setAccessible(true); |
|
||||||
|
|
||||||
$check = $method->invokeArgs($this->_app->last['onClose'][0], array()); |
|
||||||
|
|
||||||
$this->assertSame($conn, $check); |
|
||||||
} |
|
||||||
|
|
||||||
public function testOnErrorPropagation() { |
|
||||||
$conn = new Connection; |
|
||||||
|
|
||||||
$e = new \Exception('Nope'); |
|
||||||
|
|
||||||
$this->_comp->onOpen($conn); |
|
||||||
$this->_comp->onError($conn, $e); |
|
||||||
|
|
||||||
$class = new \ReflectionClass('\\Ratchet\\Wamp\\WampConnection'); |
|
||||||
$method = $class->getMethod('getConnection'); |
|
||||||
$method->setAccessible(true); |
|
||||||
|
|
||||||
$check = $method->invokeArgs($this->_app->last['onError'][0], array()); |
|
||||||
|
|
||||||
$this->assertSame($conn, $check); |
|
||||||
$this->assertSame($e, $this->_app->last['onError'][1]); |
|
||||||
} |
|
||||||
|
|
||||||
public function testPrefix() { |
|
||||||
$conn = new WampConnection($this->newConn()); |
|
||||||
$this->_comp->onOpen($conn); |
|
||||||
|
|
||||||
$prefix = 'incoming'; |
|
||||||
$fullURI = "http://example.com/$prefix"; |
|
||||||
$method = 'call'; |
|
||||||
|
|
||||||
$this->_comp->onMessage($conn, json_encode(array(1, $prefix, $fullURI))); |
|
||||||
|
|
||||||
$this->assertEquals($fullURI, $conn->WAMP->prefixes[$prefix]); |
|
||||||
$this->assertEquals("$fullURI#$method", $conn->getUri("$prefix:$method")); |
|
||||||
} |
|
||||||
|
|
||||||
public function testMessageMustBeJson() { |
|
||||||
$this->setExpectedException('\\Ratchet\\Wamp\\JsonException'); |
|
||||||
|
|
||||||
$conn = new Connection; |
|
||||||
|
|
||||||
$this->_comp->onOpen($conn); |
|
||||||
$this->_comp->onMessage($conn, 'Hello World!'); |
|
||||||
} |
|
||||||
|
|
||||||
public function testGetSubProtocolsReturnsArray() { |
|
||||||
$this->assertTrue(is_array($this->_comp->getSubProtocols())); |
|
||||||
} |
|
||||||
|
|
||||||
public function testGetSubProtocolsGetFromApp() { |
|
||||||
$this->_app->protocols = array('hello', 'world'); |
|
||||||
|
|
||||||
$this->assertGreaterThanOrEqual(3, count($this->_comp->getSubProtocols())); |
|
||||||
} |
|
||||||
|
|
||||||
public function testWampOnMessageApp() { |
|
||||||
$app = $this->getMock('\\Ratchet\\Wamp\\WampServerInterface'); |
|
||||||
$wamp = new ServerProtocol($app); |
|
||||||
|
|
||||||
$this->assertContains('wamp', $wamp->getSubProtocols()); |
|
||||||
} |
|
||||||
|
|
||||||
public function badFormatProvider() { |
|
||||||
return array( |
|
||||||
array(json_encode(true)) |
|
||||||
, array('{"valid":"json", "invalid": "message"}') |
|
||||||
, array('{"0": "fail", "hello": "world"}') |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @dataProvider badFormatProvider |
|
||||||
*/ |
|
||||||
public function testValidJsonButInvalidProtocol($message) { |
|
||||||
$this->setExpectedException('\Ratchet\Wamp\Exception'); |
|
||||||
|
|
||||||
$conn = $this->newConn(); |
|
||||||
$this->_comp->onOpen($conn); |
|
||||||
$this->_comp->onMessage($conn, $message); |
|
||||||
} |
|
||||||
} |
|
@ -1,229 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Wamp; |
|
||||||
|
|
||||||
/** |
|
||||||
* @covers Ratchet\Wamp\TopicManager |
|
||||||
*/ |
|
||||||
class TopicManagerTest extends \PHPUnit_Framework_TestCase { |
|
||||||
private $mock; |
|
||||||
|
|
||||||
/** |
|
||||||
* @var \Ratchet\Wamp\TopicManager |
|
||||||
*/ |
|
||||||
private $mngr; |
|
||||||
|
|
||||||
/** |
|
||||||
* @var \Ratchet\ConnectionInterface |
|
||||||
*/ |
|
||||||
private $conn; |
|
||||||
|
|
||||||
public function setUp() { |
|
||||||
$this->conn = $this->getMock('\Ratchet\ConnectionInterface'); |
|
||||||
$this->mock = $this->getMock('\Ratchet\Wamp\WampServerInterface'); |
|
||||||
$this->mngr = new TopicManager($this->mock); |
|
||||||
|
|
||||||
$this->conn->WAMP = new \StdClass; |
|
||||||
$this->mngr->onOpen($this->conn); |
|
||||||
} |
|
||||||
|
|
||||||
public function testGetTopicReturnsTopicObject() { |
|
||||||
$class = new \ReflectionClass('Ratchet\Wamp\TopicManager'); |
|
||||||
$method = $class->getMethod('getTopic'); |
|
||||||
$method->setAccessible(true); |
|
||||||
|
|
||||||
$topic = $method->invokeArgs($this->mngr, array('The Topic')); |
|
||||||
|
|
||||||
$this->assertInstanceOf('Ratchet\Wamp\Topic', $topic); |
|
||||||
} |
|
||||||
|
|
||||||
public function testGetTopicCreatesTopicWithSameName() { |
|
||||||
$name = 'The Topic'; |
|
||||||
|
|
||||||
$class = new \ReflectionClass('Ratchet\Wamp\TopicManager'); |
|
||||||
$method = $class->getMethod('getTopic'); |
|
||||||
$method->setAccessible(true); |
|
||||||
|
|
||||||
$topic = $method->invokeArgs($this->mngr, array($name)); |
|
||||||
|
|
||||||
$this->assertEquals($name, $topic->getId()); |
|
||||||
} |
|
||||||
|
|
||||||
public function testGetTopicReturnsSameObject() { |
|
||||||
$class = new \ReflectionClass('Ratchet\Wamp\TopicManager'); |
|
||||||
$method = $class->getMethod('getTopic'); |
|
||||||
$method->setAccessible(true); |
|
||||||
|
|
||||||
$topic = $method->invokeArgs($this->mngr, array('No copy')); |
|
||||||
$again = $method->invokeArgs($this->mngr, array('No copy')); |
|
||||||
|
|
||||||
$this->assertSame($topic, $again); |
|
||||||
} |
|
||||||
|
|
||||||
public function testOnOpen() { |
|
||||||
$this->mock->expects($this->once())->method('onOpen'); |
|
||||||
$this->mngr->onOpen($this->conn); |
|
||||||
} |
|
||||||
|
|
||||||
public function testOnCall() { |
|
||||||
$id = uniqid(); |
|
||||||
|
|
||||||
$this->mock->expects($this->once())->method('onCall')->with( |
|
||||||
$this->conn |
|
||||||
, $id |
|
||||||
, $this->isInstanceOf('Ratchet\Wamp\Topic') |
|
||||||
, array() |
|
||||||
); |
|
||||||
|
|
||||||
$this->mngr->onCall($this->conn, $id, 'new topic', array()); |
|
||||||
} |
|
||||||
|
|
||||||
public function testOnSubscribeCreatesTopicObject() { |
|
||||||
$this->mock->expects($this->once())->method('onSubscribe')->with( |
|
||||||
$this->conn, $this->isInstanceOf('Ratchet\Wamp\Topic') |
|
||||||
); |
|
||||||
|
|
||||||
$this->mngr->onSubscribe($this->conn, 'new topic'); |
|
||||||
} |
|
||||||
|
|
||||||
public function testTopicIsInConnectionOnSubscribe() { |
|
||||||
$name = 'New Topic'; |
|
||||||
|
|
||||||
$class = new \ReflectionClass('Ratchet\Wamp\TopicManager'); |
|
||||||
$method = $class->getMethod('getTopic'); |
|
||||||
$method->setAccessible(true); |
|
||||||
|
|
||||||
$topic = $method->invokeArgs($this->mngr, array($name)); |
|
||||||
|
|
||||||
$this->mngr->onSubscribe($this->conn, $name); |
|
||||||
|
|
||||||
$this->assertTrue($this->conn->WAMP->subscriptions->contains($topic)); |
|
||||||
} |
|
||||||
|
|
||||||
public function testDoubleSubscriptionFiresOnce() { |
|
||||||
$this->mock->expects($this->exactly(1))->method('onSubscribe'); |
|
||||||
|
|
||||||
$this->mngr->onSubscribe($this->conn, 'same topic'); |
|
||||||
$this->mngr->onSubscribe($this->conn, 'same topic'); |
|
||||||
} |
|
||||||
|
|
||||||
public function testUnsubscribeEvent() { |
|
||||||
$name = 'in and out'; |
|
||||||
$this->mock->expects($this->once())->method('onUnsubscribe')->with( |
|
||||||
$this->conn, $this->isInstanceOf('Ratchet\Wamp\Topic') |
|
||||||
); |
|
||||||
|
|
||||||
$this->mngr->onSubscribe($this->conn, $name); |
|
||||||
$this->mngr->onUnsubscribe($this->conn, $name); |
|
||||||
} |
|
||||||
|
|
||||||
public function testUnsubscribeFiresOnce() { |
|
||||||
$name = 'getting sleepy'; |
|
||||||
$this->mock->expects($this->exactly(1))->method('onUnsubscribe'); |
|
||||||
|
|
||||||
$this->mngr->onSubscribe($this->conn, $name); |
|
||||||
$this->mngr->onUnsubscribe($this->conn, $name); |
|
||||||
$this->mngr->onUnsubscribe($this->conn, $name); |
|
||||||
} |
|
||||||
|
|
||||||
public function testUnsubscribeRemovesTopicFromConnection() { |
|
||||||
$name = 'Bye Bye Topic'; |
|
||||||
|
|
||||||
$class = new \ReflectionClass('Ratchet\Wamp\TopicManager'); |
|
||||||
$method = $class->getMethod('getTopic'); |
|
||||||
$method->setAccessible(true); |
|
||||||
|
|
||||||
$topic = $method->invokeArgs($this->mngr, array($name)); |
|
||||||
|
|
||||||
$this->mngr->onSubscribe($this->conn, $name); |
|
||||||
$this->mngr->onUnsubscribe($this->conn, $name); |
|
||||||
|
|
||||||
$this->assertFalse($this->conn->WAMP->subscriptions->contains($topic)); |
|
||||||
} |
|
||||||
|
|
||||||
public function testOnPublishBubbles() { |
|
||||||
$msg = 'Cover all the code!'; |
|
||||||
|
|
||||||
$this->mock->expects($this->once())->method('onPublish')->with( |
|
||||||
$this->conn |
|
||||||
, $this->isInstanceOf('Ratchet\Wamp\Topic') |
|
||||||
, $msg |
|
||||||
, $this->isType('array') |
|
||||||
, $this->isType('array') |
|
||||||
); |
|
||||||
|
|
||||||
$this->mngr->onPublish($this->conn, 'topic coverage', $msg, array(), array()); |
|
||||||
} |
|
||||||
|
|
||||||
public function testOnCloseBubbles() { |
|
||||||
$this->mock->expects($this->once())->method('onClose')->with($this->conn); |
|
||||||
$this->mngr->onClose($this->conn); |
|
||||||
} |
|
||||||
|
|
||||||
protected function topicProvider($name) { |
|
||||||
$class = new \ReflectionClass('Ratchet\Wamp\TopicManager'); |
|
||||||
$method = $class->getMethod('getTopic'); |
|
||||||
$method->setAccessible(true); |
|
||||||
|
|
||||||
$attribute = $class->getProperty('topicLookup'); |
|
||||||
$attribute->setAccessible(true); |
|
||||||
|
|
||||||
$topic = $method->invokeArgs($this->mngr, array($name)); |
|
||||||
|
|
||||||
return array($topic, $attribute); |
|
||||||
} |
|
||||||
|
|
||||||
public function testConnIsRemovedFromTopicOnClose() { |
|
||||||
$name = 'State Testing'; |
|
||||||
list($topic, $attribute) = $this->topicProvider($name); |
|
||||||
|
|
||||||
$this->assertCount(1, $attribute->getValue($this->mngr)); |
|
||||||
|
|
||||||
$this->mngr->onSubscribe($this->conn, $name); |
|
||||||
$this->mngr->onClose($this->conn); |
|
||||||
|
|
||||||
$this->assertFalse($topic->has($this->conn)); |
|
||||||
} |
|
||||||
|
|
||||||
public static function topicConnExpectationProvider() { |
|
||||||
return array( |
|
||||||
array(true, 'onClose', 0) |
|
||||||
, array(true, 'onUnsubscribe', 0) |
|
||||||
, array(false, 'onClose', 1) |
|
||||||
, array(false, 'onUnsubscribe', 1) |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @dataProvider topicConnExpectationProvider |
|
||||||
*/ |
|
||||||
public function testTopicRetentionFromLeavingConnections($autoDelete, $methodCall, $expectation) { |
|
||||||
$topicName = 'checkTopic'; |
|
||||||
list($topic, $attribute) = $this->topicProvider($topicName); |
|
||||||
$topic->autoDelete = $autoDelete; |
|
||||||
|
|
||||||
$this->mngr->onSubscribe($this->conn, $topicName); |
|
||||||
call_user_func_array(array($this->mngr, $methodCall), array($this->conn, $topicName)); |
|
||||||
|
|
||||||
$this->assertCount($expectation, $attribute->getValue($this->mngr)); |
|
||||||
} |
|
||||||
|
|
||||||
public function testOnErrorBubbles() { |
|
||||||
$e = new \Exception('All work and no play makes Chris a dull boy'); |
|
||||||
$this->mock->expects($this->once())->method('onError')->with($this->conn, $e); |
|
||||||
|
|
||||||
$this->mngr->onError($this->conn, $e); |
|
||||||
} |
|
||||||
|
|
||||||
public function testGetSubProtocolsReturnsArray() { |
|
||||||
$this->assertInternalType('array', $this->mngr->getSubProtocols()); |
|
||||||
} |
|
||||||
|
|
||||||
public function testGetSubProtocolsBubbles() { |
|
||||||
$subs = array('hello', 'world'); |
|
||||||
$app = $this->getMock('Ratchet\Wamp\Stub\WsWampServerInterface'); |
|
||||||
$app->expects($this->once())->method('getSubProtocols')->will($this->returnValue($subs)); |
|
||||||
$mngr = new TopicManager($app); |
|
||||||
|
|
||||||
$this->assertEquals($subs, $mngr->getSubProtocols()); |
|
||||||
} |
|
||||||
} |
|
@ -1,164 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Wamp; |
|
||||||
|
|
||||||
/** |
|
||||||
* @covers Ratchet\Wamp\Topic |
|
||||||
*/ |
|
||||||
class TopicTest extends \PHPUnit_Framework_TestCase { |
|
||||||
public function testGetId() { |
|
||||||
$id = uniqid(); |
|
||||||
$topic = new Topic($id); |
|
||||||
|
|
||||||
$this->assertEquals($id, $topic->getId()); |
|
||||||
} |
|
||||||
|
|
||||||
public function testAddAndCount() { |
|
||||||
$topic = new Topic('merp'); |
|
||||||
|
|
||||||
$topic->add($this->newConn()); |
|
||||||
$topic->add($this->newConn()); |
|
||||||
$topic->add($this->newConn()); |
|
||||||
|
|
||||||
$this->assertEquals(3, count($topic)); |
|
||||||
} |
|
||||||
|
|
||||||
public function testRemove() { |
|
||||||
$topic = new Topic('boop'); |
|
||||||
$tracked = $this->newConn(); |
|
||||||
|
|
||||||
$topic->add($this->newConn()); |
|
||||||
$topic->add($tracked); |
|
||||||
$topic->add($this->newConn()); |
|
||||||
|
|
||||||
$topic->remove($tracked); |
|
||||||
|
|
||||||
$this->assertEquals(2, count($topic)); |
|
||||||
} |
|
||||||
|
|
||||||
public function testBroadcast() { |
|
||||||
$msg = 'Hello World!'; |
|
||||||
$name = 'Batman'; |
|
||||||
$protocol = json_encode(array(8, $name, $msg)); |
|
||||||
|
|
||||||
$first = $this->getMock('Ratchet\\Wamp\\WampConnection', array('send'), array($this->getMock('\\Ratchet\\ConnectionInterface'))); |
|
||||||
$second = $this->getMock('Ratchet\\Wamp\\WampConnection', array('send'), array($this->getMock('\\Ratchet\\ConnectionInterface'))); |
|
||||||
|
|
||||||
$first->expects($this->once()) |
|
||||||
->method('send') |
|
||||||
->with($this->equalTo($protocol)); |
|
||||||
|
|
||||||
$second->expects($this->once()) |
|
||||||
->method('send') |
|
||||||
->with($this->equalTo($protocol)); |
|
||||||
|
|
||||||
$topic = new Topic($name); |
|
||||||
$topic->add($first); |
|
||||||
$topic->add($second); |
|
||||||
|
|
||||||
$topic->broadcast($msg); |
|
||||||
} |
|
||||||
|
|
||||||
public function testBroadcastWithExclude() { |
|
||||||
$msg = 'Hello odd numbers'; |
|
||||||
$name = 'Excluding'; |
|
||||||
$protocol = json_encode(array(8, $name, $msg)); |
|
||||||
|
|
||||||
$first = $this->getMock('Ratchet\\Wamp\\WampConnection', array('send'), array($this->getMock('\\Ratchet\\ConnectionInterface'))); |
|
||||||
$second = $this->getMock('Ratchet\\Wamp\\WampConnection', array('send'), array($this->getMock('\\Ratchet\\ConnectionInterface'))); |
|
||||||
$third = $this->getMock('Ratchet\\Wamp\\WampConnection', array('send'), array($this->getMock('\\Ratchet\\ConnectionInterface'))); |
|
||||||
|
|
||||||
$first->expects($this->once()) |
|
||||||
->method('send') |
|
||||||
->with($this->equalTo($protocol)); |
|
||||||
|
|
||||||
$second->expects($this->never())->method('send'); |
|
||||||
|
|
||||||
$third->expects($this->once()) |
|
||||||
->method('send') |
|
||||||
->with($this->equalTo($protocol)); |
|
||||||
|
|
||||||
$topic = new Topic($name); |
|
||||||
$topic->add($first); |
|
||||||
$topic->add($second); |
|
||||||
$topic->add($third); |
|
||||||
|
|
||||||
$topic->broadcast($msg, array($second->WAMP->sessionId)); |
|
||||||
} |
|
||||||
|
|
||||||
public function testBroadcastWithEligible() { |
|
||||||
$msg = 'Hello white list'; |
|
||||||
$name = 'Eligible'; |
|
||||||
$protocol = json_encode(array(8, $name, $msg)); |
|
||||||
|
|
||||||
$first = $this->getMock('Ratchet\\Wamp\\WampConnection', array('send'), array($this->getMock('\\Ratchet\\ConnectionInterface'))); |
|
||||||
$second = $this->getMock('Ratchet\\Wamp\\WampConnection', array('send'), array($this->getMock('\\Ratchet\\ConnectionInterface'))); |
|
||||||
$third = $this->getMock('Ratchet\\Wamp\\WampConnection', array('send'), array($this->getMock('\\Ratchet\\ConnectionInterface'))); |
|
||||||
|
|
||||||
$first->expects($this->once()) |
|
||||||
->method('send') |
|
||||||
->with($this->equalTo($protocol)); |
|
||||||
|
|
||||||
$second->expects($this->never())->method('send'); |
|
||||||
|
|
||||||
$third->expects($this->once()) |
|
||||||
->method('send') |
|
||||||
->with($this->equalTo($protocol)); |
|
||||||
|
|
||||||
$topic = new Topic($name); |
|
||||||
$topic->add($first); |
|
||||||
$topic->add($second); |
|
||||||
$topic->add($third); |
|
||||||
|
|
||||||
$topic->broadcast($msg, array(), array($first->WAMP->sessionId, $third->WAMP->sessionId)); |
|
||||||
} |
|
||||||
|
|
||||||
public function testIterator() { |
|
||||||
$first = $this->newConn(); |
|
||||||
$second = $this->newConn(); |
|
||||||
$third = $this->newConn(); |
|
||||||
|
|
||||||
$topic = new Topic('Joker'); |
|
||||||
$topic->add($first)->add($second)->add($third); |
|
||||||
|
|
||||||
$check = array($first, $second, $third); |
|
||||||
|
|
||||||
foreach ($topic as $mock) { |
|
||||||
$this->assertNotSame(false, array_search($mock, $check)); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public function testToString() { |
|
||||||
$name = 'Bane'; |
|
||||||
$topic = new Topic($name); |
|
||||||
|
|
||||||
$this->assertEquals($name, (string)$topic); |
|
||||||
} |
|
||||||
|
|
||||||
public function testDoesHave() { |
|
||||||
$conn = $this->newConn(); |
|
||||||
$topic = new Topic('Two Face'); |
|
||||||
$topic->add($conn); |
|
||||||
|
|
||||||
$this->assertTrue($topic->has($conn)); |
|
||||||
} |
|
||||||
|
|
||||||
public function testDoesNotHave() { |
|
||||||
$conn = $this->newConn(); |
|
||||||
$topic = new Topic('Alfred'); |
|
||||||
|
|
||||||
$this->assertFalse($topic->has($conn)); |
|
||||||
} |
|
||||||
|
|
||||||
public function testDoesNotHaveAfterRemove() { |
|
||||||
$conn = $this->newConn(); |
|
||||||
$topic = new Topic('Ras'); |
|
||||||
|
|
||||||
$topic->add($conn)->remove($conn); |
|
||||||
|
|
||||||
$this->assertFalse($topic->has($conn)); |
|
||||||
} |
|
||||||
|
|
||||||
protected function newConn() { |
|
||||||
return new WampConnection($this->getMock('\\Ratchet\\ConnectionInterface')); |
|
||||||
} |
|
||||||
} |
|
@ -1,77 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Wamp; |
|
||||||
|
|
||||||
/** |
|
||||||
* @covers Ratchet\Wamp\WampConnection |
|
||||||
*/ |
|
||||||
class WampConnectionTest extends \PHPUnit_Framework_TestCase { |
|
||||||
protected $conn; |
|
||||||
protected $mock; |
|
||||||
|
|
||||||
public function setUp() { |
|
||||||
$this->mock = $this->getMock('\\Ratchet\\ConnectionInterface'); |
|
||||||
$this->conn = new WampConnection($this->mock); |
|
||||||
} |
|
||||||
|
|
||||||
public function testCallResult() { |
|
||||||
$callId = uniqid(); |
|
||||||
$data = array('hello' => 'world', 'herp' => 'derp'); |
|
||||||
|
|
||||||
$this->mock->expects($this->once())->method('send')->with(json_encode(array(3, $callId, $data))); |
|
||||||
|
|
||||||
$this->conn->callResult($callId, $data); |
|
||||||
} |
|
||||||
|
|
||||||
public function testCallError() { |
|
||||||
$callId = uniqid(); |
|
||||||
$uri = 'http://example.com/end/point'; |
|
||||||
|
|
||||||
$this->mock->expects($this->once())->method('send')->with(json_encode(array(4, $callId, $uri, ''))); |
|
||||||
|
|
||||||
$this->conn->callError($callId, $uri); |
|
||||||
} |
|
||||||
|
|
||||||
public function testCallErrorWithTopic() { |
|
||||||
$callId = uniqid(); |
|
||||||
$uri = 'http://example.com/end/point'; |
|
||||||
|
|
||||||
$this->mock->expects($this->once())->method('send')->with(json_encode(array(4, $callId, $uri, ''))); |
|
||||||
|
|
||||||
$this->conn->callError($callId, new Topic($uri)); |
|
||||||
} |
|
||||||
|
|
||||||
public function testDetailedCallError() { |
|
||||||
$callId = uniqid(); |
|
||||||
$uri = 'http://example.com/end/point'; |
|
||||||
$desc = 'beep boop beep'; |
|
||||||
$detail = 'Error: Too much awesome'; |
|
||||||
|
|
||||||
$this->mock->expects($this->once())->method('send')->with(json_encode(array(4, $callId, $uri, $desc, $detail))); |
|
||||||
|
|
||||||
$this->conn->callError($callId, $uri, $desc, $detail); |
|
||||||
} |
|
||||||
|
|
||||||
public function testPrefix() { |
|
||||||
$shortOut = 'outgoing'; |
|
||||||
$longOut = 'http://example.com/outgoing'; |
|
||||||
|
|
||||||
$this->mock->expects($this->once())->method('send')->with(json_encode(array(1, $shortOut, $longOut))); |
|
||||||
|
|
||||||
$this->conn->prefix($shortOut, $longOut); |
|
||||||
} |
|
||||||
|
|
||||||
public function testGetUriWhenNoCurieGiven() { |
|
||||||
$uri = 'http://example.com/noshort'; |
|
||||||
|
|
||||||
$this->assertEquals($uri, $this->conn->getUri($uri)); |
|
||||||
} |
|
||||||
|
|
||||||
public function testClose() { |
|
||||||
$mock = $this->getMock('\\Ratchet\\ConnectionInterface'); |
|
||||||
$conn = new WampConnection($mock); |
|
||||||
|
|
||||||
$mock->expects($this->once())->method('close'); |
|
||||||
|
|
||||||
$conn->close(); |
|
||||||
} |
|
||||||
} |
|
@ -1,49 +0,0 @@ |
|||||||
<?php |
|
||||||
namespace Ratchet\Wamp; |
|
||||||
use Ratchet\AbstractMessageComponentTestCase; |
|
||||||
|
|
||||||
/** |
|
||||||
* @covers Ratchet\Wamp\WampServer |
|
||||||
*/ |
|
||||||
class WampServerTest extends AbstractMessageComponentTestCase { |
|
||||||
public function getConnectionClassString() { |
|
||||||
return '\Ratchet\Wamp\WampConnection'; |
|
||||||
} |
|
||||||
|
|
||||||
public function getDecoratorClassString() { |
|
||||||
return 'Ratchet\Wamp\WampServer'; |
|
||||||
} |
|
||||||
|
|
||||||
public function getComponentClassString() { |
|
||||||
return '\Ratchet\Wamp\WampServerInterface'; |
|
||||||
} |
|
||||||
|
|
||||||
public function testOnMessageToEvent() { |
|
||||||
$published = 'Client published this message'; |
|
||||||
|
|
||||||
$this->_app->expects($this->once())->method('onPublish')->with( |
|
||||||
$this->isExpectedConnection() |
|
||||||
, new \PHPUnit_Framework_Constraint_IsInstanceOf('\Ratchet\Wamp\Topic') |
|
||||||
, $published |
|
||||||
, array() |
|
||||||
, array() |
|
||||||
); |
|
||||||
|
|
||||||
$this->_serv->onMessage($this->_conn, json_encode(array(7, 'topic', $published))); |
|
||||||
} |
|
||||||
|
|
||||||
public function testGetSubProtocols() { |
|
||||||
// todo: could expand on this |
|
||||||
$this->assertInternalType('array', $this->_serv->getSubProtocols()); |
|
||||||
} |
|
||||||
|
|
||||||
public function testConnectionClosesOnInvalidJson() { |
|
||||||
$this->_conn->expects($this->once())->method('close'); |
|
||||||
$this->_serv->onMessage($this->_conn, 'invalid json'); |
|
||||||
} |
|
||||||
|
|
||||||
public function testConnectionClosesOnProtocolError() { |
|
||||||
$this->_conn->expects($this->once())->method('close'); |
|
||||||
$this->_serv->onMessage($this->_conn, json_encode(array('valid' => 'json', 'invalid' => 'protocol'))); |
|
||||||
} |
|
||||||
} |
|
@ -1,445 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
/* |
|
||||||
* This file is part of Composer. |
|
||||||
* |
|
||||||
* (c) Nils Adermann <naderman@naderman.de> |
|
||||||
* Jordi Boggiano <j.boggiano@seld.be> |
|
||||||
* |
|
||||||
* For the full copyright and license information, please view the LICENSE |
|
||||||
* file that was distributed with this source code. |
|
||||||
*/ |
|
||||||
|
|
||||||
namespace Composer\Autoload; |
|
||||||
|
|
||||||
/** |
|
||||||
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader. |
|
||||||
* |
|
||||||
* $loader = new \Composer\Autoload\ClassLoader(); |
|
||||||
* |
|
||||||
* // register classes with namespaces |
|
||||||
* $loader->add('Symfony\Component', __DIR__.'/component'); |
|
||||||
* $loader->add('Symfony', __DIR__.'/framework'); |
|
||||||
* |
|
||||||
* // activate the autoloader |
|
||||||
* $loader->register(); |
|
||||||
* |
|
||||||
* // to enable searching the include path (eg. for PEAR packages) |
|
||||||
* $loader->setUseIncludePath(true); |
|
||||||
* |
|
||||||
* In this example, if you try to use a class in the Symfony\Component |
|
||||||
* namespace or one of its children (Symfony\Component\Console for instance), |
|
||||||
* the autoloader will first look for the class under the component/ |
|
||||||
* directory, and it will then fallback to the framework/ directory if not |
|
||||||
* found before giving up. |
|
||||||
* |
|
||||||
* This class is loosely based on the Symfony UniversalClassLoader. |
|
||||||
* |
|
||||||
* @author Fabien Potencier <fabien@symfony.com> |
|
||||||
* @author Jordi Boggiano <j.boggiano@seld.be> |
|
||||||
* @see http://www.php-fig.org/psr/psr-0/ |
|
||||||
* @see http://www.php-fig.org/psr/psr-4/ |
|
||||||
*/ |
|
||||||
class ClassLoader |
|
||||||
{ |
|
||||||
// PSR-4 |
|
||||||
private $prefixLengthsPsr4 = array(); |
|
||||||
private $prefixDirsPsr4 = array(); |
|
||||||
private $fallbackDirsPsr4 = array(); |
|
||||||
|
|
||||||
// PSR-0 |
|
||||||
private $prefixesPsr0 = array(); |
|
||||||
private $fallbackDirsPsr0 = array(); |
|
||||||
|
|
||||||
private $useIncludePath = false; |
|
||||||
private $classMap = array(); |
|
||||||
private $classMapAuthoritative = false; |
|
||||||
private $missingClasses = array(); |
|
||||||
private $apcuPrefix; |
|
||||||
|
|
||||||
public function getPrefixes() |
|
||||||
{ |
|
||||||
if (!empty($this->prefixesPsr0)) { |
|
||||||
return call_user_func_array('array_merge', $this->prefixesPsr0); |
|
||||||
} |
|
||||||
|
|
||||||
return array(); |
|
||||||
} |
|
||||||
|
|
||||||
public function getPrefixesPsr4() |
|
||||||
{ |
|
||||||
return $this->prefixDirsPsr4; |
|
||||||
} |
|
||||||
|
|
||||||
public function getFallbackDirs() |
|
||||||
{ |
|
||||||
return $this->fallbackDirsPsr0; |
|
||||||
} |
|
||||||
|
|
||||||
public function getFallbackDirsPsr4() |
|
||||||
{ |
|
||||||
return $this->fallbackDirsPsr4; |
|
||||||
} |
|
||||||
|
|
||||||
public function getClassMap() |
|
||||||
{ |
|
||||||
return $this->classMap; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @param array $classMap Class to filename map |
|
||||||
*/ |
|
||||||
public function addClassMap(array $classMap) |
|
||||||
{ |
|
||||||
if ($this->classMap) { |
|
||||||
$this->classMap = array_merge($this->classMap, $classMap); |
|
||||||
} else { |
|
||||||
$this->classMap = $classMap; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Registers a set of PSR-0 directories for a given prefix, either |
|
||||||
* appending or prepending to the ones previously set for this prefix. |
|
||||||
* |
|
||||||
* @param string $prefix The prefix |
|
||||||
* @param array|string $paths The PSR-0 root directories |
|
||||||
* @param bool $prepend Whether to prepend the directories |
|
||||||
*/ |
|
||||||
public function add($prefix, $paths, $prepend = false) |
|
||||||
{ |
|
||||||
if (!$prefix) { |
|
||||||
if ($prepend) { |
|
||||||
$this->fallbackDirsPsr0 = array_merge( |
|
||||||
(array) $paths, |
|
||||||
$this->fallbackDirsPsr0 |
|
||||||
); |
|
||||||
} else { |
|
||||||
$this->fallbackDirsPsr0 = array_merge( |
|
||||||
$this->fallbackDirsPsr0, |
|
||||||
(array) $paths |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
$first = $prefix[0]; |
|
||||||
if (!isset($this->prefixesPsr0[$first][$prefix])) { |
|
||||||
$this->prefixesPsr0[$first][$prefix] = (array) $paths; |
|
||||||
|
|
||||||
return; |
|
||||||
} |
|
||||||
if ($prepend) { |
|
||||||
$this->prefixesPsr0[$first][$prefix] = array_merge( |
|
||||||
(array) $paths, |
|
||||||
$this->prefixesPsr0[$first][$prefix] |
|
||||||
); |
|
||||||
} else { |
|
||||||
$this->prefixesPsr0[$first][$prefix] = array_merge( |
|
||||||
$this->prefixesPsr0[$first][$prefix], |
|
||||||
(array) $paths |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Registers a set of PSR-4 directories for a given namespace, either |
|
||||||
* appending or prepending to the ones previously set for this namespace. |
|
||||||
* |
|
||||||
* @param string $prefix The prefix/namespace, with trailing '\\' |
|
||||||
* @param array|string $paths The PSR-4 base directories |
|
||||||
* @param bool $prepend Whether to prepend the directories |
|
||||||
* |
|
||||||
* @throws \InvalidArgumentException |
|
||||||
*/ |
|
||||||
public function addPsr4($prefix, $paths, $prepend = false) |
|
||||||
{ |
|
||||||
if (!$prefix) { |
|
||||||
// Register directories for the root namespace. |
|
||||||
if ($prepend) { |
|
||||||
$this->fallbackDirsPsr4 = array_merge( |
|
||||||
(array) $paths, |
|
||||||
$this->fallbackDirsPsr4 |
|
||||||
); |
|
||||||
} else { |
|
||||||
$this->fallbackDirsPsr4 = array_merge( |
|
||||||
$this->fallbackDirsPsr4, |
|
||||||
(array) $paths |
|
||||||
); |
|
||||||
} |
|
||||||
} elseif (!isset($this->prefixDirsPsr4[$prefix])) { |
|
||||||
// Register directories for a new namespace. |
|
||||||
$length = strlen($prefix); |
|
||||||
if ('\\' !== $prefix[$length - 1]) { |
|
||||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); |
|
||||||
} |
|
||||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; |
|
||||||
$this->prefixDirsPsr4[$prefix] = (array) $paths; |
|
||||||
} elseif ($prepend) { |
|
||||||
// Prepend directories for an already registered namespace. |
|
||||||
$this->prefixDirsPsr4[$prefix] = array_merge( |
|
||||||
(array) $paths, |
|
||||||
$this->prefixDirsPsr4[$prefix] |
|
||||||
); |
|
||||||
} else { |
|
||||||
// Append directories for an already registered namespace. |
|
||||||
$this->prefixDirsPsr4[$prefix] = array_merge( |
|
||||||
$this->prefixDirsPsr4[$prefix], |
|
||||||
(array) $paths |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Registers a set of PSR-0 directories for a given prefix, |
|
||||||
* replacing any others previously set for this prefix. |
|
||||||
* |
|
||||||
* @param string $prefix The prefix |
|
||||||
* @param array|string $paths The PSR-0 base directories |
|
||||||
*/ |
|
||||||
public function set($prefix, $paths) |
|
||||||
{ |
|
||||||
if (!$prefix) { |
|
||||||
$this->fallbackDirsPsr0 = (array) $paths; |
|
||||||
} else { |
|
||||||
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Registers a set of PSR-4 directories for a given namespace, |
|
||||||
* replacing any others previously set for this namespace. |
|
||||||
* |
|
||||||
* @param string $prefix The prefix/namespace, with trailing '\\' |
|
||||||
* @param array|string $paths The PSR-4 base directories |
|
||||||
* |
|
||||||
* @throws \InvalidArgumentException |
|
||||||
*/ |
|
||||||
public function setPsr4($prefix, $paths) |
|
||||||
{ |
|
||||||
if (!$prefix) { |
|
||||||
$this->fallbackDirsPsr4 = (array) $paths; |
|
||||||
} else { |
|
||||||
$length = strlen($prefix); |
|
||||||
if ('\\' !== $prefix[$length - 1]) { |
|
||||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); |
|
||||||
} |
|
||||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; |
|
||||||
$this->prefixDirsPsr4[$prefix] = (array) $paths; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Turns on searching the include path for class files. |
|
||||||
* |
|
||||||
* @param bool $useIncludePath |
|
||||||
*/ |
|
||||||
public function setUseIncludePath($useIncludePath) |
|
||||||
{ |
|
||||||
$this->useIncludePath = $useIncludePath; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Can be used to check if the autoloader uses the include path to check |
|
||||||
* for classes. |
|
||||||
* |
|
||||||
* @return bool |
|
||||||
*/ |
|
||||||
public function getUseIncludePath() |
|
||||||
{ |
|
||||||
return $this->useIncludePath; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Turns off searching the prefix and fallback directories for classes |
|
||||||
* that have not been registered with the class map. |
|
||||||
* |
|
||||||
* @param bool $classMapAuthoritative |
|
||||||
*/ |
|
||||||
public function setClassMapAuthoritative($classMapAuthoritative) |
|
||||||
{ |
|
||||||
$this->classMapAuthoritative = $classMapAuthoritative; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Should class lookup fail if not found in the current class map? |
|
||||||
* |
|
||||||
* @return bool |
|
||||||
*/ |
|
||||||
public function isClassMapAuthoritative() |
|
||||||
{ |
|
||||||
return $this->classMapAuthoritative; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* APCu prefix to use to cache found/not-found classes, if the extension is enabled. |
|
||||||
* |
|
||||||
* @param string|null $apcuPrefix |
|
||||||
*/ |
|
||||||
public function setApcuPrefix($apcuPrefix) |
|
||||||
{ |
|
||||||
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* The APCu prefix in use, or null if APCu caching is not enabled. |
|
||||||
* |
|
||||||
* @return string|null |
|
||||||
*/ |
|
||||||
public function getApcuPrefix() |
|
||||||
{ |
|
||||||
return $this->apcuPrefix; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Registers this instance as an autoloader. |
|
||||||
* |
|
||||||
* @param bool $prepend Whether to prepend the autoloader or not |
|
||||||
*/ |
|
||||||
public function register($prepend = false) |
|
||||||
{ |
|
||||||
spl_autoload_register(array($this, 'loadClass'), true, $prepend); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Unregisters this instance as an autoloader. |
|
||||||
*/ |
|
||||||
public function unregister() |
|
||||||
{ |
|
||||||
spl_autoload_unregister(array($this, 'loadClass')); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Loads the given class or interface. |
|
||||||
* |
|
||||||
* @param string $class The name of the class |
|
||||||
* @return bool|null True if loaded, null otherwise |
|
||||||
*/ |
|
||||||
public function loadClass($class) |
|
||||||
{ |
|
||||||
if ($file = $this->findFile($class)) { |
|
||||||
includeFile($file); |
|
||||||
|
|
||||||
return true; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Finds the path to the file where the class is defined. |
|
||||||
* |
|
||||||
* @param string $class The name of the class |
|
||||||
* |
|
||||||
* @return string|false The path if found, false otherwise |
|
||||||
*/ |
|
||||||
public function findFile($class) |
|
||||||
{ |
|
||||||
// class map lookup |
|
||||||
if (isset($this->classMap[$class])) { |
|
||||||
return $this->classMap[$class]; |
|
||||||
} |
|
||||||
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
if (null !== $this->apcuPrefix) { |
|
||||||
$file = apcu_fetch($this->apcuPrefix.$class, $hit); |
|
||||||
if ($hit) { |
|
||||||
return $file; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
$file = $this->findFileWithExtension($class, '.php'); |
|
||||||
|
|
||||||
// Search for Hack files if we are running on HHVM |
|
||||||
if (false === $file && defined('HHVM_VERSION')) { |
|
||||||
$file = $this->findFileWithExtension($class, '.hh'); |
|
||||||
} |
|
||||||
|
|
||||||
if (null !== $this->apcuPrefix) { |
|
||||||
apcu_add($this->apcuPrefix.$class, $file); |
|
||||||
} |
|
||||||
|
|
||||||
if (false === $file) { |
|
||||||
// Remember that this class does not exist. |
|
||||||
$this->missingClasses[$class] = true; |
|
||||||
} |
|
||||||
|
|
||||||
return $file; |
|
||||||
} |
|
||||||
|
|
||||||
private function findFileWithExtension($class, $ext) |
|
||||||
{ |
|
||||||
// PSR-4 lookup |
|
||||||
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; |
|
||||||
|
|
||||||
$first = $class[0]; |
|
||||||
if (isset($this->prefixLengthsPsr4[$first])) { |
|
||||||
$subPath = $class; |
|
||||||
while (false !== $lastPos = strrpos($subPath, '\\')) { |
|
||||||
$subPath = substr($subPath, 0, $lastPos); |
|
||||||
$search = $subPath . '\\'; |
|
||||||
if (isset($this->prefixDirsPsr4[$search])) { |
|
||||||
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); |
|
||||||
foreach ($this->prefixDirsPsr4[$search] as $dir) { |
|
||||||
if (file_exists($file = $dir . $pathEnd)) { |
|
||||||
return $file; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// PSR-4 fallback dirs |
|
||||||
foreach ($this->fallbackDirsPsr4 as $dir) { |
|
||||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { |
|
||||||
return $file; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// PSR-0 lookup |
|
||||||
if (false !== $pos = strrpos($class, '\\')) { |
|
||||||
// namespaced class name |
|
||||||
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) |
|
||||||
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); |
|
||||||
} else { |
|
||||||
// PEAR-like class name |
|
||||||
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; |
|
||||||
} |
|
||||||
|
|
||||||
if (isset($this->prefixesPsr0[$first])) { |
|
||||||
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { |
|
||||||
if (0 === strpos($class, $prefix)) { |
|
||||||
foreach ($dirs as $dir) { |
|
||||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { |
|
||||||
return $file; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// PSR-0 fallback dirs |
|
||||||
foreach ($this->fallbackDirsPsr0 as $dir) { |
|
||||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { |
|
||||||
return $file; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// PSR-0 include paths. |
|
||||||
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { |
|
||||||
return $file; |
|
||||||
} |
|
||||||
|
|
||||||
return false; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Scope isolated include. |
|
||||||
* |
|
||||||
* Prevents access to $this/self from included files. |
|
||||||
*/ |
|
||||||
function includeFile($file) |
|
||||||
{ |
|
||||||
include $file; |
|
||||||
} |
|
@ -1,21 +0,0 @@ |
|||||||
|
|
||||||
Copyright (c) Nils Adermann, Jordi Boggiano |
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
|
||||||
of this software and associated documentation files (the "Software"), to deal |
|
||||||
in the Software without restriction, including without limitation the rights |
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
||||||
copies of the Software, and to permit persons to whom the Software is furnished |
|
||||||
to do so, subject to the following conditions: |
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all |
|
||||||
copies or substantial portions of the Software. |
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
||||||
THE SOFTWARE. |
|
||||||
|
|
@ -1,16 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
// autoload_classmap.php @generated by Composer |
|
||||||
|
|
||||||
$vendorDir = dirname(dirname(__FILE__)); |
|
||||||
$baseDir = dirname($vendorDir); |
|
||||||
|
|
||||||
return array( |
|
||||||
'ArithmeticError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php', |
|
||||||
'AssertionError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/AssertionError.php', |
|
||||||
'DivisionByZeroError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/DivisionByZeroError.php', |
|
||||||
'Error' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/Error.php', |
|
||||||
'ParseError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/ParseError.php', |
|
||||||
'SessionUpdateTimestampHandlerInterface' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/SessionUpdateTimestampHandlerInterface.php', |
|
||||||
'TypeError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/TypeError.php', |
|
||||||
); |
|
@ -1,14 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
// autoload_files.php @generated by Composer |
|
||||||
|
|
||||||
$vendorDir = dirname(dirname(__FILE__)); |
|
||||||
$baseDir = dirname($vendorDir); |
|
||||||
|
|
||||||
return array( |
|
||||||
'ad155f8f1cf0d418fe49e248db8c661b' => $vendorDir . '/react/promise/src/functions_include.php', |
|
||||||
'7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php', |
|
||||||
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', |
|
||||||
'023d27dca8066ef29e6739335ea73bad' => $vendorDir . '/symfony/polyfill-php70/bootstrap.php', |
|
||||||
'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php', |
|
||||||
); |
|
@ -1,10 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
// autoload_namespaces.php @generated by Composer |
|
||||||
|
|
||||||
$vendorDir = dirname(dirname(__FILE__)); |
|
||||||
$baseDir = dirname($vendorDir); |
|
||||||
|
|
||||||
return array( |
|
||||||
'Evenement' => array($vendorDir . '/evenement/evenement/src'), |
|
||||||
); |
|
@ -1,22 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
// autoload_psr4.php @generated by Composer |
|
||||||
|
|
||||||
$vendorDir = dirname(dirname(__FILE__)); |
|
||||||
$baseDir = dirname($vendorDir); |
|
||||||
|
|
||||||
return array( |
|
||||||
'Symfony\\Polyfill\\Php70\\' => array($vendorDir . '/symfony/polyfill-php70'), |
|
||||||
'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'), |
|
||||||
'Symfony\\Component\\Routing\\' => array($vendorDir . '/symfony/routing'), |
|
||||||
'Symfony\\Component\\HttpFoundation\\' => array($vendorDir . '/symfony/http-foundation'), |
|
||||||
'React\\Stream\\' => array($vendorDir . '/react/stream/src'), |
|
||||||
'React\\Socket\\' => array($vendorDir . '/react/socket/src'), |
|
||||||
'React\\Promise\\' => array($vendorDir . '/react/promise/src'), |
|
||||||
'React\\EventLoop\\' => array($vendorDir . '/react/event-loop/src'), |
|
||||||
'Ratchet\\RFC6455\\' => array($vendorDir . '/ratchet/rfc6455/src'), |
|
||||||
'Ratchet\\' => array($vendorDir . '/cboden/ratchet/src/Ratchet'), |
|
||||||
'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'), |
|
||||||
'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'), |
|
||||||
'Amir\\' => array($baseDir . '/bin/amir'), |
|
||||||
); |
|
@ -1,70 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
// autoload_real.php @generated by Composer |
|
||||||
|
|
||||||
class ComposerAutoloaderInita3d708ca3bb0f3f4e817238e4fb57153 |
|
||||||
{ |
|
||||||
private static $loader; |
|
||||||
|
|
||||||
public static function loadClassLoader($class) |
|
||||||
{ |
|
||||||
if ('Composer\Autoload\ClassLoader' === $class) { |
|
||||||
require __DIR__ . '/ClassLoader.php'; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static function getLoader() |
|
||||||
{ |
|
||||||
if (null !== self::$loader) { |
|
||||||
return self::$loader; |
|
||||||
} |
|
||||||
|
|
||||||
spl_autoload_register(array('ComposerAutoloaderInita3d708ca3bb0f3f4e817238e4fb57153', 'loadClassLoader'), true, true); |
|
||||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader(); |
|
||||||
spl_autoload_unregister(array('ComposerAutoloaderInita3d708ca3bb0f3f4e817238e4fb57153', 'loadClassLoader')); |
|
||||||
|
|
||||||
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); |
|
||||||
if ($useStaticLoader) { |
|
||||||
require_once __DIR__ . '/autoload_static.php'; |
|
||||||
|
|
||||||
call_user_func(\Composer\Autoload\ComposerStaticInita3d708ca3bb0f3f4e817238e4fb57153::getInitializer($loader)); |
|
||||||
} else { |
|
||||||
$map = require __DIR__ . '/autoload_namespaces.php'; |
|
||||||
foreach ($map as $namespace => $path) { |
|
||||||
$loader->set($namespace, $path); |
|
||||||
} |
|
||||||
|
|
||||||
$map = require __DIR__ . '/autoload_psr4.php'; |
|
||||||
foreach ($map as $namespace => $path) { |
|
||||||
$loader->setPsr4($namespace, $path); |
|
||||||
} |
|
||||||
|
|
||||||
$classMap = require __DIR__ . '/autoload_classmap.php'; |
|
||||||
if ($classMap) { |
|
||||||
$loader->addClassMap($classMap); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
$loader->register(true); |
|
||||||
|
|
||||||
if ($useStaticLoader) { |
|
||||||
$includeFiles = Composer\Autoload\ComposerStaticInita3d708ca3bb0f3f4e817238e4fb57153::$files; |
|
||||||
} else { |
|
||||||
$includeFiles = require __DIR__ . '/autoload_files.php'; |
|
||||||
} |
|
||||||
foreach ($includeFiles as $fileIdentifier => $file) { |
|
||||||
composerRequirea3d708ca3bb0f3f4e817238e4fb57153($fileIdentifier, $file); |
|
||||||
} |
|
||||||
|
|
||||||
return $loader; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
function composerRequirea3d708ca3bb0f3f4e817238e4fb57153($fileIdentifier, $file) |
|
||||||
{ |
|
||||||
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { |
|
||||||
require $file; |
|
||||||
|
|
||||||
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; |
|
||||||
} |
|
||||||
} |
|
@ -1,133 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
// autoload_static.php @generated by Composer |
|
||||||
|
|
||||||
namespace Composer\Autoload; |
|
||||||
|
|
||||||
class ComposerStaticInita3d708ca3bb0f3f4e817238e4fb57153 |
|
||||||
{ |
|
||||||
public static $files = array ( |
|
||||||
'ad155f8f1cf0d418fe49e248db8c661b' => __DIR__ . '/..' . '/react/promise/src/functions_include.php', |
|
||||||
'7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php', |
|
||||||
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', |
|
||||||
'023d27dca8066ef29e6739335ea73bad' => __DIR__ . '/..' . '/symfony/polyfill-php70/bootstrap.php', |
|
||||||
'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php', |
|
||||||
); |
|
||||||
|
|
||||||
public static $prefixLengthsPsr4 = array ( |
|
||||||
'S' => |
|
||||||
array ( |
|
||||||
'Symfony\\Polyfill\\Php70\\' => 23, |
|
||||||
'Symfony\\Polyfill\\Mbstring\\' => 26, |
|
||||||
'Symfony\\Component\\Routing\\' => 26, |
|
||||||
'Symfony\\Component\\HttpFoundation\\' => 33, |
|
||||||
), |
|
||||||
'R' => |
|
||||||
array ( |
|
||||||
'React\\Stream\\' => 13, |
|
||||||
'React\\Socket\\' => 13, |
|
||||||
'React\\Promise\\' => 14, |
|
||||||
'React\\EventLoop\\' => 16, |
|
||||||
'Ratchet\\RFC6455\\' => 16, |
|
||||||
'Ratchet\\' => 8, |
|
||||||
), |
|
||||||
'P' => |
|
||||||
array ( |
|
||||||
'Psr\\Http\\Message\\' => 17, |
|
||||||
), |
|
||||||
'G' => |
|
||||||
array ( |
|
||||||
'GuzzleHttp\\Psr7\\' => 16, |
|
||||||
), |
|
||||||
'A' => |
|
||||||
array ( |
|
||||||
'Amir\\' => 5, |
|
||||||
), |
|
||||||
); |
|
||||||
|
|
||||||
public static $prefixDirsPsr4 = array ( |
|
||||||
'Symfony\\Polyfill\\Php70\\' => |
|
||||||
array ( |
|
||||||
0 => __DIR__ . '/..' . '/symfony/polyfill-php70', |
|
||||||
), |
|
||||||
'Symfony\\Polyfill\\Mbstring\\' => |
|
||||||
array ( |
|
||||||
0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring', |
|
||||||
), |
|
||||||
'Symfony\\Component\\Routing\\' => |
|
||||||
array ( |
|
||||||
0 => __DIR__ . '/..' . '/symfony/routing', |
|
||||||
), |
|
||||||
'Symfony\\Component\\HttpFoundation\\' => |
|
||||||
array ( |
|
||||||
0 => __DIR__ . '/..' . '/symfony/http-foundation', |
|
||||||
), |
|
||||||
'React\\Stream\\' => |
|
||||||
array ( |
|
||||||
0 => __DIR__ . '/..' . '/react/stream/src', |
|
||||||
), |
|
||||||
'React\\Socket\\' => |
|
||||||
array ( |
|
||||||
0 => __DIR__ . '/..' . '/react/socket/src', |
|
||||||
), |
|
||||||
'React\\Promise\\' => |
|
||||||
array ( |
|
||||||
0 => __DIR__ . '/..' . '/react/promise/src', |
|
||||||
), |
|
||||||
'React\\EventLoop\\' => |
|
||||||
array ( |
|
||||||
0 => __DIR__ . '/..' . '/react/event-loop/src', |
|
||||||
), |
|
||||||
'Ratchet\\RFC6455\\' => |
|
||||||
array ( |
|
||||||
0 => __DIR__ . '/..' . '/ratchet/rfc6455/src', |
|
||||||
), |
|
||||||
'Ratchet\\' => |
|
||||||
array ( |
|
||||||
0 => __DIR__ . '/..' . '/cboden/ratchet/src/Ratchet', |
|
||||||
), |
|
||||||
'Psr\\Http\\Message\\' => |
|
||||||
array ( |
|
||||||
0 => __DIR__ . '/..' . '/psr/http-message/src', |
|
||||||
), |
|
||||||
'GuzzleHttp\\Psr7\\' => |
|
||||||
array ( |
|
||||||
0 => __DIR__ . '/..' . '/guzzlehttp/psr7/src', |
|
||||||
), |
|
||||||
'Amir\\' => |
|
||||||
array ( |
|
||||||
0 => __DIR__ . '/../..' . '/bin/amir', |
|
||||||
), |
|
||||||
); |
|
||||||
|
|
||||||
public static $prefixesPsr0 = array ( |
|
||||||
'E' => |
|
||||||
array ( |
|
||||||
'Evenement' => |
|
||||||
array ( |
|
||||||
0 => __DIR__ . '/..' . '/evenement/evenement/src', |
|
||||||
), |
|
||||||
), |
|
||||||
); |
|
||||||
|
|
||||||
public static $classMap = array ( |
|
||||||
'ArithmeticError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php', |
|
||||||
'AssertionError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/AssertionError.php', |
|
||||||
'DivisionByZeroError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/DivisionByZeroError.php', |
|
||||||
'Error' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/Error.php', |
|
||||||
'ParseError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/ParseError.php', |
|
||||||
'SessionUpdateTimestampHandlerInterface' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/SessionUpdateTimestampHandlerInterface.php', |
|
||||||
'TypeError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/TypeError.php', |
|
||||||
); |
|
||||||
|
|
||||||
public static function getInitializer(ClassLoader $loader) |
|
||||||
{ |
|
||||||
return \Closure::bind(function () use ($loader) { |
|
||||||
$loader->prefixLengthsPsr4 = ComposerStaticInita3d708ca3bb0f3f4e817238e4fb57153::$prefixLengthsPsr4; |
|
||||||
$loader->prefixDirsPsr4 = ComposerStaticInita3d708ca3bb0f3f4e817238e4fb57153::$prefixDirsPsr4; |
|
||||||
$loader->prefixesPsr0 = ComposerStaticInita3d708ca3bb0f3f4e817238e4fb57153::$prefixesPsr0; |
|
||||||
$loader->classMap = ComposerStaticInita3d708ca3bb0f3f4e817238e4fb57153::$classMap; |
|
||||||
|
|
||||||
}, null, ClassLoader::class); |
|
||||||
} |
|
||||||
} |
|
@ -1,810 +0,0 @@ |
|||||||
[ |
|
||||||
{ |
|
||||||
"name": "cboden/ratchet", |
|
||||||
"version": "0.4.x-dev", |
|
||||||
"version_normalized": "0.4.9999999.9999999-dev", |
|
||||||
"source": { |
|
||||||
"type": "git", |
|
||||||
"url": "https://github.com/ratchetphp/Ratchet.git", |
|
||||||
"reference": "a78c8d2ddff78aef1d05cbf08e8bdcf8c21e1b14" |
|
||||||
}, |
|
||||||
"dist": { |
|
||||||
"type": "zip", |
|
||||||
"url": "https://api.github.com/repos/ratchetphp/Ratchet/zipball/a78c8d2ddff78aef1d05cbf08e8bdcf8c21e1b14", |
|
||||||
"reference": "a78c8d2ddff78aef1d05cbf08e8bdcf8c21e1b14", |
|
||||||
"shasum": "" |
|
||||||
}, |
|
||||||
"require": { |
|
||||||
"guzzlehttp/psr7": "^1.0", |
|
||||||
"php": ">=5.4.2", |
|
||||||
"ratchet/rfc6455": "^0.2", |
|
||||||
"react/socket": "^0.3 || ^0.4", |
|
||||||
"symfony/http-foundation": "^2.2|^3.0", |
|
||||||
"symfony/routing": "^2.2|^3.0" |
|
||||||
}, |
|
||||||
"suggest": { |
|
||||||
"ext-pecl_http": "^2.0" |
|
||||||
}, |
|
||||||
"time": "2016-06-06T13:13:02+00:00", |
|
||||||
"type": "library", |
|
||||||
"installation-source": "dist", |
|
||||||
"autoload": { |
|
||||||
"psr-4": { |
|
||||||
"Ratchet\\": "src/Ratchet" |
|
||||||
} |
|
||||||
}, |
|
||||||
"notification-url": "https://packagist.org/downloads/", |
|
||||||
"license": [ |
|
||||||
"MIT" |
|
||||||
], |
|
||||||
"authors": [ |
|
||||||
{ |
|
||||||
"name": "Chris Boden", |
|
||||||
"email": "cboden@gmail.com", |
|
||||||
"role": "Developer" |
|
||||||
} |
|
||||||
], |
|
||||||
"description": "PHP WebSocket library", |
|
||||||
"homepage": "http://socketo.me", |
|
||||||
"keywords": [ |
|
||||||
"Ratchet", |
|
||||||
"WebSockets", |
|
||||||
"server", |
|
||||||
"sockets", |
|
||||||
"websocket" |
|
||||||
] |
|
||||||
}, |
|
||||||
{ |
|
||||||
"name": "evenement/evenement", |
|
||||||
"version": "v2.1.0", |
|
||||||
"version_normalized": "2.1.0.0", |
|
||||||
"source": { |
|
||||||
"type": "git", |
|
||||||
"url": "https://github.com/igorw/evenement.git", |
|
||||||
"reference": "6ba9a777870ab49f417e703229d53931ed40fd7a" |
|
||||||
}, |
|
||||||
"dist": { |
|
||||||
"type": "zip", |
|
||||||
"url": "https://api.github.com/repos/igorw/evenement/zipball/6ba9a777870ab49f417e703229d53931ed40fd7a", |
|
||||||
"reference": "6ba9a777870ab49f417e703229d53931ed40fd7a", |
|
||||||
"shasum": "" |
|
||||||
}, |
|
||||||
"require": { |
|
||||||
"php": ">=5.4.0" |
|
||||||
}, |
|
||||||
"require-dev": { |
|
||||||
"phpunit/phpunit": "^6.0||^5.7||^4.8.35" |
|
||||||
}, |
|
||||||
"time": "2017-07-17T17:39:19+00:00", |
|
||||||
"type": "library", |
|
||||||
"extra": { |
|
||||||
"branch-alias": { |
|
||||||
"dev-master": "2.0-dev" |
|
||||||
} |
|
||||||
}, |
|
||||||
"installation-source": "dist", |
|
||||||
"autoload": { |
|
||||||
"psr-0": { |
|
||||||
"Evenement": "src" |
|
||||||
} |
|
||||||
}, |
|
||||||
"notification-url": "https://packagist.org/downloads/", |
|
||||||
"license": [ |
|
||||||
"MIT" |
|
||||||
], |
|
||||||
"authors": [ |
|
||||||
{ |
|
||||||
"name": "Igor Wiedler", |
|
||||||
"email": "igor@wiedler.ch" |
|
||||||
} |
|
||||||
], |
|
||||||
"description": "Événement is a very simple event dispatching library for PHP", |
|
||||||
"keywords": [ |
|
||||||
"event-dispatcher", |
|
||||||
"event-emitter" |
|
||||||
] |
|
||||||
}, |
|
||||||
{ |
|
||||||
"name": "guzzlehttp/psr7", |
|
||||||
"version": "1.6.1", |
|
||||||
"version_normalized": "1.6.1.0", |
|
||||||
"source": { |
|
||||||
"type": "git", |
|
||||||
"url": "https://github.com/guzzle/psr7.git", |
|
||||||
"reference": "239400de7a173fe9901b9ac7c06497751f00727a" |
|
||||||
}, |
|
||||||
"dist": { |
|
||||||
"type": "zip", |
|
||||||
"url": "https://api.github.com/repos/guzzle/psr7/zipball/239400de7a173fe9901b9ac7c06497751f00727a", |
|
||||||
"reference": "239400de7a173fe9901b9ac7c06497751f00727a", |
|
||||||
"shasum": "" |
|
||||||
}, |
|
||||||
"require": { |
|
||||||
"php": ">=5.4.0", |
|
||||||
"psr/http-message": "~1.0", |
|
||||||
"ralouphie/getallheaders": "^2.0.5 || ^3.0.0" |
|
||||||
}, |
|
||||||
"provide": { |
|
||||||
"psr/http-message-implementation": "1.0" |
|
||||||
}, |
|
||||||
"require-dev": { |
|
||||||
"ext-zlib": "*", |
|
||||||
"phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8" |
|
||||||
}, |
|
||||||
"suggest": { |
|
||||||
"zendframework/zend-httphandlerrunner": "Emit PSR-7 responses" |
|
||||||
}, |
|
||||||
"time": "2019-07-01T23:21:34+00:00", |
|
||||||
"type": "library", |
|
||||||
"extra": { |
|
||||||
"branch-alias": { |
|
||||||
"dev-master": "1.6-dev" |
|
||||||
} |
|
||||||
}, |
|
||||||
"installation-source": "dist", |
|
||||||
"autoload": { |
|
||||||
"psr-4": { |
|
||||||
"GuzzleHttp\\Psr7\\": "src/" |
|
||||||
}, |
|
||||||
"files": [ |
|
||||||
"src/functions_include.php" |
|
||||||
] |
|
||||||
}, |
|
||||||
"notification-url": "https://packagist.org/downloads/", |
|
||||||
"license": [ |
|
||||||
"MIT" |
|
||||||
], |
|
||||||
"authors": [ |
|
||||||
{ |
|
||||||
"name": "Michael Dowling", |
|
||||||
"email": "mtdowling@gmail.com", |
|
||||||
"homepage": "https://github.com/mtdowling" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"name": "Tobias Schultze", |
|
||||||
"homepage": "https://github.com/Tobion" |
|
||||||
} |
|
||||||
], |
|
||||||
"description": "PSR-7 message implementation that also provides common utility methods", |
|
||||||
"keywords": [ |
|
||||||
"http", |
|
||||||
"message", |
|
||||||
"psr-7", |
|
||||||
"request", |
|
||||||
"response", |
|
||||||
"stream", |
|
||||||
"uri", |
|
||||||
"url" |
|
||||||
] |
|
||||||
}, |
|
||||||
{ |
|
||||||
"name": "paragonie/random_compat", |
|
||||||
"version": "v9.99.99", |
|
||||||
"version_normalized": "9.99.99.0", |
|
||||||
"source": { |
|
||||||
"type": "git", |
|
||||||
"url": "https://github.com/paragonie/random_compat.git", |
|
||||||
"reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95" |
|
||||||
}, |
|
||||||
"dist": { |
|
||||||
"type": "zip", |
|
||||||
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", |
|
||||||
"reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", |
|
||||||
"shasum": "" |
|
||||||
}, |
|
||||||
"require": { |
|
||||||
"php": "^7" |
|
||||||
}, |
|
||||||
"require-dev": { |
|
||||||
"phpunit/phpunit": "4.*|5.*", |
|
||||||
"vimeo/psalm": "^1" |
|
||||||
}, |
|
||||||
"suggest": { |
|
||||||
"ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." |
|
||||||
}, |
|
||||||
"time": "2018-07-02T15:55:56+00:00", |
|
||||||
"type": "library", |
|
||||||
"installation-source": "dist", |
|
||||||
"notification-url": "https://packagist.org/downloads/", |
|
||||||
"license": [ |
|
||||||
"MIT" |
|
||||||
], |
|
||||||
"authors": [ |
|
||||||
{ |
|
||||||
"name": "Paragon Initiative Enterprises", |
|
||||||
"email": "security@paragonie.com", |
|
||||||
"homepage": "https://paragonie.com" |
|
||||||
} |
|
||||||
], |
|
||||||
"description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", |
|
||||||
"keywords": [ |
|
||||||
"csprng", |
|
||||||
"polyfill", |
|
||||||
"pseudorandom", |
|
||||||
"random" |
|
||||||
] |
|
||||||
}, |
|
||||||
{ |
|
||||||
"name": "psr/http-message", |
|
||||||
"version": "1.0.1", |
|
||||||
"version_normalized": "1.0.1.0", |
|
||||||
"source": { |
|
||||||
"type": "git", |
|
||||||
"url": "https://github.com/php-fig/http-message.git", |
|
||||||
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" |
|
||||||
}, |
|
||||||
"dist": { |
|
||||||
"type": "zip", |
|
||||||
"url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", |
|
||||||
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", |
|
||||||
"shasum": "" |
|
||||||
}, |
|
||||||
"require": { |
|
||||||
"php": ">=5.3.0" |
|
||||||
}, |
|
||||||
"time": "2016-08-06T14:39:51+00:00", |
|
||||||
"type": "library", |
|
||||||
"extra": { |
|
||||||
"branch-alias": { |
|
||||||
"dev-master": "1.0.x-dev" |
|
||||||
} |
|
||||||
}, |
|
||||||
"installation-source": "dist", |
|
||||||
"autoload": { |
|
||||||
"psr-4": { |
|
||||||
"Psr\\Http\\Message\\": "src/" |
|
||||||
} |
|
||||||
}, |
|
||||||
"notification-url": "https://packagist.org/downloads/", |
|
||||||
"license": [ |
|
||||||
"MIT" |
|
||||||
], |
|
||||||
"authors": [ |
|
||||||
{ |
|
||||||
"name": "PHP-FIG", |
|
||||||
"homepage": "http://www.php-fig.org/" |
|
||||||
} |
|
||||||
], |
|
||||||
"description": "Common interface for HTTP messages", |
|
||||||
"homepage": "https://github.com/php-fig/http-message", |
|
||||||
"keywords": [ |
|
||||||
"http", |
|
||||||
"http-message", |
|
||||||
"psr", |
|
||||||
"psr-7", |
|
||||||
"request", |
|
||||||
"response" |
|
||||||
] |
|
||||||
}, |
|
||||||
{ |
|
||||||
"name": "ralouphie/getallheaders", |
|
||||||
"version": "3.0.3", |
|
||||||
"version_normalized": "3.0.3.0", |
|
||||||
"source": { |
|
||||||
"type": "git", |
|
||||||
"url": "https://github.com/ralouphie/getallheaders.git", |
|
||||||
"reference": "120b605dfeb996808c31b6477290a714d356e822" |
|
||||||
}, |
|
||||||
"dist": { |
|
||||||
"type": "zip", |
|
||||||
"url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", |
|
||||||
"reference": "120b605dfeb996808c31b6477290a714d356e822", |
|
||||||
"shasum": "" |
|
||||||
}, |
|
||||||
"require": { |
|
||||||
"php": ">=5.6" |
|
||||||
}, |
|
||||||
"require-dev": { |
|
||||||
"php-coveralls/php-coveralls": "^2.1", |
|
||||||
"phpunit/phpunit": "^5 || ^6.5" |
|
||||||
}, |
|
||||||
"time": "2019-03-08T08:55:37+00:00", |
|
||||||
"type": "library", |
|
||||||
"installation-source": "dist", |
|
||||||
"autoload": { |
|
||||||
"files": [ |
|
||||||
"src/getallheaders.php" |
|
||||||
] |
|
||||||
}, |
|
||||||
"notification-url": "https://packagist.org/downloads/", |
|
||||||
"license": [ |
|
||||||
"MIT" |
|
||||||
], |
|
||||||
"authors": [ |
|
||||||
{ |
|
||||||
"name": "Ralph Khattar", |
|
||||||
"email": "ralph.khattar@gmail.com" |
|
||||||
} |
|
||||||
], |
|
||||||
"description": "A polyfill for getallheaders." |
|
||||||
}, |
|
||||||
{ |
|
||||||
"name": "ratchet/rfc6455", |
|
||||||
"version": "v0.2.5", |
|
||||||
"version_normalized": "0.2.5.0", |
|
||||||
"source": { |
|
||||||
"type": "git", |
|
||||||
"url": "https://github.com/ratchetphp/RFC6455.git", |
|
||||||
"reference": "c62f7cd95ffbb6e94fd657be694fc7372ecd6e62" |
|
||||||
}, |
|
||||||
"dist": { |
|
||||||
"type": "zip", |
|
||||||
"url": "https://api.github.com/repos/ratchetphp/RFC6455/zipball/c62f7cd95ffbb6e94fd657be694fc7372ecd6e62", |
|
||||||
"reference": "c62f7cd95ffbb6e94fd657be694fc7372ecd6e62", |
|
||||||
"shasum": "" |
|
||||||
}, |
|
||||||
"require": { |
|
||||||
"guzzlehttp/psr7": "^1.0", |
|
||||||
"php": ">=5.4.2" |
|
||||||
}, |
|
||||||
"require-dev": { |
|
||||||
"phpunit/phpunit": "4.8.*", |
|
||||||
"react/http": "^0.4.1", |
|
||||||
"react/socket-client": "^0.4.3" |
|
||||||
}, |
|
||||||
"time": "2019-03-10T17:10:42+00:00", |
|
||||||
"type": "library", |
|
||||||
"installation-source": "dist", |
|
||||||
"autoload": { |
|
||||||
"psr-4": { |
|
||||||
"Ratchet\\RFC6455\\": "src" |
|
||||||
} |
|
||||||
}, |
|
||||||
"notification-url": "https://packagist.org/downloads/", |
|
||||||
"license": [ |
|
||||||
"MIT" |
|
||||||
], |
|
||||||
"authors": [ |
|
||||||
{ |
|
||||||
"name": "Chris Boden", |
|
||||||
"email": "cboden@gmail.com", |
|
||||||
"role": "Developer" |
|
||||||
} |
|
||||||
], |
|
||||||
"description": "RFC6455 WebSocket protocol handler", |
|
||||||
"homepage": "http://socketo.me", |
|
||||||
"keywords": [ |
|
||||||
"WebSockets", |
|
||||||
"rfc6455", |
|
||||||
"websocket" |
|
||||||
] |
|
||||||
}, |
|
||||||
{ |
|
||||||
"name": "react/event-loop", |
|
||||||
"version": "v0.4.3", |
|
||||||
"version_normalized": "0.4.3.0", |
|
||||||
"source": { |
|
||||||
"type": "git", |
|
||||||
"url": "https://github.com/reactphp/event-loop.git", |
|
||||||
"reference": "8bde03488ee897dc6bb3d91e4e17c353f9c5252f" |
|
||||||
}, |
|
||||||
"dist": { |
|
||||||
"type": "zip", |
|
||||||
"url": "https://api.github.com/repos/reactphp/event-loop/zipball/8bde03488ee897dc6bb3d91e4e17c353f9c5252f", |
|
||||||
"reference": "8bde03488ee897dc6bb3d91e4e17c353f9c5252f", |
|
||||||
"shasum": "" |
|
||||||
}, |
|
||||||
"require": { |
|
||||||
"php": ">=5.4.0" |
|
||||||
}, |
|
||||||
"require-dev": { |
|
||||||
"phpunit/phpunit": "~4.8" |
|
||||||
}, |
|
||||||
"suggest": { |
|
||||||
"ext-event": "~1.0", |
|
||||||
"ext-libev": "*", |
|
||||||
"ext-libevent": ">=0.1.0" |
|
||||||
}, |
|
||||||
"time": "2017-04-27T10:56:23+00:00", |
|
||||||
"type": "library", |
|
||||||
"installation-source": "dist", |
|
||||||
"autoload": { |
|
||||||
"psr-4": { |
|
||||||
"React\\EventLoop\\": "src" |
|
||||||
} |
|
||||||
}, |
|
||||||
"notification-url": "https://packagist.org/downloads/", |
|
||||||
"license": [ |
|
||||||
"MIT" |
|
||||||
], |
|
||||||
"description": "Event loop abstraction layer that libraries can use for evented I/O.", |
|
||||||
"keywords": [ |
|
||||||
"asynchronous", |
|
||||||
"event-loop" |
|
||||||
] |
|
||||||
}, |
|
||||||
{ |
|
||||||
"name": "react/promise", |
|
||||||
"version": "v2.7.1", |
|
||||||
"version_normalized": "2.7.1.0", |
|
||||||
"source": { |
|
||||||
"type": "git", |
|
||||||
"url": "https://github.com/reactphp/promise.git", |
|
||||||
"reference": "31ffa96f8d2ed0341a57848cbb84d88b89dd664d" |
|
||||||
}, |
|
||||||
"dist": { |
|
||||||
"type": "zip", |
|
||||||
"url": "https://api.github.com/repos/reactphp/promise/zipball/31ffa96f8d2ed0341a57848cbb84d88b89dd664d", |
|
||||||
"reference": "31ffa96f8d2ed0341a57848cbb84d88b89dd664d", |
|
||||||
"shasum": "" |
|
||||||
}, |
|
||||||
"require": { |
|
||||||
"php": ">=5.4.0" |
|
||||||
}, |
|
||||||
"require-dev": { |
|
||||||
"phpunit/phpunit": "~4.8" |
|
||||||
}, |
|
||||||
"time": "2019-01-07T21:25:54+00:00", |
|
||||||
"type": "library", |
|
||||||
"installation-source": "dist", |
|
||||||
"autoload": { |
|
||||||
"psr-4": { |
|
||||||
"React\\Promise\\": "src/" |
|
||||||
}, |
|
||||||
"files": [ |
|
||||||
"src/functions_include.php" |
|
||||||
] |
|
||||||
}, |
|
||||||
"notification-url": "https://packagist.org/downloads/", |
|
||||||
"license": [ |
|
||||||
"MIT" |
|
||||||
], |
|
||||||
"authors": [ |
|
||||||
{ |
|
||||||
"name": "Jan Sorgalla", |
|
||||||
"email": "jsorgalla@gmail.com" |
|
||||||
} |
|
||||||
], |
|
||||||
"description": "A lightweight implementation of CommonJS Promises/A for PHP", |
|
||||||
"keywords": [ |
|
||||||
"promise", |
|
||||||
"promises" |
|
||||||
] |
|
||||||
}, |
|
||||||
{ |
|
||||||
"name": "react/socket", |
|
||||||
"version": "v0.4.6", |
|
||||||
"version_normalized": "0.4.6.0", |
|
||||||
"source": { |
|
||||||
"type": "git", |
|
||||||
"url": "https://github.com/reactphp/socket.git", |
|
||||||
"reference": "cf074e53c974df52388ebd09710a9018894745d2" |
|
||||||
}, |
|
||||||
"dist": { |
|
||||||
"type": "zip", |
|
||||||
"url": "https://api.github.com/repos/reactphp/socket/zipball/cf074e53c974df52388ebd09710a9018894745d2", |
|
||||||
"reference": "cf074e53c974df52388ebd09710a9018894745d2", |
|
||||||
"shasum": "" |
|
||||||
}, |
|
||||||
"require": { |
|
||||||
"evenement/evenement": "~2.0|~1.0", |
|
||||||
"php": ">=5.3.0", |
|
||||||
"react/event-loop": "0.4.*|0.3.*", |
|
||||||
"react/promise": "^2.0 || ^1.1", |
|
||||||
"react/stream": "^0.4.5" |
|
||||||
}, |
|
||||||
"require-dev": { |
|
||||||
"clue/block-react": "^1.1", |
|
||||||
"phpunit/phpunit": "~4.8", |
|
||||||
"react/socket-client": "^0.5.1" |
|
||||||
}, |
|
||||||
"time": "2017-01-26T09:23:38+00:00", |
|
||||||
"type": "library", |
|
||||||
"installation-source": "dist", |
|
||||||
"autoload": { |
|
||||||
"psr-4": { |
|
||||||
"React\\Socket\\": "src" |
|
||||||
} |
|
||||||
}, |
|
||||||
"notification-url": "https://packagist.org/downloads/", |
|
||||||
"license": [ |
|
||||||
"MIT" |
|
||||||
], |
|
||||||
"description": "Async, streaming plaintext TCP/IP and secure TLS socket server for React PHP", |
|
||||||
"keywords": [ |
|
||||||
"Socket" |
|
||||||
] |
|
||||||
}, |
|
||||||
{ |
|
||||||
"name": "react/stream", |
|
||||||
"version": "v0.4.6", |
|
||||||
"version_normalized": "0.4.6.0", |
|
||||||
"source": { |
|
||||||
"type": "git", |
|
||||||
"url": "https://github.com/reactphp/stream.git", |
|
||||||
"reference": "44dc7f51ea48624110136b535b9ba44fd7d0c1ee" |
|
||||||
}, |
|
||||||
"dist": { |
|
||||||
"type": "zip", |
|
||||||
"url": "https://api.github.com/repos/reactphp/stream/zipball/44dc7f51ea48624110136b535b9ba44fd7d0c1ee", |
|
||||||
"reference": "44dc7f51ea48624110136b535b9ba44fd7d0c1ee", |
|
||||||
"shasum": "" |
|
||||||
}, |
|
||||||
"require": { |
|
||||||
"evenement/evenement": "^2.0|^1.0", |
|
||||||
"php": ">=5.3.8" |
|
||||||
}, |
|
||||||
"require-dev": { |
|
||||||
"clue/stream-filter": "~1.2", |
|
||||||
"react/event-loop": "^0.4|^0.3", |
|
||||||
"react/promise": "^2.0|^1.0" |
|
||||||
}, |
|
||||||
"suggest": { |
|
||||||
"react/event-loop": "^0.4", |
|
||||||
"react/promise": "^2.0" |
|
||||||
}, |
|
||||||
"time": "2017-01-25T14:44:14+00:00", |
|
||||||
"type": "library", |
|
||||||
"installation-source": "dist", |
|
||||||
"autoload": { |
|
||||||
"psr-4": { |
|
||||||
"React\\Stream\\": "src" |
|
||||||
} |
|
||||||
}, |
|
||||||
"notification-url": "https://packagist.org/downloads/", |
|
||||||
"license": [ |
|
||||||
"MIT" |
|
||||||
], |
|
||||||
"description": "Basic readable and writable stream interfaces that support piping.", |
|
||||||
"keywords": [ |
|
||||||
"pipe", |
|
||||||
"stream" |
|
||||||
] |
|
||||||
}, |
|
||||||
{ |
|
||||||
"name": "symfony/http-foundation", |
|
||||||
"version": "v3.4.36", |
|
||||||
"version_normalized": "3.4.36.0", |
|
||||||
"source": { |
|
||||||
"type": "git", |
|
||||||
"url": "https://github.com/symfony/http-foundation.git", |
|
||||||
"reference": "d2d0cfe8e319d9df44c4cca570710fcf221d4593" |
|
||||||
}, |
|
||||||
"dist": { |
|
||||||
"type": "zip", |
|
||||||
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/d2d0cfe8e319d9df44c4cca570710fcf221d4593", |
|
||||||
"reference": "d2d0cfe8e319d9df44c4cca570710fcf221d4593", |
|
||||||
"shasum": "" |
|
||||||
}, |
|
||||||
"require": { |
|
||||||
"php": "^5.5.9|>=7.0.8", |
|
||||||
"symfony/polyfill-mbstring": "~1.1", |
|
||||||
"symfony/polyfill-php70": "~1.6" |
|
||||||
}, |
|
||||||
"require-dev": { |
|
||||||
"symfony/expression-language": "~2.8|~3.0|~4.0" |
|
||||||
}, |
|
||||||
"time": "2019-11-28T12:52:59+00:00", |
|
||||||
"type": "library", |
|
||||||
"extra": { |
|
||||||
"branch-alias": { |
|
||||||
"dev-master": "3.4-dev" |
|
||||||
} |
|
||||||
}, |
|
||||||
"installation-source": "dist", |
|
||||||
"autoload": { |
|
||||||
"psr-4": { |
|
||||||
"Symfony\\Component\\HttpFoundation\\": "" |
|
||||||
}, |
|
||||||
"exclude-from-classmap": [ |
|
||||||
"/Tests/" |
|
||||||
] |
|
||||||
}, |
|
||||||
"notification-url": "https://packagist.org/downloads/", |
|
||||||
"license": [ |
|
||||||
"MIT" |
|
||||||
], |
|
||||||
"authors": [ |
|
||||||
{ |
|
||||||
"name": "Fabien Potencier", |
|
||||||
"email": "fabien@symfony.com" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"name": "Symfony Community", |
|
||||||
"homepage": "https://symfony.com/contributors" |
|
||||||
} |
|
||||||
], |
|
||||||
"description": "Symfony HttpFoundation Component", |
|
||||||
"homepage": "https://symfony.com" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"name": "symfony/polyfill-mbstring", |
|
||||||
"version": "v1.13.1", |
|
||||||
"version_normalized": "1.13.1.0", |
|
||||||
"source": { |
|
||||||
"type": "git", |
|
||||||
"url": "https://github.com/symfony/polyfill-mbstring.git", |
|
||||||
"reference": "7b4aab9743c30be783b73de055d24a39cf4b954f" |
|
||||||
}, |
|
||||||
"dist": { |
|
||||||
"type": "zip", |
|
||||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/7b4aab9743c30be783b73de055d24a39cf4b954f", |
|
||||||
"reference": "7b4aab9743c30be783b73de055d24a39cf4b954f", |
|
||||||
"shasum": "" |
|
||||||
}, |
|
||||||
"require": { |
|
||||||
"php": ">=5.3.3" |
|
||||||
}, |
|
||||||
"suggest": { |
|
||||||
"ext-mbstring": "For best performance" |
|
||||||
}, |
|
||||||
"time": "2019-11-27T14:18:11+00:00", |
|
||||||
"type": "library", |
|
||||||
"extra": { |
|
||||||
"branch-alias": { |
|
||||||
"dev-master": "1.13-dev" |
|
||||||
} |
|
||||||
}, |
|
||||||
"installation-source": "dist", |
|
||||||
"autoload": { |
|
||||||
"psr-4": { |
|
||||||
"Symfony\\Polyfill\\Mbstring\\": "" |
|
||||||
}, |
|
||||||
"files": [ |
|
||||||
"bootstrap.php" |
|
||||||
] |
|
||||||
}, |
|
||||||
"notification-url": "https://packagist.org/downloads/", |
|
||||||
"license": [ |
|
||||||
"MIT" |
|
||||||
], |
|
||||||
"authors": [ |
|
||||||
{ |
|
||||||
"name": "Nicolas Grekas", |
|
||||||
"email": "p@tchwork.com" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"name": "Symfony Community", |
|
||||||
"homepage": "https://symfony.com/contributors" |
|
||||||
} |
|
||||||
], |
|
||||||
"description": "Symfony polyfill for the Mbstring extension", |
|
||||||
"homepage": "https://symfony.com", |
|
||||||
"keywords": [ |
|
||||||
"compatibility", |
|
||||||
"mbstring", |
|
||||||
"polyfill", |
|
||||||
"portable", |
|
||||||
"shim" |
|
||||||
] |
|
||||||
}, |
|
||||||
{ |
|
||||||
"name": "symfony/polyfill-php70", |
|
||||||
"version": "v1.13.1", |
|
||||||
"version_normalized": "1.13.1.0", |
|
||||||
"source": { |
|
||||||
"type": "git", |
|
||||||
"url": "https://github.com/symfony/polyfill-php70.git", |
|
||||||
"reference": "af23c7bb26a73b850840823662dda371484926c4" |
|
||||||
}, |
|
||||||
"dist": { |
|
||||||
"type": "zip", |
|
||||||
"url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/af23c7bb26a73b850840823662dda371484926c4", |
|
||||||
"reference": "af23c7bb26a73b850840823662dda371484926c4", |
|
||||||
"shasum": "" |
|
||||||
}, |
|
||||||
"require": { |
|
||||||
"paragonie/random_compat": "~1.0|~2.0|~9.99", |
|
||||||
"php": ">=5.3.3" |
|
||||||
}, |
|
||||||
"time": "2019-11-27T13:56:44+00:00", |
|
||||||
"type": "library", |
|
||||||
"extra": { |
|
||||||
"branch-alias": { |
|
||||||
"dev-master": "1.13-dev" |
|
||||||
} |
|
||||||
}, |
|
||||||
"installation-source": "dist", |
|
||||||
"autoload": { |
|
||||||
"psr-4": { |
|
||||||
"Symfony\\Polyfill\\Php70\\": "" |
|
||||||
}, |
|
||||||
"files": [ |
|
||||||
"bootstrap.php" |
|
||||||
], |
|
||||||
"classmap": [ |
|
||||||
"Resources/stubs" |
|
||||||
] |
|
||||||
}, |
|
||||||
"notification-url": "https://packagist.org/downloads/", |
|
||||||
"license": [ |
|
||||||
"MIT" |
|
||||||
], |
|
||||||
"authors": [ |
|
||||||
{ |
|
||||||
"name": "Nicolas Grekas", |
|
||||||
"email": "p@tchwork.com" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"name": "Symfony Community", |
|
||||||
"homepage": "https://symfony.com/contributors" |
|
||||||
} |
|
||||||
], |
|
||||||
"description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions", |
|
||||||
"homepage": "https://symfony.com", |
|
||||||
"keywords": [ |
|
||||||
"compatibility", |
|
||||||
"polyfill", |
|
||||||
"portable", |
|
||||||
"shim" |
|
||||||
] |
|
||||||
}, |
|
||||||
{ |
|
||||||
"name": "symfony/routing", |
|
||||||
"version": "v3.4.36", |
|
||||||
"version_normalized": "3.4.36.0", |
|
||||||
"source": { |
|
||||||
"type": "git", |
|
||||||
"url": "https://github.com/symfony/routing.git", |
|
||||||
"reference": "b689ccd48e234ea404806d94b07eeb45f9f6f06a" |
|
||||||
}, |
|
||||||
"dist": { |
|
||||||
"type": "zip", |
|
||||||
"url": "https://api.github.com/repos/symfony/routing/zipball/b689ccd48e234ea404806d94b07eeb45f9f6f06a", |
|
||||||
"reference": "b689ccd48e234ea404806d94b07eeb45f9f6f06a", |
|
||||||
"shasum": "" |
|
||||||
}, |
|
||||||
"require": { |
|
||||||
"php": "^5.5.9|>=7.0.8" |
|
||||||
}, |
|
||||||
"conflict": { |
|
||||||
"symfony/config": "<3.3.1", |
|
||||||
"symfony/dependency-injection": "<3.3", |
|
||||||
"symfony/yaml": "<3.4" |
|
||||||
}, |
|
||||||
"require-dev": { |
|
||||||
"doctrine/annotations": "~1.0", |
|
||||||
"psr/log": "~1.0", |
|
||||||
"symfony/config": "^3.3.1|~4.0", |
|
||||||
"symfony/dependency-injection": "~3.3|~4.0", |
|
||||||
"symfony/expression-language": "~2.8|~3.0|~4.0", |
|
||||||
"symfony/http-foundation": "~2.8|~3.0|~4.0", |
|
||||||
"symfony/yaml": "~3.4|~4.0" |
|
||||||
}, |
|
||||||
"suggest": { |
|
||||||
"doctrine/annotations": "For using the annotation loader", |
|
||||||
"symfony/config": "For using the all-in-one router or any loader", |
|
||||||
"symfony/expression-language": "For using expression matching", |
|
||||||
"symfony/http-foundation": "For using a Symfony Request object", |
|
||||||
"symfony/yaml": "For using the YAML loader" |
|
||||||
}, |
|
||||||
"time": "2019-12-01T08:33:36+00:00", |
|
||||||
"type": "library", |
|
||||||
"extra": { |
|
||||||
"branch-alias": { |
|
||||||
"dev-master": "3.4-dev" |
|
||||||
} |
|
||||||
}, |
|
||||||
"installation-source": "dist", |
|
||||||
"autoload": { |
|
||||||
"psr-4": { |
|
||||||
"Symfony\\Component\\Routing\\": "" |
|
||||||
}, |
|
||||||
"exclude-from-classmap": [ |
|
||||||
"/Tests/" |
|
||||||
] |
|
||||||
}, |
|
||||||
"notification-url": "https://packagist.org/downloads/", |
|
||||||
"license": [ |
|
||||||
"MIT" |
|
||||||
], |
|
||||||
"authors": [ |
|
||||||
{ |
|
||||||
"name": "Fabien Potencier", |
|
||||||
"email": "fabien@symfony.com" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"name": "Symfony Community", |
|
||||||
"homepage": "https://symfony.com/contributors" |
|
||||||
} |
|
||||||
], |
|
||||||
"description": "Symfony Routing Component", |
|
||||||
"homepage": "https://symfony.com", |
|
||||||
"keywords": [ |
|
||||||
"router", |
|
||||||
"routing", |
|
||||||
"uri", |
|
||||||
"url" |
|
||||||
] |
|
||||||
} |
|
||||||
] |
|
@ -1,2 +0,0 @@ |
|||||||
composer.lock |
|
||||||
vendor |
|
@ -1,26 +0,0 @@ |
|||||||
language: php |
|
||||||
|
|
||||||
php: |
|
||||||
- 5.4 |
|
||||||
- 5.5 |
|
||||||
- 5.6 |
|
||||||
- 7.0 |
|
||||||
- 7.1 |
|
||||||
- hhvm |
|
||||||
- nightly |
|
||||||
|
|
||||||
matrix: |
|
||||||
allow_failures: |
|
||||||
- php: hhvm |
|
||||||
- php: nightly |
|
||||||
|
|
||||||
before_script: |
|
||||||
- wget http://getcomposer.org/composer.phar |
|
||||||
- php composer.phar install |
|
||||||
|
|
||||||
script: |
|
||||||
- ./vendor/bin/phpunit --coverage-text |
|
||||||
- php -n examples/benchmark-emit-no-arguments.php |
|
||||||
- php -n examples/benchmark-emit-one-argument.php |
|
||||||
- php -n examples/benchmark-emit.php |
|
||||||
- php -n examples/benchmark-emit-once.php |
|
@ -1,8 +0,0 @@ |
|||||||
CHANGELOG |
|
||||||
========= |
|
||||||
|
|
||||||
* 2.0.0 (2012-11-02) |
|
||||||
|
|
||||||
* Require PHP >=5.4.0 |
|
||||||
* Added EventEmitterTrait |
|
||||||
* Removed EventEmitter2 |
|
@ -1,19 +0,0 @@ |
|||||||
Copyright (c) 2011 Igor Wiedler |
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
|
||||||
of this software and associated documentation files (the "Software"), to deal |
|
||||||
in the Software without restriction, including without limitation the rights |
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
||||||
copies of the Software, and to permit persons to whom the Software is furnished |
|
||||||
to do so, subject to the following conditions: |
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all |
|
||||||
copies or substantial portions of the Software. |
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
||||||
THE SOFTWARE. |
|
@ -1,83 +0,0 @@ |
|||||||
# Événement |
|
||||||
|
|
||||||
Événement is a very simple event dispatching library for PHP. |
|
||||||
|
|
||||||
It has the same design goals as [Silex](http://silex-project.org) and |
|
||||||
[Pimple](http://pimple-project.org), to empower the user while staying concise |
|
||||||
and simple. |
|
||||||
|
|
||||||
It is very strongly inspired by the EventEmitter API found in |
|
||||||
[node.js](http://nodejs.org). |
|
||||||
|
|
||||||
[](http://travis-ci.org/igorw/evenement) |
|
||||||
|
|
||||||
## Fetch |
|
||||||
|
|
||||||
The recommended way to install Événement is [through composer](http://getcomposer.org). |
|
||||||
|
|
||||||
Just create a composer.json file for your project: |
|
||||||
|
|
||||||
```JSON |
|
||||||
{ |
|
||||||
"require": { |
|
||||||
"evenement/evenement": "2.0.*" |
|
||||||
} |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
**Note:** The `2.0.*` version of Événement requires PHP 5.4. If you are |
|
||||||
using PHP 5.3, please use the `1.0.*` version: |
|
||||||
|
|
||||||
```JSON |
|
||||||
{ |
|
||||||
"require": { |
|
||||||
"evenement/evenement": "1.0.*" |
|
||||||
} |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
And run these two commands to install it: |
|
||||||
|
|
||||||
$ curl -s http://getcomposer.org/installer | php |
|
||||||
$ php composer.phar install |
|
||||||
|
|
||||||
Now you can add the autoloader, and you will have access to the library: |
|
||||||
|
|
||||||
```php |
|
||||||
<?php |
|
||||||
require 'vendor/autoload.php'; |
|
||||||
``` |
|
||||||
|
|
||||||
## Usage |
|
||||||
|
|
||||||
### Creating an Emitter |
|
||||||
|
|
||||||
```php |
|
||||||
<?php |
|
||||||
$emitter = new Evenement\EventEmitter(); |
|
||||||
``` |
|
||||||
|
|
||||||
### Adding Listeners |
|
||||||
|
|
||||||
```php |
|
||||||
<?php |
|
||||||
$emitter->on('user.created', function (User $user) use ($logger) { |
|
||||||
$logger->log(sprintf("User '%s' was created.", $user->getLogin())); |
|
||||||
}); |
|
||||||
``` |
|
||||||
|
|
||||||
### Emitting Events |
|
||||||
|
|
||||||
```php |
|
||||||
<?php |
|
||||||
$emitter->emit('user.created', array($user)); |
|
||||||
``` |
|
||||||
|
|
||||||
Tests |
|
||||||
----- |
|
||||||
|
|
||||||
$ phpunit |
|
||||||
|
|
||||||
License |
|
||||||
------- |
|
||||||
MIT, see LICENSE. |
|
@ -1,34 +0,0 @@ |
|||||||
{ |
|
||||||
"name": "evenement/evenement", |
|
||||||
"description": "Événement is a very simple event dispatching library for PHP", |
|
||||||
"keywords": ["event-dispatcher", "event-emitter"], |
|
||||||
"license": "MIT", |
|
||||||
"authors": [ |
|
||||||
{ |
|
||||||
"name": "Igor Wiedler", |
|
||||||
"email": "igor@wiedler.ch" |
|
||||||
} |
|
||||||
], |
|
||||||
"require": { |
|
||||||
"php": ">=5.4.0" |
|
||||||
}, |
|
||||||
"require-dev": { |
|
||||||
"phpunit/phpunit": "^6.0||^5.7||^4.8.35" |
|
||||||
}, |
|
||||||
"autoload": { |
|
||||||
"psr-0": { |
|
||||||
"Evenement": "src" |
|
||||||
} |
|
||||||
}, |
|
||||||
"autoload-dev": { |
|
||||||
"psr-0": { |
|
||||||
"Evenement": "tests" |
|
||||||
}, |
|
||||||
"files": ["tests/Evenement/Tests/functions.php"] |
|
||||||
}, |
|
||||||
"extra": { |
|
||||||
"branch-alias": { |
|
||||||
"dev-master": "2.0-dev" |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,24 +0,0 @@ |
|||||||
<?xml version="1.0" encoding="UTF-8"?> |
|
||||||
|
|
||||||
<phpunit backupGlobals="false" |
|
||||||
backupStaticAttributes="false" |
|
||||||
colors="true" |
|
||||||
convertErrorsToExceptions="true" |
|
||||||
convertNoticesToExceptions="true" |
|
||||||
convertWarningsToExceptions="true" |
|
||||||
processIsolation="false" |
|
||||||
stopOnFailure="false" |
|
||||||
syntaxCheck="false" |
|
||||||
> |
|
||||||
<testsuites> |
|
||||||
<testsuite name="Evenement Test Suite"> |
|
||||||
<directory>./tests/Evenement/</directory> |
|
||||||
</testsuite> |
|
||||||
</testsuites> |
|
||||||
|
|
||||||
<filter> |
|
||||||
<whitelist> |
|
||||||
<directory>./src/</directory> |
|
||||||
</whitelist> |
|
||||||
</filter> |
|
||||||
</phpunit> |
|
@ -1,17 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
/* |
|
||||||
* This file is part of Evenement. |
|
||||||
* |
|
||||||
* (c) Igor Wiedler <igor@wiedler.ch> |
|
||||||
* |
|
||||||
* For the full copyright and license information, please view the LICENSE |
|
||||||
* file that was distributed with this source code. |
|
||||||
*/ |
|
||||||
|
|
||||||
namespace Evenement; |
|
||||||
|
|
||||||
class EventEmitter implements EventEmitterInterface |
|
||||||
{ |
|
||||||
use EventEmitterTrait; |
|
||||||
} |
|
@ -1,22 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
/* |
|
||||||
* This file is part of Evenement. |
|
||||||
* |
|
||||||
* (c) Igor Wiedler <igor@wiedler.ch> |
|
||||||
* |
|
||||||
* For the full copyright and license information, please view the LICENSE |
|
||||||
* file that was distributed with this source code. |
|
||||||
*/ |
|
||||||
|
|
||||||
namespace Evenement; |
|
||||||
|
|
||||||
interface EventEmitterInterface |
|
||||||
{ |
|
||||||
public function on($event, callable $listener); |
|
||||||
public function once($event, callable $listener); |
|
||||||
public function removeListener($event, callable $listener); |
|
||||||
public function removeAllListeners($event = null); |
|
||||||
public function listeners($event); |
|
||||||
public function emit($event, array $arguments = []); |
|
||||||
} |
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue