gpt4 book ai didi

javascript - 有没有一种干净的方法可以使用 symfony 2.6 设置 websocket

转载 作者:行者123 更新时间:2023-11-30 16:52:35 25 4
gpt4 key购买 nike

我使用 symfony 2 开发了一个网站。直到现在它还没有使用ajax。当您发布新评论时,页面已刷新。

我添加了一个 ajax 层,因此无需刷新即可提交表单。

每次我发布新帖子时,我都希望允许所有在线用户在他们的时间线中看到这篇帖子。

这就是我现在所做的:

我创建了一个事件 NewPostAdded 和一个订阅者渲染到 html 帖子(希望我将它发送给客户端并且客户端将 $('.timeline').prepend(post) )

我正在寻找一种方法来实现将启动 websocket 服务器的 symfony2 命令。我的订户将能够将帖子+数据(它是公开的吗?否则允许查看它的用户 ID 列表)推送到此服务器。然后,该服务器将有一个在线用户列表,如果该帖子是公开的,它将推送给其他所有人,并将其推送给正确的在线用户。

我在使用 symfony 2.1 + redis + nodejs + socket.io 之前已经这样做了,但它显然无法维护,而且由于这个网站不是针对大量观众的,所以我想保持简单。

这是我的第二个问题:

  • 是否有一个 bundle 使思考变得简单,提供了一种简单的方式来编写带有收入事件监听器(从 symfony 接收帖子)和事件发送器(向用户发送帖子)的服务器,添加事件监听器客户端(准备好使用 Assets 添加以能够对客户端进行编码)对服务器消息使用react?

  • 有没有办法在客户端使用除用户 ID 之外的其他东西来“验证”websocket 服务器上的用户,以避免用户更改客户端代码中的 ID 以接收他们不应该查看的帖子?

最佳答案

是的,你可以使用 php web socket Ratchet "http://socketo.me/ ",你可以将它用作 composer 包 https://packagist.org/packages/cboden/ratchet

您应该创建一个服务应用程序,然后您应该创建一个将运行套接字应用程序的控制台命令。

您应该生成一个 secret token ,例如 userId 的 md5 散列 + 一些将用于检查套接字连接是否可信的 secret key ,而不是 userId。

更新:

Composer .json

...
"cboden/ratchet": "0.3.*",
...

然后你应该创建一个新的包,假设是“WebSocketBundle”

  1. 创建服务应用程序WebSocketBundle/WebSocket/WebSocketApplication.php

    namespace MyApp\WebSocketBundle\WebSocket;

use Ratchet\ConnectionInterface;
use Ratchet\MessageComponentInterface;

class WebSocketApplication implements MessageComponentInterface
{
protected $container;
protected $clients;
protected $redis;

public function __construct($container)
{
$this->clients = [];
$this->container = $container;
$this->redis = $container->get('snc_redis.something'); // your redis service
}

public function onMessage(ConnectionInterface $from, $msg)
{
$messageData = $this->decodeJSONAndCheckMessage($from, $msg);

// here you must pass a token in messageData and implement own function to check is the token valid
$loginResult = $this->userLogin($from, $messageData);

if ($loginResult instanceof Success) { // my custom success class message
$this->handleMessage($from, $messageData);
} else {
$this->onError($from, new \Exception('Cannot login a user.'));
}
}

// some strategy wrapper
private function handleMessage($from, $messageData)
{
$message = $messageData->message;
if (method_exists($this, $message)) {
try {
$this->$message($from, $messageData);
} catch (Exception $ex) {
$this->onError($from, $ex);
}
} else {
$this->onError($from, new \Exception(sprintf('Unknown method "%s"', $message)));
}
}

// you can use here post new message action
private function eventStartSomething($from, $messageData)
{
if (!$messageData->somethingId) {
$this->onError($from, new \Exception('Bad parameters'));
return;
}
$scope = [];
$scope['clients'][$from->resourceId] = null;

// I need socket for something only limited amount of time, you can implement here own logic
$this->redis->setex($messageData->somethingId, 600, serialize($scope));

$this->clients[$from->resourceId]['scope'] = $messageData->eventId;
$this->logMessage($from, 'started new something with Id: ' . $messageData->somethingId);
$from->send($this->getResultOKMessage());
}

private function eventGetSomething($from, $messageData)
{
$scopeKey = $this->redis->get($messageData->somethingId);
if (!$scopeKey) {
$this->onError($from, new \Exception('Bad or expired something ' . $messageData->somethingId));
return;
}
if (!$this->checkForClientInScope($from->resourceId, $messageData->eventId)) {
if ($this->assignClientToScope($from->resourceId, $messageData->eventId)) {
$this->sendMessageToScope($from, $messageData->eventId, $this->getScopeWatchMessage($from, $messageData->eventId));
$from->send($this->getScopeWatchMessage($from, $messageData->eventId));
}
}
}

private function assignClientToScope($clienResourseId, $scopeId)
{
$result = false;
$scopeKey = $this->redis->get($scopeId);
if (!$scopeKey) {
return $result;
}
$scope = unserialize($scopeKey);
if (!array_key_exists($clienResourseId, $scope['clients'])) {

// I need socket for something only limited amount of time, you can implement here own logic
$this->redis->setex($scopeId, 600, serialize($scope));

if (array_key_exists($clienResourseId, $this->clients)) {
$this->clients[$clienResourseId]['scope'] = $scopeId;
}
$result = true;
}
return $result;
}

private function sendMessageToScope($from, $scopeId, $message)
{
$scopeKey = $this->redis->get($scopeId);
if (!$scopeKey) {
$this->onError($from, new \Exception('Bad or expired event ' . $scopeId . ' for sending message'));
return;
}
$scope = unserialize($scopeKey);

foreach ($scope['clients'] as $clientResourceId => $remoteAddress) {
if (array_key_exists($clientResourceId, $this->clients) &&
$this->clients[$clientResourceId]['connection'] != $from) {
$this->clients[$clientResourceId]['connection']->send($message);
}
}
}

public function onClose(ConnectionInterface $conn)
{
if (isset($this->clients[$conn->resourceId]['scope'])) {
$scopeId = $this->clients[$conn->resourceId]['scope'];
$this->removeClientFromScope($conn->resourceId);
$this->sendMessageToScope($conn, $scopeId, $this->getScopeWatchMessage($conn, $scopeId));
}
unset($this->clients[$conn->resourceId]);
$this->logMessage($conn, 'Connection closed.');
}

public function onError(ConnectionInterface $conn, \Exception $e)
{
echo date("Y-m-d H:i:s") . ":" . "WebSocket error::" . $e->getMessage() . " resourceId:" . $conn->resourceId . ". remoteAddress:" . $conn->remoteAddress . "\n";
$conn->send($this->getErrorMessage($e->getMessage()));
}

public function onOpen(ConnectionInterface $conn)
{
$this->clients[$conn->resourceId]['connection'] = $conn;
$this->logMessage($conn, 'New connection.');
}
}
  1. 控制台命令:

use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputOption;
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use Snc\RedisBundle\Session\Storage\Handler\RedisSessionHandler;
use Ratchet\Session\SessionProvider;
use MyApp\WebSocketBundle\WebSocket\WebSocketApplication;

class ListenCommand extends ContainerAwareCommand
{
protected function configure()
{
$this->setName('myapp:websocket:listen')
->setDescription('Listen for websocket requests ')
->addOption('port', 'p', InputOption::VALUE_REQUIRED, 'The port to listen on', 8000)
->addOption('interface', 'i', InputOption::VALUE_REQUIRED, 'The interface to listen on', '0.0.0.0');
}

protected function execute(InputInterface $input, OutputInterface $output)
{
$redis = $this->getContainer()->get('snc_redis.default');
$application = new WebSocketApplication($this->getContainer());
$server = IoServer::factory(
new HttpServer(
new WsServer(
new SessionProvider(
$application,
new RedisSessionHandler($redis)
)
)
),
$input->getOption('port'),
$input->getOption('interface')
);
echo "Listening on: ".$input->getOption('interface').":".$input->getOption('port')."\n";
$server->run();

}
}

关于javascript - 有没有一种干净的方法可以使用 symfony 2.6 设置 websocket,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30290034/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com