📜 ⬆️ ⬇️

PubSub in a browser using webboxes and the WAMP protocol

Studying the methods of implementing real-time data refresh in the browser, I discovered " WAMP ", an application-level messaging protocol based on web-based software.
The protocol implements two common high-level templates for data exchange: PubSub and RPC (Remote Procedure Call).

These templates are well known and widely used in various areas of programming and interprocess communication:


In the context of web development, the most interesting use of the WAMP protocol is to use the PubSub template. With it, you can easily solve the problem of updating information on a page of a site opened by a user: for example, to display a comment just added or to show a notification of receipt of a new message.
WAMP implementation exists in the form of libraries for many languages ​​and platforms , including, of course, javascript as an autobahn project.

As an example of using the protocol, let's try to develop an abstract web application in which the browser will subscribe to the channel with new comments, and the server will send them. On the server, PHP will work with the wonderful Ratchet library, which, in addition to implementing the web sockets, is able to work with the WAMP protocol.
')
When planning methods of interaction between the client and the server on such a website, it should be remembered that there are still browsers that do not support web-sites. Although some of the problems with them can be solved by polyfills , 100% of work in any environment (for example, on android) cannot be achieved with their help. Therefore, it is reasonable, in my opinion, to limit the use of the PubSub template on the client to a subscription to events. The same events will be generated by the server receiving the “old school” ajax requests to create a new comment on behalf of its author. Thus, all clients will be able to add comments (or, in general, generate events), but only those who support web-sites will receive updates in real time.

The client part of the site.

The autobahn library exports the ab object to the global scope, a full list of methods of which can be found in the documentation . We are also interested in the connect method:

ab.connect( //  'ws://site.com:8080', //     . //    session, //          function (session) { //   .    - , //     . session.subscribe('comments', onNewComment); }, //     . //   ,    , //        . function onClose() { alert('   '); }, { //     'maxRetries': 100, 'retryDelay': 5000 } ); //     comments function onNewComment(topic, data) { //topic -  ,     // data  ,  . //       content  author. console.log(' ', data.author, data.content); } 


For simplicity, the line “comments” was chosen as the name of the channel, but according to the protocol specification such naming is not correct. Channels must be in URI format, that is, in our case the channel may be called site.com/comments site.com/comments . In turn, the channel URIs can be reduced to “compact URIs” - CURIE. These details are described in more detail on the specification page.

It is logical that the user doesn’t need all new comments at once on a real site, but only those appearing on the current page are needed. In this case, you can create for example such a channel: site.com/comments/page/1 site.com/comments/page/1 . Of course, there are no restrictions on the formation of URIs: you can dynamically create channels with any parameters, depending on the tasks.

Server part of the site.

In the example of PHP, ZMQ is responsible for delivering messages from the http server to the server responsible for sending messages to the websockets . When a new comment is received, the server saves it to the database and sends the message to the ZMQ queue, from which it in turn will be retrieved by the daemon using the Ratchet library mentioned above.
Here is how the implementation of such a function looks like:
 //  ,   ajax     $comment=array('author'=>'', 'content'=>', !'); //   ... $commentModel->save($comment); //       $loop = React\EventLoop\Factory::create(); $context = new React\ZMQ\Context($loop); $push = $context->getSocket(\ZMQ::SOCKET_PUSH); //   ZMQ   ,   ,    $push->connect('tcp://127.0.0.1:8081'); //     json $push->send(json_encode($comment)); //tick     . //     -  . $loop->tick(); 


To handle client connections and events from the ZMQ server, we need a process that will receive messages and process them. The documentation for the Ratchet library already contains detailed examples . In particular, you need to pay attention to the Pusher class (in our example, I called it WampProcessor, which seems to be more relevant) - it contains the business logic of the application and sends messages subscribed to the corresponding channels to customers.

The code to start such a process would be something like this:
 //websocket-   React $loop = React\EventLoop\Factory::create(); //processor -     WAMP,     . //    WampServerInterface. //       //        http-. $processor = new WampProcessor(); //    http-  ZMQ   8081... $context = new React\ZMQ\Context($loop); $pull = $context->getSocket(ZMQ::SOCKET_PULL); $pull->bind('tcp://127.0.0.1:8081'); //        'onComment'  'processor' $pull->on('message', array($processor, 'onComment')); //     -    8080   IP $app = new \components\SocketServer\App('site.com', 8080, '0.0.0.0', $loop); //          , //     (Ratchet    Symfony). //     ,    . //  ""     WampProcessor. $app->route('/', $processor, array('*')); //... $app->run(); 


All methods of the WampProcessor class will be almost identical to what can be seen in the Ratchet documentation; one of them is to select only the event handler - the " onComment " method:
 /** * @param string   JSON,   ZeroMQ */ public function onComment($json) { $comment = json_decode($json, true); //  ,         if (!array_key_exists('comments', $this->subscribedTopics)) { return; } $topic = $this->subscribedTopics['comments']; //     . $topic->broadcast($comment); } 


Thus, when creating a new comment, all connected browsers will receive an object with the author and content fields, which it expects to receive a javascript handler.

The messaging process can be observed in the chrome console (“websocket” filter in the “network” tab) or another browser. It can be seen that when connecting to the server, the browser sends a greeting message, and then a list of channels to subscribe.

Conclusion

So, using the WebSockets technology and the WAMP protocol, you can implement a real-time update of information on a web page using the PubSub method.
It can be argued that using nodejs and the library of socket.io would be easier to do this, but in our reality, where PHP is the dominant server platform, the described version is quite viable and even more convenient than other, more “crutch” methods (such as periodic server polling using ajax). It is also relatively easy to implement on an existing site: changes will only need to be made to those parts where any events are generated, and the handler daemon itself can be completely independent.

Key links:

Source: https://habr.com/ru/post/201658/


All Articles