Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to send a message to the client from the backend server ? #867

Open
Muradg opened this issue Jan 6, 2023 · 2 comments
Open

How to send a message to the client from the backend server ? #867

Muradg opened this issue Jan 6, 2023 · 2 comments

Comments

@Muradg
Copy link

Muradg commented Jan 6, 2023

Hey! First of all, I want to thank you for your library.
I have a problem that I don't know how to solve yet.

I have a chat in which I implemented sending simple messages, everything works fine. Now I want to send files and ran into a problem with large file sizes. I decided not to load the connection socket and send files directly to the backend server via form/data.

BUT. How, after a successful send, initialize the user and send him a socket notification that his file was successfully sent? At the moment my code looks like this:

`
$ws_worker = new Worker('websocket://'.config('websockets.server'));

// Emitted when new connection come
$ws_worker->onConnect = function (TcpConnection $connection) {

    $connection->onWebSocketConnect = function($connection) {

        if (isset($_GET['token']) && $token = PersonalAccessToken::findToken($_GET['token'])) {
            $user = $token->tokenable;

            $this->clients[$connection->id] = [
                'user' => $user,
                'connection' => $connection,
            ];
        }
        return;
    };
};


$ws_worker->onMessage = function (TcpConnection $connection, $message) {

    if (!array_key_exists($connection->id, $this->clients)) {
        echo "Error. User not authorized\n";
        return;
    }

    $sender = $this->clients[$connection->id];

    $data = json_decode($message, true);

    // send message to DB

    $connectionClientsUniques = ArrayHelper::arrayColumnsWithSaveKeys($this->clients, 'client_unique');
    $findedConnectionsClients = array_keys($connectionClientsUniques, $roomMember['client_unique'], true);

    foreach ($findedConnectionsClients as $findedConnectionClient) {
        // SEND MESSAGE FOR CONNECTION
    }
};


$ws_worker->onClose = function($connection)
{
    echo "Close connection ID ".$connection->id."\n";

    if (array_key_exists($connection->id, $this->clients)) {
        unset($this->clients[$connection->id]);
        echo "FINDED CONNECTION ID  ".$connection->id." AND LOST CONNECTIONS - ".count($this->clients)." \n";
    }
};

// Run worker
Worker::runAll();

`

My problem is that I don't know where to store active user sessions. So that I can access them from other parts of the project. Now they are stored in my clients variable in the same place where the websocket server starts. Should they be stored elsewhere? Where do you recommend?
And also, please tell me how to send notifications to the desired connection from any part of the project. For example, I imagined it like this:

`
send_alert.php

<?php
use Workerman\Worker;

$ws_worker = new Worker('websocket://11.11.111.111');
$ws_worker->findByConnection(...)->send($data);

`

@walkor
Copy link
Owner

walkor commented Jan 8, 2023

Create an http_worker in ws_worker's onWorkerStart, http_worker and ws_worker will be in the same process space,so http_worker can access any variables of ws_worker. When an external program wants to send ws data, it only needs curl call http_worker. The code looks like this.

$ws_worker = new Worker('websocket://'.config('websockets.server'));

$ws_worker->onWorkerStart = function($ws_worker)
{
    $http_worker = new Worker('http://0.0.0.0:2023');
    $http_worker->onMessage = function($http_connection, $request) use ($ws_worker){
        $to_user = $request->post('to_user');
        $msg = $request->post('msg');
        foreach ($this->clients as $client) {
            if ($client['user'] == $to_user) {
                $client['connection']->send($msg);
                break;
            }
        }
    };
    $http_worker->listen();
};

$ws_worker->onConnect = ...

Curl codes.

$to_user = "xxx";
$url = "http://127.0.0.1:2023/";
$post_data = array(
   "msg" => "hello",
   "to_user" => $to_user, 
);
$ch = curl_init ();
curl_setopt ( $ch, CURLOPT_URL, $push_api_url );
curl_setopt ( $ch, CURLOPT_POST, 1 );
curl_setopt ( $ch, CURLOPT_HEADER, 0 );
curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt ( $ch, CURLOPT_POSTFIELDS, $post_data );
curl_setopt ($ch, CURLOPT_HTTPHEADER, array("Expect:"));
$return = curl_exec ( $ch );
curl_close ( $ch );
var_export($return);

@khristyan
Copy link

khristyan commented Feb 14, 2023

Hello!
Trying to replicate the code, but I need to send data from the internal php-server to all connected users.

Server codes:

$ws_worker = new Worker('websocket://0.0.0.0:2346');
$ws_worker->count = 1;

$ws_worker->onWorkerStart = function($ws_worker) {
    $http_worker = new Worker('http://127.0.0.1:2023');
    $http_worker->onMessage = function($http_connection, $request) use ($ws_worker) {
        // this code does not work:
        foreach($ws_worker->connections as $connection) {
            $connection->send($request);
        }
    };
    $http_worker->listen();
};

// this code works correctly:
$ws_worker->onMessage = function ($con, $data) use ($ws_worker) {
    foreach($ws_worker->connections as $connection) {
        $connection->send($data);
    }
};

my CURL codes:

$url = "http://127.0.0.1:2023";
$data = "{"json": "data"}";
$ch = curl_init ();
curl_setopt_array($ch, [
 CURLOPT_URL => $url,
 CURLOPT_POSTFIELDS => $data,
 CURLOPT_POST => true
]);
$curl_result = curl_exec($ch);
curl_close($ch);
var_export($curl_result); // it's true

what am i doing wrong? help please.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants