diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1d9d32ab..d32de14a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,6 +30,8 @@ jobs: with: php-version: ${{ matrix.php }} coverage: xdebug + env: + COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: composer install - run: vendor/bin/phpunit --coverage-text if: ${{ matrix.php >= 7.3 }} @@ -46,6 +48,8 @@ jobs: with: php-version: 8.0 coverage: xdebug + env: + COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: composer install - run: vendor/bin/phpunit --coverage-text @@ -58,5 +62,7 @@ jobs: - uses: azjezz/setup-hhvm@v1 with: version: lts-3.30 + # see https://github.com/azjezz/setup-hhvm/issues/3 + - run: hhvm $(which composer) -q global config github-oauth.github.com ${{ secrets.GITHUB_TOKEN }} - run: hhvm $(which composer) install - run: hhvm vendor/bin/phpunit diff --git a/README.md b/README.md index 147db836..290b3c3a 100644 --- a/README.md +++ b/README.md @@ -58,8 +58,7 @@ handle multiple concurrent connections without blocking. Here is a server that closes the connection if you send it anything: ```php -$loop = React\EventLoop\Factory::create(); -$socket = new React\Socket\Server('127.0.0.1:8080', $loop); +$socket = new React\Socket\Server('127.0.0.1:8080'); $socket->on('connection', function (React\Socket\ConnectionInterface $connection) { $connection->write("Hello " . $connection->getRemoteAddress() . "!\n"); @@ -70,8 +69,6 @@ $socket->on('connection', function (React\Socket\ConnectionInterface $connection $connection->close(); }); }); - -$loop->run(); ``` See also the [examples](examples). @@ -80,15 +77,12 @@ Here's a client that outputs the output of said server and then attempts to send it a string: ```php -$loop = React\EventLoop\Factory::create(); -$connector = new React\Socket\Connector($loop); +$connector = new React\Socket\Connector(); -$connector->connect('127.0.0.1:8080')->then(function (React\Socket\ConnectionInterface $connection) use ($loop) { - $connection->pipe(new React\Stream\WritableResourceStream(STDOUT, $loop)); +$connector->connect('127.0.0.1:8080')->then(function (React\Socket\ConnectionInterface $connection) { + $connection->pipe(new React\Stream\WritableResourceStream(STDOUT)); $connection->write("Hello World!\n"); }); - -$loop->run(); ``` ## Connection usage @@ -317,7 +311,7 @@ Re-attach the socket resource to the EventLoop after a previous `pause()`. ```php $server->pause(); -$loop->addTimer(1.0, function () use ($server) { +Loop::addTimer(1.0, function () use ($server) { $server->resume(); }); ``` @@ -348,7 +342,7 @@ streaming connections, such as plaintext TCP/IP or secure TLS connection streams Connections can also be accepted on Unix domain sockets. ```php -$server = new React\Socket\Server(8080, $loop); +$server = new React\Socket\Server(8080); ``` As above, the `$uri` parameter can consist of only a port, in which case the @@ -358,7 +352,7 @@ which means it will not be reachable from outside of this system. In order to use a random port assignment, you can use the port `0`: ```php -$server = new React\Socket\Server(0, $loop); +$server = new React\Socket\Server(0); $address = $server->getAddress(); ``` @@ -367,21 +361,21 @@ address through the first parameter provided to the constructor, optionally preceded by the `tcp://` scheme: ```php -$server = new React\Socket\Server('192.168.0.1:8080', $loop); +$server = new React\Socket\Server('192.168.0.1:8080'); ``` If you want to listen on an IPv6 address, you MUST enclose the host in square brackets: ```php -$server = new React\Socket\Server('[::1]:8080', $loop); +$server = new React\Socket\Server('[::1]:8080'); ``` To listen on a Unix domain socket (UDS) path, you MUST prefix the URI with the `unix://` scheme: ```php -$server = new React\Socket\Server('unix:///tmp/server.sock', $loop); +$server = new React\Socket\Server('unix:///tmp/server.sock'); ``` If the given URI is invalid, does not contain a port, any other scheme or if it @@ -389,7 +383,7 @@ contains a hostname, it will throw an `InvalidArgumentException`: ```php // throws InvalidArgumentException due to missing port -$server = new React\Socket\Server('127.0.0.1', $loop); +$server = new React\Socket\Server('127.0.0.1'); ``` If the given URI appears to be valid, but listening on it fails (such as if port @@ -397,10 +391,10 @@ is already in use or port below 1024 may require root access etc.), it will throw a `RuntimeException`: ```php -$first = new React\Socket\Server(8080, $loop); +$first = new React\Socket\Server(8080); // throws RuntimeException because port is already in use -$second = new React\Socket\Server(8080, $loop); +$second = new React\Socket\Server(8080); ``` > Note that these error conditions may vary depending on your system and/or @@ -408,11 +402,17 @@ $second = new React\Socket\Server(8080, $loop); See the exception message and code for more details about the actual error condition. +This class takes an optional `LoopInterface|null $loop` parameter that can be used to +pass the event loop instance to use for this object. You can use a `null` value +here in order to use the [default loop](https://github.com/reactphp/event-loop#loop). +This value SHOULD NOT be given unless you're sure you want to explicitly use a +given event loop instance. + Optionally, you can specify [TCP socket context options](https://www.php.net/manual/en/context.socket.php) for the underlying stream socket resource like this: ```php -$server = new React\Socket\Server('[::1]:8080', $loop, array( +$server = new React\Socket\Server('[::1]:8080', null, array( 'tcp' => array( 'backlog' => 200, 'so_reuseport' => true, @@ -438,7 +438,7 @@ which in its most basic form may look something like this if you're using a PEM encoded certificate file: ```php -$server = new React\Socket\Server('tls://127.0.0.1:8080', $loop, array( +$server = new React\Socket\Server('tls://127.0.0.1:8080', null, array( 'tls' => array( 'local_cert' => 'server.pem' ) @@ -454,7 +454,7 @@ If your private key is encrypted with a passphrase, you have to specify it like this: ```php -$server = new React\Socket\Server('tls://127.0.0.1:8000', $loop, array( +$server = new React\Socket\Server('tls://127.0.0.1:8000', null, array( 'tls' => array( 'local_cert' => 'server.pem', 'passphrase' => 'secret' @@ -467,7 +467,7 @@ SSLv2/SSLv3. As of PHP 5.6+ you can also explicitly choose the TLS version you want to negotiate with the remote side: ```php -$server = new React\Socket\Server('tls://127.0.0.1:8000', $loop, array( +$server = new React\Socket\Server('tls://127.0.0.1:8000', null, array( 'tls' => array( 'local_cert' => 'server.pem', 'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_SERVER @@ -510,7 +510,7 @@ The `TcpServer` class implements the [`ServerInterface`](#serverinterface) and is responsible for accepting plaintext TCP/IP connections. ```php -$server = new React\Socket\TcpServer(8080, $loop); +$server = new React\Socket\TcpServer(8080); ``` As above, the `$uri` parameter can consist of only a port, in which case the @@ -520,7 +520,7 @@ which means it will not be reachable from outside of this system. In order to use a random port assignment, you can use the port `0`: ```php -$server = new React\Socket\TcpServer(0, $loop); +$server = new React\Socket\TcpServer(0); $address = $server->getAddress(); ``` @@ -529,14 +529,14 @@ address through the first parameter provided to the constructor, optionally preceded by the `tcp://` scheme: ```php -$server = new React\Socket\TcpServer('192.168.0.1:8080', $loop); +$server = new React\Socket\TcpServer('192.168.0.1:8080'); ``` If you want to listen on an IPv6 address, you MUST enclose the host in square brackets: ```php -$server = new React\Socket\TcpServer('[::1]:8080', $loop); +$server = new React\Socket\TcpServer('[::1]:8080'); ``` If the given URI is invalid, does not contain a port, any other scheme or if it @@ -544,7 +544,7 @@ contains a hostname, it will throw an `InvalidArgumentException`: ```php // throws InvalidArgumentException due to missing port -$server = new React\Socket\TcpServer('127.0.0.1', $loop); +$server = new React\Socket\TcpServer('127.0.0.1'); ``` If the given URI appears to be valid, but listening on it fails (such as if port @@ -552,10 +552,10 @@ is already in use or port below 1024 may require root access etc.), it will throw a `RuntimeException`: ```php -$first = new React\Socket\TcpServer(8080, $loop); +$first = new React\Socket\TcpServer(8080); // throws RuntimeException because port is already in use -$second = new React\Socket\TcpServer(8080, $loop); +$second = new React\Socket\TcpServer(8080); ``` > Note that these error conditions may vary depending on your system and/or @@ -563,11 +563,17 @@ configuration. See the exception message and code for more details about the actual error condition. +This class takes an optional `LoopInterface|null $loop` parameter that can be used to +pass the event loop instance to use for this object. You can use a `null` value +here in order to use the [default loop](https://github.com/reactphp/event-loop#loop). +This value SHOULD NOT be given unless you're sure you want to explicitly use a +given event loop instance. + Optionally, you can specify [socket context options](https://www.php.net/manual/en/context.socket.php) for the underlying stream socket resource like this: ```php -$server = new React\Socket\TcpServer('[::1]:8080', $loop, array( +$server = new React\Socket\TcpServer('[::1]:8080', null, array( 'backlog' => 200, 'so_reuseport' => true, 'ipv6_v6only' => true @@ -606,8 +612,8 @@ which in its most basic form may look something like this if you're using a PEM encoded certificate file: ```php -$server = new React\Socket\TcpServer(8000, $loop); -$server = new React\Socket\SecureServer($server, $loop, array( +$server = new React\Socket\TcpServer(8000); +$server = new React\Socket\SecureServer($server, null, array( 'local_cert' => 'server.pem' )); ``` @@ -621,8 +627,8 @@ If your private key is encrypted with a passphrase, you have to specify it like this: ```php -$server = new React\Socket\TcpServer(8000, $loop); -$server = new React\Socket\SecureServer($server, $loop, array( +$server = new React\Socket\TcpServer(8000); +$server = new React\Socket\SecureServer($server, null, array( 'local_cert' => 'server.pem', 'passphrase' => 'secret' )); @@ -633,8 +639,8 @@ SSLv2/SSLv3. As of PHP 5.6+ you can also explicitly choose the TLS version you want to negotiate with the remote side: ```php -$server = new React\Socket\TcpServer(8000, $loop); -$server = new React\Socket\SecureServer($server, $loop, array( +$server = new React\Socket\TcpServer(8000); +$server = new React\Socket\SecureServer($server, null, array( 'local_cert' => 'server.pem', 'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_SERVER )); @@ -672,6 +678,12 @@ Note that the `SecureServer` class is a concrete implementation for TLS sockets. If you want to typehint in your higher-level protocol implementation, you SHOULD use the generic [`ServerInterface`](#serverinterface) instead. +This class takes an optional `LoopInterface|null $loop` parameter that can be used to +pass the event loop instance to use for this object. You can use a `null` value +here in order to use the [default loop](https://github.com/reactphp/event-loop#loop). +This value SHOULD NOT be given unless you're sure you want to explicitly use a +given event loop instance. + > Advanced usage: Despite allowing any `ServerInterface` as first parameter, you SHOULD pass a `TcpServer` instance as first parameter, unless you know what you're doing. @@ -692,7 +704,7 @@ The `UnixServer` class implements the [`ServerInterface`](#serverinterface) and is responsible for accepting connections on Unix domain sockets (UDS). ```php -$server = new React\Socket\UnixServer('/tmp/server.sock', $loop); +$server = new React\Socket\UnixServer('/tmp/server.sock'); ``` As above, the `$uri` parameter can consist of only a socket path or socket path @@ -703,10 +715,10 @@ socket is already in use or the file not accessible etc.), it will throw a `RuntimeException`: ```php -$first = new React\Socket\UnixServer('/tmp/same.sock', $loop); +$first = new React\Socket\UnixServer('/tmp/same.sock'); // throws RuntimeException because socket is already in use -$second = new React\Socket\UnixServer('/tmp/same.sock', $loop); +$second = new React\Socket\UnixServer('/tmp/same.sock'); ``` > Note that these error conditions may vary depending on your system and/or @@ -717,6 +729,12 @@ $second = new React\Socket\UnixServer('/tmp/same.sock', $loop); See the exception message and code for more details about the actual error condition. +This class takes an optional `LoopInterface|null $loop` parameter that can be used to +pass the event loop instance to use for this object. You can use a `null` value +here in order to use the [default loop](https://github.com/reactphp/event-loop#loop). +This value SHOULD NOT be given unless you're sure you want to explicitly use a +given event loop instance. + Whenever a client connects, it will emit a `connection` event with a connection instance implementing [`ConnectionInterface`](#connectioninterface): @@ -871,15 +889,12 @@ as plaintext TCP/IP, secure TLS or local Unix connection streams. It binds to the main event loop and can be used like this: ```php -$loop = React\EventLoop\Factory::create(); -$connector = new React\Socket\Connector($loop); +$connector = new React\Socket\Connector(); $connector->connect($uri)->then(function (React\Socket\ConnectionInterface $connection) { $connection->write('...'); $connection->end(); }); - -$loop->run(); ``` In order to create a plaintext TCP/IP connection, you can simply pass a host @@ -929,6 +944,12 @@ also shares all of their features and implementation details. If you want to typehint in your higher-level protocol implementation, you SHOULD use the generic [`ConnectorInterface`](#connectorinterface) instead. +This class takes an optional `LoopInterface|null $loop` parameter that can be used to +pass the event loop instance to use for this object. You can use a `null` value +here in order to use the [default loop](https://github.com/reactphp/event-loop#loop). +This value SHOULD NOT be given unless you're sure you want to explicitly use a +given event loop instance. + As of `v1.4.0`, the `Connector` class defaults to using the [happy eyeballs algorithm](https://en.wikipedia.org/wiki/Happy_Eyeballs) to automatically connect over IPv4 or IPv6 when a hostname is given. @@ -939,7 +960,7 @@ If you want to revert to the old behavior of only doing an IPv4 lookup and only attempt a single IPv4 connection, you can set up the `Connector` like this: ```php -$connector = new React\Socket\Connector($loop, array( +$connector = new React\Socket\Connector(null, array( 'happy_eyeballs' => false )); ``` @@ -953,7 +974,7 @@ If you explicitly want to use a custom DNS server (such as a local DNS relay or a company wide DNS server), you can set up the `Connector` like this: ```php -$connector = new React\Socket\Connector($loop, array( +$connector = new React\Socket\Connector(null, array( 'dns' => '127.0.1.1' )); @@ -967,7 +988,7 @@ If you do not want to use a DNS resolver at all and want to connect to IP addresses only, you can also set up your `Connector` like this: ```php -$connector = new React\Socket\Connector($loop, array( +$connector = new React\Socket\Connector(null, array( 'dns' => false )); @@ -982,9 +1003,9 @@ can also set up your `Connector` like this: ```php $dnsResolverFactory = new React\Dns\Resolver\Factory(); -$resolver = $dnsResolverFactory->createCached('127.0.1.1', $loop); +$resolver = $dnsResolverFactory->createCached('127.0.1.1'); -$connector = new React\Socket\Connector($loop, array( +$connector = new React\Socket\Connector(null, array( 'dns' => $resolver )); @@ -999,7 +1020,7 @@ respects your `default_socket_timeout` ini setting (which defaults to 60s). If you want a custom timeout value, you can simply pass this like this: ```php -$connector = new React\Socket\Connector($loop, array( +$connector = new React\Socket\Connector(null, array( 'timeout' => 10.0 )); ``` @@ -1008,7 +1029,7 @@ Similarly, if you do not want to apply a timeout at all and let the operating system handle this, you can pass a boolean flag like this: ```php -$connector = new React\Socket\Connector($loop, array( +$connector = new React\Socket\Connector(null, array( 'timeout' => false )); ``` @@ -1019,7 +1040,7 @@ pass boolean flags like this: ```php // only allow secure TLS connections -$connector = new React\Socket\Connector($loop, array( +$connector = new React\Socket\Connector(null, array( 'tcp' => false, 'tls' => true, 'unix' => false, @@ -1038,7 +1059,7 @@ pass arrays of context options like this: ```php // allow insecure TLS connections -$connector = new React\Socket\Connector($loop, array( +$connector = new React\Socket\Connector(null, array( 'tcp' => array( 'bindto' => '192.168.0.1:0' ), @@ -1059,7 +1080,7 @@ SSLv2/SSLv3. As of PHP 5.6+ you can also explicitly choose the TLS version you want to negotiate with the remote side: ```php -$connector = new React\Socket\Connector($loop, array( +$connector = new React\Socket\Connector(null, array( 'tls' => array( 'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT ) @@ -1078,14 +1099,14 @@ pass an instance implementing the `ConnectorInterface` like this: ```php $dnsResolverFactory = new React\Dns\Resolver\Factory(); -$resolver = $dnsResolverFactory->createCached('127.0.1.1', $loop); -$tcp = new React\Socket\HappyEyeBallsConnector($loop, new React\Socket\TcpConnector($loop), $resolver); +$resolver = $dnsResolverFactory->createCached('127.0.1.1'); +$tcp = new React\Socket\HappyEyeBallsConnector(null, new React\Socket\TcpConnector(), $resolver); -$tls = new React\Socket\SecureConnector($tcp, $loop); +$tls = new React\Socket\SecureConnector($tcp); -$unix = new React\Socket\UnixConnector($loop); +$unix = new React\Socket\UnixConnector(); -$connector = new React\Socket\Connector($loop, array( +$connector = new React\Socket\Connector(null, array( 'tcp' => $tcp, 'tls' => $tls, 'unix' => $unix, @@ -1121,14 +1142,12 @@ The `TcpConnector` class implements the TCP/IP connections to any IP-port-combination: ```php -$tcpConnector = new React\Socket\TcpConnector($loop); +$tcpConnector = new React\Socket\TcpConnector(); $tcpConnector->connect('127.0.0.1:80')->then(function (React\Socket\ConnectionInterface $connection) { $connection->write('...'); $connection->end(); }); - -$loop->run(); ``` See also the [examples](examples). @@ -1145,12 +1164,18 @@ Calling `cancel()` on a pending promise will close the underlying socket resource, thus cancelling the pending TCP/IP connection, and reject the resulting promise. +This class takes an optional `LoopInterface|null $loop` parameter that can be used to +pass the event loop instance to use for this object. You can use a `null` value +here in order to use the [default loop](https://github.com/reactphp/event-loop#loop). +This value SHOULD NOT be given unless you're sure you want to explicitly use a +given event loop instance. + You can optionally pass additional [socket context options](https://www.php.net/manual/en/context.socket.php) to the constructor like this: ```php -$tcpConnector = new React\Socket\TcpConnector($loop, array( +$tcpConnector = new React\Socket\TcpConnector(null, array( 'bindto' => '192.168.0.1:0' )); ``` @@ -1189,16 +1214,14 @@ Make sure to set up your DNS resolver and underlying TCP connector like this: ```php $dnsResolverFactory = new React\Dns\Resolver\Factory(); -$dns = $dnsResolverFactory->createCached('8.8.8.8', $loop); +$dns = $dnsResolverFactory->createCached('8.8.8.8'); -$dnsConnector = new React\Socket\HappyEyeBallsConnector($loop, $tcpConnector, $dns); +$dnsConnector = new React\Socket\HappyEyeBallsConnector(null, $tcpConnector, $dns); $dnsConnector->connect('www.google.com:80')->then(function (React\Socket\ConnectionInterface $connection) { $connection->write('...'); $connection->end(); }); - -$loop->run(); ``` See also the [examples](examples). @@ -1214,6 +1237,11 @@ $promise->cancel(); Calling `cancel()` on a pending promise will cancel the underlying DNS lookups and/or the underlying TCP/IP connection(s) and reject the resulting promise. +This class takes an optional `LoopInterface|null $loop` parameter that can be used to +pass the event loop instance to use for this object. You can use a `null` value +here in order to use the [default loop](https://github.com/reactphp/event-loop#loop). +This value SHOULD NOT be given unless you're sure you want to explicitly use a +given event loop instance. > Advanced usage: Internally, the `HappyEyeBallsConnector` relies on a `Resolver` to look up the IP addresses for the given hostname. @@ -1241,7 +1269,7 @@ Make sure to set up your DNS resolver and underlying TCP connector like this: ```php $dnsResolverFactory = new React\Dns\Resolver\Factory(); -$dns = $dnsResolverFactory->createCached('8.8.8.8', $loop); +$dns = $dnsResolverFactory->createCached('8.8.8.8'); $dnsConnector = new React\Socket\DnsConnector($tcpConnector, $dns); @@ -1249,8 +1277,6 @@ $dnsConnector->connect('www.google.com:80')->then(function (React\Socket\Connect $connection->write('...'); $connection->end(); }); - -$loop->run(); ``` See also the [examples](examples). @@ -1288,14 +1314,12 @@ creates a plaintext TCP/IP connection and then enables TLS encryption on this stream. ```php -$secureConnector = new React\Socket\SecureConnector($dnsConnector, $loop); +$secureConnector = new React\Socket\SecureConnector($dnsConnector); $secureConnector->connect('www.google.com:443')->then(function (React\Socket\ConnectionInterface $connection) { $connection->write("GET / HTTP/1.0\r\nHost: www.google.com\r\n\r\n"); ... }); - -$loop->run(); ``` See also the [examples](examples). @@ -1311,12 +1335,18 @@ $promise->cancel(); Calling `cancel()` on a pending promise will cancel the underlying TCP/IP connection and/or the SSL/TLS negotiation and reject the resulting promise. +This class takes an optional `LoopInterface|null $loop` parameter that can be used to +pass the event loop instance to use for this object. You can use a `null` value +here in order to use the [default loop](https://github.com/reactphp/event-loop#loop). +This value SHOULD NOT be given unless you're sure you want to explicitly use a +given event loop instance. + You can optionally pass additional [SSL context options](https://www.php.net/manual/en/context.ssl.php) to the constructor like this: ```php -$secureConnector = new React\Socket\SecureConnector($dnsConnector, $loop, array( +$secureConnector = new React\Socket\SecureConnector($dnsConnector, null, array( 'verify_peer' => false, 'verify_peer_name' => false )); @@ -1327,7 +1357,7 @@ SSLv2/SSLv3. As of PHP 5.6+ you can also explicitly choose the TLS version you want to negotiate with the remote side: ```php -$secureConnector = new React\Socket\SecureConnector($dnsConnector, $loop, array( +$secureConnector = new React\Socket\SecureConnector($dnsConnector, null, array( 'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT )); ``` @@ -1352,7 +1382,7 @@ instance and starting a timer that will automatically reject and abort any underlying connection attempt if it takes too long. ```php -$timeoutConnector = new React\Socket\TimeoutConnector($connector, 3.0, $loop); +$timeoutConnector = new React\Socket\TimeoutConnector($connector, 3.0); $timeoutConnector->connect('google.com:80')->then(function (React\Socket\ConnectionInterface $connection) { // connection succeeded within 3.0 seconds @@ -1361,6 +1391,12 @@ $timeoutConnector->connect('google.com:80')->then(function (React\Socket\Connect See also any of the [examples](examples). +This class takes an optional `LoopInterface|null $loop` parameter that can be used to +pass the event loop instance to use for this object. You can use a `null` value +here in order to use the [default loop](https://github.com/reactphp/event-loop#loop). +This value SHOULD NOT be given unless you're sure you want to explicitly use a +given event loop instance. + Pending connection attempts can be cancelled by cancelling its pending promise like so: ```php @@ -1379,13 +1415,11 @@ The `UnixConnector` class implements the Unix domain socket (UDS) paths like this: ```php -$connector = new React\Socket\UnixConnector($loop); +$connector = new React\Socket\UnixConnector(); $connector->connect('/tmp/demo.sock')->then(function (React\Socket\ConnectionInterface $connection) { $connection->write("HELLO\n"); }); - -$loop->run(); ``` Connecting to Unix domain sockets is an atomic operation, i.e. its promise will @@ -1398,6 +1432,12 @@ As such, calling `cancel()` on the resulting promise has no effect. The [`getLocalAddress()`](#getlocaladdress) method will most likely return a `null` value as this value is not applicable to UDS connections here. +This class takes an optional `LoopInterface|null $loop` parameter that can be used to +pass the event loop instance to use for this object. You can use a `null` value +here in order to use the [default loop](https://github.com/reactphp/event-loop#loop). +This value SHOULD NOT be given unless you're sure you want to explicitly use a +given event loop instance. + #### FixedUriConnector The `FixedUriConnector` class implements the @@ -1411,7 +1451,7 @@ instead of connecting to a default address assumed by an higher-level API: ```php $connector = new React\Socket\FixedUriConnector( 'unix:///var/run/docker.sock', - new React\Socket\UnixConnector($loop) + new React\Socket\UnixConnector() ); // destination will be ignored, actually connects to Unix domain socket diff --git a/composer.json b/composer.json index b3fdc636..7cdbac02 100644 --- a/composer.json +++ b/composer.json @@ -28,11 +28,11 @@ "require": { "php": ">=5.3.0", "evenement/evenement": "^3.0 || ^2.0 || ^1.0", - "react/dns": "^1.7", - "react/event-loop": "^1.0 || ^0.5", + "react/dns": "dev-default-loop#28e5df1 as 1.8.0", + "react/event-loop": "dev-master#1a709e2 as 1.2.0", "react/promise": "^2.6.0 || ^1.2.1", "react/promise-timer": "^1.4.0", - "react/stream": "^1.1" + "react/stream": "dev-default-loop#e617d63 as 1.2.0" }, "require-dev": { "clue/block-react": "^1.2", @@ -48,5 +48,15 @@ "psr-4": { "React\\Tests\\Socket\\": "tests" } - } + }, + "repositories": [ + { + "type": "vcs", + "url": "https://github.com/clue-labs/dns" + }, + { + "type": "vcs", + "url": "https://github.com/clue-labs/stream" + } + ] } diff --git a/examples/01-echo-server.php b/examples/01-echo-server.php index 781e7c32..8a729009 100644 --- a/examples/01-echo-server.php +++ b/examples/01-echo-server.php @@ -16,15 +16,12 @@ // $ php examples/01-echo-server.php unix:///tmp/server.sock // $ nc -U /tmp/server.sock -use React\EventLoop\Factory; use React\Socket\Server; use React\Socket\ConnectionInterface; require __DIR__ . '/../vendor/autoload.php'; -$loop = Factory::create(); - -$server = new Server(isset($argv[1]) ? $argv[1] : 0, $loop, array( +$server = new Server(isset($argv[1]) ? $argv[1] : 0, null, array( 'tls' => array( 'local_cert' => isset($argv[2]) ? $argv[2] : (__DIR__ . '/localhost.pem') ) @@ -38,5 +35,3 @@ $server->on('error', 'printf'); echo 'Listening on ' . $server->getAddress() . PHP_EOL; - -$loop->run(); diff --git a/examples/02-chat-server.php b/examples/02-chat-server.php index 46439e04..ede541d9 100644 --- a/examples/02-chat-server.php +++ b/examples/02-chat-server.php @@ -16,16 +16,13 @@ // $ php examples/02-chat-server.php unix:///tmp/server.sock // $ nc -U /tmp/server.sock -use React\EventLoop\Factory; use React\Socket\Server; use React\Socket\ConnectionInterface; use React\Socket\LimitingServer; require __DIR__ . '/../vendor/autoload.php'; -$loop = Factory::create(); - -$server = new Server(isset($argv[1]) ? $argv[1] : 0, $loop, array( +$server = new Server(isset($argv[1]) ? $argv[1] : 0, null, array( 'tls' => array( 'local_cert' => isset($argv[2]) ? $argv[2] : (__DIR__ . '/localhost.pem') ) @@ -55,5 +52,3 @@ $server->on('error', 'printf'); echo 'Listening on ' . $server->getAddress() . PHP_EOL; - -$loop->run(); diff --git a/examples/03-http-server.php b/examples/03-http-server.php index 47ae5848..5b96646c 100644 --- a/examples/03-http-server.php +++ b/examples/03-http-server.php @@ -29,15 +29,12 @@ // $ php examples/03-http-server.php unix:///tmp/server.sock // $ nc -U /tmp/server.sock -use React\EventLoop\Factory; use React\Socket\Server; use React\Socket\ConnectionInterface; require __DIR__ . '/../vendor/autoload.php'; -$loop = Factory::create(); - -$server = new Server(isset($argv[1]) ? $argv[1] : 0, $loop, array( +$server = new Server(isset($argv[1]) ? $argv[1] : 0, null, array( 'tls' => array( 'local_cert' => isset($argv[2]) ? $argv[2] : (__DIR__ . '/localhost.pem') ) @@ -53,5 +50,3 @@ $server->on('error', 'printf'); echo 'Listening on ' . strtr($server->getAddress(), array('tcp:' => 'http:', 'tls:' => 'https:')) . PHP_EOL; - -$loop->run(); diff --git a/examples/11-http-client.php b/examples/11-http-client.php index 2b64a431..cdbd7eca 100644 --- a/examples/11-http-client.php +++ b/examples/11-http-client.php @@ -11,7 +11,6 @@ // $ php examples/11-http-client.php // $ php examples/11-http-client.php reactphp.org -use React\EventLoop\Factory; use React\Socket\Connector; use React\Socket\ConnectionInterface; @@ -19,8 +18,7 @@ require __DIR__ . '/../vendor/autoload.php'; -$loop = Factory::create(); -$connector = new Connector($loop); +$connector = new Connector(); $connector->connect($host. ':80')->then(function (ConnectionInterface $connection) use ($host) { $connection->on('data', function ($data) { @@ -32,5 +30,3 @@ $connection->write("GET / HTTP/1.0\r\nHost: $host\r\n\r\n"); }, 'printf'); - -$loop->run(); diff --git a/examples/12-https-client.php b/examples/12-https-client.php index 6e3f2796..d5878935 100644 --- a/examples/12-https-client.php +++ b/examples/12-https-client.php @@ -11,7 +11,6 @@ // $ php examples/12-https-client.php // $ php examples/12-https-client.php reactphp.org -use React\EventLoop\Factory; use React\Socket\Connector; use React\Socket\ConnectionInterface; @@ -19,8 +18,7 @@ require __DIR__ . '/../vendor/autoload.php'; -$loop = Factory::create(); -$connector = new Connector($loop); +$connector = new Connector(); $connector->connect('tls://' . $host . ':443')->then(function (ConnectionInterface $connection) use ($host) { $connection->on('data', function ($data) { @@ -32,5 +30,3 @@ $connection->write("GET / HTTP/1.0\r\nHost: $host\r\n\r\n"); }, 'printf'); - -$loop->run(); diff --git a/examples/21-netcat-client.php b/examples/21-netcat-client.php index 9140e2c0..6b0f9bf4 100644 --- a/examples/21-netcat-client.php +++ b/examples/21-netcat-client.php @@ -8,7 +8,6 @@ // $ php examples/21-netcat-client.php www.google.com:80 // $ php examples/21-netcat-client.php tls://www.google.com:443 -use React\EventLoop\Factory; use React\Socket\Connector; use React\Socket\ConnectionInterface; use React\Stream\ReadableResourceStream; @@ -31,13 +30,12 @@ exit(1); } -$loop = Factory::create(); -$connector = new Connector($loop); +$connector = new Connector(); -$stdin = new ReadableResourceStream(STDIN, $loop); +$stdin = new ReadableResourceStream(STDIN); $stdin->pause(); -$stdout = new WritableResourceStream(STDOUT, $loop); -$stderr = new WritableResourceStream(STDERR, $loop); +$stdout = new WritableResourceStream(STDOUT); +$stderr = new WritableResourceStream(STDERR); $stderr->write('Connecting' . PHP_EOL); @@ -64,5 +62,3 @@ }, function ($error) use ($stderr) { $stderr->write('Connection ERROR: ' . $error . PHP_EOL); }); - -$loop->run(); diff --git a/examples/22-http-client.php b/examples/22-http-client.php index fcb8107a..4d0ddeb2 100644 --- a/examples/22-http-client.php +++ b/examples/22-http-client.php @@ -13,7 +13,6 @@ // $ php examples/22-http-client.php // $ php examples/22-http-client.php https://reactphp.org/ -use React\EventLoop\Factory; use React\Socket\ConnectionInterface; use React\Socket\Connector; use React\Stream\WritableResourceStream; @@ -32,8 +31,7 @@ exit(1); } -$loop = Factory::create(); -$connector = new Connector($loop); +$connector = new Connector(); if (!isset($parts['port'])) { $parts['port'] = $parts['scheme'] === 'https' ? 443 : 80; @@ -49,12 +47,10 @@ $resource .= '?' . $parts['query']; } -$stdout = new WritableResourceStream(STDOUT, $loop); +$stdout = new WritableResourceStream(STDOUT); $connector->connect($target)->then(function (ConnectionInterface $connection) use ($resource, $host, $stdout) { $connection->pipe($stdout); $connection->write("GET $resource HTTP/1.0\r\nHost: $host\r\n\r\n"); }, 'printf'); - -$loop->run(); diff --git a/examples/91-benchmark-server.php b/examples/91-benchmark-server.php index 0fcd2583..b54c5cfc 100644 --- a/examples/91-benchmark-server.php +++ b/examples/91-benchmark-server.php @@ -22,21 +22,18 @@ // $ nc -N -U /tmp/server.sock // $ dd if=/dev/zero bs=1M count=1000 | nc -N -U /tmp/server.sock -use React\EventLoop\Factory; use React\Socket\Server; use React\Socket\ConnectionInterface; require __DIR__ . '/../vendor/autoload.php'; -$loop = Factory::create(); - -$server = new Server(isset($argv[1]) ? $argv[1] : 0, $loop, array( +$server = new Server(isset($argv[1]) ? $argv[1] : 0, null, array( 'tls' => array( 'local_cert' => isset($argv[2]) ? $argv[2] : (__DIR__ . '/localhost.pem') ) )); -$server->on('connection', function (ConnectionInterface $connection) use ($loop) { +$server->on('connection', function (ConnectionInterface $connection) { echo '[connected]' . PHP_EOL; // count the number of bytes received from this connection @@ -56,5 +53,3 @@ $server->on('error', 'printf'); echo 'Listening on ' . $server->getAddress() . PHP_EOL; - -$loop->run(); diff --git a/src/Connector.php b/src/Connector.php index 914c6a98..42099a77 100644 --- a/src/Connector.php +++ b/src/Connector.php @@ -5,6 +5,7 @@ use React\Dns\Config\Config as DnsConfig; use React\Dns\Resolver\Factory as DnsFactory; use React\Dns\Resolver\ResolverInterface; +use React\EventLoop\Loop; use React\EventLoop\LoopInterface; /** @@ -26,8 +27,9 @@ final class Connector implements ConnectorInterface { private $connectors = array(); - public function __construct(LoopInterface $loop, array $options = array()) + public function __construct(LoopInterface $loop = null, array $options = array()) { + $loop = $loop ?: Loop::get(); // apply default options if not explicitly given $options += array( 'tcp' => true, diff --git a/src/FixedUriConnector.php b/src/FixedUriConnector.php index 9317eee9..f83241d6 100644 --- a/src/FixedUriConnector.php +++ b/src/FixedUriConnector.php @@ -12,7 +12,7 @@ * ```php * $connector = new React\Socket\FixedUriConnector( * 'unix:///var/run/docker.sock', - * new React\Socket\UnixConnector($loop) + * new React\Socket\UnixConnector() * ); * * // destination will be ignored, actually connects to Unix domain socket diff --git a/src/HappyEyeBallsConnector.php b/src/HappyEyeBallsConnector.php index 1d4a21df..677b7c76 100644 --- a/src/HappyEyeBallsConnector.php +++ b/src/HappyEyeBallsConnector.php @@ -3,6 +3,7 @@ namespace React\Socket; use React\Dns\Resolver\ResolverInterface; +use React\EventLoop\Loop; use React\EventLoop\LoopInterface; use React\Promise; @@ -12,9 +13,18 @@ final class HappyEyeBallsConnector implements ConnectorInterface private $connector; private $resolver; - public function __construct(LoopInterface $loop, ConnectorInterface $connector, ResolverInterface $resolver) + public function __construct(LoopInterface $loop = null, ConnectorInterface $connector = null, ResolverInterface $resolver = null) { - $this->loop = $loop; + // $connector and $resolver arguments are actually required, marked + // optional for technical reasons only. Nullable $loop without default + // requires PHP 7.1, null default is also supported in legacy PHP + // versions, but required parameters are not allowed after arguments + // with null default. Mark all parameters optional and check accordingly. + if ($connector === null || $resolver === null) { + throw new \InvalidArgumentException('Missing required $connector or $resolver argument'); + } + + $this->loop = $loop ?: Loop::get(); $this->connector = $connector; $this->resolver = $resolver; } @@ -34,7 +44,7 @@ public function connect($uri) } $host = \trim($parts['host'], '[]'); - + // skip DNS lookup / URI manipulation if this URI already contains an IP if (false !== \filter_var($host, \FILTER_VALIDATE_IP)) { return $this->connector->connect($uri); diff --git a/src/SecureConnector.php b/src/SecureConnector.php index e5ebc73e..0e6bd7c3 100644 --- a/src/SecureConnector.php +++ b/src/SecureConnector.php @@ -2,6 +2,7 @@ namespace React\Socket; +use React\EventLoop\Loop; use React\EventLoop\LoopInterface; use React\Promise; use BadMethodCallException; @@ -14,10 +15,10 @@ final class SecureConnector implements ConnectorInterface private $streamEncryption; private $context; - public function __construct(ConnectorInterface $connector, LoopInterface $loop, array $context = array()) + public function __construct(ConnectorInterface $connector, LoopInterface $loop = null, array $context = array()) { $this->connector = $connector; - $this->streamEncryption = new StreamEncryption($loop, false); + $this->streamEncryption = new StreamEncryption($loop ?: Loop::get(), false); $this->context = $context; } diff --git a/src/SecureServer.php b/src/SecureServer.php index f091c341..d0525c94 100644 --- a/src/SecureServer.php +++ b/src/SecureServer.php @@ -3,6 +3,7 @@ namespace React\Socket; use Evenement\EventEmitter; +use React\EventLoop\Loop; use React\EventLoop\LoopInterface; use BadMethodCallException; use UnexpectedValueException; @@ -15,8 +16,8 @@ * TCP/IP connections and then performs a TLS handshake for each connection. * * ```php - * $server = new React\Socket\TcpServer(8000, $loop); - * $server = new React\Socket\SecureServer($server, $loop, array( + * $server = new React\Socket\TcpServer(8000); + * $server = new React\Socket\SecureServer($server, null, array( * // tls context options hereā€¦ * )); * ``` @@ -67,8 +68,8 @@ final class SecureServer extends EventEmitter implements ServerInterface * PEM encoded certificate file: * * ```php - * $server = new React\Socket\TcpServer(8000, $loop); - * $server = new React\Socket\SecureServer($server, $loop, array( + * $server = new React\Socket\TcpServer(8000); + * $server = new React\Socket\SecureServer($server, null, array( * 'local_cert' => 'server.pem' * )); * ``` @@ -82,8 +83,8 @@ final class SecureServer extends EventEmitter implements ServerInterface * like this: * * ```php - * $server = new React\Socket\TcpServer(8000, $loop); - * $server = new React\Socket\SecureServer($server, $loop, array( + * $server = new React\Socket\TcpServer(8000); + * $server = new React\Socket\SecureServer($server, null, array( * 'local_cert' => 'server.pem', * 'passphrase' => 'secret' * )); @@ -94,6 +95,12 @@ final class SecureServer extends EventEmitter implements ServerInterface * and/or PHP version. * Passing unknown context options has no effect. * + * This class takes an optional `LoopInterface|null $loop` parameter that can be used to + * pass the event loop instance to use for this object. You can use a `null` value + * here in order to use the [default loop](https://github.com/reactphp/event-loop#loop). + * This value SHOULD NOT be given unless you're sure you want to explicitly use a + * given event loop instance. + * * Advanced usage: Despite allowing any `ServerInterface` as first parameter, * you SHOULD pass a `TcpServer` instance as first parameter, unless you * know what you're doing. @@ -109,13 +116,13 @@ final class SecureServer extends EventEmitter implements ServerInterface * then close the underlying connection. * * @param ServerInterface|TcpServer $tcp - * @param LoopInterface $loop + * @param ?LoopInterface $loop * @param array $context * @throws BadMethodCallException for legacy HHVM < 3.8 due to lack of support * @see TcpServer * @link https://www.php.net/manual/en/context.ssl.php for TLS context options */ - public function __construct(ServerInterface $tcp, LoopInterface $loop, array $context) + public function __construct(ServerInterface $tcp, LoopInterface $loop = null, array $context = array()) { if (!\function_exists('stream_socket_enable_crypto')) { throw new \BadMethodCallException('Encryption not supported on your platform (HHVM < 3.8?)'); // @codeCoverageIgnore @@ -127,7 +134,7 @@ public function __construct(ServerInterface $tcp, LoopInterface $loop, array $co ); $this->tcp = $tcp; - $this->encryption = new StreamEncryption($loop); + $this->encryption = new StreamEncryption($loop ?: Loop::get()); $this->context = $context; $that = $this; diff --git a/src/Server.php b/src/Server.php index d62b6683..193fe0d0 100644 --- a/src/Server.php +++ b/src/Server.php @@ -3,6 +3,7 @@ namespace React\Socket; use Evenement\EventEmitter; +use React\EventLoop\Loop; use React\EventLoop\LoopInterface; use Exception; @@ -10,8 +11,10 @@ final class Server extends EventEmitter implements ServerInterface { private $server; - public function __construct($uri, LoopInterface $loop, array $context = array()) + public function __construct($uri, LoopInterface $loop = null, array $context = array()) { + $loop = $loop ?: Loop::get(); + // sanitize TCP context options if not properly wrapped if ($context && (!isset($context['tcp']) && !isset($context['tls']) && !isset($context['unix']))) { $context = array('tcp' => $context); diff --git a/src/ServerInterface.php b/src/ServerInterface.php index beae751a..694abbf1 100644 --- a/src/ServerInterface.php +++ b/src/ServerInterface.php @@ -124,7 +124,7 @@ public function pause(); * ```php * $server->pause(); * - * $loop->addTimer(1.0, function () use ($server) { + * Loop::addTimer(1.0, function () use ($server) { * $server->resume(); * }); * ``` diff --git a/src/TcpConnector.php b/src/TcpConnector.php index d09e9901..532533bd 100644 --- a/src/TcpConnector.php +++ b/src/TcpConnector.php @@ -2,6 +2,7 @@ namespace React\Socket; +use React\EventLoop\Loop; use React\EventLoop\LoopInterface; use React\Promise; use InvalidArgumentException; @@ -12,9 +13,9 @@ final class TcpConnector implements ConnectorInterface private $loop; private $context; - public function __construct(LoopInterface $loop, array $context = array()) + public function __construct(LoopInterface $loop = null, array $context = array()) { - $this->loop = $loop; + $this->loop = $loop ?: Loop::get(); $this->context = $context; } diff --git a/src/TcpServer.php b/src/TcpServer.php index dd5fe0f6..26eda8f7 100644 --- a/src/TcpServer.php +++ b/src/TcpServer.php @@ -3,6 +3,7 @@ namespace React\Socket; use Evenement\EventEmitter; +use React\EventLoop\Loop; use React\EventLoop\LoopInterface; use InvalidArgumentException; use RuntimeException; @@ -12,7 +13,7 @@ * is responsible for accepting plaintext TCP/IP connections. * * ```php - * $server = new React\Socket\TcpServer(8080, $loop); + * $server = new React\Socket\TcpServer(8080); * ``` * * Whenever a client connects, it will emit a `connection` event with a connection @@ -45,7 +46,7 @@ final class TcpServer extends EventEmitter implements ServerInterface * for more details. * * ```php - * $server = new React\Socket\TcpServer(8080, $loop); + * $server = new React\Socket\TcpServer(8080); * ``` * * As above, the `$uri` parameter can consist of only a port, in which case the @@ -55,7 +56,7 @@ final class TcpServer extends EventEmitter implements ServerInterface * In order to use a random port assignment, you can use the port `0`: * * ```php - * $server = new React\Socket\TcpServer(0, $loop); + * $server = new React\Socket\TcpServer(0); * $address = $server->getAddress(); * ``` * @@ -64,14 +65,14 @@ final class TcpServer extends EventEmitter implements ServerInterface * preceded by the `tcp://` scheme: * * ```php - * $server = new React\Socket\TcpServer('192.168.0.1:8080', $loop); + * $server = new React\Socket\TcpServer('192.168.0.1:8080'); * ``` * * If you want to listen on an IPv6 address, you MUST enclose the host in square * brackets: * * ```php - * $server = new React\Socket\TcpServer('[::1]:8080', $loop); + * $server = new React\Socket\TcpServer('[::1]:8080'); * ``` * * If the given URI is invalid, does not contain a port, any other scheme or if it @@ -79,7 +80,7 @@ final class TcpServer extends EventEmitter implements ServerInterface * * ```php * // throws InvalidArgumentException due to missing port - * $server = new React\Socket\TcpServer('127.0.0.1', $loop); + * $server = new React\Socket\TcpServer('127.0.0.1'); * ``` * * If the given URI appears to be valid, but listening on it fails (such as if port @@ -87,10 +88,10 @@ final class TcpServer extends EventEmitter implements ServerInterface * throw a `RuntimeException`: * * ```php - * $first = new React\Socket\TcpServer(8080, $loop); + * $first = new React\Socket\TcpServer(8080); * * // throws RuntimeException because port is already in use - * $second = new React\Socket\TcpServer(8080, $loop); + * $second = new React\Socket\TcpServer(8080); * ``` * * Note that these error conditions may vary depending on your system and/or @@ -98,11 +99,17 @@ final class TcpServer extends EventEmitter implements ServerInterface * See the exception message and code for more details about the actual error * condition. * + * This class takes an optional `LoopInterface|null $loop` parameter that can be used to + * pass the event loop instance to use for this object. You can use a `null` value + * here in order to use the [default loop](https://github.com/reactphp/event-loop#loop). + * This value SHOULD NOT be given unless you're sure you want to explicitly use a + * given event loop instance. + * * Optionally, you can specify [socket context options](https://www.php.net/manual/en/context.socket.php) * for the underlying stream socket resource like this: * * ```php - * $server = new React\Socket\TcpServer('[::1]:8080', $loop, array( + * $server = new React\Socket\TcpServer('[::1]:8080', null, array( * 'backlog' => 200, * 'so_reuseport' => true, * 'ipv6_v6only' => true @@ -115,15 +122,15 @@ final class TcpServer extends EventEmitter implements ServerInterface * Passing unknown context options has no effect. * The `backlog` context option defaults to `511` unless given explicitly. * - * @param string|int $uri - * @param LoopInterface $loop - * @param array $context + * @param string|int $uri + * @param ?LoopInterface $loop + * @param array $context * @throws InvalidArgumentException if the listening address is invalid * @throws RuntimeException if listening on this address fails (already in use etc.) */ - public function __construct($uri, LoopInterface $loop, array $context = array()) + public function __construct($uri, LoopInterface $loop = null, array $context = array()) { - $this->loop = $loop; + $this->loop = $loop ?: Loop::get(); // a single port has been given => assume localhost if ((string)(int)$uri === (string)$uri) { diff --git a/src/TimeoutConnector.php b/src/TimeoutConnector.php index 33863e61..02ccceee 100644 --- a/src/TimeoutConnector.php +++ b/src/TimeoutConnector.php @@ -2,6 +2,7 @@ namespace React\Socket; +use React\EventLoop\Loop; use React\EventLoop\LoopInterface; use React\Promise\Timer; use React\Promise\Timer\TimeoutException; @@ -12,11 +13,11 @@ final class TimeoutConnector implements ConnectorInterface private $timeout; private $loop; - public function __construct(ConnectorInterface $connector, $timeout, LoopInterface $loop) + public function __construct(ConnectorInterface $connector, $timeout, LoopInterface $loop = null) { $this->connector = $connector; $this->timeout = $timeout; - $this->loop = $loop; + $this->loop = $loop ?: Loop::get(); } public function connect($uri) diff --git a/src/UnixConnector.php b/src/UnixConnector.php index 881dad21..4cfb5a37 100644 --- a/src/UnixConnector.php +++ b/src/UnixConnector.php @@ -2,6 +2,7 @@ namespace React\Socket; +use React\EventLoop\Loop; use React\EventLoop\LoopInterface; use React\Promise; use InvalidArgumentException; @@ -17,9 +18,9 @@ final class UnixConnector implements ConnectorInterface { private $loop; - public function __construct(LoopInterface $loop) + public function __construct(LoopInterface $loop = null) { - $this->loop = $loop; + $this->loop = $loop ?: Loop::get(); } public function connect($path) diff --git a/src/UnixServer.php b/src/UnixServer.php index 452f4f67..a3dd8a1a 100644 --- a/src/UnixServer.php +++ b/src/UnixServer.php @@ -3,6 +3,7 @@ namespace React\Socket; use Evenement\EventEmitter; +use React\EventLoop\Loop; use React\EventLoop\LoopInterface; use InvalidArgumentException; use RuntimeException; @@ -12,7 +13,7 @@ * is responsible for accepting plaintext connections on unix domain sockets. * * ```php - * $server = new React\Socket\UnixServer('unix:///tmp/app.sock', $loop); + * $server = new React\Socket\UnixServer('unix:///tmp/app.sock'); * ``` * * See also the `ServerInterface` for more details. @@ -34,18 +35,24 @@ final class UnixServer extends EventEmitter implements ServerInterface * for more details. * * ```php - * $server = new React\Socket\UnixServer('unix:///tmp/app.sock', $loop); + * $server = new React\Socket\UnixServer('unix:///tmp/app.sock'); * ``` * - * @param string $path - * @param LoopInterface $loop - * @param array $context + * This class takes an optional `LoopInterface|null $loop` parameter that can be used to + * pass the event loop instance to use for this object. You can use a `null` value + * here in order to use the [default loop](https://github.com/reactphp/event-loop#loop). + * This value SHOULD NOT be given unless you're sure you want to explicitly use a + * given event loop instance. + * + * @param string $path + * @param ?LoopInterface $loop + * @param array $context * @throws InvalidArgumentException if the listening address is invalid * @throws RuntimeException if listening on this address fails (already in use etc.) */ - public function __construct($path, LoopInterface $loop, array $context = array()) + public function __construct($path, LoopInterface $loop = null, array $context = array()) { - $this->loop = $loop; + $this->loop = $loop ?: Loop::get(); if (\strpos($path, '://') === false) { $path = 'unix://' . $path; diff --git a/tests/ConnectorTest.php b/tests/ConnectorTest.php index a8ffc0be..6046767c 100644 --- a/tests/ConnectorTest.php +++ b/tests/ConnectorTest.php @@ -7,6 +7,21 @@ class ConnectorTest extends TestCase { + public function testConstructWithoutLoopAssignsLoopAutomatically() + { + $connector = new Connector(); + + $ref = new \ReflectionProperty($connector, 'connectors'); + $ref->setAccessible(true); + $connectors = $ref->getValue($connector); + + $ref = new \ReflectionProperty($connectors['tcp'], 'loop'); + $ref->setAccessible(true); + $loop = $ref->getValue($connectors['tcp']); + + $this->assertInstanceOf('React\EventLoop\LoopInterface', $loop); + } + public function testConnectorUsesTcpAsDefaultScheme() { $loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock(); diff --git a/tests/HappyEyeBallsConnectorTest.php b/tests/HappyEyeBallsConnectorTest.php index 6af7807a..b661d5b2 100644 --- a/tests/HappyEyeBallsConnectorTest.php +++ b/tests/HappyEyeBallsConnectorTest.php @@ -30,6 +30,29 @@ public function setUpMocks() $this->connector = new HappyEyeBallsConnector($this->loop, $this->tcp, $this->resolver); } + public function testConstructWithoutLoopAssignsLoopAutomatically() + { + $connector = new HappyEyeBallsConnector(null, $this->tcp, $this->resolver); + + $ref = new \ReflectionProperty($connector, 'loop'); + $ref->setAccessible(true); + $loop = $ref->getValue($connector); + + $this->assertInstanceOf('React\EventLoop\LoopInterface', $loop); + } + + public function testConstructWithoutRequiredConnectorThrows() + { + $this->setExpectedException('InvalidArgumentException'); + new HappyEyeBallsConnector(null, null, $this->resolver); + } + + public function testConstructWithoutRequiredResolverThrows() + { + $this->setExpectedException('InvalidArgumentException'); + new HappyEyeBallsConnector(null, $this->tcp); + } + public function testHappyFlow() { $first = new Deferred(); diff --git a/tests/SecureConnectorTest.php b/tests/SecureConnectorTest.php index 7f00028f..66491696 100644 --- a/tests/SecureConnectorTest.php +++ b/tests/SecureConnectorTest.php @@ -26,6 +26,21 @@ public function setUpConnector() $this->connector = new SecureConnector($this->tcp, $this->loop); } + public function testConstructWithoutLoopAssignsLoopAutomatically() + { + $connector = new SecureConnector($this->tcp); + + $ref = new \ReflectionProperty($connector, 'streamEncryption'); + $ref->setAccessible(true); + $streamEncryption = $ref->getValue($connector); + + $ref = new \ReflectionProperty($streamEncryption, 'loop'); + $ref->setAccessible(true); + $loop = $ref->getValue($streamEncryption); + + $this->assertInstanceOf('React\EventLoop\LoopInterface', $loop); + } + public function testConnectionWillWaitForTcpConnection() { $pending = new Promise\Promise(function () { }); diff --git a/tests/SecureServerTest.php b/tests/SecureServerTest.php index c5911c3c..a6ddcf29 100644 --- a/tests/SecureServerTest.php +++ b/tests/SecureServerTest.php @@ -18,6 +18,23 @@ public function setUpSkipTest() } } + public function testConstructWithoutLoopAssignsLoopAutomatically() + { + $tcp = $this->getMockBuilder('React\Socket\ServerInterface')->getMock(); + + $server = new SecureServer($tcp); + + $ref = new \ReflectionProperty($server, 'encryption'); + $ref->setAccessible(true); + $encryption = $ref->getValue($server); + + $ref = new \ReflectionProperty($encryption, 'loop'); + $ref->setAccessible(true); + $loop = $ref->getValue($encryption); + + $this->assertInstanceOf('React\EventLoop\LoopInterface', $loop); + } + public function testGetAddressWillBePassedThroughToTcpServer() { $tcp = $this->getMockBuilder('React\Socket\ServerInterface')->getMock(); diff --git a/tests/ServerTest.php b/tests/ServerTest.php index 99e69883..02e10301 100644 --- a/tests/ServerTest.php +++ b/tests/ServerTest.php @@ -14,6 +14,21 @@ class ServerTest extends TestCase { const TIMEOUT = 0.1; + public function testConstructWithoutLoopAssignsLoopAutomatically() + { + $server = new Server(0); + + $ref = new \ReflectionProperty($server, 'server'); + $ref->setAccessible(true); + $tcp = $ref->getValue($server); + + $ref = new \ReflectionProperty($tcp, 'loop'); + $ref->setAccessible(true); + $loop = $ref->getValue($tcp); + + $this->assertInstanceOf('React\EventLoop\LoopInterface', $loop); + } + public function testCreateServerWithZeroPortAssignsRandomPort() { $loop = Factory::create(); diff --git a/tests/TcpConnectorTest.php b/tests/TcpConnectorTest.php index d9798595..e6a03e6e 100644 --- a/tests/TcpConnectorTest.php +++ b/tests/TcpConnectorTest.php @@ -13,6 +13,17 @@ class TcpConnectorTest extends TestCase { const TIMEOUT = 5.0; + public function testConstructWithoutLoopAssignsLoopAutomatically() + { + $connector = new TcpConnector(); + + $ref = new \ReflectionProperty($connector, 'loop'); + $ref->setAccessible(true); + $loop = $ref->getValue($connector); + + $this->assertInstanceOf('React\EventLoop\LoopInterface', $loop); + } + /** @test */ public function connectionToEmptyPortShouldFail() { diff --git a/tests/TcpServerTest.php b/tests/TcpServerTest.php index 58ce216e..564614ca 100644 --- a/tests/TcpServerTest.php +++ b/tests/TcpServerTest.php @@ -34,6 +34,17 @@ public function setUpServer() $this->port = parse_url($this->server->getAddress(), PHP_URL_PORT); } + public function testConstructWithoutLoopAssignsLoopAutomatically() + { + $server = new TcpServer(0); + + $ref = new \ReflectionProperty($server, 'loop'); + $ref->setAccessible(true); + $loop = $ref->getValue($server); + + $this->assertInstanceOf('React\EventLoop\LoopInterface', $loop); + } + /** * @covers React\Socket\TcpServer::handleConnection */ diff --git a/tests/TimeoutConnectorTest.php b/tests/TimeoutConnectorTest.php index 8595b981..98dedca7 100644 --- a/tests/TimeoutConnectorTest.php +++ b/tests/TimeoutConnectorTest.php @@ -10,6 +10,19 @@ class TimeoutConnectorTest extends TestCase { + public function testConstructWithoutLoopAssignsLoopAutomatically() + { + $base = $this->getMockBuilder('React\Socket\ConnectorInterface')->getMock(); + + $connector = new TimeoutConnector($base, 0.01); + + $ref = new \ReflectionProperty($connector, 'loop'); + $ref->setAccessible(true); + $loop = $ref->getValue($connector); + + $this->assertInstanceOf('React\EventLoop\LoopInterface', $loop); + } + public function testRejectsWithTimeoutReasonOnTimeout() { $promise = new Promise\Promise(function () { }); diff --git a/tests/UnixConnectorTest.php b/tests/UnixConnectorTest.php index d9fe79cd..9f68c2d9 100644 --- a/tests/UnixConnectorTest.php +++ b/tests/UnixConnectorTest.php @@ -19,6 +19,17 @@ public function setUpConnector() $this->connector = new UnixConnector($this->loop); } + public function testConstructWithoutLoopAssignsLoopAutomatically() + { + $connector = new UnixConnector(); + + $ref = new \ReflectionProperty($connector, 'loop'); + $ref->setAccessible(true); + $loop = $ref->getValue($connector); + + $this->assertInstanceOf('React\EventLoop\LoopInterface', $loop); + } + public function testInvalid() { $promise = $this->connector->connect('google.com:80'); diff --git a/tests/UnixServerTest.php b/tests/UnixServerTest.php index 5a62b1ea..2e240933 100644 --- a/tests/UnixServerTest.php +++ b/tests/UnixServerTest.php @@ -29,6 +29,17 @@ public function setUpServer() $this->server = new UnixServer($this->uds, $this->loop); } + public function testConstructWithoutLoopAssignsLoopAutomatically() + { + $server = new UnixServer($this->getRandomSocketUri()); + + $ref = new \ReflectionProperty($server, 'loop'); + $ref->setAccessible(true); + $loop = $ref->getValue($server); + + $this->assertInstanceOf('React\EventLoop\LoopInterface', $loop); + } + /** * @covers React\Socket\UnixServer::handleConnection */