Laravel + Ratchet:向特定客户端推送通知
Laravel + Ratchet: Pushing notifications to specific clients
我是 websockets 的新手,我想在我的 Laravel 应用程序中实现这样的服务。
我已经阅读了几本关于这个主题的文章 posts/pages,但是 none 解释了我需要做什么。它们都展示了如何创建一个“Echo”websocket 服务器,其中服务器只响应从客户端收到的消息,这不是我的情况。
作为起始基础,我使用了提供的代码:
其中 websocket 服务器是 运行 从命令行或另一个控制台。服务器有自己的 class 来定义它并导入 WebSocketController class (MessageComponentInterface),其中包含 classic WebSocket 服务器事件(onOpen、onMessage、onClose、onError)。
一切正常,但是,我如何“告诉”WebSocket 服务器从另一个 class 也属于另一个名称空间的特定连接(客户端)发送消息?这是通知或事件的情况,其中必须将新的 Web 内容发送到该特定客户端。没有来自客户端的订阅或发布。
正如@Alias 在他的 post Ratchet PHP - Push messaging service 中所问,我显然无法创建 Websocket 服务器或其事件管理的新实例 class,那么最好的方法是什么向客户端发送内容或消息?
如您所见,通信只有一种方式:从 WebSocket 服务器到客户端,而不是相反。
我已经为此准备了一个通知 class 和一个监听器 class 但是,我仍然不知道如何通过 handle() 方法处理与客户端的通信:
namespace App\Listeners;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Events\NotificationSent;
use Illuminate\Queue\InteractsWithQueue;
class LogNotification
{
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param NotificationSent $event
* @return void
*/
public function handle(NotificationSent $event)
{
// Can content or message be sent to the client from here? how?
}
}
好的,经过大量研究和研究,我可以post回答类似问题:
How to send a message to specific websocket clients with symfony ratchet?
这是我找到的解决方案,根据我在此线程中的第二条评论中写的内容。
我使用 composer 为 websocket 服务器安装了 cboden/Ratchet 包。
当后端触发事件时,我需要向 user/group 用户发送通知,或更新 UI。
我做的是这样的:
1) 使用 composer 安装 amphp/websocket-client 包。
2) 创建了一个单独的 class 以实例化一个可以连接到的 object websocket 服务器,发送所需的消息并断开连接:
namespace App;
use Amp\Websocket\Client;
class wsClient {
public function __construct() {
//
}
// Creates a temporary connection to the WebSocket Server
// The parameter $to is the user name the server should reply to.
public function connect($msg) {
global $x;
$x = $msg;
\Amp\Loop::run(
function() {
global $x;
$connection = yield Client\connect('ws://ssa:8090');
yield $connection->send(json_encode($x));
yield $connection->close();
\Amp\Loop::stop();
}
);
}
}
3) onMessage()
事件,在 webSocket 服务器的处理程序 class 中,看起来像这个:
/**
* @method onMessage
* @param ConnectionInterface $conn
* @param string $msg
*/
public function onMessage(ConnectionInterface $from, $msg) {
$data = json_decode($msg);
// The following line is for debugging purposes only
echo " Incoming message: " . $msg . PHP_EOL;
if (isset($data->username)) {
// Register the name of the just connected user.
if ($data->username != '') {
$this->names[$from->resourceId] = $data->username;
}
}
else {
if (isset($data->to)) {
// The "to" field contains the name of the users the message should be sent to.
if (str_contains($data->to, ',')) {
// It is a comma separated list of names.
$arrayUsers = explode(",", $data->to);
foreach($arrayUsers as $name) {
$key = array_search($name, $this->names);
if ($key !== false) {
$this->clients[$key]->send($data->message);
}
}
}
else {
// Find a single user name in the $names array to get the key.
$key = array_search($data->to, $this->names);
if ($key !== false) {
$this->clients[$key]->send($data->message);
}
else {
echo " User: " . $data->to . " not found";
}
}
}
}
echo " Connected users:\n";
foreach($this->names as $key => $data) {
echo " " . $key . '->' . $data . PHP_EOL;
}
}
如您所见,您希望 websocket 服务器将消息发送到的用户在 $msg 参数中指定为字符串($data->to)以及消息本身($数据->消息)。这两件事是 JSON 编码的,因此参数 $msg 可以被视为 object.
4) 在客户端(javascript 在布局 blade 文件中)我发送客户端连接时到 websocket 服务器的用户名:
var currentUser = "{{ Auth::user()->name }}";
socket = new WebSocket("ws://ssa:8090");
socket.onopen = function(e) {
console.log(currentUser + " has connected to websocket server");
socket.send(JSON.stringify({ username: currentUser }));
};
socket.onmessage = function(event) {
console.log('Data received from server: ' + event.data);
};
所以,用户名和它的连接号被保存在websocket服务器中。
5) 处理程序 class 中的 onOpen()
方法如下所示:
public function onOpen(ConnectionInterface $conn) {
// Store the new connection to send messages to later
$this->clients[$conn->resourceId] = $conn;
echo " \n";
echo " New connection ({$conn->resourceId}) " . date('Y/m/d h:i:sa') . "\n";
}
每次客户端连接到 websocket 服务器时,它的连接号或 resourceId 都存储在一个数组中。因此,用户名存储在一个数组($names)中,而键存储在另一个数组($clients)中。
6) 最后,我可以在项目的任何地方创建 PHP websocket 客户端 (wsClient) 的实例向任何用户发送任何数据:
public function handle(NotificationSent $event) {
$clientSocket = new wsClient();
$clientSocket->connect(array('to'=>'Anatoly,Joachim,Caralampio', 'message'=>$event->notification->data));
}
在这种情况下,我使用通知事件监听器的 handle() 方法。
好的,这是为任何想知道如何从 PHP websocket 服务器(AKA 回显服务器)向一个特定客户端或一组客户端发送消息的人准备的。
我是 websockets 的新手,我想在我的 Laravel 应用程序中实现这样的服务。 我已经阅读了几本关于这个主题的文章 posts/pages,但是 none 解释了我需要做什么。它们都展示了如何创建一个“Echo”websocket 服务器,其中服务器只响应从客户端收到的消息,这不是我的情况。
作为起始基础,我使用了提供的代码:
其中 websocket 服务器是 运行 从命令行或另一个控制台。服务器有自己的 class 来定义它并导入 WebSocketController class (MessageComponentInterface),其中包含 classic WebSocket 服务器事件(onOpen、onMessage、onClose、onError)。
一切正常,但是,我如何“告诉”WebSocket 服务器从另一个 class 也属于另一个名称空间的特定连接(客户端)发送消息?这是通知或事件的情况,其中必须将新的 Web 内容发送到该特定客户端。没有来自客户端的订阅或发布。
正如@Alias 在他的 post Ratchet PHP - Push messaging service 中所问,我显然无法创建 Websocket 服务器或其事件管理的新实例 class,那么最好的方法是什么向客户端发送内容或消息?
如您所见,通信只有一种方式:从 WebSocket 服务器到客户端,而不是相反。 我已经为此准备了一个通知 class 和一个监听器 class 但是,我仍然不知道如何通过 handle() 方法处理与客户端的通信:
namespace App\Listeners;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Events\NotificationSent;
use Illuminate\Queue\InteractsWithQueue;
class LogNotification
{
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param NotificationSent $event
* @return void
*/
public function handle(NotificationSent $event)
{
// Can content or message be sent to the client from here? how?
}
}
好的,经过大量研究和研究,我可以post回答类似问题:
How to send a message to specific websocket clients with symfony ratchet?
这是我找到的解决方案,根据我在此线程中的第二条评论中写的内容。
我使用 composer 为 websocket 服务器安装了 cboden/Ratchet 包。 当后端触发事件时,我需要向 user/group 用户发送通知,或更新 UI。
我做的是这样的:
1) 使用 composer 安装 amphp/websocket-client 包。
2) 创建了一个单独的 class 以实例化一个可以连接到的 object websocket 服务器,发送所需的消息并断开连接:
namespace App;
use Amp\Websocket\Client;
class wsClient {
public function __construct() {
//
}
// Creates a temporary connection to the WebSocket Server
// The parameter $to is the user name the server should reply to.
public function connect($msg) {
global $x;
$x = $msg;
\Amp\Loop::run(
function() {
global $x;
$connection = yield Client\connect('ws://ssa:8090');
yield $connection->send(json_encode($x));
yield $connection->close();
\Amp\Loop::stop();
}
);
}
}
3) onMessage()
事件,在 webSocket 服务器的处理程序 class 中,看起来像这个:
/**
* @method onMessage
* @param ConnectionInterface $conn
* @param string $msg
*/
public function onMessage(ConnectionInterface $from, $msg) {
$data = json_decode($msg);
// The following line is for debugging purposes only
echo " Incoming message: " . $msg . PHP_EOL;
if (isset($data->username)) {
// Register the name of the just connected user.
if ($data->username != '') {
$this->names[$from->resourceId] = $data->username;
}
}
else {
if (isset($data->to)) {
// The "to" field contains the name of the users the message should be sent to.
if (str_contains($data->to, ',')) {
// It is a comma separated list of names.
$arrayUsers = explode(",", $data->to);
foreach($arrayUsers as $name) {
$key = array_search($name, $this->names);
if ($key !== false) {
$this->clients[$key]->send($data->message);
}
}
}
else {
// Find a single user name in the $names array to get the key.
$key = array_search($data->to, $this->names);
if ($key !== false) {
$this->clients[$key]->send($data->message);
}
else {
echo " User: " . $data->to . " not found";
}
}
}
}
echo " Connected users:\n";
foreach($this->names as $key => $data) {
echo " " . $key . '->' . $data . PHP_EOL;
}
}
如您所见,您希望 websocket 服务器将消息发送到的用户在 $msg 参数中指定为字符串($data->to)以及消息本身($数据->消息)。这两件事是 JSON 编码的,因此参数 $msg 可以被视为 object.
4) 在客户端(javascript 在布局 blade 文件中)我发送客户端连接时到 websocket 服务器的用户名:
var currentUser = "{{ Auth::user()->name }}";
socket = new WebSocket("ws://ssa:8090");
socket.onopen = function(e) {
console.log(currentUser + " has connected to websocket server");
socket.send(JSON.stringify({ username: currentUser }));
};
socket.onmessage = function(event) {
console.log('Data received from server: ' + event.data);
};
所以,用户名和它的连接号被保存在websocket服务器中。
5) 处理程序 class 中的 onOpen()
方法如下所示:
public function onOpen(ConnectionInterface $conn) {
// Store the new connection to send messages to later
$this->clients[$conn->resourceId] = $conn;
echo " \n";
echo " New connection ({$conn->resourceId}) " . date('Y/m/d h:i:sa') . "\n";
}
每次客户端连接到 websocket 服务器时,它的连接号或 resourceId 都存储在一个数组中。因此,用户名存储在一个数组($names)中,而键存储在另一个数组($clients)中。
6) 最后,我可以在项目的任何地方创建 PHP websocket 客户端 (wsClient) 的实例向任何用户发送任何数据:
public function handle(NotificationSent $event) {
$clientSocket = new wsClient();
$clientSocket->connect(array('to'=>'Anatoly,Joachim,Caralampio', 'message'=>$event->notification->data));
}
在这种情况下,我使用通知事件监听器的 handle() 方法。
好的,这是为任何想知道如何从 PHP websocket 服务器(AKA 回显服务器)向一个特定客户端或一组客户端发送消息的人准备的。