Ratchet icon indicating copy to clipboard operation
Ratchet copied to clipboard

How to save information about a Client on Server-Side?

Open fx1234 opened this issue 5 years ago • 7 comments

Hi

What is the proper way to save infomartions about a connected client on the Server-Side.

Lets say we have a chat-app and want to keep the username somewhere.

In the tutorial we have the $this->clients... can we just add some additional data here? And how would we do this?

fx1234 avatar May 11 '20 05:05 fx1234

Hi, Using SplObjectStorage you can attach additional data to connection:

<?php
//...
    public function __construct() {
        $this->clients = new \SplObjectStorage;
    }
    public function onMessage(ConnectionInterface $from, $msg) {
        // set username
        $this->clients->attach($from, $username);
        // reading
        $username = $this->clients[$from];
        // updating
        $this->clients[$from] = $newUsername;
    }

Because SplObjectStorage stores mixed type, you can set any structure. See https://www.php.net/manual/en/class.splobjectstorage.php

taavit avatar May 14 '20 17:05 taavit

you could also add public properties to the connection object:

<?php
//...
    public function __construct() {
        $this->clients = new \SplObjectStorage;
    }
    public function onOpen(ConnectionInterface $conn) {
        $conn->someProperty = 'someValue';
        $conn->someOtherProperty = 'someothervalue'; //set properties before attaching the connection to the storage
        $this->clients->attach($conn);       
    }

Just be carefull if you deside to not give every connection the same parameters to check for their existance when accessing them again.

nineff avatar May 23 '20 12:05 nineff

Hi guys,

I'm trying to figure out a way to attach some datas to the client too, but I'm kind of stuck... since too long now.

public function onOpen(ConnectionInterface $conn)
{
       $this->clients->attach($conn);

       $querystring = $conn->httpRequest->getUri()->getQuery();
       parse_str($querystring, $queryarray);

       $this->users[isset($queryarray['token']) && $queryarray['token'] != '' ? $queryarray['token'] : $conn->resourceId] = $conn;

       echo "New connection! ({$conn->resourceId})\n";
}

public function onMessage(ConnectionInterface $from, $msg)
   {
       $numRecv = count($this->clients) - 1;
       echo sprintf('Connection %d sending message "%s" to %d other connection%s' . "\n", $from->resourceId, $msg, $numRecv, $numRecv == 1 ? '' : 's');

       // Data from the SENDER SIDE
       $dataArray = json_decode($msg, true);

       /** @var User $userModel */
       $userModel = new User($this->database);
       $listUserChannel = $userModel->listUserChannel($dataArray['workshopId']);

       $this->clients->attach( (object) $listUserChannel);

       // SEND TO USERS WITH THE SAME CHANNEL
       if (isset($dataArray['workshopId']) && $dataArray['workshopId'] > 0) {
           $this->sendMessageToChannel($from, $msg);

       // SEND TO EVERYBODY
       } else {

           print_r("SEND TO EVERYBODY");
           $this->sendMessageToAll($from, $msg);
       }
   }

But... it does not seems to work. So what I need to do is to attach $listUserChannel to the client, and compare a value $dataArray['workshopId'] to the attached value, to know if I send my message to everybody or only to the users with the same workshopId.

Can somebody help me maybe ?

Thank you very much

chrisVdd avatar Aug 21 '20 09:08 chrisVdd

What's the purpose of creating User (I guess this is something like repository) on each message?

       $userModel = new User($this->database);

What is listUserChannel? Array of users attached to given workshopId? If so you already have everything you need. Just iterate over array, and send message to those users.

Also you are mixing listUserChannel with Connection data:

       $this->clients->attach($conn);
       $this->clients->attach( (object) $listUserChannel);

taavit avatar Aug 21 '20 19:08 taavit

@taavit

The purpose of:

$userModel = new User($this->database);
$listUserChannel = $userModel->listUserChannel($dataArray['workshopId']);

is to be able to retrieve a list of users, from the database since I need to select all the users with a certain worskhopId.

If $user['workshopId'] = $data["worskhopId"] Than, you send this message to every users with this workshopID.

I'm not so use to the use of the SplObjectStorage. I think it's part of my issue..

My logic: I wanted to add the value of $user['workshopId'] to $client, in order to send the message only to list of users.

chrisVdd avatar Aug 24 '20 20:08 chrisVdd

I'm not so use to the use of the SplObjectStorage. I think it's part of my issue.. My logic: I wanted to add the value of $user['workshopId'] to $client, in order to send the message only to list of users.

Yes that's exactly your problem. in your above example you're attaching the $dataArray basically as a new client instead of "appending" it to an existing connection. The confusing part here is probably the attach() method of the SplObjectStorage Object. See my comment from above on one way to add information to the actual connection. Another way would be for you to extend ratchets WsConnection object and use them instead. You could then add any property (and method) you like directly to the connections. This would however require you to modify ratchet itself to use the new objects.

nineff avatar Aug 25 '20 16:08 nineff

Hi, Using SplObjectStorage you can attach additional data to connection:

<?php
//...
    public function __construct() {
        $this->clients = new \SplObjectStorage;
    }
    public function onMessage(ConnectionInterface $from, $msg) {
        // set username
        $this->clients->attach($from, $username);
        // reading
        $username = $this->clients[$from];
        // updating
        $this->clients[$from] = $newUsername;
    }

Because SplObjectStorage stores mixed type, you can set any structure. See https://www.php.net/manual/en/class.splobjectstorage.php

SplObjectStorage uses hash of the object as key, updating username will change the key for connection object. What is the implication of frequently updating username of large number of connections?

zhiyong-ft avatar Dec 18 '21 16:12 zhiyong-ft