Примечание: это не то же самое, что этот вопрос, который использует
MessageComponentInterface
. Вместо этого я используюWampServerInterface
, поэтому этот вопрос относится именно к этой части. Мне нужен ответ с примерами кода и объяснением, поскольку я вижу, что это будет полезно для других в будущем.
Попытка циклических нажатий для отдельных пользователей
Я использую часть WAMP для Ratchet и ZeroMQ, и в настоящее время у меня есть рабочая версия push tutorial.
Я пытаюсь выполнить следующее:
- Сервер zeromq запущен и готов, чтобы протоколировать подписчиков и отменить подписку.
- Пользователь подключается в своем браузере по протоколу websocket
- Запускается цикл, который отправляет данные конкретному пользователю, который запросил его
- Когда пользователь отключается, цикл для данных пользователя останавливается
У меня есть пункты (1) и (2), однако проблема у меня есть с третьей:
Во-первых: Как я могу отправлять данные только каждому конкретному пользователю? Широковещательная передача отправляет его всем, если, возможно, "темы" в конечном итоге не являются индивидуальными идентификаторами пользователя?
Во-вторых: У меня большая проблема с безопасностью. Если я отправляю идентификатор пользователя, который хочет подписаться с клиентской стороны, что мне кажется, мне нужно, тогда пользователь может просто изменить вместо этого возвращается переменная в другой идентификатор пользователя и их данные.
В-третьих: Мне нужно запустить отдельный php script, содержащий код для zeromq, чтобы начать фактический цикл. Я не уверен, что это лучший способ сделать это, и я предпочел бы, чтобы эта работа полностью работала в кодовой базе, а не в отдельном php файле. Это основная область, которую мне нужно отсортировать.
Следующий код показывает, что у меня есть.
Сервер, который только запускается с консоли
Я буквально набираю php bin/push-server.php
для запуска этого. Подписки и un-subscriptions выводятся на этот терминал для целей отладки.
$loop = React\EventLoop\Factory::create();
$pusher = Pusher;
$context = new React\ZMQ\Context($loop);
$pull = $context->getSocket(ZMQ::SOCKET_PULL);
$pull->bind('tcp://127.0.0.1:5555');
$pull->on('message', array($pusher, 'onMessage'));
$webSock = new React\Socket\Server($loop);
$webSock->listen(8080, '0.0.0.0'); // Binding to 0.0.0.0 means remotes can connect
$webServer = new Ratchet\Server\IoServer(
new Ratchet\WebSocket\WsServer(
new Ratchet\Wamp\WampServer(
$pusher
)
),
$webSock
);
$loop->run();
Толкатель, который отправляет данные через websockets
Я опустил бесполезный материал и сосредоточился на методах onMessage()
и onSubscribe()
.
public function onSubscribe(ConnectionInterface $conn, $topic)
{
$subject = $topic->getId();
$ip = $conn->remoteAddress;
if (!array_key_exists($subject, $this->subscribedTopics))
{
$this->subscribedTopics[$subject] = $topic;
}
$this->clients[] = $conn->resourceId;
echo sprintf("New Connection: %s" . PHP_EOL, $conn->remoteAddress);
}
public function onMessage($entry) {
$entryData = json_decode($entry, true);
var_dump($entryData);
if (!array_key_exists($entryData['topic'], $this->subscribedTopics)) {
return;
}
$topic = $this->subscribedTopics[$entryData['topic']];
// This sends out everything to multiple users, not what I want!!
// I can't send() to individual connections from here I don't think :S
$topic->broadcast($entryData);
}
script, чтобы начать использовать вышеуказанный код Pusher в цикле
Это моя проблема - это отдельный php файл, который, надеюсь, может быть интегрирован в другой код в будущем, но в настоящее время я не уверен, как правильно его использовать. Я беру идентификатор пользователя из сеанса? Мне все равно нужно отправить его с клиентской стороны...
// Thought sessions might work here but they don't work for subscription
session_start();
$userId = $_SESSION['userId'];
$loop = React\EventLoop\Factory::create();
$context = new ZMQContext();
$socket = $context->getSocket(ZMQ::SOCKET_PUSH, 'my pusher');
$socket->connect("tcp://localhost:5555");
$i = 0;
$loop->addPeriodicTimer(4, function() use ($socket, $loop, $userId, &$i) {
$entryData = array(
'topic' => 'subscriptionTopicHere',
'userId' => $userId
);
$i++;
// So it doesn't go on infinitely if run from browser
if ($i >= 3)
{
$loop->stop();
}
// Send stuff to the queue
$socket->send(json_encode($entryData));
});
Наконец, клиентская сторона js для подписки на
$(document).ready(function() {
var conn = new ab.Session(
'ws://localhost:8080'
, function() {
conn.subscribe('topicHere', function(topic, data) {
console.log(topic);
console.log(data);
});
}
, function() {
console.warn('WebSocket connection closed');
}
, {
'skipSubprotocolCheck': true
}
);
});
Заключение
Вышеприведенное работает, но мне действительно нужно выяснить следующее:
-
Как я могу отправлять отдельные сообщения отдельным пользователям? Когда они посещают страницу, которая запускает соединение с websocket в JS, должен ли я также запускать script, который заставляет вещи в очередь в PHP (zeromq)? Это то, что я сейчас делаю вручную, и это просто неправильно.
-
При подписке на пользователя из JS не может быть безопасно захватить идентификатор пользователя из сеанса и отправить его с клиентской стороны. Это может быть фальшивка. Скажите, пожалуйста, есть ли более простой способ, и если да, то как?