98
Building Real-Time Apps with EmberJS & WebSockets

Building Realtime Apps with Ember.js and WebSockets

Embed Size (px)

Citation preview

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