amphp / websocket-server

WebSocket component for PHP based on the Amp HTTP server.
MIT License
115 stars 17 forks source link

How can I get the websocket client by using the resource id from the request ? #20

Closed elovin closed 4 years ago

elovin commented 4 years ago

Im trying to disconnect clients who did not send a valid message after 5 Seconds (the authorization is done with the first message send by the client, in case the message has never been send I want to disconnect the client), for this I use a delay within the handleHandshake method. So far this works just fine but it seems there is no way to get the websocket client ( \Amp\Websocket\Client) belonging to the resource client (\Amp\Http\Server\Driver\Client ) which is the only information I have during the handshake.

I think it would be useful If the endpoint had a method to get the websocket client belonging to the resource client e.g. something like this (I know this will not work if its used directly within the handshake method but after the delay the websocket client should exist): $endpoint->getClientByResourceId($request->getClient()->getId());

Example handshake and delay method:

    /**
     * @inheritDoc
     */
    public function handleHandshake(Endpoint $endpoint, Request $request, Response $response): Promise
    {
        /** @var \Amp\Http\Server\Driver\Client  $rawNetworkClient */
        $rawNetworkClient = $request->getClient();

        if ($this->shutDownSignalReceived) {
            $rawNetworkClient->close();
        }

        $this->handleUnusedConnections($request->getClient(), $endpoint);

        return new Success($response);
    }
    private function handleUnusedConnections(\Amp\Http\Server\Driver\Client $rawNetworkClient, Endpoint $endpoint): void
    {
        Loop::delay(self::AUTHORIZATION_TIMEOUT, function () use ($rawNetworkClient, $endpoint): void {

            $websocketClient = null;
            $workflowClient = null;

            try {
            /** @var \Amp\Websocket\Client $websocketClient */
                $websocketClient = $endpoint->getClientByResourceId($rawNetworkClient->getId());
                // @throws ClientNotFoundException
                $workflowClient = $this->clientRegistry->getClientByConnectionId($websocketClient->getId());
            } catch (\Throwable $e) {
                // close if there is any exception
            }
            finally {
                if (isset($e) || !$workflowClient->wasAuthorized()) {
                    call(function () use ($websocketClient): \Generator {
                        yield $websocketClient->close();
                    });
                }
            }
        });
    }
kelunik commented 4 years ago

If you want to accept any connection and do the authentication after the handshake instead of within the handshake, you can use handleClient directly and just return new Success($response) in handleHandshake. In handleClient you have both the Client and the other client object as part of Request available.