amphp / websocket-server

WebSocket component for PHP based on the Amp HTTP server.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Server crash on client disconnect

xtrime-ru opened this issue · comments

[2023-09-28 16:00:52] [critical] TypeError: Amp\Websocket\Server\Websocket::Amp\Websocket\Server\{closure}(): Argument #2 ($closeInfo) must be of type Amp\Websocket\WebsocketCloseInfo, null given, called in /app-host-link/vendor/amphp/websocket/src/Rfc6455Client.php on line 313 and defined in /app-host-link/vendor/amphp/websocket-server/src/Websocket.php:85
Stack trace:
#0 /app-host-link/vendor/amphp/websocket/src/Rfc6455Client.php(313): Amp\Websocket\Server\Websocket->Amp\Websocket\Server\{closure}(0, NULL)
#1 /app-host-link/vendor/amphp/amp/src/Future.php(202): Amp\Websocket\Rfc6455Client::Amp\Websocket\{closure}()

Steps to reproduce:

  1. run server.php:
  2. run client.php
  3. send SIGINT (ctrl+c) to client.php to crash server.

Versions checked:

  1. ^v3 8a57456

server.php:

<?php

// Note that this example requires amphp/http-server-router,
// amphp/http-server-static-content and amphp/log to be installed.

use Amp\Http\Server\DefaultErrorHandler;
use Amp\Http\Server\Request;
use Amp\Http\Server\Response;
use Amp\Http\Server\Router;
use Amp\Http\Server\SocketHttpServer;
use Amp\Log\ConsoleFormatter;
use Amp\Log\StreamHandler;
use Amp\Socket;
use Amp\Websocket\Server\Websocket;
use Amp\Websocket\Server\WebsocketClientGateway;
use Amp\Websocket\Server\WebsocketClientHandler;
use Amp\Websocket\Server\WebsocketGateway;
use Amp\Websocket\WebsocketClient;
use Monolog\Logger;
use Psr\Log\NullLogger;
use function Amp\ByteStream\getStdout;

require __DIR__ . '/vendor/autoload.php';

$logHandler = new StreamHandler(getStdout());
$logHandler->setFormatter(new ConsoleFormatter);
$logger = new Logger('server');
$logger->pushHandler($logHandler);

$server = SocketHttpServer::createForDirectAccess($logger);

$server->expose(new Socket\InternetAddress('127.0.0.1', 1337));
$server->expose(new Socket\InternetAddress('[::1]', 1337));

$errorHandler = new DefaultErrorHandler();

$acceptor = new \Amp\Websocket\Server\Rfc6455Acceptor();

$clientHandler = new class implements WebsocketClientHandler {
    public function __construct(
        private readonly WebsocketGateway $gateway = new WebsocketClientGateway(),
    ) {
    }

    public function handleClient(WebsocketClient $client, Request $request, Response $response): void
    {
        $this->gateway->addClient($client);

        while ($message = $client->receive()) {
            $message = (string) $message->buffer();
            var_dump($message);
            $this->gateway->broadcastText(\sprintf('%d: %s', $client->getId(), $message))->ignore();
        }
    }
};

$websocket = new Websocket($server, $logger, $acceptor, $clientHandler);

$router = new Router($server, new NullLogger(), $errorHandler);
$router->addRoute('GET', '/', $websocket);

$server->start($router, $errorHandler);

// Await SIGINT or SIGTERM to be received.
$signal = Amp\trapSignal([\SIGINT, \SIGTERM]);

$logger->info(\sprintf("Received signal %d, stopping HTTP server", $signal));

$server->stop();

client.php

<?php

require 'vendor/autoload.php';

use Amp\Websocket\Client\WebsocketHandshake;
use function Amp\Websocket\Client\connect;

// Connects to the websocket endpoint at libwebsockets.org which sends a message every 50ms.
$handshake = (new WebsocketHandshake('ws://127.0.0.1:1337'));

$connection = connect($handshake);

\Revolt\EventLoop::repeat(1, fn() => $connection->sendText(date('Y-m-d H:i:s')));

while ($message = $connection->receive()) {
    $payload = $message->buffer();

    printf("Received: %s\n", $payload);
}