Since the earliest betas, all my OroCRM installations have eventually developed a small quirk where I’d see the following spit out into Chrome’s error console.
WebSocket connection to ‘ws://127.0.0.1:8080/’ failed: Error during WebSocket handshake: Unexpected response code: 200
autobahn.js:364
This, obviously, pointed towards OroCRM using WebSockets, but I was never sure for what, and never sure how to set up to system properly.
Based on Dima’s answer in the forums, OroCRM has big plans for WebSockets. Today we’re going to look at the underlying technology projects needed to get WebSockets up and running in your OroCRM and OroBAP system.
What are Web Sockets
WebSockets let your server talk to your web browser, and your web browser talk to your server without a page refresh, and without ajax polling. That’s what the terms bi-directional/full duplex are referring to on the WebSockets Wikipedia page. The name sockets was borrowed from unix/POSIX socket programming.
If that’s still a little esoteric for you, WebSockets let you deploy a small bit of code to your application, and then you can write code on your server that sends messages to your web application in real time without the server overhead of an ajax request constantly asking if there’s anything to do.
WebSocket Servers
WebSockets are cool, but they present a few challenges for the traditional PHP web developer. First, a web server isn’t a WebSocket server. There are many ways to turn a web server into a WebSockets server, but from a working web developer’s view, it’s a new technology stack. From a working PHP developer’s point of view, it’s not a technology that’s easily available on the vast network of shared hosts that support PHP.
This is where Ratchet comes into the picture. Ratchet is a WebSockets server for PHP. Ratchet will let you turn your linux server (VPS, etc.) into a WebSockets server, and to write event driven code in PHP to communicate with the subscribing WebSockets clients (i.e. the web browsers). Ratchet doesn’t solve the shared hosting problem, and you’ll still want to proceed cautiously into the “new technology in production” tar pit. That said, Ratchet greatly simplifies the process of setting up a WebSockets server for a PHP developer. If you can use composer and follow a tutorial, you can use Ratchet.
WebSocket Clients
The second challenge with WebSockets is web browsers. WebSockets require browser makers to implement them — you can’t drop a shim/polyfill/etc… into place and make an old web browser support WebSockets. I’m not sure how accurate it is, but this chart should give you an idea of the lay of the land, (and the complexity of the modern browser landscape).
Because of the browser problem, more cautions developers have been wary of embracing WebSockets. Beyond the yes/no question of “does this support WebSockets”, there’s also the problem of the loose pseudo-standards implemented in browsers. Like the browser DOM, even if all the major browser makers implement the same standard, there are small subtle differences between implementations. This is where Autobahn|JS and WAMP come into the picture.
WAMP, in this context, is not the application for quickly installing PHP/MySQL/Apache on Windows. Instead, WAMP is a protocol — specifically a subset of the WebSockets protocol that allows you to do the most common things you’d want to do with WebSockets (remote procedure calls, publish/subscribe/etc).
Autobahn|JS is a javascript implementation of WAMP, and effectively provides a standard API for accessing WAMP/WebSockets features in a browser agnostic way.
Pulling it All Together
If, like me, you’re sane, you’re old, you’re conservative with your technology choices, all this can look like a lot of loose fitting cogs stung together with bubble gum and duct tape. I like to remind myself that perl/PHP/MySQL probably looked the same way to Java and C developers back in the late 90s. The ever pressing future aside, this is a cacophony of independent, individually moving pieces.
This is where, for Symfony developers, Clank comes into the picture. This is not “Clank: The open source HTML/CSS framework for prototyping native phone/tablet applications”. It’s also not Clang, the LLVM compiler project. It’s not even Clank, from Ratchet and Clank.
Instead, this is the jdare/clank-bundle Symfony bundle. This bundle ties together Ratchet and Autobahn|JS. It allows developers to write their WebSockets server code using Symfony services, and provides an additional layer of javascript abstraction on top of Autobahn|JS.
This means, as a Symfony developer, all you need to do is
- Start your Ratchet server with the
php app/console clank:server
command - Write your client side dispatchers/listeners using the
Clank
object -
Create your server side logic using Symfony services, whether they’re remote procedure calls or publish/subscribe event logic
If that’s still a little overwhelming, try starting by installing a empty Symfony project (no OroCRM or OroBAP), and walking through the Clank README, which will lead off to different topics. After doing this you should have the basic idea of how WebSockets work.
Final OroCRM Twists
Although I haven’t had as much time as I’d like to sit down with Oro’s implementation, it looks like the SyncBundle is the only bundle using clank. You can see a clank service has been registered in the main config.yml
file
#File: app/config/config.yml
clank:
...
periodic:
-
service: "oro_wamp.db_ping"
...
This is where the Oro developers are telling Clank to treat the oro_wamp.db_ping
service as a periodic clank service.
The oro_wamp.db_ping
service is registered with Symfony in
#File: vendor/oro/platform/src/Oro/Bundle/SyncBundle/Resources/config/services.yml
parameters:
oro_wamp.db_ping.class: Oro\Bundle\SyncBundle\Wamp\DbPing
If you’re not up on Symfony services, this is where we (the programmer) tell Symfony that the oro_wamp.db_ping
service is really the PHP class Oro\Bundle\SyncBundle\Wamp\DbPing
. This class is defined here
#File: vendor/oro/platform/src/Oro/Bundle/SyncBundle/Wamp/DbPing.php
namespace Oro\Bundle\SyncBundle\Wamp;
use JDare\ClankBundle\Periodic\PeriodicInterface;
class DbPing implements PeriodicInterface
{
//...
}
While the Oro core team is using the Clank interfaces for the WebSockets server code, they’re not using the Clank
javascript object. Instead, there’s a RequireJS module named sync/wamp
which uses the Autobahn|JS abstraction directly.
#File: vendor/oro/platform/src/Oro/Bundle/SyncBundle/Resources/public/js/sync/wamp.js
define(['jquery', 'underscore', 'backbone', 'autobahn'],
function ($, _, Backbone, ab) {
//..
});
If you’re not familiar with it, RequireJS is a javascript module system which enables python/ruby like code module separation for javascript.
The other part of OroCRM’s web socket implementation has nothing to do with clank.
#File: vendor/oro/platform/src/Oro/Bundle/SyncBundle/Wamp/WebSocket.php
class WebSocket
{
//...
}
The Oro\Bundle\SyncBundle\Wamp\WebSocket
class is a PHP WebSocket client. When something happens in the OroCRM backend, a developer can use this class/object to publish messages to the WebSocket server, which in turn will be picked up by the browser clients, (if the browsers are subscribed). If that hurt your head a little, don’t feel bad. WebSocket applications are architected in a fundamentally different way than traditional web applications, and the new patterns can take some getting used to.
Wrap Up
OroCRM’s decisions to use WebSockets in a full stack, open source, business application is a bold one. WebSockets, for all their power, are not a drop-in/turn-key technology, and if the OroCRM core team continues to build out WebSocket based features they’ll be clearing new ground in the PHP world. For all the Laravel tutorials on building a WebSocket chat client out there, I haven’t any full stack open source applications that have embraced the technology.
Despite OroCRM making some technology choices I never would it’s this sort of bold adoption of new technology, coupled with a business application people will use, that keeps me interested. If the OroCRM core team can pull off these WebSocket based features, developers joining the OroCRM community will be able to benefit from their R&D work; both in being able to use WebSockets in their CRM applications, as well as observing what does and doesn’t work in the Oro implementation.
While I can foresee a lot of head scratching on programming forums in the future, and the usual chorus of why won’t this work on my $3/year hosting account, I’m looking forward to the possibilities.