Top Banner
Building Real-Time Apps with EmberJS & WebSockets
98

Building Realtime Apps with Ember.js and WebSockets

Jan 14, 2017

Download

Technology

Ben Limmer
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Building Realtime Apps with Ember.js and WebSockets

Building Real-Time Apps with EmberJS & WebSockets

Page 2: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

" blimmer

Page 3: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerEmberJS Meetup - 2/24/2016 ! ember.party

Page 4: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

Talk Roadmap

• WebSockets vs. AJAX

• Fundamentals of WebSockets

• Code!

• Other Considerations

Page 5: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

request

response

request

response

AJAX

Page 6: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

with a lot of apps, this paradigm still works

Page 7: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

but what about real-time apps?

Page 8: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

e.g.

Page 9: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

live dashboards

Page 10: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

Source: http://www.heckyl.com/

Page 11: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

2nd screen apps

Page 12: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party© MLB / Source: MLB.com

Page 13: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

deployment notifications

Page 14: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

Source: inbox.google.com

Page 15: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

games

Page 16: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

Source: http://browserquest.mozilla.org/img/common/promo-title.jpg

Page 17: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

chat

gamesdeployment notifications

live dashboards

2nd screen apps

activity streams

comment sections

realtime progresscollaborative

editing

Page 18: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

how do we build a real-time app?

Page 19: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

update?

nope.

(old way) short polling

update?

nope.

dataupdate?

yep!

Page 20: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

(old way) long polling

requestKeep-Alive

timeout

requestKeep-Alive

data

response

requestKeep-Alive

Page 21: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

WebSockets

handshake

connection ope

ned

bi-directionalcommunication

Page 22: Building Realtime Apps with Ember.js and WebSockets

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

Page 23: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

Talk Roadmap

• WebSockets vs. AJAX

• Fundamentals of WebSockets

• Code!

• Other Considerations

Page 24: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

the handshake

Page 25: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

RequestGET 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

ResponseHTTP/1.1 101 Switching Protocols Connection: Upgrade Sec-WebSocket-Accept: EDJa7WCAQQzMCYNJM42Syuo9SqQ= Upgrade: websocket

Page 26: Building Realtime Apps with Ember.js and WebSockets

events• open • message • error • close

• send • close

methods

Page 27: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

WebSocket.send()

Page 28: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

send(String 'foo');

send(Blob 010101);

send(ArrayBuffer file);

Page 29: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

WebSocket.send(’YOLO’);

Page 30: Building Realtime Apps with Ember.js and WebSockets

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

Page 31: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

Request with ProtocolGET 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

Page 32: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

STOMPSENDdestination:/queue/a

hello queue a^@

MESSAGEdestination:/queue/amessage-id: <message-identifier>

hello queue a^@

Page 33: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

STOMP

SENDdestination:/queue/a

hello queue a^@

Page 34: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

subprotocols bring structure to ws

Page 35: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

Talk Roadmap

• AJAX vs. WebSockets

• Fundamentals of WebSockets

• Code!

• Other Considerations

Page 36: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

let’s build something!

Page 37: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

Page 38: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerEmberJS Meetup - 2/24/2016 ! ember.party

alice clicks

bob / everyone sees

Page 39: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerEmberJS Meetup - 2/24/2016 ! ember.party

bob clicks

alice / everyone sees

Page 40: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

npm install ws

Page 41: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

Page 42: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

• fast

• simple WebSocket implementation

• few bells and whistles

npm install ws

Page 43: Building Realtime Apps with Ember.js and WebSockets

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 });

Page 44: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

waiting for socket connection…

Page 45: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

ember install ember-websockets

Page 46: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

Page 47: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

ember install ember-websockets

• integrates with the Ember runloop

• is an Ember.ObjectProxy

• abstracts away the WebSocket

Page 48: Building Realtime Apps with Ember.js and WebSockets

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 },

Page 49: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

Page 50: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

rtember-1.0 - sub-protocol

Page 51: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

rtember-1.0 - sub-protocol

data events

Page 52: Building Realtime Apps with Ember.js and WebSockets

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 });

Page 53: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

Page 54: Building Realtime Apps with Ember.js and WebSockets

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 },

Page 55: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

Page 56: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

rtember-1.0 - sub-protocol

data events

Page 57: Building Realtime Apps with Ember.js and WebSockets

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

Page 58: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

rtember-1.0 - sub-protocol

data events

Page 59: Building Realtime Apps with Ember.js and WebSockets

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 }

Page 60: Building Realtime Apps with Ember.js and WebSockets

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 }

Page 61: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

Page 62: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

{ "frameType": "data", "payload": { "data": [{ "type": "gif", "id": "3o8doPV2heuYjdN2Fy", "attributes": { "url": "http://giphy.com/3o8doPV2heuYjdN2Fy/giphy.gif" } }, { ... }, { ... }] }}

Page 63: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

Page 64: Building Realtime Apps with Ember.js and WebSockets

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 });

Page 65: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

Page 66: Building Realtime Apps with Ember.js and WebSockets

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>

Page 67: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

Page 68: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

Page 69: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

rtember-1.0 - sub-protocol

data events

Page 70: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

rtember-1.0 - sub-protocol

{ "frameType": "event", "payload": { “eventType": ... event type ..., "eventInfo": ... event info ... }}

Page 71: Building Realtime Apps with Ember.js and WebSockets

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> ]}}

Page 72: Building Realtime Apps with Ember.js and WebSockets

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 } } ] }}

Page 73: Building Realtime Apps with Ember.js and WebSockets

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 });

Page 74: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

5 this.get('rtEmberSocket') 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 }

Page 75: Building Realtime Apps with Ember.js and WebSockets

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 });

Page 76: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

beware

Page 77: Building Realtime Apps with Ember.js and WebSockets

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 });

Page 78: Building Realtime Apps with Ember.js and WebSockets

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 } } ] }}

Page 79: Building Realtime Apps with Ember.js and WebSockets

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('[email protected]', function() { 3 return this.get('gifs').findBy('shared', true); 4 }), 5 });

<div class='shared-gif'> <img src={{sharedGif.url}} /></div>

<div class='suggestions'> <!-- ... --></div>

Page 80: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

Page 81: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

ember.party/gemconf

Page 82: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

Page 83: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

Talk Roadmap

• AJAX vs. WebSockets

• Fundamentals of WebSockets

• Code!

• Other Considerations

Page 84: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

other considerations

• security

• websocket support (libraries)

• learn from example

Page 85: Building Realtime Apps with Ember.js and WebSockets

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

Page 86: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

other considerations

• security

• websocket support (libraries)

• learn from example

Page 87: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

support

Page 88: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

9

Page 89: Building Realtime Apps with Ember.js and WebSockets

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

Page 90: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

Page 91: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

pusher.com

• Graceful fallback

• Presence support

• Authentication / Security strategies

• No infrastructure required

Page 92: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

other considerations

• security

• websocket support (libraries)

• learn from example

Page 93: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

learn by example

Page 94: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

learn by example

Page 95: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

https://github.com/blimmer/real-time-ember-clienthttps://github.com/blimmer/real-time-ember-server

# l1m5" blimmer

Page 96: Building Realtime Apps with Ember.js and WebSockets

Ben LimmerGEMConf - 5/21/2016 ! ember.party

thanks!

Page 97: Building Realtime Apps with Ember.js and WebSockets

• WebSocket: Lightweight Client-Server Communications (O’Reilly)

• WebSockets: Methods for Real-Time Data Streaming (Steve Schwartz)

Credits

Page 98: Building Realtime Apps with Ember.js and WebSockets

• pusher.com

• socket.io

• node ws

• websocket security (heroku)

Resources