SlideShare a Scribd company logo
Building Real-Time Apps with
EmberJS & WebSockets
Ben LimmerGEMConf - 5/21/2016 ember.party
blimmer
Ben LimmerEmberJS Meetup - 2/24/2016 ember.party
♥
Ben LimmerGEMConf - 5/21/2016 ember.party
Talk Roadmap
• WebSockets vs. AJAX
• Fundamentals of WebSockets
• Code!
• Other Considerations
Ben LimmerGEMConf - 5/21/2016 ember.party
request
response
request
response
AJAX
Ben LimmerGEMConf - 5/21/2016 ember.party
with a lot of apps, this
paradigm still works
Ben LimmerGEMConf - 5/21/2016 ember.party
but what about
real-time apps?
Ben LimmerGEMConf - 5/21/2016 ember.party
e.g.
Ben LimmerGEMConf - 5/21/2016 ember.party
live dashboards
Ben LimmerGEMConf - 5/21/2016 ember.party
Source: http://www.heckyl.com/
Ben LimmerGEMConf - 5/21/2016 ember.party
2nd screen apps
Ben LimmerGEMConf - 5/21/2016 ember.party© MLB / Source: MLB.com
Ben LimmerGEMConf - 5/21/2016 ember.party
deployment
notifications
Ben LimmerGEMConf - 5/21/2016 ember.party
Source: inbox.google.com
Ben LimmerGEMConf - 5/21/2016 ember.party
games
Ben LimmerGEMConf - 5/21/2016 ember.party
Source: http://browserquest.mozilla.org/img/common/promo-title.jpg
Ben LimmerGEMConf - 5/21/2016 ember.party
chat
gamesdeployment
notifications
live dashboards
2nd screen
apps
activity
streams
comment
sections
realtime
progress
collaborative
editing
Ben LimmerGEMConf - 5/21/2016 ember.party
how do we build a
real-time app?
Ben LimmerGEMConf - 5/21/2016 ember.party
update?
nope.
(old way)
short polling
update?
nope.
data
update?
yep!
Ben LimmerGEMConf - 5/21/2016 ember.party
(old way)
long polling
request
Keep-Alive
timeout
request
Keep-Alive
data
response
request
Keep-Alive
Ben LimmerGEMConf - 5/21/2016 ember.party
WebSockets
handshake
connection opened
bi-directional
communication
Ben LimmerGEMConf - 5/21/2016 ember.party
WebSockets
no polling
full duplex over TCP
communication over
standard HTTP(S) ports
broadcast to all
connected clients
Ben LimmerGEMConf - 5/21/2016 ember.party
Talk Roadmap
• WebSockets vs. AJAX
• Fundamentals of WebSockets
• Code!
• Other Considerations
Ben LimmerGEMConf - 5/21/2016 ember.party
the handshake
Ben LimmerGEMConf - 5/21/2016 ember.party
Request
GET wss://example.org/socket HTTP/1.1
Origin: https://example.org
Host: example.org
Sec-WebSocket-Key: zy6Dy9mSAIM7GJZNf9rI1A==
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Version: 13
Response
HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Sec-WebSocket-Accept: EDJa7WCAQQzMCYNJM42Syuo9SqQ=
Upgrade: websocket
events
• open
• message
• error
• close
• send
• close
methods
Ben LimmerGEMConf - 5/21/2016 ember.party
WebSocket.send()
Ben LimmerGEMConf - 5/21/2016 ember.party
send(String 'foo');
send(Blob 010101);
send(ArrayBuffer file);
Ben LimmerGEMConf - 5/21/2016 ember.party
WebSocket.send(’YOLO’);
Ben LimmerGEMConf - 5/21/2016 ember.party
sub-protocols
• a contract between client/server
• 2 classes of sub-protocols
• well-defined (e.g. STOMP, WAMP)
• application specific protocols
Ben LimmerGEMConf - 5/21/2016 ember.party
Request with Protocol
GET wss://example.org/socket HTTP/1.1
Origin: https://example.org
Host: example.org
Sec-WebSocket-Key: zy6Dy9mSAIM7GJZNf9rI1A==
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Version: 13
Sec-WebSocket-Protocol: v10.stomp
Ben LimmerGEMConf - 5/21/2016 ember.party
STOMP
SEND
destination:/queue/a
hello queue a
^@
MESSAGE
destination:/queue/a
message-id: <message-identifier>
hello queue a
^@
Ben LimmerGEMConf - 5/21/2016 ember.party
STOMP
SEND
destination:/queue/a
hello queue a
^@
Ben LimmerGEMConf - 5/21/2016 ember.party
subprotocols bring
structure to ws
Ben LimmerGEMConf - 5/21/2016 ember.party
Talk Roadmap
• AJAX vs. WebSockets
• Fundamentals of WebSockets
• Code!
• Other Considerations
Ben LimmerGEMConf - 5/21/2016 ember.party
let’s build something!
Ben LimmerGEMConf - 5/21/2016 ember.party
Ben LimmerEmberJS Meetup - 2/24/2016 ember.party
alice clicks
bob / everyone
sees
Ben LimmerEmberJS Meetup - 2/24/2016 ember.party
bob clicks
alice / everyone
sees
Ben LimmerGEMConf - 5/21/2016 ember.party
npm install ws
Ben LimmerGEMConf - 5/21/2016 ember.party
Ben LimmerGEMConf - 5/21/2016 ember.party
• fast
• simple WebSocket implementation
• few bells and whistles
npm install ws
Ben LimmerGEMConf - 5/21/2016 ember.party
server/index.js
1 const WebSocketServer = require('ws').Server;
2
3 const wss = new WebSocketServer({
4 port: process.env.PORT
5 });
Ben LimmerGEMConf - 5/21/2016 ember.party
waiting for socket
connection…
Ben LimmerGEMConf - 5/21/2016 ember.party
ember install ember-websockets
Ben LimmerGEMConf - 5/21/2016 ember.party
Ben LimmerGEMConf - 5/21/2016 ember.party
ember install ember-websockets
• integrates with the Ember runloop
• is an Ember.ObjectProxy
• abstracts away the WebSocket
Ben LimmerGEMConf - 5/21/2016 ember.party
app/services/rt-ember-socket.js
1 websockets: service(),
2
3 init() {
4 this._super(...arguments);
5
6 const socket = this.get('websockets').socketFor(host);
7
8 socket.on('open', this.open, this);
9 socket.on('close', this.reconnect, this);
10 },
11
12 online: false,
13 open() {
14 this.set('online', true);
15 },
16
17 reconnect() {
18 this.set('online', false);
19
20 Ember.run.later(this, () => {
21 this.get('socket').reconnect();
22 }, 5000);
23 },
Ben LimmerGEMConf - 5/21/2016 ember.party
Ben LimmerGEMConf - 5/21/2016 ember.party
rtember-1.0 - sub-protocol
Ben LimmerGEMConf - 5/21/2016 ember.party
rtember-1.0 - sub-protocol
data events
Ben LimmerGEMConf - 5/21/2016 ember.party
server/index.js
1 const WebSocketServer = require('ws').Server;
2
3 const wss = new WebSocketServer({
4 port: process.env.PORT,
5 handleProtocols: function(protocol, cb) {
6 const supportedProtocol =
7 protocol[protocol.indexOf('rtember-1.0')];
8 if (supportedProtocol) {
9 cb(true, supportedProtocol);
10 } else {
11 cb(false);
12 }
13 },
14 });
Ben LimmerGEMConf - 5/21/2016 ember.party
Ben LimmerGEMConf - 5/21/2016 ember.party
app/services/rt-ember-socket.js
1 websockets: Ember.inject.service(),
2
3 socket: null,
4 init() {
5 this._super(...arguments);
6
7 const socket = this.get('websockets')
8 .socketFor(host, ['rtember-1.0']);
9
10 socket.on('open', this.open, this);
11 socket.on('close', this.reconnect, this);
12
13 this.set('socket', socket);
14 },
Ben LimmerGEMConf - 5/21/2016 ember.party
Ben LimmerGEMConf - 5/21/2016 ember.party
rtember-1.0 - sub-protocol
data events
Ben LimmerGEMConf - 5/21/2016 ember.party
rtember-1.0 - sub-protocol
{
"frameType": "event",
"payload": {
“eventType": ... event type ...,
"eventInfo": ... event info ...
}
}
{
"frameType": "data",
"payload": {
... json api payload ...
}
}
or
Ben LimmerGEMConf - 5/21/2016 ember.party
rtember-1.0 - sub-protocol
data events
Ben LimmerGEMConf - 5/21/2016 ember.party
1 wss.on('connection', function(ws) {
2 sendInitialGifs(ws);
3 });
4
5 function sendInitialGifs(ws) {
6 const gifs = gifDb;
7 const random = _.sampleSize(gifs, 25);
8
9 sendDataToClient(ws, serializeGifs(random));
10 }
11
12 function sendDataToClient(ws, payload) {
13 const payload = {
14 frameType: FRAME_TYPES.DATA,
15 payload,
16 }
17 ws.send(JSON.stringify(payload));
18 }
Ben LimmerGEMConf - 5/21/2016 ember.party
app/services/rt-ember-socket.js
1 init() {
2 ...
3 socket.on('message', this.handleMessage, this);
4 ...
5 },
6
7 handleMessage(msg) {
8 const { frameType, payload } = JSON.parse(msg.data);
9
10 if (frameType === FRAME_TYPES.DATA) {
11 this.handleData(payload);
12 } else {
13 warn(`Encountered unknown frame type: ${frameType}`);
14 }
15 },
16
17 handleData(payload) {
18 this.get('store').pushPayload(payload);
19 }
Ben LimmerGEMConf - 5/21/2016 ember.party
Ben LimmerGEMConf - 5/21/2016 ember.party
{
"frameType": "data",
"payload": {
"data": [{
"type": "gif",
"id": "3o8doPV2heuYjdN2Fy",
"attributes": {
"url": "http://giphy.com/3o8doPV2heuYjdN2Fy/giphy.gif"
}
}, { ... }, { ... }]
}
}
Ben LimmerGEMConf - 5/21/2016 ember.party
Ben LimmerGEMConf - 5/21/2016 ember.party
app/routes/index.js
1 export default Ember.Route.extend({
2 model() {
3 return this.store.peekAll('gif');
4 }
5 });
Ben LimmerGEMConf - 5/21/2016 ember.party
Ben LimmerGEMConf - 5/21/2016 ember.party
app/templates/index.hbs
{{gif-tv gifs=model}}
app/templates/components/gif-tv.hbs
<div class='suggestions'>
{{#each gifs as |gif|}}
<img src={{gif.url}} />
{{/each}}
</div>
Ben LimmerGEMConf - 5/21/2016 ember.party
Ben LimmerGEMConf - 5/21/2016 ember.party
Ben LimmerGEMConf - 5/21/2016 ember.party
rtember-1.0 - sub-protocol
data events
Ben LimmerGEMConf - 5/21/2016 ember.party
rtember-1.0 - sub-protocol
{
"frameType": "event",
"payload": {
“eventType": ... event type ...,
"eventInfo": ... event info ...
}
}
Ben LimmerGEMConf - 5/21/2016 ember.party
Share GIF Event
{
"frameType": "event",
"payload": {
"eventType": "share_gif",
"eventInfo": "<gif_id>"
}
}
{
"frameType": "data",
"payload": {[
<shared_gif>,
<previously_shared_gif>
]}
}
Ben LimmerGEMConf - 5/21/2016 ember.party
{
"frameType": "data",
"payload": {
"data": [
{
"type": "gifs",
"id": "3o8doPV2heuYjdN2Fy",
"attributes": {
"url": "http://giphy.com/3o8doPV2heuYjdN2Fy/giphy.gif",
"shared": false
}
},
{
"type": "gifs",
"id": "xTiQyBOIQe5cgiyUPS",
"attributes": {
"url": "http://giphy.com/xTiQyBOIQe5cgiyUPS/giphy.gif",
"shared": true
}
}
]
}
}
Ben LimmerGEMConf - 5/21/2016 ember.party
app/templates/components/gif-tv.hbs
<div class='suggestions'>
{{#each gifs as |gif|}}
<img {{action shareGif gif}} src={{gif.url}} />
{{/each}}
</div>
app/components/gif-tv.js
1 export default Ember.Component.extend({
2 rtEmberSocket: service(),
3
4 shareGif(gif) {
5 this.get('rtEmberSocket')
6 .sendEvent(EVENTS.SHARE_GIF, gif.get('id'));
7 },
8 });
Ben LimmerGEMConf - 5/21/2016 ember.party
6 .sendEvent(EVENTS.SHARE_GIF, gif.get('id'));
7 },
8 });
app/services/rt-ember-socket.js
1 sendEvent(eventType, eventInfo) {
2 this.get('socket').send(JSON.stringify({
3 frameType: FRAME_TYPES.EVENT,
4 payload: {
5 eventType,
6 eventInfo,
7 },
8 }));
9 }
Ben LimmerEmberJS Meetup - 2/24/2016 ember.party
1 ws.on('message', function(rawData) {
2 const data = JSON.parse(rawData);
3
4 if (data.frameType === FRAME_TYPES.EVENT) {
5 const newShare = _.find(gifDb, {
6 id: data.payload.eventInfo
7 });
8 const previouslyShared = _.find(gifDb, 'shared');
9
10 newShare.shared = true;
11 previouslyShared.shared = false;
12
13 const framePayload = {
14 frameType: FRAME_TYPES.DATA,
15 payload: serializeGifs([previouslyShared, newShare]),
16 };
17 const rawPayload = JSON.stringify(framePayload);
18 wss.clients.forEach((client) => {
19 client.send(rawPayload);
20 });
21 }
22 });
Ben LimmerGEMConf - 5/21/2016 ember.party
beware
Ben LimmerGEMConf - 5/21/2016 ember.party
1 ws.on('message', function(rawData) {
2 try {
3 const data = JSON.parse(rawData);
4
5 if (data.frameType === FRAME_TYPES.EVENT) {
6 if (data.payload.eventType !== EVENTS.SHARE_GIF) {
7 throw Error(); // unknown event
8 }
9
10 const newShare = ...;
11 if (!newShare) {
12 throw Error(); // unknown gif
13 }
14 ...
15 }
16 } catch(e) {
17 ws.close(1003); // unsupported data
18 }
19 });
Ben LimmerGEMConf - 5/21/2016 ember.party
{
"frameType": "data",
"payload": {
"data": [
{
"type": "gifs",
"id": "3o8doPV2heuYjdN2Fy",
"attributes": {
"url": "http://giphy.com/3o8doPV2heuYjdN2Fy/giphy.gif",
"shared": false
}
},
{
"type": "gifs",
"id": "xTiQyBOIQe5cgiyUPS",
"attributes": {
"url": "http://giphy.com/xTiQyBOIQe5cgiyUPS/giphy.gif",
"shared": true
}
}
]
}
}
Ben LimmerGEMConf - 5/21/2016 ember.party
app/templates/components/gif-tv.hbs
app/components/gif-tv.js
1 export default Ember.Component.extend({
2 sharedGif: computed('gifs.@each.shared', function() {
3 return this.get('gifs').findBy('shared', true);
4 }),
5 });
<div class='shared-gif'>
<img src={{sharedGif.url}} />
</div>
<div class='suggestions'>
<!-- ... -->
</div>
Ben LimmerGEMConf - 5/21/2016 ember.party
Ben LimmerGEMConf - 5/21/2016 ember.party
ember.party/gemconf
Ben LimmerGEMConf - 5/21/2016 ember.party
Ben LimmerGEMConf - 5/21/2016 ember.party
Talk Roadmap
• AJAX vs. WebSockets
• Fundamentals of WebSockets
• Code!
• Other Considerations
Ben LimmerGEMConf - 5/21/2016 ember.party
other considerations
• security
• websocket support (libraries)
• learn from example
Ben LimmerGEMConf - 5/21/2016 ember.party
security
• Use TLS (wss:// vs. ws://)
• Verify the Origin header
• Verify the request by using a random token on
handshake
source: WebSocket (Andrew Lombardi) - O’Reilly
Ben LimmerGEMConf - 5/21/2016 ember.party
other considerations
• security
• websocket support (libraries)
• learn from example
Ben LimmerGEMConf - 5/21/2016 ember.party
support
Ben LimmerGEMConf - 5/21/2016 ember.party
9
Ben LimmerGEMConf - 5/21/2016 ember.party
socket.io
• Graceful fallback to polling / flash (!)
• Syntactic Sugar vs. ws package
• Support in ember-websockets add-on
Ben LimmerGEMConf - 5/21/2016 ember.party
Ben LimmerGEMConf - 5/21/2016 ember.party
pusher.com
• Graceful fallback
• Presence support
• Authentication / Security strategies
• No infrastructure required
Ben LimmerGEMConf - 5/21/2016 ember.party
other considerations
• security
• websocket support (libraries)
• learn from example
Ben LimmerGEMConf - 5/21/2016 ember.party
learn by example
Ben LimmerGEMConf - 5/21/2016 ember.party
learn by example
Ben LimmerGEMConf - 5/21/2016 ember.party
https://github.com/blimmer/real-time-ember-client
https://github.com/blimmer/real-time-ember-server
l1m5blimmer
Ben LimmerGEMConf - 5/21/2016 ember.party
thanks!
• WebSocket: Lightweight Client-Server
Communications (O’Reilly)
• WebSockets: Methods for Real-Time Data
Streaming (Steve Schwartz)
Credits
• pusher.com
• socket.io
• node ws
• websocket security (heroku)
Resources

More Related Content

PDF
Building a Single Page Application using Ember.js ... for fun and profit
PPTX
Real-Time Web applications with WebSockets
PDF
CouchDB Google
PDF
Performance Improvements in Browsers
PDF
Going Live! with Comet
PDF
Release with confidence
PDF
Time for Comet?
PDF
SDPHP - Percona Toolkit (It's Basically Magic)
Building a Single Page Application using Ember.js ... for fun and profit
Real-Time Web applications with WebSockets
CouchDB Google
Performance Improvements in Browsers
Going Live! with Comet
Release with confidence
Time for Comet?
SDPHP - Percona Toolkit (It's Basically Magic)

What's hot (20)

PPT
Real Time Event Dispatcher
KEY
Intro to PSGI and Plack
PPTX
Ruby in the Browser - RubyConf 2011
PPTX
Ruby C10K: High Performance Networking - RubyKaigi '09
KEY
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
KEY
Plack - LPW 2009
PDF
Seven Reasons for Code Bloat
PDF
Unity and WebSockets
PDF
Strangers In The Night: Ruby, Rack y Sinatra - Herramientas potentes para con...
PDF
Building a desktop app with HTTP::Engine, SQLite and jQuery
PPT
Web::Scraper
PDF
plumbing for the next web
PPTX
Nahlédněte za oponu VersionPressu
PPTX
No callbacks, No Threads - Cooperative web servers in Ruby 1.9
KEY
Plack at YAPC::NA 2010
PPT
Html5, css3, canvas, svg and webgl
PPTX
Real-time Ruby for the Real-time Web
PDF
WPDay Bologna 2013
PPTX
0-60 with Goliath: Building High Performance Ruby Web-Services
PDF
Ruby HTTP clients comparison
Real Time Event Dispatcher
Intro to PSGI and Plack
Ruby in the Browser - RubyConf 2011
Ruby C10K: High Performance Networking - RubyKaigi '09
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Plack - LPW 2009
Seven Reasons for Code Bloat
Unity and WebSockets
Strangers In The Night: Ruby, Rack y Sinatra - Herramientas potentes para con...
Building a desktop app with HTTP::Engine, SQLite and jQuery
Web::Scraper
plumbing for the next web
Nahlédněte za oponu VersionPressu
No callbacks, No Threads - Cooperative web servers in Ruby 1.9
Plack at YAPC::NA 2010
Html5, css3, canvas, svg and webgl
Real-time Ruby for the Real-time Web
WPDay Bologna 2013
0-60 with Goliath: Building High Performance Ruby Web-Services
Ruby HTTP clients comparison
Ad

Viewers also liked (9)

PPTX
Ember and WebSockets
PDF
Building Real-Time Applications in Ember.js
PDF
Ember js meetup treviso liquid-fire
PDF
HTML5 Websockets and Java - Arun Gupta
PDF
Real-Time Web Apps in 2015 & Beyond
PDF
Ember.js internals backburner.js and rsvp.js
PDF
Parse Apps with Ember.js
PPT
Facebook UI Evolution
PDF
Introduction to WAMP, a protocol enabling PUB/SUB and RPC over Websocket
Ember and WebSockets
Building Real-Time Applications in Ember.js
Ember js meetup treviso liquid-fire
HTML5 Websockets and Java - Arun Gupta
Real-Time Web Apps in 2015 & Beyond
Ember.js internals backburner.js and rsvp.js
Parse Apps with Ember.js
Facebook UI Evolution
Introduction to WAMP, a protocol enabling PUB/SUB and RPC over Websocket
Ad

Similar to Building Realtime Apps with Ember.js and WebSockets (20)

PDF
Hitchhiker's guide to the front end development
PPTX
Top-5-production-devconMunich-2023.pptx
PDF
The curious case of misrendered JSON
PPTX
Top-5-Performance-JaxLondon-2023.pptx
PDF
Socket.io
PDF
WPE WebKit for Android
PDF
스트리밍과 디지털 권리 관리
PPT
WebSocket JSON Hackday
PDF
itjsbagg410
KEY
The HTML5 WebSocket API
PDF
Comet from JavaOne 2008
PDF
Bfg Ploneconf Oct2008
PDF
Analyzing the Performance of Mobile Web
PDF
IE 8 et les standards du Web - Chris Wilson - Paris Web 2008
PDF
Web Leaps Forward
PPTX
Consuming GRIN GLOBAL Webservices
PDF
WebRTC: A front-end perspective
PDF
"Hidden difficulties of debugger implementation for .NET WASM apps", Andrii R...
PDF
Python, WebRTC and You (v2)
PDF
08 ajax
Hitchhiker's guide to the front end development
Top-5-production-devconMunich-2023.pptx
The curious case of misrendered JSON
Top-5-Performance-JaxLondon-2023.pptx
Socket.io
WPE WebKit for Android
스트리밍과 디지털 권리 관리
WebSocket JSON Hackday
itjsbagg410
The HTML5 WebSocket API
Comet from JavaOne 2008
Bfg Ploneconf Oct2008
Analyzing the Performance of Mobile Web
IE 8 et les standards du Web - Chris Wilson - Paris Web 2008
Web Leaps Forward
Consuming GRIN GLOBAL Webservices
WebRTC: A front-end perspective
"Hidden difficulties of debugger implementation for .NET WASM apps", Andrii R...
Python, WebRTC and You (v2)
08 ajax

More from Ben Limmer (8)

PDF
Tips & Tricks for Being a Successful Tech Lead
PDF
1-Up Your Git Skills
PDF
Maximize your output (sans productivity shame)
PDF
[OLD] Understanding Github PR Merge Options (1up-ing your git skills part 2)
PDF
Upgrading Ember.js Apps
PDF
Fun with Ember 2.x Features
PDF
Automated Testing in EmberJS
PDF
Deploying a Location-Aware Ember Application
Tips & Tricks for Being a Successful Tech Lead
1-Up Your Git Skills
Maximize your output (sans productivity shame)
[OLD] Understanding Github PR Merge Options (1up-ing your git skills part 2)
Upgrading Ember.js Apps
Fun with Ember 2.x Features
Automated Testing in EmberJS
Deploying a Location-Aware Ember Application

Recently uploaded (20)

PPTX
MYSQL Presentation for SQL database connectivity
PDF
Empathic Computing: Creating Shared Understanding
PDF
Modernizing your data center with Dell and AMD
PPTX
A Presentation on Artificial Intelligence
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PPTX
Understanding_Digital_Forensics_Presentation.pptx
PDF
Spectral efficient network and resource selection model in 5G networks
PDF
Machine learning based COVID-19 study performance prediction
PPTX
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PDF
NewMind AI Weekly Chronicles - August'25 Week I
PPTX
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
PDF
Electronic commerce courselecture one. Pdf
PDF
Encapsulation_ Review paper, used for researhc scholars
PDF
Chapter 3 Spatial Domain Image Processing.pdf
PDF
cuic standard and advanced reporting.pdf
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
MYSQL Presentation for SQL database connectivity
Empathic Computing: Creating Shared Understanding
Modernizing your data center with Dell and AMD
A Presentation on Artificial Intelligence
Per capita expenditure prediction using model stacking based on satellite ima...
20250228 LYD VKU AI Blended-Learning.pptx
Advanced methodologies resolving dimensionality complications for autism neur...
Understanding_Digital_Forensics_Presentation.pptx
Spectral efficient network and resource selection model in 5G networks
Machine learning based COVID-19 study performance prediction
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Dropbox Q2 2025 Financial Results & Investor Presentation
NewMind AI Weekly Chronicles - August'25 Week I
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
Electronic commerce courselecture one. Pdf
Encapsulation_ Review paper, used for researhc scholars
Chapter 3 Spatial Domain Image Processing.pdf
cuic standard and advanced reporting.pdf
“AI and Expert System Decision Support & Business Intelligence Systems”

Building Realtime Apps with Ember.js and WebSockets

  • 1. Building Real-Time Apps with EmberJS & WebSockets
  • 2. Ben LimmerGEMConf - 5/21/2016 ember.party blimmer
  • 3. Ben LimmerEmberJS Meetup - 2/24/2016 ember.party ♥
  • 4. Ben LimmerGEMConf - 5/21/2016 ember.party Talk Roadmap • WebSockets vs. AJAX • Fundamentals of WebSockets • Code! • Other Considerations
  • 5. Ben LimmerGEMConf - 5/21/2016 ember.party request response request response AJAX
  • 6. Ben LimmerGEMConf - 5/21/2016 ember.party with a lot of apps, this paradigm still works
  • 7. Ben LimmerGEMConf - 5/21/2016 ember.party but what about real-time apps?
  • 8. Ben LimmerGEMConf - 5/21/2016 ember.party e.g.
  • 9. Ben LimmerGEMConf - 5/21/2016 ember.party live dashboards
  • 10. Ben LimmerGEMConf - 5/21/2016 ember.party Source: http://www.heckyl.com/
  • 11. Ben LimmerGEMConf - 5/21/2016 ember.party 2nd screen apps
  • 12. Ben LimmerGEMConf - 5/21/2016 ember.party© MLB / Source: MLB.com
  • 13. Ben LimmerGEMConf - 5/21/2016 ember.party deployment notifications
  • 14. Ben LimmerGEMConf - 5/21/2016 ember.party Source: inbox.google.com
  • 15. Ben LimmerGEMConf - 5/21/2016 ember.party games
  • 16. Ben LimmerGEMConf - 5/21/2016 ember.party Source: http://browserquest.mozilla.org/img/common/promo-title.jpg
  • 17. Ben LimmerGEMConf - 5/21/2016 ember.party chat gamesdeployment notifications live dashboards 2nd screen apps activity streams comment sections realtime progress collaborative editing
  • 18. Ben LimmerGEMConf - 5/21/2016 ember.party how do we build a real-time app?
  • 19. Ben LimmerGEMConf - 5/21/2016 ember.party update? nope. (old way) short polling update? nope. data update? yep!
  • 20. Ben LimmerGEMConf - 5/21/2016 ember.party (old way) long polling request Keep-Alive timeout request Keep-Alive data response request Keep-Alive
  • 21. Ben LimmerGEMConf - 5/21/2016 ember.party WebSockets handshake connection opened bi-directional communication
  • 22. Ben LimmerGEMConf - 5/21/2016 ember.party WebSockets no polling full duplex over TCP communication over standard HTTP(S) ports broadcast to all connected clients
  • 23. Ben LimmerGEMConf - 5/21/2016 ember.party Talk Roadmap • WebSockets vs. AJAX • Fundamentals of WebSockets • Code! • Other Considerations
  • 24. Ben LimmerGEMConf - 5/21/2016 ember.party the handshake
  • 25. Ben LimmerGEMConf - 5/21/2016 ember.party Request GET wss://example.org/socket HTTP/1.1 Origin: https://example.org Host: example.org Sec-WebSocket-Key: zy6Dy9mSAIM7GJZNf9rI1A== Upgrade: websocket Connection: Upgrade Sec-WebSocket-Version: 13 Response HTTP/1.1 101 Switching Protocols Connection: Upgrade Sec-WebSocket-Accept: EDJa7WCAQQzMCYNJM42Syuo9SqQ= Upgrade: websocket
  • 26. events • open • message • error • close • send • close methods
  • 27. Ben LimmerGEMConf - 5/21/2016 ember.party WebSocket.send()
  • 28. Ben LimmerGEMConf - 5/21/2016 ember.party send(String 'foo'); send(Blob 010101); send(ArrayBuffer file);
  • 29. Ben LimmerGEMConf - 5/21/2016 ember.party WebSocket.send(’YOLO’);
  • 30. Ben LimmerGEMConf - 5/21/2016 ember.party sub-protocols • a contract between client/server • 2 classes of sub-protocols • well-defined (e.g. STOMP, WAMP) • application specific protocols
  • 31. Ben LimmerGEMConf - 5/21/2016 ember.party Request with Protocol GET wss://example.org/socket HTTP/1.1 Origin: https://example.org Host: example.org Sec-WebSocket-Key: zy6Dy9mSAIM7GJZNf9rI1A== Upgrade: websocket Connection: Upgrade Sec-WebSocket-Version: 13 Sec-WebSocket-Protocol: v10.stomp
  • 32. Ben LimmerGEMConf - 5/21/2016 ember.party STOMP SEND destination:/queue/a hello queue a ^@ MESSAGE destination:/queue/a message-id: <message-identifier> hello queue a ^@
  • 33. Ben LimmerGEMConf - 5/21/2016 ember.party STOMP SEND destination:/queue/a hello queue a ^@
  • 34. Ben LimmerGEMConf - 5/21/2016 ember.party subprotocols bring structure to ws
  • 35. Ben LimmerGEMConf - 5/21/2016 ember.party Talk Roadmap • AJAX vs. WebSockets • Fundamentals of WebSockets • Code! • Other Considerations
  • 36. Ben LimmerGEMConf - 5/21/2016 ember.party let’s build something!
  • 37. Ben LimmerGEMConf - 5/21/2016 ember.party
  • 38. Ben LimmerEmberJS Meetup - 2/24/2016 ember.party alice clicks bob / everyone sees
  • 39. Ben LimmerEmberJS Meetup - 2/24/2016 ember.party bob clicks alice / everyone sees
  • 40. Ben LimmerGEMConf - 5/21/2016 ember.party npm install ws
  • 41. Ben LimmerGEMConf - 5/21/2016 ember.party
  • 42. Ben LimmerGEMConf - 5/21/2016 ember.party • fast • simple WebSocket implementation • few bells and whistles npm install ws
  • 43. Ben LimmerGEMConf - 5/21/2016 ember.party server/index.js 1 const WebSocketServer = require('ws').Server; 2 3 const wss = new WebSocketServer({ 4 port: process.env.PORT 5 });
  • 44. Ben LimmerGEMConf - 5/21/2016 ember.party waiting for socket connection…
  • 45. Ben LimmerGEMConf - 5/21/2016 ember.party ember install ember-websockets
  • 46. Ben LimmerGEMConf - 5/21/2016 ember.party
  • 47. Ben LimmerGEMConf - 5/21/2016 ember.party ember install ember-websockets • integrates with the Ember runloop • is an Ember.ObjectProxy • abstracts away the WebSocket
  • 48. Ben LimmerGEMConf - 5/21/2016 ember.party app/services/rt-ember-socket.js 1 websockets: service(), 2 3 init() { 4 this._super(...arguments); 5 6 const socket = this.get('websockets').socketFor(host); 7 8 socket.on('open', this.open, this); 9 socket.on('close', this.reconnect, this); 10 }, 11 12 online: false, 13 open() { 14 this.set('online', true); 15 }, 16 17 reconnect() { 18 this.set('online', false); 19 20 Ember.run.later(this, () => { 21 this.get('socket').reconnect(); 22 }, 5000); 23 },
  • 49. Ben LimmerGEMConf - 5/21/2016 ember.party
  • 50. Ben LimmerGEMConf - 5/21/2016 ember.party rtember-1.0 - sub-protocol
  • 51. Ben LimmerGEMConf - 5/21/2016 ember.party rtember-1.0 - sub-protocol data events
  • 52. Ben LimmerGEMConf - 5/21/2016 ember.party server/index.js 1 const WebSocketServer = require('ws').Server; 2 3 const wss = new WebSocketServer({ 4 port: process.env.PORT, 5 handleProtocols: function(protocol, cb) { 6 const supportedProtocol = 7 protocol[protocol.indexOf('rtember-1.0')]; 8 if (supportedProtocol) { 9 cb(true, supportedProtocol); 10 } else { 11 cb(false); 12 } 13 }, 14 });
  • 53. Ben LimmerGEMConf - 5/21/2016 ember.party
  • 54. Ben LimmerGEMConf - 5/21/2016 ember.party app/services/rt-ember-socket.js 1 websockets: Ember.inject.service(), 2 3 socket: null, 4 init() { 5 this._super(...arguments); 6 7 const socket = this.get('websockets') 8 .socketFor(host, ['rtember-1.0']); 9 10 socket.on('open', this.open, this); 11 socket.on('close', this.reconnect, this); 12 13 this.set('socket', socket); 14 },
  • 55. Ben LimmerGEMConf - 5/21/2016 ember.party
  • 56. Ben LimmerGEMConf - 5/21/2016 ember.party rtember-1.0 - sub-protocol data events
  • 57. Ben LimmerGEMConf - 5/21/2016 ember.party rtember-1.0 - sub-protocol { "frameType": "event", "payload": { “eventType": ... event type ..., "eventInfo": ... event info ... } } { "frameType": "data", "payload": { ... json api payload ... } } or
  • 58. Ben LimmerGEMConf - 5/21/2016 ember.party rtember-1.0 - sub-protocol data events
  • 59. Ben LimmerGEMConf - 5/21/2016 ember.party 1 wss.on('connection', function(ws) { 2 sendInitialGifs(ws); 3 }); 4 5 function sendInitialGifs(ws) { 6 const gifs = gifDb; 7 const random = _.sampleSize(gifs, 25); 8 9 sendDataToClient(ws, serializeGifs(random)); 10 } 11 12 function sendDataToClient(ws, payload) { 13 const payload = { 14 frameType: FRAME_TYPES.DATA, 15 payload, 16 } 17 ws.send(JSON.stringify(payload)); 18 }
  • 60. Ben LimmerGEMConf - 5/21/2016 ember.party app/services/rt-ember-socket.js 1 init() { 2 ... 3 socket.on('message', this.handleMessage, this); 4 ... 5 }, 6 7 handleMessage(msg) { 8 const { frameType, payload } = JSON.parse(msg.data); 9 10 if (frameType === FRAME_TYPES.DATA) { 11 this.handleData(payload); 12 } else { 13 warn(`Encountered unknown frame type: ${frameType}`); 14 } 15 }, 16 17 handleData(payload) { 18 this.get('store').pushPayload(payload); 19 }
  • 61. Ben LimmerGEMConf - 5/21/2016 ember.party
  • 62. Ben LimmerGEMConf - 5/21/2016 ember.party { "frameType": "data", "payload": { "data": [{ "type": "gif", "id": "3o8doPV2heuYjdN2Fy", "attributes": { "url": "http://giphy.com/3o8doPV2heuYjdN2Fy/giphy.gif" } }, { ... }, { ... }] } }
  • 63. Ben LimmerGEMConf - 5/21/2016 ember.party
  • 64. Ben LimmerGEMConf - 5/21/2016 ember.party app/routes/index.js 1 export default Ember.Route.extend({ 2 model() { 3 return this.store.peekAll('gif'); 4 } 5 });
  • 65. Ben LimmerGEMConf - 5/21/2016 ember.party
  • 66. Ben LimmerGEMConf - 5/21/2016 ember.party app/templates/index.hbs {{gif-tv gifs=model}} app/templates/components/gif-tv.hbs <div class='suggestions'> {{#each gifs as |gif|}} <img src={{gif.url}} /> {{/each}} </div>
  • 67. Ben LimmerGEMConf - 5/21/2016 ember.party
  • 68. Ben LimmerGEMConf - 5/21/2016 ember.party
  • 69. Ben LimmerGEMConf - 5/21/2016 ember.party rtember-1.0 - sub-protocol data events
  • 70. Ben LimmerGEMConf - 5/21/2016 ember.party rtember-1.0 - sub-protocol { "frameType": "event", "payload": { “eventType": ... event type ..., "eventInfo": ... event info ... } }
  • 71. Ben LimmerGEMConf - 5/21/2016 ember.party Share GIF Event { "frameType": "event", "payload": { "eventType": "share_gif", "eventInfo": "<gif_id>" } } { "frameType": "data", "payload": {[ <shared_gif>, <previously_shared_gif> ]} }
  • 72. Ben LimmerGEMConf - 5/21/2016 ember.party { "frameType": "data", "payload": { "data": [ { "type": "gifs", "id": "3o8doPV2heuYjdN2Fy", "attributes": { "url": "http://giphy.com/3o8doPV2heuYjdN2Fy/giphy.gif", "shared": false } }, { "type": "gifs", "id": "xTiQyBOIQe5cgiyUPS", "attributes": { "url": "http://giphy.com/xTiQyBOIQe5cgiyUPS/giphy.gif", "shared": true } } ] } }
  • 73. Ben LimmerGEMConf - 5/21/2016 ember.party app/templates/components/gif-tv.hbs <div class='suggestions'> {{#each gifs as |gif|}} <img {{action shareGif gif}} src={{gif.url}} /> {{/each}} </div> app/components/gif-tv.js 1 export default Ember.Component.extend({ 2 rtEmberSocket: service(), 3 4 shareGif(gif) { 5 this.get('rtEmberSocket') 6 .sendEvent(EVENTS.SHARE_GIF, gif.get('id')); 7 }, 8 });
  • 74. Ben LimmerGEMConf - 5/21/2016 ember.party 6 .sendEvent(EVENTS.SHARE_GIF, gif.get('id')); 7 }, 8 }); app/services/rt-ember-socket.js 1 sendEvent(eventType, eventInfo) { 2 this.get('socket').send(JSON.stringify({ 3 frameType: FRAME_TYPES.EVENT, 4 payload: { 5 eventType, 6 eventInfo, 7 }, 8 })); 9 }
  • 75. Ben LimmerEmberJS Meetup - 2/24/2016 ember.party 1 ws.on('message', function(rawData) { 2 const data = JSON.parse(rawData); 3 4 if (data.frameType === FRAME_TYPES.EVENT) { 5 const newShare = _.find(gifDb, { 6 id: data.payload.eventInfo 7 }); 8 const previouslyShared = _.find(gifDb, 'shared'); 9 10 newShare.shared = true; 11 previouslyShared.shared = false; 12 13 const framePayload = { 14 frameType: FRAME_TYPES.DATA, 15 payload: serializeGifs([previouslyShared, newShare]), 16 }; 17 const rawPayload = JSON.stringify(framePayload); 18 wss.clients.forEach((client) => { 19 client.send(rawPayload); 20 }); 21 } 22 });
  • 76. Ben LimmerGEMConf - 5/21/2016 ember.party beware
  • 77. Ben LimmerGEMConf - 5/21/2016 ember.party 1 ws.on('message', function(rawData) { 2 try { 3 const data = JSON.parse(rawData); 4 5 if (data.frameType === FRAME_TYPES.EVENT) { 6 if (data.payload.eventType !== EVENTS.SHARE_GIF) { 7 throw Error(); // unknown event 8 } 9 10 const newShare = ...; 11 if (!newShare) { 12 throw Error(); // unknown gif 13 } 14 ... 15 } 16 } catch(e) { 17 ws.close(1003); // unsupported data 18 } 19 });
  • 78. Ben LimmerGEMConf - 5/21/2016 ember.party { "frameType": "data", "payload": { "data": [ { "type": "gifs", "id": "3o8doPV2heuYjdN2Fy", "attributes": { "url": "http://giphy.com/3o8doPV2heuYjdN2Fy/giphy.gif", "shared": false } }, { "type": "gifs", "id": "xTiQyBOIQe5cgiyUPS", "attributes": { "url": "http://giphy.com/xTiQyBOIQe5cgiyUPS/giphy.gif", "shared": true } } ] } }
  • 79. Ben LimmerGEMConf - 5/21/2016 ember.party app/templates/components/gif-tv.hbs app/components/gif-tv.js 1 export default Ember.Component.extend({ 2 sharedGif: computed('gifs.@each.shared', function() { 3 return this.get('gifs').findBy('shared', true); 4 }), 5 }); <div class='shared-gif'> <img src={{sharedGif.url}} /> </div> <div class='suggestions'> <!-- ... --> </div>
  • 80. Ben LimmerGEMConf - 5/21/2016 ember.party
  • 81. Ben LimmerGEMConf - 5/21/2016 ember.party ember.party/gemconf
  • 82. Ben LimmerGEMConf - 5/21/2016 ember.party
  • 83. Ben LimmerGEMConf - 5/21/2016 ember.party Talk Roadmap • AJAX vs. WebSockets • Fundamentals of WebSockets • Code! • Other Considerations
  • 84. Ben LimmerGEMConf - 5/21/2016 ember.party other considerations • security • websocket support (libraries) • learn from example
  • 85. Ben LimmerGEMConf - 5/21/2016 ember.party security • Use TLS (wss:// vs. ws://) • Verify the Origin header • Verify the request by using a random token on handshake source: WebSocket (Andrew Lombardi) - O’Reilly
  • 86. Ben LimmerGEMConf - 5/21/2016 ember.party other considerations • security • websocket support (libraries) • learn from example
  • 87. Ben LimmerGEMConf - 5/21/2016 ember.party support
  • 88. Ben LimmerGEMConf - 5/21/2016 ember.party 9
  • 89. Ben LimmerGEMConf - 5/21/2016 ember.party socket.io • Graceful fallback to polling / flash (!) • Syntactic Sugar vs. ws package • Support in ember-websockets add-on
  • 90. Ben LimmerGEMConf - 5/21/2016 ember.party
  • 91. Ben LimmerGEMConf - 5/21/2016 ember.party pusher.com • Graceful fallback • Presence support • Authentication / Security strategies • No infrastructure required
  • 92. Ben LimmerGEMConf - 5/21/2016 ember.party other considerations • security • websocket support (libraries) • learn from example
  • 93. Ben LimmerGEMConf - 5/21/2016 ember.party learn by example
  • 94. Ben LimmerGEMConf - 5/21/2016 ember.party learn by example
  • 95. Ben LimmerGEMConf - 5/21/2016 ember.party https://github.com/blimmer/real-time-ember-client https://github.com/blimmer/real-time-ember-server l1m5blimmer
  • 96. Ben LimmerGEMConf - 5/21/2016 ember.party thanks!
  • 97. • WebSocket: Lightweight Client-Server Communications (O’Reilly) • WebSockets: Methods for Real-Time Data Streaming (Steve Schwartz) Credits
  • 98. • pusher.com • socket.io • node ws • websocket security (heroku) Resources