Talk to Anything with Broadcastable Events
The problem is not a new one in web development: you have a page you want to update with some bit of dynamic information, so you get to work crafting an AJAX request that continuously polls some back-end service, waiting for that precious bit of data.
There are a bunch of problems with this approach, however, including possible memory leaks, timeouts and unnecessary server load. Wouldn’t it be better if we didn’t have to bug the server continually for the status of our job, and instead it could let us know when it was complete?
This is not a new technology: NodeJS is particularly good at dealing with this kind of setup, and Laravel has had its own native ability to work with this technology for awhile. Now it’s coming to concrete5.
Here’s the general idea between asynchronous, broadcastable events.
- A concrete5 application dispatches an event using the Event Dispatcher component. This is just like when the core uses events to allow developers to run custom code when certain core operations occur, like adding a page or updating a user. This custom event can carry any type of custom data with it, and doesn’t necessarily have anything to do with concrete5 – it is likely related to the custom business logic of the site. In version 9.0, the EventDispatcher component is actually concrete5’s own, in order to enable this type of advanced functionality – although it does build upon and subclass
- This event object is a special event object, implementing the
\Concrete\Core\Events\Broadcast\BroadcastableEventInterface, which forces events to be serializable to JSON, and declare their names and the channel that they should be broadcast on.
- When you run
$dispatcher->dispatch($event);with a broadcastable event, the regular event dispatching code runs, enabling other components to hook into these events. However, in addition to this behavior, the currently active Broadcaster broadcasts that event somewhere, in realtime.
I could define it, but https://redis.io does a better job:
Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache and message broker.
Redis is already a supported technology in concrete5 – it’s a possible backend for our caching layers. Redis will always be faster than using a filesystem-based cache, and may be a requirement in certain load-balanced setups, where filesystem-based caching is not an option. We’ve used redis for caching, but it also has a fantastic realtime publish/subscribe messaging system – and that’s going to be the basis for our first broadcaster driver.
By using a custom configuration, you can enable redis as the active broadcaster. If this is the case, your broadcastable events will be broadcasted via redis’s publish/subscribe system.
But again, what does this get you?
The third leg of this four-legged approach is a socket server. This is some kind of lightweight web server that’s capable of running as a backend to a [websocket]((https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API). Likely written in NodeJS, this simple app does just a couple things:
- It, too, connects to your Redis system.
- It listens on certain channels – subscribing to the Redis publish/subscribe system.
- Finally, it emits events that your application can work with. These are published over a socket, that the web application connects to.
Websocket Connection – socket.io
The result is the kind of latency-free, instant gratification that so many web apps are capable of delivering. concrete5 is late to the party here, but we’re catching up in a big way. More code examples are coming soon as APIs finalize, but if you're interesting in checking out the bleeding edge, please head over to GitHub