diff --git a/composer.json b/composer.json index 33935ac9..106fa41d 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { - "name": "gos/web-socket-bundle", + "name": "oroinc/web-socket-bundle", "type": "symfony-bundle", - "description": "Symfony Web Socket Bundle", + "description": "A fork of Symfony Web Socket Bundle that enables PHP 8.4 and Symfony 7 support", "keywords": ["Web Socket Bundle", "Websocket", "WAMP", "IO", "Ratchet"], "homepage": "https://github.com/GeniusesOfSymfony/WebSocketBundle", "license": "MIT", @@ -16,25 +16,24 @@ } ], "require": { - "php": "^7.4 || ^8.0", - "cboden/ratchet": "^0.4.4", - "gos/pubsub-router-bundle": "^2.2", - "gos/websocket-client": "^1.1", + "php": "^8.4", + "cboden/ratchet": "^0.4", + "oroinc/pubsub-router-bundle": "~2.9", "psr/log": "^1.1 || ^2.0 || ^3.0", "react/event-loop": "^1.2", "react/socket": "^1.9", - "symfony/config": "^4.4 || ^5.4 || ^6.0", - "symfony/console": "^4.4 || ^5.4 || ^6.0", - "symfony/dependency-injection": "^4.4 || ^5.4 || ^6.0", + "symfony/config": "^6.0 || ^7.0", + "symfony/console": "^6.0 || ^7.0", + "symfony/dependency-injection": "^6.0 || ^7.0", "symfony/deprecation-contracts": "^2.1 || ^3.0", - "symfony/event-dispatcher": "^4.4 || ^5.4 || ^6.0", - "symfony/http-foundation": "^4.4 || ^5.4 || ^6.0", - "symfony/http-kernel": "^4.4 || ^5.4 || ^6.0", + "symfony/event-dispatcher": "^6.0 || ^7.0", + "symfony/http-foundation": "^6.0 || ^7.0", + "symfony/http-kernel": "^6.0 || ^7.0", "symfony/polyfill-php80": "^1.15", - "symfony/security-core": "^4.4 || ^5.4 || ^6.0", - "symfony/serializer": "^4.4 || ^5.4 || ^6.0", - "symfony/string": "^5.4 || ^6.0", - "symfony/yaml": "^4.4 || ^5.4 || ^6.0" + "symfony/security-core": "^6.0 || ^7.0", + "symfony/serializer": "^6.0 || ^7.0", + "symfony/string": "^6.0 || ^7.0", + "symfony/yaml": "^6.0 || ^7.0" }, "require-dev": { "doctrine/cache": "^1.11 || ^2.0", @@ -45,12 +44,12 @@ "phpstan/phpstan-phpunit": "1.1.1", "phpstan/phpstan-symfony": "1.2.13", "phpunit/phpunit": "^9.5", - "symfony/cache": "^4.4 || ^5.4 || ^6.0", - "symfony/options-resolver": "^4.4 || ^5.4 || ^6.0", - "symfony/phpunit-bridge": "^5.4 || ^6.0", - "symfony/stopwatch": "^4.4 || ^5.4 || ^6.0", - "symfony/twig-bundle": "^4.4 || ^5.4 || ^6.0", - "symfony/web-profiler-bundle": "^4.4 || ^5.4 || ^6.0" + "symfony/cache": "^6.0 || ^7.0", + "symfony/options-resolver": "^6.0 || ^7.0", + "symfony/phpunit-bridge": "^6.0 || ^7.0", + "symfony/stopwatch": "^6.0 || ^7.0", + "symfony/twig-bundle": "^6.0 || ^7.0", + "symfony/web-profiler-bundle": "^6.0 || ^7.0" }, "conflict": { "doctrine/cache": "<1.11", @@ -65,7 +64,10 @@ "twig/twig": "<1.36 || >=2.0,<2.6" }, "autoload": { - "psr-4": { "Gos\\Bundle\\WebSocketBundle\\": "src/" } + "psr-4": { + "Gos\\Bundle\\WebSocketBundle\\": "src/", + "Gos\\Component\\WebSocketClient\\": "src/Component/WebSocketClient/" + } }, "autoload-dev": { "psr-4": { "Gos\\Bundle\\WebSocketBundle\\Tests\\": "tests/" } diff --git a/src/Authentication/ConnectionRepository.php b/src/Authentication/ConnectionRepository.php index bf4f3cd9..fda7360a 100644 --- a/src/Authentication/ConnectionRepository.php +++ b/src/Authentication/ConnectionRepository.php @@ -118,12 +118,6 @@ public function findTokenForConnection(ConnectionInterface $connection): TokenIn */ public function getUser(ConnectionInterface $connection) { - $user = $this->findTokenForConnection($connection)->getUser(); - - if (null !== $user && !($user instanceof UserInterface)) { - trigger_deprecation('gos/web-socket-bundle', '3.14', 'Retrieving a user that is not an instance of %s is deprecated in %s().', UserInterface::class, __METHOD__); - } - - return $user; + return $this->findTokenForConnection($connection)->getUser(); } } diff --git a/src/Client/Auth/WebsocketAuthenticationProvider.php b/src/Client/Auth/WebsocketAuthenticationProvider.php index b46a210d..bf0be2f6 100644 --- a/src/Client/Auth/WebsocketAuthenticationProvider.php +++ b/src/Client/Auth/WebsocketAuthenticationProvider.php @@ -10,10 +10,8 @@ use Symfony\Component\Security\Core\Authentication\Token\NullToken; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; -trigger_deprecation('gos/web-socket-bundle', '3.11', 'The "%s" class is deprecated and will be removed in 4.0, use the new websocket authentication API instead.', WebsocketAuthenticationProvider::class); - /** - * @deprecated to be removed in 4.0, use the new websocket authentication API instead + * deprecated to be removed in 4.0, use the new websocket authentication API instead */ final class WebsocketAuthenticationProvider implements WebsocketAuthenticationProviderInterface, LoggerAwareInterface { diff --git a/src/Client/Auth/WebsocketAuthenticationProviderInterface.php b/src/Client/Auth/WebsocketAuthenticationProviderInterface.php index 3d08726b..75b0a154 100644 --- a/src/Client/Auth/WebsocketAuthenticationProviderInterface.php +++ b/src/Client/Auth/WebsocketAuthenticationProviderInterface.php @@ -5,10 +5,8 @@ use Ratchet\ConnectionInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; -trigger_deprecation('gos/web-socket-bundle', '3.11', 'The "%s" interface is deprecated and will be removed in 4.0, use the new websocket authentication API instead.', WebsocketAuthenticationProviderInterface::class); - /** - * @deprecated to be removed in 4.0, use the new websocket authentication API instead + * deprecated to be removed in 4.0, use the new websocket authentication API instead */ interface WebsocketAuthenticationProviderInterface { diff --git a/src/Client/ClientConnection.php b/src/Client/ClientConnection.php index 274c8400..d6222ac0 100644 --- a/src/Client/ClientConnection.php +++ b/src/Client/ClientConnection.php @@ -6,10 +6,8 @@ use ReturnTypeWillChange; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; -trigger_deprecation('gos/web-socket-bundle', '3.11', 'The "%s" class is deprecated and will be removed in 4.0, use the new websocket authentication API instead.', ClientConnection::class); - /** - * @deprecated to be removed in 4.0, use the new websocket authentication API instead + * deprecated to be removed in 4.0, use the new websocket authentication API instead */ final class ClientConnection implements \ArrayAccess { @@ -37,8 +35,6 @@ public function getConnection(): ConnectionInterface */ public function offsetExists($offset): bool { - trigger_deprecation('gos/web-socket-bundle', '3.0', 'Accessing properties from %s as an array is deprecated and will be removed in 4.0, use the getters to access the properties.', self::class); - return \in_array($offset, ['client', 'connection'], true); } @@ -50,8 +46,6 @@ public function offsetExists($offset): bool #[ReturnTypeWillChange] public function offsetGet($offset) { - trigger_deprecation('gos/web-socket-bundle', '3.0', 'Accessing properties from %s as an array is deprecated and will be removed in 4.0, use the getters to access the properties.', self::class); - switch ($offset) { case 'client': return $this->client; diff --git a/src/Client/ClientManipulator.php b/src/Client/ClientManipulator.php index cef6dc2a..f5feabe2 100644 --- a/src/Client/ClientManipulator.php +++ b/src/Client/ClientManipulator.php @@ -9,10 +9,8 @@ use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\User\UserInterface; -trigger_deprecation('gos/web-socket-bundle', '3.11', 'The "%s" class is deprecated and will be removed in 4.0, use the new websocket authentication API instead.', ClientManipulator::class); - /** - * @deprecated to be removed in 4.0, use the new websocket authentication API instead + * deprecated to be removed in 4.0, use the new websocket authentication API instead */ final class ClientManipulator implements ClientManipulatorInterface { diff --git a/src/Client/ClientManipulatorInterface.php b/src/Client/ClientManipulatorInterface.php index 2146be60..8da190d1 100644 --- a/src/Client/ClientManipulatorInterface.php +++ b/src/Client/ClientManipulatorInterface.php @@ -7,10 +7,8 @@ use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\User\UserInterface; -trigger_deprecation('gos/web-socket-bundle', '3.11', 'The "%s" interface is deprecated and will be removed in 4.0, use the new websocket authentication API instead.', ClientManipulatorInterface::class); - /** - * @deprecated to be removed in 4.0, use the new websocket authentication API instead + * deprecated to be removed in 4.0, use the new websocket authentication API instead */ interface ClientManipulatorInterface { diff --git a/src/Client/ClientStorage.php b/src/Client/ClientStorage.php index 773b9b89..c1b6ee15 100644 --- a/src/Client/ClientStorage.php +++ b/src/Client/ClientStorage.php @@ -10,10 +10,8 @@ use Ratchet\ConnectionInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; -trigger_deprecation('gos/web-socket-bundle', '3.11', 'The "%s" class is deprecated and will be removed in 4.0, use the new websocket authentication API instead.', ClientStorage::class); - /** - * @deprecated to be removed in 4.0, use the new websocket authentication API instead + * deprecated to be removed in 4.0, use the new websocket authentication API instead */ final class ClientStorage implements ClientStorageInterface, LoggerAwareInterface { diff --git a/src/Client/ClientStorageInterface.php b/src/Client/ClientStorageInterface.php index 7f3b3539..1da1da9a 100644 --- a/src/Client/ClientStorageInterface.php +++ b/src/Client/ClientStorageInterface.php @@ -7,10 +7,8 @@ use Ratchet\ConnectionInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; -trigger_deprecation('gos/web-socket-bundle', '3.11', 'The "%s" interface is deprecated and will be removed in 4.0, use the new websocket authentication API instead.', ClientStorageInterface::class); - /** - * @deprecated to be removed in 4.0, use the new websocket authentication API instead + * deprecated to be removed in 4.0, use the new websocket authentication API instead * * @method void removeAllClients() */ diff --git a/src/Client/Driver/DoctrineCacheDriverDecorator.php b/src/Client/Driver/DoctrineCacheDriverDecorator.php index bb8b5802..7137e909 100644 --- a/src/Client/Driver/DoctrineCacheDriverDecorator.php +++ b/src/Client/Driver/DoctrineCacheDriverDecorator.php @@ -6,12 +6,10 @@ use Doctrine\Common\Cache\ClearableCache; use Symfony\Component\Cache\DoctrineProvider; -trigger_deprecation('gos/web-socket-bundle', '3.4', 'The "%s" class is deprecated and will be removed in 4.0, use the "%s" class with a "%s" instance instead.', DoctrineCacheDriverDecorator::class, SymfonyCacheDriverDecorator::class, DoctrineProvider::class); - /** * @author Johann Saunier * - * @deprecated to be removed in 4.0, use the `Gos\Bundle\WebSocketBundle\Client\Driver\SymfonyCacheDriverDecorator` with a `Symfony\Component\Cache\DoctrineProvider` instance instead + * deprecated to be removed in 4.0, use the `Gos\Bundle\WebSocketBundle\Client\Driver\SymfonyCacheDriverDecorator` with a `Symfony\Component\Cache\DoctrineProvider` instance instead */ final class DoctrineCacheDriverDecorator implements DriverInterface { diff --git a/src/Client/Driver/DriverException.php b/src/Client/Driver/DriverException.php index 54062f86..f2083752 100644 --- a/src/Client/Driver/DriverException.php +++ b/src/Client/Driver/DriverException.php @@ -2,10 +2,8 @@ namespace Gos\Bundle\WebSocketBundle\Client\Driver; -trigger_deprecation('gos/web-socket-bundle', '3.11', 'The "%s" class is deprecated and will be removed in 4.0, use the new websocket authentication API instead.', DriverException::class); - /** - * @deprecated to be removed in 4.0, use the new websocket authentication API instead + * deprecated to be removed in 4.0, use the new websocket authentication API instead */ class DriverException extends \Exception { diff --git a/src/Client/Driver/DriverInterface.php b/src/Client/Driver/DriverInterface.php index 8736851c..9f7abb28 100644 --- a/src/Client/Driver/DriverInterface.php +++ b/src/Client/Driver/DriverInterface.php @@ -2,10 +2,8 @@ namespace Gos\Bundle\WebSocketBundle\Client\Driver; -trigger_deprecation('gos/web-socket-bundle', '3.11', 'The "%s" interface is deprecated and will be removed in 4.0, use the new websocket authentication API instead.', DriverInterface::class); - /** - * @deprecated to be removed in 4.0, use the new websocket authentication API instead + * deprecated to be removed in 4.0, use the new websocket authentication API instead * * @method void clear() */ diff --git a/src/Client/Driver/InMemoryDriver.php b/src/Client/Driver/InMemoryDriver.php index ba9685a7..a6a3812d 100644 --- a/src/Client/Driver/InMemoryDriver.php +++ b/src/Client/Driver/InMemoryDriver.php @@ -2,10 +2,8 @@ namespace Gos\Bundle\WebSocketBundle\Client\Driver; -trigger_deprecation('gos/web-socket-bundle', '3.11', 'The "%s" class is deprecated and will be removed in 4.0, use the new websocket authentication API instead.', InMemoryDriver::class); - /** - * @deprecated to be removed in 4.0, use the new websocket authentication API instead + * deprecated to be removed in 4.0, use the new websocket authentication API instead */ final class InMemoryDriver implements DriverInterface { diff --git a/src/Client/Driver/SymfonyCacheDriverDecorator.php b/src/Client/Driver/SymfonyCacheDriverDecorator.php index dabc477c..af52885e 100644 --- a/src/Client/Driver/SymfonyCacheDriverDecorator.php +++ b/src/Client/Driver/SymfonyCacheDriverDecorator.php @@ -4,10 +4,8 @@ use Symfony\Component\Cache\Adapter\AdapterInterface; -trigger_deprecation('gos/web-socket-bundle', '3.11', 'The "%s" class is deprecated and will be removed in 4.0, use the new websocket authentication API instead.', SymfonyCacheDriverDecorator::class); - /** - * @deprecated to be removed in 4.0, use the new websocket authentication API instead + * deprecated to be removed in 4.0, use the new websocket authentication API instead */ final class SymfonyCacheDriverDecorator implements DriverInterface { diff --git a/src/Client/Exception/ClientNotFoundException.php b/src/Client/Exception/ClientNotFoundException.php index 175ed9c7..e9948811 100644 --- a/src/Client/Exception/ClientNotFoundException.php +++ b/src/Client/Exception/ClientNotFoundException.php @@ -2,10 +2,8 @@ namespace Gos\Bundle\WebSocketBundle\Client\Exception; -trigger_deprecation('gos/web-socket-bundle', '3.11', 'The "%s" class is deprecated and will be removed in 4.0, use the new websocket authentication API instead.', ClientNotFoundException::class); - /** - * @deprecated to be removed in 4.0, use the new websocket authentication API instead + * deprecated to be removed in 4.0, use the new websocket authentication API instead */ class ClientNotFoundException extends StorageException { diff --git a/src/Client/Exception/StorageException.php b/src/Client/Exception/StorageException.php index 15a90564..1d44ce72 100644 --- a/src/Client/Exception/StorageException.php +++ b/src/Client/Exception/StorageException.php @@ -2,10 +2,8 @@ namespace Gos\Bundle\WebSocketBundle\Client\Exception; -trigger_deprecation('gos/web-socket-bundle', '3.11', 'The "%s" class is deprecated and will be removed in 4.0, use the new websocket authentication API instead.', StorageException::class); - /** - * @deprecated to be removed in 4.0, use the new websocket authentication API instead + * deprecated to be removed in 4.0, use the new websocket authentication API instead */ class StorageException extends \Exception { diff --git a/src/Command/WebsocketServerCommand.php b/src/Command/WebsocketServerCommand.php index 261b1004..7de9b798 100644 --- a/src/Command/WebsocketServerCommand.php +++ b/src/Command/WebsocketServerCommand.php @@ -34,10 +34,6 @@ public function __construct(ServerLauncherInterface $entryPoint, string $host, i { parent::__construct(); - if (null === $serverRegistry) { - trigger_deprecation('gos/web-socket-bundle', '3.12', 'Not passing the "%s" to the "%s" constructor is deprecated and will be required as of 4.0.', ServerRegistry::class, self::class); - } - $this->serverLauncher = $entryPoint; $this->port = $port; $this->host = $host; diff --git a/src/Component/WebSocketClient/Exception/BadResponseException.php b/src/Component/WebSocketClient/Exception/BadResponseException.php new file mode 100644 index 00000000..cf10017f --- /dev/null +++ b/src/Component/WebSocketClient/Exception/BadResponseException.php @@ -0,0 +1,24 @@ + + * + * 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. + */ +class BadResponseException extends WebSocketException +{ +} diff --git a/src/Component/WebSocketClient/Exception/WebSocketException.php b/src/Component/WebSocketClient/Exception/WebSocketException.php new file mode 100644 index 00000000..ccd103e0 --- /dev/null +++ b/src/Component/WebSocketClient/Exception/WebSocketException.php @@ -0,0 +1,24 @@ + + * + * 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. + */ +class WebSocketException extends \Exception +{ +} diff --git a/src/Component/WebSocketClient/Wamp/Client.php b/src/Component/WebSocketClient/Wamp/Client.php new file mode 100644 index 00000000..df0d45ae --- /dev/null +++ b/src/Component/WebSocketClient/Wamp/Client.php @@ -0,0 +1,428 @@ + + * + * 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. + */ +final class Client implements ClientInterface, LoggerAwareInterface +{ + use LoggerAwareTrait; + + /** + * @var bool + */ + private $connected = false; + + /** + * @var string + */ + private $endpoint; + + /** + * @var string|null + */ + private $target; + + /** + * @var resource|null + */ + private $socket; + + /** + * @var string|null + */ + private $sessionId; + + /** + * @var string + */ + private $serverHost; + + /** + * @var int + */ + private $serverPort; + + /** + * @var bool + */ + private $secured = false; + + /** + * @var string|null + */ + private $origin; + + /** + * @var PayloadGeneratorInterface + */ + private $payloadGenerator; + + public function __construct(string $host, int $port, bool $secured = false, ?string $origin = null, ?PayloadGeneratorInterface $payloadGenerator = null) + { + $this->serverHost = $host; + $this->serverPort = $port; + $this->secured = $secured; + $this->origin = null !== $origin ? $origin : $host; + $this->payloadGenerator = $payloadGenerator ?: new PayloadGenerator(); + + $this->endpoint = sprintf( + '%s://%s:%s', + $secured ? 'ssl' : 'tcp', + $host, + $port + ); + } + + /** + * @return string The session identifier for the connection + * + * @throws BadResponseException if a response could not be received from the websocket server + * @throws WebsocketException if the target URI is invalid + */ + public function connect(string $target = '/'): string + { + if ($this->connected) { + return $this->sessionId; + } + + $socket = @stream_socket_client($this->endpoint, $errno, $errstr); + + if (false === $socket) { + if (null !== $this->logger) { + $this->logger->error('Could not open socket.', ['errno' => $errno, 'errstr' => $errstr]); + } + + throw new BadResponseException('Could not open socket. Reason: '.$errstr, $errno); + } + + $this->target = $target; + $this->socket = $socket; + + $this->verifyResponse($this->upgradeProtocol($this->target)); + + $payload = json_decode($this->read()); + + if (false === $payload) { + throw new BadResponseException('WAMP Server sent an invalid payload.'); + } + + if (Protocol::MSG_WELCOME !== $payload[0]) { + if (null !== $this->logger) { + $this->logger->error('WAMP Server did not send a welcome message.', ['payload' => $payload]); + } + + throw new BadResponseException('WAMP Server did not send a welcome message.'); + } + + $this->connected = true; + + return $this->sessionId = $payload[1]; + } + + /** + * @return string|false Response body from the request or boolean false on failure + * + * @throws WebsocketException if the target URI is invalid + */ + private function upgradeProtocol(string $target) + { + $key = $this->generateKey(); + + if (false === strpos($target, '/')) { + if (null !== $this->logger) { + $this->logger->error('Invalid target path for WAMP server.', ['target' => $target]); + } + + throw new WebsocketException('WAMP server target must contain a "/"'); + } + + $protocol = $this->secured ? 'wss' : 'ws'; + + $out = "GET {$protocol}://{$this->serverHost}:{$this->serverPort}{$target} HTTP/1.1\r\n"; + $out .= "Host: {$this->serverHost}:{$this->serverPort}\r\n"; + $out .= "Pragma: no-cache\r\n"; + $out .= "Cache-Control: no-cache\r\n"; + $out .= "Upgrade: WebSocket\r\n"; + $out .= "Connection: Upgrade\r\n"; + $out .= "Sec-WebSocket-Key: $key\r\n"; + $out .= "Sec-WebSocket-Protocol: wamp\r\n"; + $out .= "Sec-WebSocket-Version: 13\r\n"; + $out .= "Origin: {$this->origin}\r\n\r\n"; + + fwrite($this->socket, $out); + + return fgets($this->socket); + } + + /** + * @param string|false $response Response body from the upgrade request or boolean false on failure + * + * @throws BadResponseException if an invalid response was received + */ + private function verifyResponse($response): void + { + if (false === $response) { + if (null !== $this->logger) { + $this->logger->error('WAMP Server did not respond properly'); + } + + throw new BadResponseException('WAMP Server did not respond properly'); + } + + $responseStatus = substr($response, 0, 12); + + if ('HTTP/1.1 101' !== $responseStatus) { + if (null !== $this->logger) { + $this->logger->error('Unexpected HTTP response from WAMP server.', ['response' => $response]); + } + + throw new BadResponseException(sprintf('Unexpected response status. Expected "HTTP/1.1 101", got "%s".', $responseStatus)); + } + } + + /** + * Read the buffer and return the oldest event in stack. + * + * @see https://tools.ietf.org/html/rfc6455#section-5.2 + * + * @throws BadResponseException if the buffer could not be read + */ + private function read(): string + { + $streamBody = stream_get_contents($this->socket, stream_get_meta_data($this->socket)['unread_bytes']); + + if (false === $streamBody) { + if (null !== $this->logger) { + $this->logger->error('The stream buffer could not be read.', ['error' => error_get_last()]); + } + + throw new BadResponseException('The stream buffer could not be read.'); + } + + $startPos = strpos($streamBody, '['); + $endPos = strpos($streamBody, ']'); + + if (false === $startPos || false === $endPos) { + if (null !== $this->logger) { + $this->logger->error('Could not extract response body from stream.', ['body' => $streamBody]); + } + + throw new BadResponseException('Could not extract response body from stream.'); + } + + return substr( + $streamBody, + $startPos, + $endPos + ); + } + + /** + * @throws WebsocketException if the connection could not be disconnected cleanly + */ + public function disconnect(): bool + { + if (false === $this->connected) { + return true; + } + + if (null === $this->socket) { + return true; + } + + $this->send($this->payloadGenerator->generateClosePayload(), WebsocketPayload::OPCODE_CLOSE); + + $firstByte = fread($this->socket, 1); + + if (false === $firstByte) { + if (null !== $this->logger) { + $this->logger->error('Could not extract the payload from the buffer.', ['error' => error_get_last()]); + } + + throw new WebsocketException('Could not extract the payload from the buffer.'); + } + + /** @phpstan-var int<0, 255> $payloadLength */ + $payloadLength = \ord($firstByte); + $payload = fread($this->socket, $payloadLength); + + if (false === $payload) { + if (null !== $this->logger) { + $this->logger->error('Could not extract the payload from the buffer.', ['error' => error_get_last()]); + } + + throw new WebsocketException('Could not extract the payload from the buffer.'); + } + + if ($payloadLength >= 2) { + $bin = $payload[0].$payload[1]; + $status = bindec(sprintf('%08b%08b', \ord($payload[0]), \ord($payload[1]))); + + $this->send($bin.'Close acknowledged: '.$status, WebsocketPayload::OPCODE_CLOSE); + } + + fclose($this->socket); + $this->connected = false; + + return true; + } + + /** + * @param mixed $data Any JSON encodable data + * + * @throws WebsocketException if the data cannot be encoded properly + */ + private function send($data, int $opcode = WebsocketPayload::OPCODE_TEXT): void + { + if (\is_array($data)) { + $payload = json_encode($data); + + if (false === $payload) { + throw new WebsocketException('The data could not be encoded: '.json_last_error_msg()); + } + } elseif (is_scalar($data)) { + $payload = $data; + } else { + throw new WebsocketException('The data must be an array or a scalar value.'); + } + + $encoded = $this->payloadGenerator->encode( + (new WebsocketPayload()) + ->setOpcode($opcode) + ->setMask(0x1) + ->setPayload($payload) + ); + + // Check if the connection was reset, if so try to reconnect + if (false === @fwrite($this->socket, $encoded)) { + $this->connected = false; + $this->connect($this->target); + + fwrite($this->socket, $encoded); + } + } + + /** + * Establish a prefix on server. + * + * @see http://wamp.ws/spec#prefix_message + */ + public function prefix(string $prefix, string $uri): void + { + if (null !== $this->logger) { + $this->logger->info(sprintf('Establishing prefix "%s" for URI "%s"', $prefix, $uri)); + } + + $this->send([Protocol::MSG_PREFIX, $prefix, $uri]); + } + + /** + * Call a procedure on server. + * + * @see http://wamp.ws/spec#call_message + * + * @param array|mixed $args Arguments for the message either as an array or variadic set of parameters + */ + public function call(string $procUri, $args): void + { + if (!\is_array($args)) { + $args = \func_get_args(); + array_shift($args); + } + + if (null !== $this->logger) { + $this->logger->info( + sprintf('Websocket client calling %s', $procUri), + [ + 'callArguments' => $args, + ] + ); + } + + $this->send( + array_merge( + [Protocol::MSG_CALL, uniqid('', true), $procUri], + $args + ) + ); + } + + /** + * The client will send an event to all clients connected to the server who have subscribed to the topicURI. + * + * @see http://wamp.ws/spec#publish_message + * + * @param string[] $exclude + * @param string[] $eligible + */ + public function publish(string $topicUri, string $payload, array $exclude = [], array $eligible = []): void + { + if (null !== $this->logger) { + $this->logger->info( + sprintf('Websocket client publishing to %s', $topicUri), + [ + 'payload' => $payload, + 'excludedIds' => $exclude, + 'eligibleIds' => $eligible, + ] + ); + } + + $this->send([Protocol::MSG_PUBLISH, $topicUri, $payload, $exclude, $eligible]); + } + + /** + * Subscribers receive PubSub events published by subscribers via the EVENT message. The EVENT message contains the topicURI, the topic under which the event was published, and event, the PubSub event payload. + */ + public function event(string $topicUri, string $payload): void + { + if (null !== $this->logger) { + $this->logger->info( + sprintf('Websocket client sending event to %s', $topicUri), + [ + 'payload' => $payload, + ] + ); + } + + $this->send([Protocol::MSG_EVENT, $topicUri, $payload]); + } + + private function generateKey(int $length = 16): string + { + $c = 0; + $tmp = ''; + + while ($c++ * 16 < $length) { + $tmp .= md5((string) mt_rand(), true); + } + + return base64_encode(substr($tmp, 0, $length)); + } + + public function isConnected(): bool + { + return $this->connected; + } +} diff --git a/src/Component/WebSocketClient/Wamp/ClientFactory.php b/src/Component/WebSocketClient/Wamp/ClientFactory.php new file mode 100644 index 00000000..27b31f63 --- /dev/null +++ b/src/Component/WebSocketClient/Wamp/ClientFactory.php @@ -0,0 +1,81 @@ + + * + * 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. + */ +final class ClientFactory implements ClientFactoryInterface, LoggerAwareInterface +{ + use LoggerAwareTrait; + + /** + * @var array + */ + private $config; + + public function __construct(array $config) + { + $this->config = $this->resolveConfig($config); + } + + public function createConnection(): ClientInterface + { + $client = new Client( + $this->config['host'], + $this->config['port'], + $this->config['ssl'], + $this->config['origin'] + ); + + if (null !== $this->logger) { + $client->setLogger($this->logger); + } + + return $client; + } + + private function resolveConfig(array $config): array + { + $resolver = new OptionsResolver(); + + $resolver->setRequired( + [ + 'host', + 'port', + ] + ); + + $resolver->setDefaults( + [ + 'ssl' => false, + 'origin' => null, + ] + ); + + $resolver->setAllowedTypes('host', 'string'); + $resolver->setAllowedTypes('port', ['string', 'integer']); + $resolver->setAllowedTypes('ssl', 'boolean'); + $resolver->setAllowedTypes('origin', ['string', 'null']); + + return $resolver->resolve($config); + } +} diff --git a/src/Component/WebSocketClient/Wamp/ClientFactoryInterface.php b/src/Component/WebSocketClient/Wamp/ClientFactoryInterface.php new file mode 100644 index 00000000..377de1f8 --- /dev/null +++ b/src/Component/WebSocketClient/Wamp/ClientFactoryInterface.php @@ -0,0 +1,25 @@ + + * + * 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. + */ +interface ClientFactoryInterface +{ + public function createConnection(): ClientInterface; +} diff --git a/src/Component/WebSocketClient/Wamp/ClientInterface.php b/src/Component/WebSocketClient/Wamp/ClientInterface.php new file mode 100644 index 00000000..f2a9646c --- /dev/null +++ b/src/Component/WebSocketClient/Wamp/ClientInterface.php @@ -0,0 +1,72 @@ + + * + * 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. + */ +interface ClientInterface +{ + /** + * @return string The session identifier for the connection + * + * @throws BadResponseException if a response could not be received from the websocket server + * @throws WebsocketException if the target URI is invalid + */ + public function connect(string $target = '/'): string; + + /** + * @throws WebsocketException if the connection could not be disconnected cleanly + */ + public function disconnect(): bool; + + public function isConnected(): bool; + + /** + * Establish a prefix on server. + * + * @see http://wamp.ws/spec#prefix_message + */ + public function prefix(string $prefix, string $uri): void; + + /** + * Call a procedure on server. + * + * @see http://wamp.ws/spec#call_message + * + * @param array|mixed $args Arguments for the message either as an array or variadic set of parameters + */ + public function call(string $procUri, $args): void; + + /** + * The client will send an event to all clients connected to the server who have subscribed to the topicURI. + * + * @see http://wamp.ws/spec#publish_message + * + * @param string[] $exclude + * @param string[] $eligible + */ + public function publish(string $topicUri, string $payload, array $exclude = [], array $eligible = []): void; + + /** + * Subscribers receive PubSub events published by subscribers via the EVENT message. The EVENT message contains the topicURI, the topic under which the event was published, and event, the PubSub event payload. + */ + public function event(string $topicUri, string $payload): void; +} diff --git a/src/Component/WebSocketClient/Wamp/PayloadGenerator.php b/src/Component/WebSocketClient/Wamp/PayloadGenerator.php new file mode 100644 index 00000000..f7a503c7 --- /dev/null +++ b/src/Component/WebSocketClient/Wamp/PayloadGenerator.php @@ -0,0 +1,74 @@ + + * + * 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. + */ +final class PayloadGenerator implements PayloadGeneratorInterface +{ + public function encode(WebsocketPayload $websocketPayload): string + { + $payload = $websocketPayload->getFin() << 1 | $websocketPayload->getRsv1(); + $payload = $payload << 1 | $websocketPayload->getRsv2(); + $payload = $payload << 1 | $websocketPayload->getRsv3(); + $payload = $payload << 4 | $websocketPayload->getOpcode(); + $payload = $payload << 1 | $websocketPayload->getMask(); + + if ($websocketPayload->getLength() <= 125) { + $payload = $payload << 7 | $websocketPayload->getLength(); + $payload = pack('n', $payload); + } elseif ($websocketPayload->getLength() <= 0xffff) { + $payload = $payload << 7 | 126; + $payload = pack('n', $payload).pack('n*', $websocketPayload->getLength()); + } else { + $payload = $payload << 7 | 127; + $payload = pack('n', $payload).pack('NN', ($websocketPayload->getLength() & 0xffffffff00000000) >> 32, $websocketPayload->getLength() & 0x00000000ffffffff); + } + + if (0x1 == $websocketPayload->getMask()) { + $payload .= $websocketPayload->getMaskKey(); + $data = $this->maskData($websocketPayload->getPayload(), $websocketPayload->getMaskKey()); + } else { + $data = $websocketPayload->getPayload(); + } + + return $payload.$data; + } + + public function generateClosePayload(): string + { + $str = ''; + + foreach (str_split(sprintf('%016b', 1000), 8) as $binstr) { + $str .= \chr((int) bindec($binstr)); + } + + return $str.'ttfn'; + } + + private function maskData(?string $data, ?string $key): string + { + $masked = ''; + + for ($i = 0; $i < \strlen($data); ++$i) { + $masked .= $data[$i] ^ $key[$i % 4]; + } + + return $masked; + } +} diff --git a/src/Component/WebSocketClient/Wamp/PayloadGeneratorInterface.php b/src/Component/WebSocketClient/Wamp/PayloadGeneratorInterface.php new file mode 100644 index 00000000..c314eb7a --- /dev/null +++ b/src/Component/WebSocketClient/Wamp/PayloadGeneratorInterface.php @@ -0,0 +1,27 @@ + + * + * 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. + */ +interface PayloadGeneratorInterface +{ + public function encode(WebsocketPayload $websocketPayload): string; + + public function generateClosePayload(): string; +} diff --git a/src/Component/WebSocketClient/Wamp/Protocol.php b/src/Component/WebSocketClient/Wamp/Protocol.php new file mode 100644 index 00000000..ae7906ad --- /dev/null +++ b/src/Component/WebSocketClient/Wamp/Protocol.php @@ -0,0 +1,37 @@ + + * + * 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. + */ +final class Protocol +{ + public const MSG_WELCOME = 0; + public const MSG_PREFIX = 1; + public const MSG_CALL = 2; + public const MSG_CALL_RESULT = 3; + public const MSG_CALL_ERROR = 4; + public const MSG_SUBSCRIBE = 5; + public const MSG_UNSUBSCRIBE = 6; + public const MSG_PUBLISH = 7; + public const MSG_EVENT = 8; + + private function __construct() + { + } +} diff --git a/src/Component/WebSocketClient/Wamp/WebsocketPayload.php b/src/Component/WebSocketClient/Wamp/WebsocketPayload.php new file mode 100644 index 00000000..30b34362 --- /dev/null +++ b/src/Component/WebSocketClient/Wamp/WebsocketPayload.php @@ -0,0 +1,198 @@ + + * + * 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. + */ +final class WebsocketPayload +{ + public const OPCODE_CONTINUE = 0x0; + public const OPCODE_TEXT = 0x1; + public const OPCODE_BINARY = 0x2; + public const OPCODE_NON_CONTROL_RESERVED_1 = 0x3; + public const OPCODE_NON_CONTROL_RESERVED_2 = 0x4; + public const OPCODE_NON_CONTROL_RESERVED_3 = 0x5; + public const OPCODE_NON_CONTROL_RESERVED_4 = 0x6; + public const OPCODE_NON_CONTROL_RESERVED_5 = 0x7; + public const OPCODE_CLOSE = 0x8; + public const OPCODE_PING = 0x9; + public const OPCODE_PONG = 0xA; + public const OPCODE_CONTROL_RESERVED_1 = 0xB; + public const OPCODE_CONTROL_RESERVED_2 = 0xC; + public const OPCODE_CONTROL_RESERVED_3 = 0xD; + public const OPCODE_CONTROL_RESERVED_4 = 0xE; + public const OPCODE_CONTROL_RESERVED_5 = 0xF; + + /** + * @var int + */ + private $fin = 0x1; + + /** + * @var int + */ + private $rsv1 = 0x0; + + /** + * @var int + */ + private $rsv2 = 0x0; + + /** + * @var int + */ + private $rsv3 = 0x0; + + /** + * @var int|null + */ + private $opcode; + + /** + * @var int + */ + private $mask = 0x0; + + /** + * @var string + */ + private $maskKey; + + /** + * @var mixed + */ + private $payload; + + public function setFin(int $fin): self + { + $this->fin = $fin; + + return $this; + } + + public function getFin(): int + { + return $this->fin; + } + + public function setRsv1(int $rsv1): self + { + $this->rsv1 = $rsv1; + + return $this; + } + + public function getRsv1(): int + { + return $this->rsv1; + } + + public function setRsv2(int $rsv2): self + { + $this->rsv2 = $rsv2; + + return $this; + } + + public function getRsv2(): int + { + return $this->rsv2; + } + + public function setRsv3(int $rsv3): self + { + $this->rsv3 = $rsv3; + + return $this; + } + + public function getRsv3(): int + { + return $this->rsv3; + } + + public function setOpcode(?int $opcode): self + { + $this->opcode = $opcode; + + return $this; + } + + public function getOpcode(): ?int + { + return $this->opcode; + } + + public function setMask(int $mask): self + { + $this->mask = $mask; + + if (true == $this->mask) { + $this->generateMaskKey(); + } + + return $this; + } + + public function getMask(): int + { + return $this->mask; + } + + public function getLength(): int + { + return \strlen($this->getPayload()); + } + + public function setMaskKey(string $maskKey): self + { + $this->maskKey = $maskKey; + + return $this; + } + + public function getMaskKey(): ?string + { + return $this->maskKey; + } + + /** + * @param mixed $payload + */ + public function setPayload($payload): self + { + $this->payload = $payload; + + return $this; + } + + /** + * @return mixed + */ + public function getPayload() + { + return $this->payload; + } + + public function generateMaskKey(): string + { + $this->setMaskKey(random_bytes(4)); + + return $this->getMaskKey(); + } +} diff --git a/src/DataCollector/WebsocketDataCollector.php b/src/DataCollector/WebsocketDataCollector.php index 2eff8a38..a3ff69ce 100644 --- a/src/DataCollector/WebsocketDataCollector.php +++ b/src/DataCollector/WebsocketDataCollector.php @@ -4,10 +4,8 @@ use Symfony\Component\Stopwatch\StopwatchEvent; -trigger_deprecation('gos/web-socket-bundle', '3.1', 'The "%s" class is deprecated and will be removed in 4.0.', WebsocketDataCollector::class); - /** - * @deprecated to be removed in 4.0 + * deprecated to be removed in 4.0 */ final class WebsocketDataCollector extends WebsocketCompatibilityDataCollector { diff --git a/src/DependencyInjection/CompilerPass/DataCollectorCompilerPass.php b/src/DependencyInjection/CompilerPass/DataCollectorCompilerPass.php index 0245458d..2dac82a3 100644 --- a/src/DependencyInjection/CompilerPass/DataCollectorCompilerPass.php +++ b/src/DependencyInjection/CompilerPass/DataCollectorCompilerPass.php @@ -25,9 +25,6 @@ public function __construct(bool $internal = false) public function process(ContainerBuilder $container): void { - if (!$this->internal) { - trigger_deprecation('gos/web-socket-bundle', '3.1', 'The "%s" class is deprecated and will be removed in 4.0, use the symfony/messenger component instead.', self::class); - } if (!$container->getParameter('kernel.debug') || !$container->hasDefinition('debug.stopwatch')) { return; diff --git a/src/DependencyInjection/CompilerPass/PusherCompilerPass.php b/src/DependencyInjection/CompilerPass/PusherCompilerPass.php index 31b14fed..0ba2a33e 100644 --- a/src/DependencyInjection/CompilerPass/PusherCompilerPass.php +++ b/src/DependencyInjection/CompilerPass/PusherCompilerPass.php @@ -27,10 +27,6 @@ public function __construct(bool $internal = false) */ public function process(ContainerBuilder $container): void { - if (!$this->internal) { - trigger_deprecation('gos/web-socket-bundle', '3.1', 'The "%s" class is deprecated and will be removed in 4.0, use the symfony/messenger component instead.', self::class); - } - if ($container->hasDefinition('gos_web_socket.registry.pusher')) { $registryDefinition = $container->getDefinition('gos_web_socket.registry.pusher'); diff --git a/src/DependencyInjection/CompilerPass/ServerPushHandlerCompilerPass.php b/src/DependencyInjection/CompilerPass/ServerPushHandlerCompilerPass.php index c6cb7dab..45f35d66 100644 --- a/src/DependencyInjection/CompilerPass/ServerPushHandlerCompilerPass.php +++ b/src/DependencyInjection/CompilerPass/ServerPushHandlerCompilerPass.php @@ -27,10 +27,6 @@ public function __construct(bool $internal = false) */ public function process(ContainerBuilder $container): void { - if (!$this->internal) { - trigger_deprecation('gos/web-socket-bundle', '3.1', 'The "%s" class is deprecated and will be removed in 4.0, use the symfony/messenger component instead.', self::class); - } - if ($container->hasDefinition('gos_web_socket.registry.server_push_handler')) { $registryDefinition = $container->getDefinition('gos_web_socket.registry.server_push_handler'); diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 28fbac44..13b18f93 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -113,7 +113,7 @@ private function addAuthenticationSection(ArrayNodeDefinition $rootNode): void ->validate() ->ifTrue(static fn (bool $enableAuthenticator): bool => !$enableAuthenticator) ->then(static function (bool $enableAuthenticator): void { - trigger_deprecation('gos/web-socket-bundle', '3.11', 'Not setting the "gos_web_socket.authentication.enable_authenticator" config option to true is deprecated.'); + // Deprecated: trigger_deprecation removed }) ->end() ->end() diff --git a/src/Event/ClientErrorEvent.php b/src/Event/ClientErrorEvent.php index faec9599..224b4ee3 100644 --- a/src/Event/ClientErrorEvent.php +++ b/src/Event/ClientErrorEvent.php @@ -11,13 +11,6 @@ final class ClientErrorEvent extends ClientEvent */ public function setException(\Throwable $exception): void { - trigger_deprecation( - 'gos/web-socket-bundle', - '3.3', - '%s() is deprecated and will be removed in 4.0, the Throwable will be a required constructor argument.', - __METHOD__ - ); - $this->throwable = $exception; } @@ -28,14 +21,6 @@ public function setException(\Throwable $exception): void */ public function getException() { - trigger_deprecation( - 'gos/web-socket-bundle', - '3.3', - '%s() is deprecated and will be removed in 4.0, use %s::getThrowable() instead.', - __METHOD__, - self::class - ); - return $this->getThrowable(); } diff --git a/src/Event/ClientRejectedEvent.php b/src/Event/ClientRejectedEvent.php index 6a61a312..0d72fecb 100644 --- a/src/Event/ClientRejectedEvent.php +++ b/src/Event/ClientRejectedEvent.php @@ -5,11 +5,9 @@ use Psr\Http\Message\RequestInterface; use Symfony\Contracts\EventDispatcher\Event; -trigger_deprecation('gos/web-socket-bundle', '3.8', 'The "%s" class is deprecated and will be removed in 4.0, subscribe to the "%s" event instead.', ClientRejectedEvent::class, ConnectionRejectedEvent::class); - /** * @author Johann Saunier - * @deprecated to be removed in 4.0, subscribe to the `Gos\Bundle\WebSocketBundle\Event\ConnectionRejectedEvent` event instead + * deprecated to be removed in 4.0, subscribe to the `Gos\Bundle\WebSocketBundle\Event\ConnectionRejectedEvent` event instead */ final class ClientRejectedEvent extends Event { diff --git a/src/Event/PushHandlerEvent.php b/src/Event/PushHandlerEvent.php index b267febf..b0a34fa0 100644 --- a/src/Event/PushHandlerEvent.php +++ b/src/Event/PushHandlerEvent.php @@ -5,10 +5,8 @@ use Gos\Bundle\WebSocketBundle\Pusher\ServerPushHandlerInterface; use Symfony\Contracts\EventDispatcher\Event; -trigger_deprecation('gos/web-socket-bundle', '3.1', 'The "%s" class is deprecated and will be removed in 4.0, use the symfony/messenger component instead.', PushHandlerEvent::class); - /** - * @deprecated to be removed in 4.0, use the symfony/messenger component instead + * deprecated to be removed in 4.0, use the symfony/messenger component instead */ abstract class PushHandlerEvent extends Event { diff --git a/src/Event/PushHandlerFailEvent.php b/src/Event/PushHandlerFailEvent.php index baa82f5c..ea59b696 100644 --- a/src/Event/PushHandlerFailEvent.php +++ b/src/Event/PushHandlerFailEvent.php @@ -2,10 +2,8 @@ namespace Gos\Bundle\WebSocketBundle\Event; -trigger_deprecation('gos/web-socket-bundle', '3.1', 'The "%s" class is deprecated and will be removed in 4.0, use the symfony/messenger component instead.', PushHandlerFailEvent::class); - /** - * @deprecated to be removed in 4.0, use the symfony/messenger component instead + * deprecated to be removed in 4.0, use the symfony/messenger component instead */ final class PushHandlerFailEvent extends PushHandlerEvent { diff --git a/src/Event/PushHandlerSuccessEvent.php b/src/Event/PushHandlerSuccessEvent.php index 864ce944..8d8f7d35 100644 --- a/src/Event/PushHandlerSuccessEvent.php +++ b/src/Event/PushHandlerSuccessEvent.php @@ -2,10 +2,8 @@ namespace Gos\Bundle\WebSocketBundle\Event; -trigger_deprecation('gos/web-socket-bundle', '3.1', 'The "%s" class is deprecated and will be removed in 4.0, use the symfony/messenger component instead.', PushHandlerSuccessEvent::class); - /** - * @deprecated to be removed in 4.0, use the symfony/messenger component instead + * deprecated to be removed in 4.0, use the symfony/messenger component instead */ final class PushHandlerSuccessEvent extends PushHandlerEvent { diff --git a/src/EventListener/ClosePusherConnectionsListener.php b/src/EventListener/ClosePusherConnectionsListener.php index cda762d9..7a290ad4 100644 --- a/src/EventListener/ClosePusherConnectionsListener.php +++ b/src/EventListener/ClosePusherConnectionsListener.php @@ -5,10 +5,8 @@ use Gos\Bundle\WebSocketBundle\Pusher\PusherRegistry; use Symfony\Component\HttpKernel\Event\TerminateEvent; -trigger_deprecation('gos/web-socket-bundle', '3.1', 'The "%s" class is deprecated and will be removed in 4.0, use the symfony/messenger component instead.', ClosePusherConnectionsListener::class); - /** - * @deprecated to be removed in 4.0, use the symfony/messenger component instead + * deprecated to be removed in 4.0, use the symfony/messenger component instead */ final class ClosePusherConnectionsListener { diff --git a/src/EventListener/RegisterPushHandlersListener.php b/src/EventListener/RegisterPushHandlersListener.php index a3147512..5c614da9 100644 --- a/src/EventListener/RegisterPushHandlersListener.php +++ b/src/EventListener/RegisterPushHandlersListener.php @@ -8,10 +8,8 @@ use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerAwareTrait; -trigger_deprecation('gos/web-socket-bundle', '3.1', 'The "%s" class is deprecated and will be removed in 4.0, use the symfony/messenger component instead.', RegisterPushHandlersListener::class); - /** - * @deprecated to be removed in 4.0, use the symfony/messenger component instead + * deprecated to be removed in 4.0, use the symfony/messenger component instead */ final class RegisterPushHandlersListener implements LoggerAwareInterface { diff --git a/src/Periodic/DoctrinePeriodicPing.php b/src/Periodic/DoctrinePeriodicPing.php index 437a9338..90db5160 100644 --- a/src/Periodic/DoctrinePeriodicPing.php +++ b/src/Periodic/DoctrinePeriodicPing.php @@ -31,16 +31,6 @@ public function __construct(object $connection, int $interval = 20) throw new \InvalidArgumentException(sprintf('The connection must be a subclass of %s or implement %s, %s does not fulfill these requirements.', Connection::class, PingableConnection::class, \get_class($connection))); } - if ($connection instanceof PingableConnection && !($connection instanceof Connection)) { - trigger_deprecation( - 'gos/web-socket-bundle', - '3.3', - 'Support for "%s" instances which are not an instance of "%s" is deprecated and will be removed in 4.0.', - PingableConnection::class, - Connection::class - ); - } - $this->connection = $connection; $this->interval = $interval; } @@ -87,15 +77,11 @@ public function getInterval(): int */ public function getTimeout(): int { - trigger_deprecation('gos/web-socket-bundle', '3.9', '%s() is deprecated and will be removed in 4.0, call %s::getInterval() instead.', __METHOD__, self::class); - return $this->getInterval(); } public function setTimeout(int $timeout): void { - trigger_deprecation('gos/web-socket-bundle', '3.9', '%s() is deprecated and will be removed in 4.0, set the timeout through the constructor instead.', __METHOD__); - $this->interval = $timeout; } } diff --git a/src/Periodic/PdoPeriodicPing.php b/src/Periodic/PdoPeriodicPing.php index 0656430a..22b0ebf0 100644 --- a/src/Periodic/PdoPeriodicPing.php +++ b/src/Periodic/PdoPeriodicPing.php @@ -59,15 +59,11 @@ public function getInterval(): int */ public function getTimeout(): int { - trigger_deprecation('gos/web-socket-bundle', '3.9', '%s() is deprecated and will be removed in 4.0, call %s::getInterval() instead.', __METHOD__, self::class); - return $this->getInterval(); } public function setTimeout(int $timeout): void { - trigger_deprecation('gos/web-socket-bundle', '3.9', '%s() is deprecated and will be removed in 4.0, set the timeout through the constructor instead.', __METHOD__); - $this->interval = $timeout; } } diff --git a/src/Periodic/PeriodicMemoryUsage.php b/src/Periodic/PeriodicMemoryUsage.php index a1a17f16..22f4ad4f 100644 --- a/src/Periodic/PeriodicMemoryUsage.php +++ b/src/Periodic/PeriodicMemoryUsage.php @@ -26,8 +26,6 @@ public function getInterval(): int */ public function getTimeout(): int { - trigger_deprecation('gos/web-socket-bundle', '3.9', '%s() is deprecated and will be removed in 4.0, call %s::getInterval() instead.', __METHOD__, self::class); - return $this->getInterval(); } } diff --git a/src/Pusher/AbstractPusher.php b/src/Pusher/AbstractPusher.php index 06e37960..0e97a7de 100644 --- a/src/Pusher/AbstractPusher.php +++ b/src/Pusher/AbstractPusher.php @@ -5,10 +5,8 @@ use Gos\Bundle\WebSocketBundle\Router\WampRouter; use Symfony\Component\Serializer\SerializerInterface; -trigger_deprecation('gos/web-socket-bundle', '3.1', 'The "%s" class is deprecated and will be removed in 4.0, use the symfony/messenger component instead.', AbstractPusher::class); - /** - * @deprecated to be removed in 4.0, use the symfony/messenger component instead + * deprecated to be removed in 4.0, use the symfony/messenger component instead */ abstract class AbstractPusher implements PusherInterface { diff --git a/src/Pusher/AbstractServerPushHandler.php b/src/Pusher/AbstractServerPushHandler.php index 7890375d..fd226835 100644 --- a/src/Pusher/AbstractServerPushHandler.php +++ b/src/Pusher/AbstractServerPushHandler.php @@ -2,10 +2,8 @@ namespace Gos\Bundle\WebSocketBundle\Pusher; -trigger_deprecation('gos/web-socket-bundle', '3.1', 'The "%s" class is deprecated and will be removed in 4.0, use the symfony/messenger component instead.', AbstractServerPushHandler::class); - /** - * @deprecated to be removed in 4.0, use the symfony/messenger component instead + * deprecated to be removed in 4.0, use the symfony/messenger component instead */ abstract class AbstractServerPushHandler implements ServerPushHandlerInterface { diff --git a/src/Pusher/Amqp/AmqpConnectionFactory.php b/src/Pusher/Amqp/AmqpConnectionFactory.php index 58b1a7eb..2122c483 100644 --- a/src/Pusher/Amqp/AmqpConnectionFactory.php +++ b/src/Pusher/Amqp/AmqpConnectionFactory.php @@ -5,10 +5,8 @@ use Gos\Bundle\WebSocketBundle\Pusher\Exception\PusherUnsupportedException; use Symfony\Component\OptionsResolver\OptionsResolver; -trigger_deprecation('gos/web-socket-bundle', '3.1', 'The "%s" class is deprecated and will be removed in 4.0, use the symfony/messenger component instead.', AmqpConnectionFactory::class); - /** - * @deprecated to be removed in 4.0, use the symfony/messenger component instead + * deprecated to be removed in 4.0, use the symfony/messenger component instead */ final class AmqpConnectionFactory implements AmqpConnectionFactoryInterface { diff --git a/src/Pusher/Amqp/AmqpConnectionFactoryInterface.php b/src/Pusher/Amqp/AmqpConnectionFactoryInterface.php index 325984ac..ccd1bc3a 100644 --- a/src/Pusher/Amqp/AmqpConnectionFactoryInterface.php +++ b/src/Pusher/Amqp/AmqpConnectionFactoryInterface.php @@ -4,10 +4,8 @@ use Gos\Bundle\WebSocketBundle\Pusher\Exception\PusherUnsupportedException; -trigger_deprecation('gos/web-socket-bundle', '3.1', 'The "%s" interface is deprecated and will be removed in 4.0, use the symfony/messenger component instead.', AmqpConnectionFactoryInterface::class); - /** - * @deprecated to be removed in 4.0, use the symfony/messenger component instead + * deprecated to be removed in 4.0, use the symfony/messenger component instead */ interface AmqpConnectionFactoryInterface { diff --git a/src/Pusher/Amqp/AmqpPusher.php b/src/Pusher/Amqp/AmqpPusher.php index f23eff61..b28c8fe7 100644 --- a/src/Pusher/Amqp/AmqpPusher.php +++ b/src/Pusher/Amqp/AmqpPusher.php @@ -8,10 +8,8 @@ use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Serializer\SerializerInterface; -trigger_deprecation('gos/web-socket-bundle', '3.1', 'The "%s" class is deprecated and will be removed in 4.0, use the symfony/messenger component instead.', AmqpPusher::class); - /** - * @deprecated to be removed in 4.0, use the symfony/messenger component instead + * deprecated to be removed in 4.0, use the symfony/messenger component instead */ final class AmqpPusher extends AbstractPusher { diff --git a/src/Pusher/Amqp/AmqpServerPushHandler.php b/src/Pusher/Amqp/AmqpServerPushHandler.php index ef89d801..e8588a42 100644 --- a/src/Pusher/Amqp/AmqpServerPushHandler.php +++ b/src/Pusher/Amqp/AmqpServerPushHandler.php @@ -17,10 +17,8 @@ use Symfony\Component\Serializer\SerializerInterface; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; -trigger_deprecation('gos/web-socket-bundle', '3.1', 'The "%s" class is deprecated and will be removed in 4.0, use the symfony/messenger component instead.', AmqpServerPushHandler::class); - /** - * @deprecated to be removed in 4.0, use the symfony/messenger component instead + * deprecated to be removed in 4.0, use the symfony/messenger component instead */ final class AmqpServerPushHandler extends AbstractServerPushHandler implements LoggerAwareInterface { diff --git a/src/Pusher/DataCollectingPusherDecorator.php b/src/Pusher/DataCollectingPusherDecorator.php index a1f624e8..3ae39397 100644 --- a/src/Pusher/DataCollectingPusherDecorator.php +++ b/src/Pusher/DataCollectingPusherDecorator.php @@ -5,10 +5,8 @@ use Gos\Bundle\WebSocketBundle\DataCollector\WebsocketDataCollector; use Symfony\Component\Stopwatch\Stopwatch; -trigger_deprecation('gos/web-socket-bundle', '3.1', 'The "%s" class is deprecated and will be removed in 4.0, use the symfony/messenger component instead.', DataCollectingPusherDecorator::class); - /** - * @deprecated to be removed in 4.0, use the symfony/messenger component instead + * deprecated to be removed in 4.0, use the symfony/messenger component instead */ final class DataCollectingPusherDecorator implements PusherInterface { diff --git a/src/Pusher/Exception/PusherUnsupportedException.php b/src/Pusher/Exception/PusherUnsupportedException.php index a73c6fac..b7fbe0ef 100644 --- a/src/Pusher/Exception/PusherUnsupportedException.php +++ b/src/Pusher/Exception/PusherUnsupportedException.php @@ -2,10 +2,8 @@ namespace Gos\Bundle\WebSocketBundle\Pusher\Exception; -trigger_deprecation('gos/web-socket-bundle', '3.1', 'The "%s" class is deprecated and will be removed in 4.0.', PusherUnsupportedException::class); - /** - * @deprecated to be removed in 4.0, use the symfony/messenger component instead + * deprecated to be removed in 4.0, use the symfony/messenger component instead */ final class PusherUnsupportedException extends \RuntimeException { diff --git a/src/Pusher/Message.php b/src/Pusher/Message.php index 73b201c6..062045b9 100644 --- a/src/Pusher/Message.php +++ b/src/Pusher/Message.php @@ -2,12 +2,10 @@ namespace Gos\Bundle\WebSocketBundle\Pusher; -trigger_deprecation('gos/web-socket-bundle', '3.1', 'The "%s" class is deprecated and will be removed in 4.0, use the symfony/messenger component instead.', Message::class); - /** * @internal * - * @deprecated to be removed in 4.0, use the symfony/messenger component instead + * deprecated to be removed in 4.0, use the symfony/messenger component instead */ final class Message { diff --git a/src/Pusher/PusherInterface.php b/src/Pusher/PusherInterface.php index a02bd5c3..320902a6 100644 --- a/src/Pusher/PusherInterface.php +++ b/src/Pusher/PusherInterface.php @@ -2,10 +2,8 @@ namespace Gos\Bundle\WebSocketBundle\Pusher; -trigger_deprecation('gos/web-socket-bundle', '3.1', 'The "%s" interface is deprecated and will be removed in 4.0, use the symfony/messenger component instead.', PusherInterface::class); - /** - * @deprecated to be removed in 4.0, use the symfony/messenger component instead + * deprecated to be removed in 4.0, use the symfony/messenger component instead */ interface PusherInterface { diff --git a/src/Pusher/PusherRegistry.php b/src/Pusher/PusherRegistry.php index a915acf2..97c952d6 100644 --- a/src/Pusher/PusherRegistry.php +++ b/src/Pusher/PusherRegistry.php @@ -2,10 +2,8 @@ namespace Gos\Bundle\WebSocketBundle\Pusher; -trigger_deprecation('gos/web-socket-bundle', '3.1', 'The "%s" class is deprecated and will be removed in 4.0, use the symfony/messenger component instead.', PusherRegistry::class); - /** - * @deprecated to be removed in 4.0, use the symfony/messenger component instead + * deprecated to be removed in 4.0, use the symfony/messenger component instead */ final class PusherRegistry { diff --git a/src/Pusher/ServerPushHandlerInterface.php b/src/Pusher/ServerPushHandlerInterface.php index ed615f4f..b4c6e753 100644 --- a/src/Pusher/ServerPushHandlerInterface.php +++ b/src/Pusher/ServerPushHandlerInterface.php @@ -5,10 +5,8 @@ use Gos\Bundle\WebSocketBundle\Server\App\PushableWampServerInterface; use React\EventLoop\LoopInterface; -trigger_deprecation('gos/web-socket-bundle', '3.1', 'The "%s" interface is deprecated and will be removed in 4.0, use the symfony/messenger component instead.', ServerPushHandlerInterface::class); - /** - * @deprecated to be removed in 4.0, use the symfony/messenger component instead + * deprecated to be removed in 4.0, use the symfony/messenger component instead */ interface ServerPushHandlerInterface { diff --git a/src/Pusher/ServerPushHandlerRegistry.php b/src/Pusher/ServerPushHandlerRegistry.php index a952e4aa..3867e8cb 100644 --- a/src/Pusher/ServerPushHandlerRegistry.php +++ b/src/Pusher/ServerPushHandlerRegistry.php @@ -2,10 +2,8 @@ namespace Gos\Bundle\WebSocketBundle\Pusher; -trigger_deprecation('gos/web-socket-bundle', '3.1', 'The "%s" class is deprecated and will be removed in 4.0, use the symfony/messenger component instead.', ServerPushHandlerRegistry::class); - /** - * @deprecated to be removed in 4.0, use the symfony/messenger component instead + * deprecated to be removed in 4.0, use the symfony/messenger component instead */ final class ServerPushHandlerRegistry { diff --git a/src/Pusher/Wamp/WampConnectionFactory.php b/src/Pusher/Wamp/WampConnectionFactory.php index 6d51c0ca..d646f6c2 100644 --- a/src/Pusher/Wamp/WampConnectionFactory.php +++ b/src/Pusher/Wamp/WampConnectionFactory.php @@ -9,10 +9,8 @@ use Psr\Log\LoggerAwareTrait; use Symfony\Component\OptionsResolver\OptionsResolver; -trigger_deprecation('gos/web-socket-bundle', '3.1', 'The "%s" class is deprecated and will be removed in 4.0, use "%s" instead.', WampConnectionFactory::class, ClientFactory::class); - /** - * @deprecated to be removed in 4.0, use Gos\Component\WebSocketClient\Wamp\ClientFactory from the gos/websocket-client package instead + * deprecated to be removed in 4.0, use Gos\Bundle\WebSocketBundle\Wamp\ClientFactory from the gos/websocket-client package instead */ final class WampConnectionFactory implements WampConnectionFactoryInterface, LoggerAwareInterface { diff --git a/src/Pusher/Wamp/WampConnectionFactoryInterface.php b/src/Pusher/Wamp/WampConnectionFactoryInterface.php index 74e8195f..23ce6a9c 100644 --- a/src/Pusher/Wamp/WampConnectionFactoryInterface.php +++ b/src/Pusher/Wamp/WampConnectionFactoryInterface.php @@ -7,7 +7,7 @@ trigger_deprecation('gos/web-socket-bundle', '3.1', 'The "%s" interface is deprecated and will be removed in 4.0, use "%s" instead.', WampConnectionFactoryInterface::class, ClientFactoryInterface::class); /** - * @deprecated to be removed in 4.0, use the Gos\Component\WebSocketClient\Wamp\ClientFactoryInterface from the gos/websocket-client package instead + * deprecated to be removed in 4.0, use the Gos\Bundle\WebSocketBundle\Wamp\ClientFactoryInterface from the gos/websocket-client package instead */ interface WampConnectionFactoryInterface extends ClientFactoryInterface { diff --git a/src/Pusher/Wamp/WampPusher.php b/src/Pusher/Wamp/WampPusher.php index e6b24bff..76cc1942 100644 --- a/src/Pusher/Wamp/WampPusher.php +++ b/src/Pusher/Wamp/WampPusher.php @@ -8,10 +8,8 @@ use Gos\Component\WebSocketClient\Wamp\ClientInterface; use Symfony\Component\Serializer\SerializerInterface; -trigger_deprecation('gos/web-socket-bundle', '3.1', 'The "%s" class is deprecated and will be removed in 4.0, use the symfony/messenger component instead.', WampPusher::class); - /** - * @deprecated to be removed in 4.0, use the symfony/messenger component instead + * deprecated to be removed in 4.0, use the symfony/messenger component instead */ final class WampPusher extends AbstractPusher { diff --git a/src/Server/App/Dispatcher/TopicDispatcher.php b/src/Server/App/Dispatcher/TopicDispatcher.php index 0c855420..8b6cc017 100644 --- a/src/Server/App/Dispatcher/TopicDispatcher.php +++ b/src/Server/App/Dispatcher/TopicDispatcher.php @@ -47,8 +47,6 @@ public function __construct( $this->topicRegistry = $topicRegistry; if ($router instanceof WampRouter) { - trigger_deprecation('gos/web-socket-bundle', '3.13', 'Passing a "%s" instance as the second argument of the "%s" class constructor is deprecated and will not be supported in 4.0.', WampRouter::class, self::class); - if (!$topicPeriodicTimer instanceof TopicPeriodicTimer) { throw new \InvalidArgumentException(sprintf('Argument 3 of the %s constructor must be an instance of %s, "%s" given.', self::class, TopicPeriodicTimer::class, get_debug_type($topicPeriodicTimer))); } @@ -85,8 +83,6 @@ public function onSubscribe(ConnectionInterface $conn, Topic $topic, WampRequest */ public function onPush(WampRequest $request, $data, string $provider): void { - trigger_deprecation('gos/web-socket-bundle', '3.7', '%s() is deprecated and will be removed in 4.0, use the symfony/messenger component instead.', __METHOD__); - $topic = $this->topicManager->getTopic($request->getMatched()); $this->dispatch(self::PUSH, null, $topic, $request, $data, null, null, $provider); } diff --git a/src/Server/App/PushableWampServerInterface.php b/src/Server/App/PushableWampServerInterface.php index 4b229491..f71e95df 100644 --- a/src/Server/App/PushableWampServerInterface.php +++ b/src/Server/App/PushableWampServerInterface.php @@ -5,10 +5,8 @@ use Gos\Bundle\WebSocketBundle\Router\WampRequest; use Ratchet\Wamp\WampServerInterface; -trigger_deprecation('gos/web-socket-bundle', '3.7', 'The "%s" interface is deprecated and will be removed in 4.0, use the symfony/messenger component instead.', PushableWampServerInterface::class); - /** - * @deprecated to be removed in 4.0, use the symfony/messenger component instead + * deprecated to be removed in 4.0, use the symfony/messenger component instead */ interface PushableWampServerInterface extends WampServerInterface { diff --git a/src/Server/App/WampApplication.php b/src/Server/App/WampApplication.php index 95fc9da2..5b99280c 100644 --- a/src/Server/App/WampApplication.php +++ b/src/Server/App/WampApplication.php @@ -100,8 +100,6 @@ public function onPublish(ConnectionInterface $conn, $topic, $event, array $excl */ public function onPush(WampRequest $request, $data, $provider): void { - trigger_deprecation('gos/web-socket-bundle', '3.7', '%s() is deprecated and will be removed in 4.0, use the symfony/messenger component instead.', __METHOD__); - if (null !== $this->logger) { $this->logger->info( sprintf('Pusher %s has pushed', $provider), diff --git a/src/Server/EntryPoint.php b/src/Server/EntryPoint.php index 63a5c281..97d7ec30 100644 --- a/src/Server/EntryPoint.php +++ b/src/Server/EntryPoint.php @@ -2,10 +2,8 @@ namespace Gos\Bundle\WebSocketBundle\Server; -trigger_deprecation('gos/web-socket-bundle', '3.7', 'The "%s" class is deprecated and will be removed in 4.0, use the "%s" class instead.', EntryPoint::class, ServerLauncher::class); - /** - * @deprecated to be removed in 4.0, use the `Gos\Bundle\WebSocketBundle\Server\ServerLauncher` class instead + * deprecated to be removed in 4.0, use the `Gos\Bundle\WebSocketBundle\Server\ServerLauncher` class instead */ final class EntryPoint extends ServerLauncher { diff --git a/src/Topic/PushableTopicInterface.php b/src/Topic/PushableTopicInterface.php index 46097bd4..56a57d0d 100644 --- a/src/Topic/PushableTopicInterface.php +++ b/src/Topic/PushableTopicInterface.php @@ -5,10 +5,8 @@ use Gos\Bundle\WebSocketBundle\Router\WampRequest; use Ratchet\Wamp\Topic; -trigger_deprecation('gos/web-socket-bundle', '3.7', 'The "%s" interface is deprecated and will be removed in 4.0, use the symfony/messenger component instead.', PushableTopicInterface::class); - /** - * @deprecated to be removed in 4.0, use the symfony/messenger component instead + * deprecated to be removed in 4.0, use the symfony/messenger component instead */ interface PushableTopicInterface { diff --git a/src/Topic/TopicManager.php b/src/Topic/TopicManager.php index 32eaceec..7aaa66d4 100644 --- a/src/Topic/TopicManager.php +++ b/src/Topic/TopicManager.php @@ -24,8 +24,6 @@ class TopicManager implements WsServerInterface, WampServerInterface */ public function setWampApplication(WampServerInterface $app): void { - trigger_deprecation('gos/web-socket-bundle', '3.7', '%s() is deprecated and will be removed in 4.0, the dependency will be injected through the constructor instead.', __METHOD__); - $this->app = $app; }