帮酷LOGO
文章标签:Websocket??WEB??SAN??REST??

一个完全工作的REST API与web socket服务器一起工作的例子。

注:此例子有一个Docker镜像,查看zareba_pawel/php-websockets-sandstone

用例

我们希望用api发布文章,多通道聊天,并在发布文章时收到通知。

如何使用Sandstone进行处理:

REST API堆栈:REST API将允许通过调用 POST rest-api.php/api/articles,然后REST API将响应创建的http状态,
web socket栈:以同样的方式,通过运行在,php websocket-server.php,我们可以输入和发布消息到通道(即,channel/general ),
推送服务器:当使用REST API发布文章时,一个事件将发送到web socket服务器线程。

安装

创建你的composer.json :

composer.json

json
PHP

{
 "require": {
 "eole/sandstone": "2.0.x"
 },
 "autoload": {
 "psr-4": {
 "": "src/"
 }
 }
}

然后运行 composer update

项目结构

 
SilexApplication

 

EoleSandstoneApplication

src/MyApp.php

PHP
PHP

class MyApp extends EoleSandstoneApplication
{
 public function __construct()
 {
 parent::__construct([
 'debug' => true,
 ]);

 // Sandstone requires JMS serializer
 $this->register(new EoleSandstoneSerializerServiceProvider());

 // Register and configure your websocket server
 $this->register(new EoleSandstoneWebsocketServiceProvider(), [
 'sandstone.websocket.server' => [
 'bind' => '0.0.0.0',
 'port' => '25569',
 ],
 ]);

 // Register Push Server and ZMQ bridge extension
 $this->register(new EoleSandstonePushServiceProvider());
 $this->register(new EoleSandstonePushBridgeZMQServiceProvider(), [
 'sandstone.push.server' => [
 'bind' => '127.0.0.1',
 'host' => '127.0.0.1',
 'port' => 5555,
 ],
 ]);

 // Register serializer metadata
 $this['serializer.builder']->addMetadataDir(
 __DIR__,
 ''
 );
 }
}

rest-api.php

PHP
PHP

require_once 'vendor/autoload.php';

use SymfonyComponentHttpFoundationJsonResponse;

$app = new MyApp();

// Creating an api endpoint at POST api/articles
$app->post('api/articles', function () use ($app) {
 // Persisting article...
 $articleId = 42;

 $event = new ArticleEvent();

 $event->id = $articleId;
 $event->title = 'Unicorns spotted in Alaska';
 $event->url = 'http://unicorn.com/articles/unicorns-spotted-alaska';

 // Dispatch an event on article creation
 $app['dispatcher']->dispatch('article.created', $event);

 return new JsonResponse($articleId, 201);
});

// Send all 'article.created' events to push server
$app->forwardEventToPushServer('article.created');

$app->run();

websocket-server.php

PHP
PHP

require_once 'vendor/autoload.php';

$app = new MyApp();

// Add a route `chat/{channel}` and its Topic factory (works same as mounting API endpoints)
$app->topic('chat/{channel}', function ($topicPattern) {
 return new ChatTopic($topicPattern);
});

// Encapsulate your application and start websocket server
$websocketServer = new EoleSandstoneWebsocketServer($app);

$websocketServer->run();

实现ChatTopic类

在本例中,我们使用了 ChatTopic 类。

在我们的例子中,我们需要:

  • ChatTopic 只是把所有收到的聊天消息广播给每个订户
  • 发布文章时广播消息,

所以我们需要听听 article.created 事件:
主题类必须实现 SymfonyComponentEventDispatcherEventSubscriberInterface 自动监听事件(用于与 forwardEventToPushServer )。

让我们来实现 ChatTopic 类:

src/ChatTopic.php

PHP

use SymfonyComponentEventDispatcherEventSubscriberInterface;

class ChatTopic extends EoleSandstoneWebsocketTopic implements EventSubscriberInterface
{
 /**
 * Broadcast message to each subscribing client.
 *
 * {@InheritDoc}
 */
 public function onPublish(RatchetWampWampConnection $conn, $topic, $event)
 {
 $this->broadcast([
 'type' => 'message',
 'message' => $event,
 ]);
 }

 /**
 * Subscribe to article.created event.
 *
 * {@InheritDoc}
 */
 public static function getSubscribedEvents()
 {
 return [
 'article.created' => 'onArticleCreated',
 ];
 }

 /**
 * Article created listener.
 *
 * @param ArticleEvent $event
 */
 public function onArticleCreated(ArticleEvent $event)
 {
 $this->broadcast([
 'type' => 'article_created',
 'message' => 'An article has just been published: '.$event->title.', read it here: '.$event->url,
 ]);
 }
}

关于序列化

365bet皇冠 当一个对象从rest api堆栈发送到websocket服务器,或者通过rest api响应发送到http客户端时,sandstone使用JMS序列化器在一侧对它进行序列化,并在另一侧进行反序列化。

在本例中,一个 ArticleEvent 被发送到web socket服务器。

所以,这就是类及它序列化器元数据的样子:

src/ArticleEvent.php

PHP

use SymfonyComponentEventDispatcherEvent;

class ArticleEvent extends Event
{
 /**
 * @var int
 */
 public $id;

 /**
 * @var string
 */
 public $title;

 /**
 * @var string
 */
 public $url;
}

src/ArticleEvent.yml

yaml
PHP

ArticleEvent:
 exclusion_policy: NONE
 properties:
 id:
 type: integer
 title:
 type: string
 url:
 type: string

我们需要加入MyApp

src/MyApp.php

PHP

// Register serializer metadata
$this['serializer.builder']->addMetadataDir(
 __DIR__,
 ''
);

现在让我们来看看

rest api端点将被命中:

Bash

POST rest-api.php/api/articles

HTTP/1.1 201 Created
Content-Length: 2
Content-Type: application/json

42

运行web socket服务器,并且使用以下命令推送服务器:

Bash

php websocket-server.php

# Websocket server is starting
[info] Initialization... []
[info] Bind websocket server {"bind":"0.0.0.0","port":"25569"}
[info] Bind push server {"bind":"127.0.0.1","host":"127.0.0.1","port":5555}

# Someone connects to websocket server
[info] Connection event {"event":"open"}
[info] Authentication... []
[info] Anonymous connection []

# the connected guy subscribes to a chat topic
[info] Topic event {"event":"subscribe","topic":"chat/general"}

# Websocket server received an event from rest api
[info] Push message event {"event":"article.created"}


文章标签:WEB??REST??Websocket??SAN??

Copyright ? 2011 HelpLib All rights reserved. ?? 知识分享协议 京ICP备05059198号-3 ?|? 如果智培 ?|? 酷兔英语