SlideShare ist ein Scribd-Unternehmen logo
1 von 40
Downloaden Sie, um offline zu lesen
WebSockets in Ruby
(and things you can do with them)
Ismael Celis @ismasan github.com/ismasan
new bamboo
new-bamboo.co.uk pusherapp.com
Polling
Long-polling
Web socket
websockets.org/about.html
HTML5 Web sockets
Use cases
•Chat (lame)
•Stocks (lame but challenging)
•Games
•Presence
•Collaboration
•Real-time notifications
WebSockets DOM API
<script type="text/javascript" charset="utf-8">
// Socket object
var socket = new WebSocket('ws://some.host.com');
// Callbacks
socket.onopen = function (evt) {
alert('Socket connected: ' + evt.data)
};
// Incoming server message
socket.onmessage = function (evt) {
alert( evt.data )
};
socket.onclose = function (evt) {
alert('Connection terminated')
// reconnect, etc.
};
</script>
WebSockets handshake
Request
Response
GET /demo HTTP/1.1
Host: example.com
Connection: Upgrade
Sec-WebSocket-Key2: 12998 5 Y3 1 .P00
Sec-WebSocket-Protocol: sample
Upgrade: WebSocket
Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5
Origin: http://example.com
^n:ds[4U
HTTP/1.1 101 WebSocket Protocol Handshake
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Origin: http://example.com
Sec-WebSocket-Location: ws://example.com/demo
Sec-WebSocket-Protocol: sample
8jKS'y:G*Co,Wxa-
(draft 76)
"x00Hello Worldxff"
Messages
// Incoming server message
socket.onmessage = function (evt) {
alert( evt.data )
};
// Send message to server
socket.send("Hello server, this is a new client");
(Ruby) WebSockets server
•Speak WebSockets (handshake)
•Keep connections alive
•Performant!
•Scalable
•Threads? Evented?
EventMachine rubyeventmachine.com
require 'eventmachine'
module EchoServer
def receive_data(data)
send_data data
end
end
EventMachine::run {
EventMachine::start_server 'localhost', 8080, EchoServer
puts 'running echo server on 8080'
}
EM-WebSocket
github.com/igrigorik/em-websocket
EventMachine.run {
EventMachine::WebSocket.start(:host=>'0.0.0.0',:port=>8080) do |socket|
socket.onopen {
# publish message to the client
socket.send 'Websocket connection open'
}
socket.onmessage {|msg|
# echo message to client
socket.send "Received message: #{msg}"
}
end
}
Multicast - subscribers
...
@channel = Channel.new
...
socket.onopen {
@channel.subscribe socket
}
socket.onmessage { |msg|
@channel.send_message msg
}
socket.onclose {
@channel.unsubscribe socket
}
Multicast - subscribers
# Server
socket.onopen {
@channel.subscribe socket
}
class Channel
def initialize
@sockets = []
end
def subscribe( socket )
@sockets << socket
end
...
end
Multicast - channel
class Channel
...
def subscribe( socket )
@sockets << socket
end
def send_message( msg )
@sockets.each do |socket|
socket.send msg
end
end
def unsubscribe( socket )
@sockets.delete socket
end
end
Multicast - example
var socket = new WebSocket('ws://localhost:8080');
socket.onmessage = function( evt ) {
$('<li>')
.text(evt.data)
.appendTo('#messages');
}
<ul id="messages">
</ul>
HTML
Javascript
Multicast - example
github.com/ismasan/websockets_examples
Pick your protocol
STOMP CONNECT
login: <username>
passcode: <passcode>
<message
from=”john@server.com/ruby”
to=”jane@server.com/ruby”>
<body>Hey Jane!</body>
</message>
XMPP
Your own (JSON?)
Custom message format
JSON
Custom JSON format
{
“event”: “user_connected”,
{
“name” : “Ismael”,
“total_users” : 10
}
}
Event name
Custom data
“data”:
Custom JSON format
{
“event”: “user_message”,
{
“message” : “Hello!”,
“date” : “23 2010 21:12:28”
}
}
“data”:
Javascript wrapper
var socket = new FancyWebSocket('ws://localhost:8080');
...
socket.bind( 'user_connected', function (user_data) {
// Add user to screen
$('#connected_users').append('<li>' + user_data.name + '</li>');
});
socket.bind( 'user_message', function (msg_data) {
// Add message to screen
$('#messages').append('<li>' + msg_data.message + '</li>');
});
// Broadcast message - jQuery example
$('form#user_input').submit(function () {
var msg = $(this).find('input[name=message]').val();
socket.send( 'user_message', {name: 'Ismael', message: msg} );
return false;
});
Javascript wrapper
{
“event” : “user_message”,
{
“name” : “Ismael”,
“message” : “hello!”
}
}
“data” :
Implementation gist.github.com/299789
var FancyWebSocket = function(url){
var conn = new WebSocket(url);
var callbacks = {};
this.bind = function(event_name, callback){
callbacks[event_name] = callbacks[event_name] || [];
callbacks[event_name].push(callback);
};
this.send = function(event_name, event_data){
var payload = JSON.stringify({event:event_name, data: event_data});
conn.send( payload );
};
// dispatch to the right handlers
conn.onmessage = function(evt){
var json = JSON.parse(evt.data)
dispatch(json.event, json.data)
};
conn.onclose = function(){dispatch('close',null)}
conn.onopen = function(){dispatch('open',null)}
var dispatch = function(event_name, message){
var chain = callbacks[event_name];
if(typeof chain == 'undefined') return; // no callbacks for this event
for(var i = 0; i < chain.length; i++){
chain[i]( message )
}
}
};
Implementation gist.github.com/299789
var FancyWebSocket = function(url){
var conn = new WebSocket(url);
var callbacks = {};
this.bind = function(event_name, callback){
callbacks[event_name] = callbacks[event_name] || [];
callbacks[event_name].push(callback);
};
this.send = function(event_name, event_data){
var payload = JSON.stringify({event:event_name, data:
event_data});
conn.send( payload );
};
Ismael Celis
Implementation gist.github.com/299789
var FancyWebSocket = function(url){
var conn = new WebSocket(url);
var callbacks = {};
this.bind = function(event_name, callback){
callbacks[event_name] = callbacks[event_name] || [];
callbacks[event_name].push(callback);
};
this.send = function(event_name, event_data){
var payload = JSON.stringify({event:event_name, data: event_d
conn.send( payload );
};
// dispatch to the right handlers
conn.onmessage = function(evt){
var json = JSON.parse(evt.data)
// dispatch to the right handlers
conn.onmessage = function(evt){
var json = JSON.parse(evt.data)
dispatch(json.event, json.data)
};
conn.onclose = function(){dispatch('close',null)}
conn.onopen = function(){dispatch('open',null)}
var dispatch = function(event_name, message){
var chain = callbacks[event_name];
if(typeof chain == 'undefined') return; // no callbacks
for this event
for(var i = 0; i < chain.length; i++){
chain[i]( message )
}
Implementation
WebSocket
gist.github.com/299789
var FancyWebSocket = function(url){
// dispatch to the right handlers
conn.onmessage = function(evt){
var json = JSON.parse(evt.data)
dispatch(json.event, json.data)
};
conn.onclose = function(){dispatch('close',null)}
conn.onopen = function(){dispatch('open',null)}
var dispatch = function(event_name, message){
var chain = callbacks[event_name];
// no callbacks for this event
if(typeof chain == 'undefined') return;
for(var i = 0; i < chain.length; i++){
chain[i]( message )
}
}
};
Implementation gist.github.com/299789
socket.send( 'user_message', {name: 'Ismael', message: msg} );
Implementation gist.github.com/299789
this.send = function(event_name, event_data){
var payload = JSON.stringify({event:event_name, data: event_data});
conn.send( payload ); // <= send JSON data to socket server
return this;
};
Multicast - JSON data
github.com/ismasan/websockets_examples
Multicast - JSON data
$('#canvas').mousedown(function () {
drawing = true;
})
.mouseup(function () {
drawing = false;
})
.mousemove(function (evt) {
if(drawing) {
var point = [evt.pageX, evt.pageY];
socket.send('mousemove', point);
}
});
Multicast - JSON data
var ctx = document.getElementById
('canvas').getContext('2d');
ctx.lineWidth = 1;
ctx.strokeStyle = '#ffffff';
ctx.beginPath();
ctx.moveTo(0, 0);
// Listen to other user's moves
socket.bind('mousemove', function (point) {
ctx.lineTo(point[0],point[1]);
ctx.stroke();
});
Activity dashboard
Rails Rumble dashboard
Scaling
?
pusherapp.com
pusherapp.com
Your app
REST
Browsers
Websockets
Existing HTTP
pusherapp.com
pusherapp.com
<script src="http://js.pusherapp.com/1.6/pusher.min.js"></script>
<script type="text/javascript" charset="utf-8">
var socket = new Pusher('293d8ae77496e1fc053b');
</script>
pusherapp.com
var socket = new Pusher('293d8ae77496e1fc053b');
// Subscribe to channels
var channel = socket.subscribe( 'test' );
channel.bind( 'new_message', function (data) {
alert( data.message );
})
pusherapp.com
// Subscribe to PRESENCE channel
var chat = socket.subscribe( 'presence-chat' );
// Listen to new members
chat.bind( 'pusher:member_added', function (member) {
alert( member.user_data.name );
})
require 'pusher'
require 'sinatra'
post '/messages' do
message = Message.create(params[:message])
Pusher['presence-chat'].trigger(:new_message, message.attributes)
redirect '/messages'
end
pusherapp.com
$ gem install pusher
pusherapp.com
github.com/
lifo/cramp
ismasan/websockets_examples
newbamboo/rumbledash
blog.new-bamboo.co.uk
blog.pusherapp.com

Weitere ähnliche Inhalte

Was ist angesagt?

The Open Web and what it means
The Open Web and what it meansThe Open Web and what it means
The Open Web and what it means
Robert Nyman
 
Unity and WebSockets
Unity and WebSocketsUnity and WebSockets
Unity and WebSockets
Josh Glover
 
HTML5 & The Open Web - at Nackademin
HTML5 & The Open Web -  at NackademinHTML5 & The Open Web -  at Nackademin
HTML5 & The Open Web - at Nackademin
Robert Nyman
 
JavaScript APIs - The Web is the Platform - MDN Hack Day, Santiago, Chile
JavaScript APIs - The Web is the Platform - MDN Hack Day, Santiago, ChileJavaScript APIs - The Web is the Platform - MDN Hack Day, Santiago, Chile
JavaScript APIs - The Web is the Platform - MDN Hack Day, Santiago, Chile
Robert Nyman
 

Was ist angesagt? (20)

ES6 is Nigh
ES6 is NighES6 is Nigh
ES6 is Nigh
 
Async Frontiers
Async FrontiersAsync Frontiers
Async Frontiers
 
FwDays 2021: Metarhia Technology Stack for Node.js
FwDays 2021: Metarhia Technology Stack for Node.jsFwDays 2021: Metarhia Technology Stack for Node.js
FwDays 2021: Metarhia Technology Stack for Node.js
 
Asynchronous programming done right - Node.js
Asynchronous programming done right - Node.jsAsynchronous programming done right - Node.js
Asynchronous programming done right - Node.js
 
JavaScript on the Desktop
JavaScript on the DesktopJavaScript on the Desktop
JavaScript on the Desktop
 
The promise of asynchronous PHP
The promise of asynchronous PHPThe promise of asynchronous PHP
The promise of asynchronous PHP
 
Future Decoded - Node.js per sviluppatori .NET
Future Decoded - Node.js per sviluppatori .NETFuture Decoded - Node.js per sviluppatori .NET
Future Decoded - Node.js per sviluppatori .NET
 
Avoiding callback hell in Node js using promises
Avoiding callback hell in Node js using promisesAvoiding callback hell in Node js using promises
Avoiding callback hell in Node js using promises
 
The Open Web and what it means
The Open Web and what it meansThe Open Web and what it means
The Open Web and what it means
 
Clojure@Nuday
Clojure@NudayClojure@Nuday
Clojure@Nuday
 
Unity and WebSockets
Unity and WebSocketsUnity and WebSockets
Unity and WebSockets
 
The promise of asynchronous php
The promise of asynchronous phpThe promise of asynchronous php
The promise of asynchronous php
 
Asynchronous Programming FTW! 2 (with AnyEvent)
Asynchronous Programming FTW! 2 (with AnyEvent)Asynchronous Programming FTW! 2 (with AnyEvent)
Asynchronous Programming FTW! 2 (with AnyEvent)
 
HTML5 & The Open Web - at Nackademin
HTML5 & The Open Web -  at NackademinHTML5 & The Open Web -  at Nackademin
HTML5 & The Open Web - at Nackademin
 
Callbacks, promises, generators - asynchronous javascript
Callbacks, promises, generators - asynchronous javascriptCallbacks, promises, generators - asynchronous javascript
Callbacks, promises, generators - asynchronous javascript
 
Bare-knuckle web development
Bare-knuckle web developmentBare-knuckle web development
Bare-knuckle web development
 
Node.js in action
Node.js in actionNode.js in action
Node.js in action
 
"Auth for React.js APP", Nikita Galkin
"Auth for React.js APP", Nikita Galkin"Auth for React.js APP", Nikita Galkin
"Auth for React.js APP", Nikita Galkin
 
React PHP: the NodeJS challenger
React PHP: the NodeJS challengerReact PHP: the NodeJS challenger
React PHP: the NodeJS challenger
 
JavaScript APIs - The Web is the Platform - MDN Hack Day, Santiago, Chile
JavaScript APIs - The Web is the Platform - MDN Hack Day, Santiago, ChileJavaScript APIs - The Web is the Platform - MDN Hack Day, Santiago, Chile
JavaScript APIs - The Web is the Platform - MDN Hack Day, Santiago, Chile
 

Ähnlich wie Websockets talk at Rubyconf Uruguay 2010

Websockets, Ruby y Pusher Webprendedor 2010
Websockets, Ruby y Pusher Webprendedor 2010Websockets, Ruby y Pusher Webprendedor 2010
Websockets, Ruby y Pusher Webprendedor 2010
Ismael Celis
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
Tom Croucher
 
Creating the interfaces of the future with the APIs of today
Creating the interfaces of the future with the APIs of todayCreating the interfaces of the future with the APIs of today
Creating the interfaces of the future with the APIs of today
gerbille
 
HTML5 APIs - Where no man has gone before! - Altran
HTML5 APIs - Where no man has gone before! - AltranHTML5 APIs - Where no man has gone before! - Altran
HTML5 APIs - Where no man has gone before! - Altran
Robert Nyman
 
JavaScript APIs - The Web is the Platform - MDN Hack Day, Sao Paulo
JavaScript APIs - The Web is the Platform - MDN Hack Day, Sao PauloJavaScript APIs - The Web is the Platform - MDN Hack Day, Sao Paulo
JavaScript APIs - The Web is the Platform - MDN Hack Day, Sao Paulo
Robert Nyman
 

Ähnlich wie Websockets talk at Rubyconf Uruguay 2010 (20)

Websockets, Ruby y Pusher Webprendedor 2010
Websockets, Ruby y Pusher Webprendedor 2010Websockets, Ruby y Pusher Webprendedor 2010
Websockets, Ruby y Pusher Webprendedor 2010
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
 
Server Side Events
Server Side EventsServer Side Events
Server Side Events
 
Building interactivity with websockets
Building interactivity with websocketsBuilding interactivity with websockets
Building interactivity with websockets
 
async/await in Swift
async/await in Swiftasync/await in Swift
async/await in Swift
 
[WSO2 Integration Summit Madrid 2019] Integration + Ballerina
[WSO2 Integration Summit Madrid 2019] Integration + Ballerina[WSO2 Integration Summit Madrid 2019] Integration + Ballerina
[WSO2 Integration Summit Madrid 2019] Integration + Ballerina
 
Managing State in React Apps with RxJS by James Wright at FrontCon 2019
Managing State in React Apps with RxJS by James Wright at FrontCon 2019Managing State in React Apps with RxJS by James Wright at FrontCon 2019
Managing State in React Apps with RxJS by James Wright at FrontCon 2019
 
Introduction to Nodejs
Introduction to NodejsIntroduction to Nodejs
Introduction to Nodejs
 
Serverless Ballerina
Serverless BallerinaServerless Ballerina
Serverless Ballerina
 
From Node to Go
From Node to GoFrom Node to Go
From Node to Go
 
Creating the interfaces of the future with the APIs of today
Creating the interfaces of the future with the APIs of todayCreating the interfaces of the future with the APIs of today
Creating the interfaces of the future with the APIs of today
 
NodeJS
NodeJSNodeJS
NodeJS
 
HTML5 APIs - Where no man has gone before! - Altran
HTML5 APIs - Where no man has gone before! - AltranHTML5 APIs - Where no man has gone before! - Altran
HTML5 APIs - Where no man has gone before! - Altran
 
soft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.jssoft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.js
 
Speed up your Web applications with HTML5 WebSockets
Speed up your Web applications with HTML5 WebSocketsSpeed up your Web applications with HTML5 WebSockets
Speed up your Web applications with HTML5 WebSockets
 
Server Side Swift: Vapor
Server Side Swift: VaporServer Side Swift: Vapor
Server Side Swift: Vapor
 
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsBonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
 
JavaScript APIs - The Web is the Platform - MDN Hack Day, Sao Paulo
JavaScript APIs - The Web is the Platform - MDN Hack Day, Sao PauloJavaScript APIs - The Web is the Platform - MDN Hack Day, Sao Paulo
JavaScript APIs - The Web is the Platform - MDN Hack Day, Sao Paulo
 
Introduction to Vert.x
Introduction to Vert.xIntroduction to Vert.x
Introduction to Vert.x
 
jQuery: Events, Animation, Ajax
jQuery: Events, Animation, AjaxjQuery: Events, Animation, Ajax
jQuery: Events, Animation, Ajax
 

Kürzlich hochgeladen

Kürzlich hochgeladen (20)

Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024
 
Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdf
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot ModelNavi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 

Websockets talk at Rubyconf Uruguay 2010

  • 1. WebSockets in Ruby (and things you can do with them) Ismael Celis @ismasan github.com/ismasan new bamboo new-bamboo.co.uk pusherapp.com
  • 3. Use cases •Chat (lame) •Stocks (lame but challenging) •Games •Presence •Collaboration •Real-time notifications
  • 4. WebSockets DOM API <script type="text/javascript" charset="utf-8"> // Socket object var socket = new WebSocket('ws://some.host.com'); // Callbacks socket.onopen = function (evt) { alert('Socket connected: ' + evt.data) }; // Incoming server message socket.onmessage = function (evt) { alert( evt.data ) }; socket.onclose = function (evt) { alert('Connection terminated') // reconnect, etc. }; </script>
  • 5. WebSockets handshake Request Response GET /demo HTTP/1.1 Host: example.com Connection: Upgrade Sec-WebSocket-Key2: 12998 5 Y3 1 .P00 Sec-WebSocket-Protocol: sample Upgrade: WebSocket Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5 Origin: http://example.com ^n:ds[4U HTTP/1.1 101 WebSocket Protocol Handshake Upgrade: WebSocket Connection: Upgrade Sec-WebSocket-Origin: http://example.com Sec-WebSocket-Location: ws://example.com/demo Sec-WebSocket-Protocol: sample 8jKS'y:G*Co,Wxa- (draft 76)
  • 6. "x00Hello Worldxff" Messages // Incoming server message socket.onmessage = function (evt) { alert( evt.data ) }; // Send message to server socket.send("Hello server, this is a new client");
  • 7. (Ruby) WebSockets server •Speak WebSockets (handshake) •Keep connections alive •Performant! •Scalable •Threads? Evented?
  • 8. EventMachine rubyeventmachine.com require 'eventmachine' module EchoServer def receive_data(data) send_data data end end EventMachine::run { EventMachine::start_server 'localhost', 8080, EchoServer puts 'running echo server on 8080' }
  • 9. EM-WebSocket github.com/igrigorik/em-websocket EventMachine.run { EventMachine::WebSocket.start(:host=>'0.0.0.0',:port=>8080) do |socket| socket.onopen { # publish message to the client socket.send 'Websocket connection open' } socket.onmessage {|msg| # echo message to client socket.send "Received message: #{msg}" } end }
  • 10. Multicast - subscribers ... @channel = Channel.new ... socket.onopen { @channel.subscribe socket } socket.onmessage { |msg| @channel.send_message msg } socket.onclose { @channel.unsubscribe socket }
  • 11. Multicast - subscribers # Server socket.onopen { @channel.subscribe socket } class Channel def initialize @sockets = [] end def subscribe( socket ) @sockets << socket end ... end
  • 12. Multicast - channel class Channel ... def subscribe( socket ) @sockets << socket end def send_message( msg ) @sockets.each do |socket| socket.send msg end end def unsubscribe( socket ) @sockets.delete socket end end
  • 13. Multicast - example var socket = new WebSocket('ws://localhost:8080'); socket.onmessage = function( evt ) { $('<li>') .text(evt.data) .appendTo('#messages'); } <ul id="messages"> </ul> HTML Javascript
  • 15. Pick your protocol STOMP CONNECT login: <username> passcode: <passcode> <message from=”john@server.com/ruby” to=”jane@server.com/ruby”> <body>Hey Jane!</body> </message> XMPP Your own (JSON?)
  • 17. Custom JSON format { “event”: “user_connected”, { “name” : “Ismael”, “total_users” : 10 } } Event name Custom data “data”:
  • 18. Custom JSON format { “event”: “user_message”, { “message” : “Hello!”, “date” : “23 2010 21:12:28” } } “data”:
  • 19. Javascript wrapper var socket = new FancyWebSocket('ws://localhost:8080'); ... socket.bind( 'user_connected', function (user_data) { // Add user to screen $('#connected_users').append('<li>' + user_data.name + '</li>'); }); socket.bind( 'user_message', function (msg_data) { // Add message to screen $('#messages').append('<li>' + msg_data.message + '</li>'); });
  • 20. // Broadcast message - jQuery example $('form#user_input').submit(function () { var msg = $(this).find('input[name=message]').val(); socket.send( 'user_message', {name: 'Ismael', message: msg} ); return false; }); Javascript wrapper { “event” : “user_message”, { “name” : “Ismael”, “message” : “hello!” } } “data” :
  • 21. Implementation gist.github.com/299789 var FancyWebSocket = function(url){ var conn = new WebSocket(url); var callbacks = {}; this.bind = function(event_name, callback){ callbacks[event_name] = callbacks[event_name] || []; callbacks[event_name].push(callback); }; this.send = function(event_name, event_data){ var payload = JSON.stringify({event:event_name, data: event_data}); conn.send( payload ); }; // dispatch to the right handlers conn.onmessage = function(evt){ var json = JSON.parse(evt.data) dispatch(json.event, json.data) }; conn.onclose = function(){dispatch('close',null)} conn.onopen = function(){dispatch('open',null)} var dispatch = function(event_name, message){ var chain = callbacks[event_name]; if(typeof chain == 'undefined') return; // no callbacks for this event for(var i = 0; i < chain.length; i++){ chain[i]( message ) } } };
  • 22. Implementation gist.github.com/299789 var FancyWebSocket = function(url){ var conn = new WebSocket(url); var callbacks = {}; this.bind = function(event_name, callback){ callbacks[event_name] = callbacks[event_name] || []; callbacks[event_name].push(callback); }; this.send = function(event_name, event_data){ var payload = JSON.stringify({event:event_name, data: event_data}); conn.send( payload ); };
  • 23. Ismael Celis Implementation gist.github.com/299789 var FancyWebSocket = function(url){ var conn = new WebSocket(url); var callbacks = {}; this.bind = function(event_name, callback){ callbacks[event_name] = callbacks[event_name] || []; callbacks[event_name].push(callback); }; this.send = function(event_name, event_data){ var payload = JSON.stringify({event:event_name, data: event_d conn.send( payload ); }; // dispatch to the right handlers conn.onmessage = function(evt){ var json = JSON.parse(evt.data)
  • 24. // dispatch to the right handlers conn.onmessage = function(evt){ var json = JSON.parse(evt.data) dispatch(json.event, json.data) }; conn.onclose = function(){dispatch('close',null)} conn.onopen = function(){dispatch('open',null)} var dispatch = function(event_name, message){ var chain = callbacks[event_name]; if(typeof chain == 'undefined') return; // no callbacks for this event for(var i = 0; i < chain.length; i++){ chain[i]( message ) } Implementation WebSocket gist.github.com/299789
  • 25. var FancyWebSocket = function(url){ // dispatch to the right handlers conn.onmessage = function(evt){ var json = JSON.parse(evt.data) dispatch(json.event, json.data) }; conn.onclose = function(){dispatch('close',null)} conn.onopen = function(){dispatch('open',null)} var dispatch = function(event_name, message){ var chain = callbacks[event_name]; // no callbacks for this event if(typeof chain == 'undefined') return; for(var i = 0; i < chain.length; i++){ chain[i]( message ) } } }; Implementation gist.github.com/299789
  • 26. socket.send( 'user_message', {name: 'Ismael', message: msg} ); Implementation gist.github.com/299789 this.send = function(event_name, event_data){ var payload = JSON.stringify({event:event_name, data: event_data}); conn.send( payload ); // <= send JSON data to socket server return this; };
  • 27. Multicast - JSON data github.com/ismasan/websockets_examples
  • 28. Multicast - JSON data $('#canvas').mousedown(function () { drawing = true; }) .mouseup(function () { drawing = false; }) .mousemove(function (evt) { if(drawing) { var point = [evt.pageX, evt.pageY]; socket.send('mousemove', point); } });
  • 29. Multicast - JSON data var ctx = document.getElementById ('canvas').getContext('2d'); ctx.lineWidth = 1; ctx.strokeStyle = '#ffffff'; ctx.beginPath(); ctx.moveTo(0, 0); // Listen to other user's moves socket.bind('mousemove', function (point) { ctx.lineTo(point[0],point[1]); ctx.stroke(); });
  • 36. pusherapp.com <script src="http://js.pusherapp.com/1.6/pusher.min.js"></script> <script type="text/javascript" charset="utf-8"> var socket = new Pusher('293d8ae77496e1fc053b'); </script>
  • 37. pusherapp.com var socket = new Pusher('293d8ae77496e1fc053b'); // Subscribe to channels var channel = socket.subscribe( 'test' ); channel.bind( 'new_message', function (data) { alert( data.message ); })
  • 38. pusherapp.com // Subscribe to PRESENCE channel var chat = socket.subscribe( 'presence-chat' ); // Listen to new members chat.bind( 'pusher:member_added', function (member) { alert( member.user_data.name ); })
  • 39. require 'pusher' require 'sinatra' post '/messages' do message = Message.create(params[:message]) Pusher['presence-chat'].trigger(:new_message, message.attributes) redirect '/messages' end pusherapp.com $ gem install pusher