From fa85d9e1326af152704335afd90154c86ca5db53 Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Thu, 25 Sep 2025 12:06:34 +0300 Subject: [PATCH] websocket changes --- application/Espo/Core/WebSocket/Pusher.php | 15 ++++++ .../WebSocket/Ratchet/EspoServerProtocol.php | 48 ++++++++++++++++++ .../WebSocket/Ratchet/EspoWampConnection.php | 49 +++++++++++++++++++ .../Core/WebSocket/Ratchet/EspoWampServer.php | 48 ++++++++++++++++++ .../Espo/Core/WebSocket/ServerStarter.php | 3 +- 5 files changed, 161 insertions(+), 2 deletions(-) create mode 100644 application/Espo/Core/WebSocket/Ratchet/EspoServerProtocol.php create mode 100644 application/Espo/Core/WebSocket/Ratchet/EspoWampConnection.php create mode 100644 application/Espo/Core/WebSocket/Ratchet/EspoWampServer.php diff --git a/application/Espo/Core/WebSocket/Pusher.php b/application/Espo/Core/WebSocket/Pusher.php index d681869964..ab78c0bcde 100644 --- a/application/Espo/Core/WebSocket/Pusher.php +++ b/application/Espo/Core/WebSocket/Pusher.php @@ -29,10 +29,12 @@ namespace Espo\Core\WebSocket; +use Espo\Core\Utils\Json; use GuzzleHttp\Psr7\Query; use Psr\Http\Message\RequestInterface; use Ratchet\ConnectionInterface; +use Ratchet\Wamp\ServerProtocol as WAMP; use Ratchet\Wamp\Topic; use Ratchet\Wamp\WampConnection; use Ratchet\Wamp\WampServerInterface; @@ -408,6 +410,8 @@ class Pusher implements WampServerInterface } $this->subscribeUser($conn, $userId); + + $this->sendWelcome($conn); }); } @@ -572,4 +576,15 @@ class Pusher implements WampServerInterface $this->topicHash[$topicId] = $topic; } + + private function sendWelcome(ConnectionInterface $conn): void + { + /** + * @noinspection PhpPossiblePolymorphicInvocationInspection + * @phpstan-ignore property.notFound + */ + $sessionId = $conn->WAMP->sessionId; + + $conn->send(Json::encode([WAMP::MSG_WELCOME, $sessionId, 1])); + } } diff --git a/application/Espo/Core/WebSocket/Ratchet/EspoServerProtocol.php b/application/Espo/Core/WebSocket/Ratchet/EspoServerProtocol.php new file mode 100644 index 0000000000..ac09dd71fb --- /dev/null +++ b/application/Espo/Core/WebSocket/Ratchet/EspoServerProtocol.php @@ -0,0 +1,48 @@ +. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. + ************************************************************************/ + +namespace Espo\Core\WebSocket\Ratchet; + +use Ratchet\ConnectionInterface; +use Ratchet\Wamp\ServerProtocol; + +class EspoServerProtocol extends ServerProtocol +{ + /** + * @inheritDoc + * @phpstan-ignore missingType.return + */ + public function onOpen(ConnectionInterface $conn) + { + $decor = new EspoWampConnection($conn); + $this->connections->attach($conn, $decor); + + $this->_decorating->onOpen($decor); + } +} diff --git a/application/Espo/Core/WebSocket/Ratchet/EspoWampConnection.php b/application/Espo/Core/WebSocket/Ratchet/EspoWampConnection.php new file mode 100644 index 0000000000..05910f3f9b --- /dev/null +++ b/application/Espo/Core/WebSocket/Ratchet/EspoWampConnection.php @@ -0,0 +1,49 @@ +. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. + ************************************************************************/ + +namespace Espo\Core\WebSocket\Ratchet; + +use Ratchet\ConnectionInterface; +use Ratchet\Wamp\WampConnection; +use stdClass; + +class EspoWampConnection extends WampConnection +{ + /** + * @noinspection PhpMissingParentConstructorInspection + */ + public function __construct(ConnectionInterface $conn) + { + $this->wrappedConn = $conn; + + $this->WAMP = new stdClass; + $this->WAMP->sessionId = str_replace('.', '', uniqid((string) mt_rand(), true)); + $this->WAMP->prefixes = []; + } +} diff --git a/application/Espo/Core/WebSocket/Ratchet/EspoWampServer.php b/application/Espo/Core/WebSocket/Ratchet/EspoWampServer.php new file mode 100644 index 0000000000..23b5218d65 --- /dev/null +++ b/application/Espo/Core/WebSocket/Ratchet/EspoWampServer.php @@ -0,0 +1,48 @@ +. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. + ************************************************************************/ + +namespace Espo\Core\WebSocket\Ratchet; + +use Ratchet\Wamp\TopicManager; +use Ratchet\Wamp\WampServer; +use Ratchet\Wamp\WampServerInterface; + +/** + * Customized so that the welcome response is not sent on open. It will be sent after async access check. + */ +class EspoWampServer extends WampServer +{ + /** + * @noinspection PhpMissingParentConstructorInspection + */ + public function __construct(WampServerInterface $app) + { + $this->wampProtocol = new EspoServerProtocol(new TopicManager($app)); + } +} diff --git a/application/Espo/Core/WebSocket/ServerStarter.php b/application/Espo/Core/WebSocket/ServerStarter.php index 421dcaf605..6e3b298fa5 100644 --- a/application/Espo/Core/WebSocket/ServerStarter.php +++ b/application/Espo/Core/WebSocket/ServerStarter.php @@ -38,7 +38,6 @@ use React\Socket\SecureServer as SocketSecureServer; use Ratchet\Server\IoServer; use Ratchet\Http\HttpServer; use Ratchet\WebSocket\WsServer; -use Ratchet\Wamp\WampServer; /** * Starts a web-socket server. @@ -90,7 +89,7 @@ class ServerStarter $socketServer = new SocketSecureServer($socketServer, $loop, $sslParams); } - $wsServer = new WsServer(new WampServer($pusher)); + $wsServer = new WsServer(new Ratchet\EspoWampServer($pusher)); $wsServer->enableKeepAlive($loop, 60); new IoServer(