Javascript 使用symfony 2.6是否有一种干净的方法来设置websocket
我用symfony2开发了一个网站。 直到现在,它还没有使用ajax。当您发布新评论时,页面已刷新 我添加了一个ajax层,因此表单提交时无需刷新 每次我发布一篇新文章,我希望所有在线用户都能在他们的时间线中看到这篇文章 这就是我现在所做的: 我创建了一个事件NewPostAdded和一个订阅者呈现html帖子(希望我将它发送给客户端,客户端将$('.timeline')。prepend(post)) 我正在寻找一种实现symfony2命令的方法,该命令将启动websocket服务器。我的订户将能够将post+数据(它是公共的吗?其他允许查看它的用户id列表)推送到该服务器。该服务器将有一个在线用户列表,如果帖子是公开的,它将推送给其他所有人,它将推送给正确的在线用户 在使用symfony2.1+redis+nodejs+socket.io之前,我已经这样做了,但它显然无法维护,因为这个网站并不是面向大受众的,所以我想保持简单 以下是我的两个问题:Javascript 使用symfony 2.6是否有一种干净的方法来设置websocket,javascript,ajax,symfony,websocket,Javascript,Ajax,Symfony,Websocket,我用symfony2开发了一个网站。 直到现在,它还没有使用ajax。当您发布新评论时,页面已刷新 我添加了一个ajax层,因此表单提交时无需刷新 每次我发布一篇新文章,我希望所有在线用户都能在他们的时间线中看到这篇文章 这就是我现在所做的: 我创建了一个事件NewPostAdded和一个订阅者呈现html帖子(希望我将它发送给客户端,客户端将$('.timeline')。prepend(post)) 我正在寻找一种实现symfony2命令的方法,该命令将启动websocket服务器。我的订户将
- 是否有一个捆绑包使think simple提供了一种“一体式”的简单方式,用income events listeners(从symfony接收帖子)和event sender(向用户发送帖子)、add event listeners客户端(准备使用资产添加以便能够对客户端进行编码)对服务器消息做出反应
- 是否有一种方法可以在客户端使用用户id以外的其他内容来“验证”websocket服务器上的用户,以避免用户更改客户端代码中的id以接收他们不应该查看的帖子
...
"cboden/ratchet": "0.3.*",
...
然后您应该创建一个新的捆绑包,比如“WebSocketBundle”
所以我可以在symfony2中使用这个包,将它添加到我的composer.json中?你有任何在symfony2中实现这个包的例子吗?是的,但不能在这里发布完整的代码案例NDA,但我会尝试向你展示一些关键点Cellent,我现在就要尝试!感谢您的帮助查看eventsource(sse),从“裸”php使用它比从套接字使用要容易得多,并且可以使用与http相同的基本例程随时推出。它无法接收,但由于这一限制,实现起来非常简单,而且您可以随时使用ajax从客户端发送。。。
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.');
}
}
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();
}
}