It's Time For Real-Time
Eric Terpstra
@eterps
A Solution For Adding
Real Time Functionality
To Your Existing Web Applications
Before We Get Started...
A Story
Warning: Following fictional anectode may contain absurd amounts of animated GIFs (pronounced: 'jiffs')
Once upon a time...
And one unsung lady
Super Serious Business Application
And all was good...
...for a time.
(image via: luke o’sullivan)
Then came the revolt.
Followed by salvation?
A New Alliance Was Forged
Through toil and torment...
...and neverending struggles
Victory
?
Then
Now
Sure, why not?
And then came JavaScript
And AJAX Happened
And users rejoiced...
...but were soon unsatisfied.
(again)
What about real-time notifications and live updates?
Time for another rewrite!
Get Ruby on Rails on the Phone!
Just Kidding :)
There has to be a better way...
Enter WebSockets!
Not the hero we deserve
but the hero we need.
WebSockets: Awesome, but hard.
And sometimes missing completely.
If only there were a library to cover up all the pain points of WebSockets and provide an easy-to-use cross-platform solution with intelligent fallbacks and helpful utilities...
for free.
Because budgets
Planning Budget: $12,490,000.32 Development Budget: $35 Software Licenses Budget: $0
Hooray For Open-Source!
And so the work continued...
... but smarter this time.
And All Was Well Again.
And Now Back to Your Regularly Scheduled Presentation...
The Solution:
This Talk Is About:
-
A possible solution to a common problem
-
A look at some new features of Socket.IO 1.0
- Foundational Knowledge
This Is Not:
- A Deep Dive Into WebSockets
- A Laundry List of Socket.IO Capabilities
- Evangelism
Warning:
This solution makes heavy use of open source libraries. If you like creating solutions by yourself, from scratch, this is not for you.
Let's Take It For a Spin,
Shall We?
Socket.IO
-
Browser Fallbacks for WebSockets
- Starts with long-poll, steps up to WS if available.
- Flash based socket connection also an option.
- Connect/Disconnect Logic
- Events
- Namespaces, Rooms
- Logging
- Binary Streams
- And More...
Like jQuery For WebSockets
- A Key-Value Store
- A Pub-Sub Mechanism
- And more... http://redis.io
important
Your Silent Partner
Socket.IO Emitter
-
Emits events TO Socket.IO Server FROM... somewhere else.
-
Implemented in YOUR FAVORITE LANGUAGE
- Redis pub/sub under the hood.
The Bolt-On Accessory For Your App
A Diagram
-
HTTP!
-
Emitter
- Socket.IO
The Redis is Silent
HOWTO: Socket.IO
-
Install Node.js
-
Install Socket.IO
-
Install Socket.IO-Redis
npm install socket.io
npm install socket.io-redis
HOWTO: Redis
-
Install & Configure
- http://redis.io/download
- http://redis.io/topics/quickstart
-
Dependencies
- Redis Client/Adaptor
- http://redis.io/clients
-
Msgpack
- http://msgpack.org/
- Redis Client/Adaptor
HOWTO: Emitter
-
Off-the-shelf
- PHP
- Java
- Ruby
- Python
- .NET
- Go
- Node.js
-
Roll-Your-Own
- Implement functions for emit, broadcast, in/to, and of.
- Publish data to Redis
-
Do Both
- Hooray Open-Source!
HOWTO: Review
-
Setup Node and Redis
- Presumably on a server
- Create some space for a node app
-
Find/Create and "Emitter" Class
- Integrate it into your app codebase
-
Install Dependencies
- Redis connector/client
- Msgpack
And now, some code.
The Socket.IO Server
var server = require('http').Server();
var io = require('socket.io')(server);
var ioredis = require('socket.io-redis');
io.adapter(ioredis({
host: '127.0.0.1',
port: 6379
}));
server.listen(3000);
Not Kidding. That's It.
socket-io-server.js
Client-Side JavaScript
// Connect to Socket.IO
var socket = io('http://demoapp.dev:3000');
// Listen for the 'Thing::update' event
socket.on('Thing::update', function(thing){
// Parse the event data
thing = JSON.parse(thing);
// Update the data in the DOM
...
});
<script src="http://yoursocketserver.org/socket.io/socket.io.js"></script>
Include Client-Side Socket.IO Library
Write some JavaScript
Server Side / Emitter
public function updateThing(thingId):Void
{
// Create an instance of your Emitter
Emitter myEmitter = new SocketIO\Emitter(redisConnObj);
// Create some data to push to connected clients
Thing thisThing = ORM.Thing.get(thingId);
thisThing.name = "Make more moneys"
thisThing.importance = 9999;
// Data must be string or binary
String eventData = thisThing.toJSON();
// Name the event
String updateEventName = "Thing::update";
// Emit the event
myEmitter.emit(updateEventName, eventData);
}
your-app-update.class.module.java.py.rb
Quick Review
"Emit" and event + data from your app using your Emitter class/module
Socket.IO (and Redis) does stuff.
You do nothing
Listen for event & data in the browser with your own JS code.
myEmitter.emit( "AwesomeEvent", importantDatas );
socket.on( 'AwesomeEvent', function(importantData){} );
Let's See That Demo Again
Live Updates: Strategies
-
Send a changeset
A record changed. Here's the new data.
-
Send a flag to do some action
You wanted to be notified about this. Do something.
-
Sync client-side models
Use a lib (or fancy code) to keep front/backend models in sync
- Use namespaces/rooms
And Another Demo
Rooms!
Requires some additional setup...
var server = require('http').Server();
var io = require('socket.io')(server);
var ioredis = require('socket.io-redis');
io.adapter(ioredis({
host: '127.0.0.1',
port: 6379
}));
io.on('connection', function(socket){
socket.on('AlertToggle::join', function(){
socket.join('ROOM::ExtraImportantUpdates');
});
socket.on('AlertToggle::leave', function(){
socket.leave('ROOM::ExtraImportantUpdates');
});
});
server.listen(3000);
socket-io-server.js
Rooms! (Browser)
$(document).on('click', '.alert-toggle', function(e){
if(!gettingAlerts) {
// Send signal to join the room
socket.emit('AlertToggle::join');
$(this).text('Stop Alerts');
} else {
// Send signal to leave the room
socket.emit('AlertToggle::leave');
$(this).text('Get Alerts');
}
gettingAlerts != gettingAlerts;
});
Rooms! (App/Emitter)
public void function deleteThing() {
...
if ( thingToDelete.importance > 100 )
{
String updateRoom = "ROOM::ExtraImportantUpdates";
String deleteEventName = "Thing::delete::important";
myEmitter.in( updateRoom ).emit( deleteEventName, thingToDelete );
}
...
}
socket.on('Thing::delete::important', function(thing){
var thing = JSON.parse(thing);
$('#myModal').modal('show');
$('#modal-important-record').text(thing.name);
});
App Server Code
Browser Code - ONLY RUNS IF IN ROOM
Namespaces Are a Thing, Too.
From http://socket.io/docs/rooms-and-namespaces/
Socket.IO allows you to “namespace” your sockets, which essentially means assigning different endpoints or paths.
var nsp = io.of('/my-namespace');
nsp.on('connection', function(socket){
console.log('someone connected'):
});
nsp.emit('hi', 'everyone!');
var socket = io('http://yoursocketserver.com/my-namespace');
Socket.IO Server Code
Browser/Client Code
Another Demo!
You've got Node and Redis now. Why not use them?
Real-Time Tracking
Browser/Client Code
$(document).on('click', function(){
socket.emit('document::clicked');
});
Socket.IO Server (socket-io-server.js)
var redis = require('redis');
var redisClient = redis.createClient();
...
io.on('connection', function(socket){
socket.on('document::clicked', function(){
redisClient.incr('analytics::counter', function(err,reply){
redisClient.get('analytics::counter',function(err,reply){
io.emit('Analytics::counter',reply);
});
});
});
});
Other Things to Ponder
-
Running the Node Process
Normal Linux stuff. Or PM2 module.
-
Scaling
Scaling solution also uses Redis adapter. Convenient!
-
Security
Share session data. Use passwords. More things.
Risks
- Shoot-Self-In-Foot Risk
- Open Source (Support)
- Just hit 1.0
- Windows
Still, better than:
- Long/Short Polling
- Platform Specific RT Solution
- Server Sent Events (SSE)
- Nothing
What is Socket.IO, Really?
-
Engine.IO
-
WebSocket Transport, low-level client & parser
-
-
Socket.IO
- Fallback Transports
- Marshall/API for other modules & functionality
-
Adapters (registry of rooms, users, namespaces)
- In-Memory
- Redis
- Clients
- Parsers
Resources
-
GitHub
- https://github.com/Automattic/socket.io/wiki
- https://github.com/Automattic/socket.io-protocol
- http://socket.io
-
The Internet
- Socket.IO For Backend Developers - Hadrain de Oliveira
-
What's New In Socket.IO 1.0 - Juriy Bura
-
7 Principles of Rich Web Applications - Guillermo Rauch
https://slides.com/eterps/time-for-real-time