SlideShare uma empresa Scribd logo
1 de 171
Baixar para ler offline
Server-side Push
Comes of Age
by Brian Sam-Bodden
http://www.integrallis.com
HTTP
HTTP
Unsuspecting Programmers
HTTP
Tim Berners-Lee
Unsuspecting Programmers
... and it was good
...for documents
it scales!
Web Applications
Uhmm, yeah...
Remember that client-server desktop app?
It should be easy to port it to the web, right?
Client Server
Request
Response
C
C
Well, hello let me make
you a page good friend
... don’t forget the images
page-by-page model
C ... hold on, I got hit the DB
C ... and cook up some HTML
C ... and all other assets
Client Server
Request
Response
C
C
Well, hello let me make
you a page good friend
... don’t forget the images
page-by-page model
C ... hold on, I got hit the DB
C ... and cook up some HTML
C ... and all other assets
Client Server
Request
Response
C
C
Well, hello let me make
you a page good friend
... don’t forget the images
page-by-page model
C ... hold on, I got hit the DB
C ... and cook up some HTML
C ... and all other assets
ask for it
background
and change the
relevant bits
Client Server
Load the “application”
C Here’s the initial page load
ajax model
C ... just what’s changedUser Action #1
C ... and againUser Action #2
The Web as a
Platform
So things got
better, until ...
Push
Uhmm, yeah...
Remember that cool web app I underpaid you to build?
It should be easy to notify the user when something
important happens, right?
PUSH
Why?
Collaboration
Chat
Comments
Notifications
Bidding Platforms
Monitoring
Stocks
Scores
Games
Bi-directional
Asynchronous
Near Real-Time
Server Initiated*
Communications
But...
until fairly recently
Browsers Sucked!
So we had (have)
to Hack it
Java
Applets
Polling
iFrame
Streaming
Long
Polling
Flash
Streaming
XHR
Streaming
Java
Applets
Polling
iFrame
Streaming
Long
Polling
Flash
Streaming
XHR
Streaming
Java
Applets
Java
Applets
Polling
Java
Applets
iFrame
Streaming
Long
Polling
Flash
Streaming
XHR
Streaming
Polling
Polling
are we there yet?
setInterval(function() {
areWeThereYet();
}, 1000);
setInterval(function() {
areWeThereYet();
}, 1000);
setInterval(function() {
areWeThereYet();
}, 1000);
setInterval(function() {
areWeThereYet();
}, 1000);
Client Server
Request
Response
Request
Response
C
C
No Soup for you!
Ok, here you go
Event
polling
chatty / high traffic
Self-inflicted DDOS Attack!
iFrame
Streaming
Java
Applets
Polling
Long
Polling
Flash
Streaming
XHR
Streaming
iFrame
Streaming
iFrame
Streaming
Oh yes, it involves
an iFrame
#sadpanda
iFrame
Streaming
Demo
first you embed an
invisible iFrame
$('<iframe />', {
name: 'hidden-iframe',
id: 'hidden-iframe',
src: '/long-running',
css: { 'display': 'none' }
}).appendTo('body');
$('<iframe />', {
name: 'hidden-iframe',
id: 'hidden-iframe',
src: '/long-running',
css: { 'display': 'none' }
}).appendTo('body');
$('<iframe />', {
name: 'hidden-iframe',
id: 'hidden-iframe',
src: '/long-running',
css: { 'display': 'none' }
}).appendTo('body');
$('<iframe />', {
name: 'hidden-iframe',
id: 'hidden-iframe',
src: '/long-running',
css: { 'display': 'none' }
}).appendTo('body');
$('<iframe />', {
name: 'hidden-iframe',
id: 'hidden-iframe',
src: '/long-running',
css: { 'display': 'none' }
}).appendTo('body');
$('<iframe />', {
name: 'hidden-iframe',
id: 'hidden-iframe',
src: '/long-running',
css: { 'display': 'none' }
}).appendTo('body');
on the server
you need
streaming
capabilities
get '/long-running' do
stream do |out|
(10..100).step(10) do |n|
word = gimme_funny_word
out << update_progress(n, word.keys.first,
word.values.first)
sleep 1.5
end
end
end
get '/long-running' do
stream do |out|
(10..100).step(10) do |n|
word = gimme_funny_word
out << update_progress(n, word.keys.first,
word.values.first)
sleep 1.5
end
end
end
get '/long-running' do
stream do |out|
(10..100).step(10) do |n|
word = gimme_funny_word
out << update_progress(n, word.keys.first,
word.values.first)
sleep 1.5
end
end
end
get '/long-running' do
stream do |out|
(10..100).step(10) do |n|
word = gimme_funny_word
out << update_progress(n, word.keys.first,
word.values.first)
sleep 1.5
end
end
end
get '/long-running' do
stream do |out|
(10..100).step(10) do |n|
word = gimme_funny_word
out << update_progress(n, word.keys.first,
word.values.first)
sleep 1.5
end
end
end
get '/long-running' do
stream do |out|
(10..100).step(10) do |n|
word = gimme_funny_word
out << update_progress(n, word.keys.first,
word.values.first)
sleep 1.5
end
end
end
def update_progress(percent, word, meaning)
%[<script type="text/javascript">
parent.updatePage(#{percent}, '#{word}', '#{meaning}');
</script>]
end
def update_progress(percent, word, meaning)
%[<script type="text/javascript">
parent.updatePage(#{percent}, '#{word}', '#{meaning}');
</script>]
end
// called by the streamed server-sent script
function updatePage(percent, word, meaning) {
$kickItButton.text(percent + '%');
$theWord.text(word);
$theMeaning.text(meaning);
if (percent == 100) {
$kickItButton.attr('disabled', false);
$kickItButton.text('Kick it again!');
}
}
// called by the streamed server-sent script
function updatePage(percent, word, meaning) {
$kickItButton.text(percent + '%');
$theWord.text(word);
$theMeaning.text(meaning);
if (percent == 100) {
$kickItButton.attr('disabled', false);
$kickItButton.text('Kick it again!');
}
}
// called by the streamed server-sent script
function updatePage(percent, word, meaning) {
$kickItButton.text(percent + '%');
$theWord.text(word);
$theMeaning.text(meaning);
if (percent == 100) {
$kickItButton.attr('disabled', false);
$kickItButton.text('Kick it again!');
}
}
// called by the streamed server-sent script
function updatePage(percent, word, meaning) {
$kickItButton.text(percent + '%');
$theWord.text(word);
$theMeaning.text(meaning);
if (percent == 100) {
$kickItButton.attr('disabled', false);
$kickItButton.text('Kick it again!');
}
}
// called by the streamed server-sent script
function updatePage(percent, word, meaning) {
$kickItButton.text(percent + '%');
$theWord.text(word);
$theMeaning.text(meaning);
if (percent == 100) {
$kickItButton.attr('disabled', false);
$kickItButton.text('Kick it again!');
}
}
Drawback:
Page is ‘forever’
loading
iFrame
Streaming
Java
Applets
Polling
Long
Polling
Flash
Streaming
XHR
Streaming
XHR
Streaming
XHR
Streaming
XHR
Streaming
Demo
better than iframes
use AJAX call
send JSON
get '/stream' do
stream do |out|
(10..100).step(2) do |n|
out << gimme_funny_word.as_json
sleep 1.5
end
end
end
get '/stream' do
stream do |out|
(10..100).step(2) do |n|
out << gimme_funny_word.as_json
sleep 1.5
end
end
end
get '/stream' do
stream do |out|
(10..100).step(2) do |n|
out << gimme_funny_word.as_json
sleep 1.5
end
end
end
polling the stream
parse = function() {
// parse the xhr.responseText and update the UI
};
xhr = new XMLHttpRequest();
url = "/stream";
xhr.open("GET", url, true);
xhr.send();
last_index = 0;
interval = setInterval(parse, 500);
setTimeout((function() {
clearInterval(interval);
parse();
xhr.abort();
}), 20000);
parse = function() {
// parse the xhr.responseText and update the UI
};
xhr = new XMLHttpRequest();
url = "/stream";
xhr.open("GET", url, true);
xhr.send();
last_index = 0;
interval = setInterval(parse, 500);
setTimeout((function() {
clearInterval(interval);
parse();
xhr.abort();
}), 20000);
parse = function() {
// parse the xhr.responseText and update the UI
};
xhr = new XMLHttpRequest();
url = "/stream";
xhr.open("GET", url, true);
xhr.send();
last_index = 0;
interval = setInterval(parse, 500);
setTimeout((function() {
clearInterval(interval);
parse();
xhr.abort();
}), 20000);
parse = function() {
// parse the xhr.responseText and update the UI
};
xhr = new XMLHttpRequest();
url = "/stream";
xhr.open("GET", url, true);
xhr.send();
last_index = 0;
interval = setInterval(parse, 500);
setTimeout((function() {
clearInterval(interval);
parse();
xhr.abort();
}), 20000);
parse = function() {
// parse the xhr.responseText and update the UI
};
xhr = new XMLHttpRequest();
url = "/stream";
xhr.open("GET", url, true);
xhr.send();
last_index = 0;
interval = setInterval(parse, 500);
setTimeout((function() {
clearInterval(interval);
parse();
xhr.abort();
}), 20000);
frequency of polling the stream
>=
server serving rate
No Throbber
Freakout
Long
Polling
iFrame
Streaming
Java
Applets
Polling
Flash
Streaming
XHR
Streaming
Long
Polling
Long
Polling
most commonly
used
response is
blocked...
...until server event
occurs
Client Server
Request
Response
C
C
Nothing here, but hang on...
... and there you go, good day!
Event
polling
Long
Polling
Demo
get '/read' do
content_type :json
filename = 'data.txt'
last = params[:timestamp] == 'null' ? 0 : params[:timestamp].to_i
current = last_modification(filename)
not_changed_or_emtpy = true
while (not_changed_or_emtpy) do
sleep 0.1
not_changed_or_emtpy = File.zero?(filename) || (current <= last)
current = last_modification(filename)
end
{ :messages => File.read(filename), :timestamp => current }.to_json
end
get '/read' do
content_type :json
filename = 'data.txt'
last = params[:timestamp] == 'null' ? 0 : params[:timestamp].to_i
current = last_modification(filename)
not_changed_or_emtpy = true
while (not_changed_or_emtpy) do
sleep 0.1
not_changed_or_emtpy = File.zero?(filename) || (current <= last)
current = last_modification(filename)
end
{ :messages => File.read(filename), :timestamp => current }.to_json
end
get '/read' do
content_type :json
filename = 'data.txt'
last = params[:timestamp] == 'null' ? 0 : params[:timestamp].to_i
current = last_modification(filename)
not_changed_or_emtpy = true
while (not_changed_or_emtpy) do
sleep 0.1
not_changed_or_emtpy = File.zero?(filename) || (current <= last)
current = last_modification(filename)
end
{ :messages => File.read(filename), :timestamp => current }.to_json
end
get '/read' do
content_type :json
filename = 'data.txt'
last = params[:timestamp] == 'null' ? 0 : params[:timestamp].to_i
current = last_modification(filename)
not_changed_or_emtpy = true
while (not_changed_or_emtpy) do
sleep 0.1
not_changed_or_emtpy = File.zero?(filename) || (current <= last)
current = last_modification(filename)
end
{ :messages => File.read(filename), :timestamp => current }.to_json
end
get '/read' do
content_type :json
filename = 'data.txt'
last = params[:timestamp] == 'null' ? 0 : params[:timestamp].to_i
current = last_modification(filename)
not_changed_or_emtpy = true
while (not_changed_or_emtpy) do
sleep 0.1
not_changed_or_emtpy = File.zero?(filename) || (current <= last)
current = last_modification(filename)
end
{ :messages => File.read(filename), :timestamp => current }.to_json
end
get '/read' do
content_type :json
filename = 'data.txt'
last = params[:timestamp] == 'null' ? 0 : params[:timestamp].to_i
current = last_modification(filename)
not_changed_or_emtpy = true
while (not_changed_or_emtpy) do
sleep 0.1
not_changed_or_emtpy = File.zero?(filename) || (current <= last)
current = last_modification(filename)
end
{ :messages => File.read(filename), :timestamp => current }.to_json
end
get '/read' do
content_type :json
filename = 'data.txt'
last = params[:timestamp] == 'null' ? 0 : params[:timestamp].to_i
current = last_modification(filename)
not_changed_or_emtpy = true
while (not_changed_or_emtpy) do
sleep 0.1
not_changed_or_emtpy = File.zero?(filename) || (current <= last)
current = last_modification(filename)
end
{ :messages => File.read(filename), :timestamp => current }.to_json
end
function longPoll() {
$.ajax({
type : 'get',
url : '/read?timestamp=' + timestamp,
async : true,
cache : false,
timeout : 10000,
success : function(json) {
var messages = json['messages'].split("n")
var last = messages[messages.length-1];
if (last) {
$('#msg').append('<div>'+last+'</div>');
timestamp = json['timestamp'];
}
setTimeout(longPoll, 1000);
},
error : function(xhr, textStatus, error) {
setTimeout(longPoll, 2000);
}
});
}
function longPoll() {
$.ajax({
type : 'get',
url : '/read?timestamp=' + timestamp,
async : true,
cache : false,
timeout : 10000,
success : function(json) {
var messages = json['messages'].split("n")
var last = messages[messages.length-1];
if (last) {
$('#msg').append('<div>'+last+'</div>');
timestamp = json['timestamp'];
}
setTimeout(longPoll, 1000);
},
error : function(xhr, textStatus, error) {
setTimeout(longPoll, 2000);
}
});
}
function longPoll() {
$.ajax({
type : 'get',
url : '/read?timestamp=' + timestamp,
async : true,
cache : false,
timeout : 10000,
success : function(json) {
var messages = json['messages'].split("n")
var last = messages[messages.length-1];
if (last) {
$('#msg').append('<div>'+last+'</div>');
timestamp = json['timestamp'];
}
setTimeout(longPoll, 1000);
},
error : function(xhr, textStatus, error) {
setTimeout(longPoll, 2000);
}
});
}
function longPoll() {
$.ajax({
type : 'get',
url : '/read?timestamp=' + timestamp,
async : true,
cache : false,
timeout : 10000,
success : function(json) {
var messages = json['messages'].split("n")
var last = messages[messages.length-1];
if (last) {
$('#msg').append('<div>'+last+'</div>');
timestamp = json['timestamp'];
}
setTimeout(longPoll, 1000);
},
error : function(xhr, textStatus, error) {
setTimeout(longPoll, 2000);
}
});
}
Naive Long polling w/ 10sec timeout
{
Requests that
returned data
Current polling
request
Requests in RED
are timed out
long polls
There is a big issue with
the previous example...
There is a big issue with
the previous example...
Besides using a Text
File as a database
The server doesn’t support
async responses...
The busy IO checking loop
will block
aget '/read' do
content_type :json
filename = 'data.txt'
last = params[:timestamp] == 'null' ? 0 : params[:timestamp].to_i
current = last_modification(filename)
EM.defer do
check_file_changes = proc do
if File.zero?(filename) || (current <= last)
current = last_modification(filename)
EM.next_tick(&check_file_changes)
else
body({ :messages => File.read(filename),
:timestamp => current }.to_json)
end
end
EM.next_tick(&check_file_changes)
end
end
aget '/read' do
content_type :json
filename = 'data.txt'
last = params[:timestamp] == 'null' ? 0 : params[:timestamp].to_i
current = last_modification(filename)
EM.defer do
check_file_changes = proc do
if File.zero?(filename) || (current <= last)
current = last_modification(filename)
EM.next_tick(&check_file_changes)
else
body({ :messages => File.read(filename),
:timestamp => current }.to_json)
end
end
EM.next_tick(&check_file_changes)
end
end
Difficult to
Implement
Flash
Streaming
Long
Polling
iFrame
Streaming
Java
Applets
Polling
XHR
Streaming
Flash
Streaming
Flash
Streaming
XML Socket
Single Pixel
Flash Movie
Go Away
Flash!
Push
Frameworks
Comet
!=
Just Long Polling
Amalgamation of
Techniques
Provide both Client
and Server
Components
Many use a
Pub-Sub Protocol
Bayeaux
Comet
Demo
with
http://faye.jcoglan.com
var client = new Faye.Client('/faye');
var subscription = client.subscribe('/<%= room %>', function(message) {
$messages = $('#messages');
$message = $('<div>' + message['user'] + ' : ' + message['text'] +'</div>')
$messages.append($message);
});
$("#chat-form").submit(function(e){
e.preventDefault();
var message = $('#message').val();
client.publish('/<%= room %>', {user: '<%= username %>', text: message});
$('#message').val('');
});
var client = new Faye.Client('/faye');
var subscription = client.subscribe('/<%= room %>', function(message) {
$messages = $('#messages');
$message = $('<div>' + message['user'] + ' : ' + message['text'] +'</div>')
$messages.append($message);
});
$("#chat-form").submit(function(e){
e.preventDefault();
var message = $('#message').val();
client.publish('/<%= room %>', {user: '<%= username %>', text: message});
$('#message').val('');
});
var client = new Faye.Client('/faye');
var subscription = client.subscribe('/<%= room %>', function(message) {
$messages = $('#messages');
$message = $('<div>' + message['user'] + ' : ' + message['text'] +'</div>')
$messages.append($message);
});
$("#chat-form").submit(function(e){
e.preventDefault();
var message = $('#message').val();
client.publish('/<%= room %>', {user: '<%= username %>', text: message});
$('#message').val('');
});
var client = new Faye.Client('/faye');
var subscription = client.subscribe('/<%= room %>', function(message) {
$messages = $('#messages');
$message = $('<div>' + message['user'] + ' : ' + message['text'] +'</div>')
$messages.append($message);
});
$("#chat-form").submit(function(e){
e.preventDefault();
var message = $('#message').val();
client.publish('/<%= room %>', {user: '<%= username %>', text: message});
$('#message').val('');
});
Now we can create a room ... and have a conversation
Web Sockets
Two Way
Communications
Over a dedicated
socket
in simple way
with security,
proxies & firewalls
in mind
Web
Sockets
Demo
EventMachine.run do
EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 8080) do |ws|
ws.onopen do
end
ws.onmessage do |msg|
end
ws.onclose do
end
end
end
em-websocket provides an
easy to use WebSocket class
On the server
we’ll implement
some WebSocket
event handlers
EventMachine.run do
@channel = EM::Channel.new
@users = {}
@messages = []
...
ws.onopen do
new_user = @channel.subscribe { |msg| ws.send msg }
@users[ws.object_id] = new_user
@messages.each do |message|
ws.send message
end
end
subscribe a new user to the channel
passing the callback to our push action
we’ll keep a list of users in a Hash keyed by
the object_id of the incoming ws connection
push the last batch of
messages to the user
ws.onmessage do |msg|
@messages << msg
@messages.shift if @messages.length > 10
@channel.push msg
end
add the new message to the end of the
queue
broadcast the message to all users
connected to the channel
we’ll keep the last 10 messages
ws.onclose do
@channel.unsubscribe(@users[ws.object_id])
@users.delete(ws.object_id)
end
we unsubscribe them from the channel
remove them from the Hash of users
EventMachine.run do
EventMachine::WebSocket.start(...) do |ws|
...
end
class App < Sinatra::Base
get '/' do
erb :index
end
end
App.run!
end
our single page
application is contained in
/public/views/index.erb
The Sinatra app runs as part
of the EV “Reactor Loop”
<div class="container">
<h1 class="visible-desktop">WebSockets Sinatra Draw</h1>
<legend>Draw Something</legend>
<div id="whiteboard" class="well well-small">
<canvas id="draw-canvas"></canvas>
</div>
</div>
We’ll nest the canvas in
a div in order to resize it
correctly
$(document).ready(function() {
var $canvas = $('#draw-canvas');
var ws = new WebSocket("ws://" + location.hostname + ":8080");
When the document is ready we’ll
connect to the EM Websocket server
running on :8080
var currentX = 0;
var currentY = 0;
var lastX, lastY, lastReceivedX, lastReceivedY;
var drawing = false;
var ctx = $('#draw-canvas')[0].getContext('2d');
We’ll grab the 2D canvas
context in order to draw on it
$canvas.bind('mousemove',function(ev){
ev = ev || window.event;
currentX = ev.pageX - $canvas.offset().left;
currentY = ev.pageY - $canvas.offset().top;
});
$canvas.bind('touchmove',function(ev){
var touch = ev.originalEvent.touches[0] || ev.originalEvent.changedTouches[0];
currentX = touch.pageX - $canvas.offset().left;
currentY = touch.pageY - $canvas.offset().top;
});
We’ll update the currentX and currentY
coordinates of the mouse over the canvas both for
desktop and mobile browsers
touchmove is provided by
jQuery-Mobile-Events
plugin
$canvas.bind('tapstart',function(ev) {
drawing = true
});
$canvas.bind('tapend',function(ev) {
drawing = false
});
tapstart and tapend are also provided
by the jQuery-Mobile-Events
ws.onopen = function(event) {
setInterval(function() {
if ((currentX !== lastX || currentY !== lastY) && drawing) {
lastX = currentX;
lastY = currentY;
ws.send(JSON.stringify({ x: currentX, y: currentY}));
}
}, 30);
}
ws.onmessage = function(event) {
var msg = $.parseJSON(event.data);
ctx.beginPath();
ctx.moveTo(lastReceivedX, lastReceivedY);
ctx.lineTo(msg.x, msg.y);
ctx.closePath();
ctx.stroke();
lastReceivedX = msg.x;
lastReceivedY = msg.y;
};
We’ll only draw indirectly when we
receive a message (even when we
are the ones doing the drawing)
On Firefox
On Safari Desktop
... and on my almost out of
batteries iPhone
What are we
missing?
Server-sent
Events
BOSH
WebRTC
What should
you do?
Use a
Framework!
That plays well
with your
framework
Thanks
All example code available at:
https://github.com/integrallis/server-side-push
Watch out for an upcoming article at http://integrallis.com
by Brian Sam-Bodden
http://www.integrallis.com
http://www.slideshare.net/bsbodden/ssp-oscon

Mais conteúdo relacionado

Mais procurados

Perl web frameworks
Perl web frameworksPerl web frameworks
Perl web frameworks
diego_k
 
Mojolicious, real-time web framework
Mojolicious, real-time web frameworkMojolicious, real-time web framework
Mojolicious, real-time web framework
taggg
 
Real-Time Python Web: Gevent and Socket.io
Real-Time Python Web: Gevent and Socket.ioReal-Time Python Web: Gevent and Socket.io
Real-Time Python Web: Gevent and Socket.io
Rick Copeland
 
Keeping it small: Getting to know the Slim micro framework
Keeping it small: Getting to know the Slim micro frameworkKeeping it small: Getting to know the Slim micro framework
Keeping it small: Getting to know the Slim micro framework
Jeremy Kendall
 
Build Lightweight Web Module
Build Lightweight Web ModuleBuild Lightweight Web Module
Build Lightweight Web Module
Morgan Cheng
 

Mais procurados (20)

Mojolicious - Perl Framework for the Real-Time Web (Lightning Talk)
Mojolicious - Perl Framework for the Real-Time Web (Lightning Talk)Mojolicious - Perl Framework for the Real-Time Web (Lightning Talk)
Mojolicious - Perl Framework for the Real-Time Web (Lightning Talk)
 
Http capturing
Http capturingHttp capturing
Http capturing
 
Py conkr 20150829_docker-python
Py conkr 20150829_docker-pythonPy conkr 20150829_docker-python
Py conkr 20150829_docker-python
 
Developing apps using Perl
Developing apps using PerlDeveloping apps using Perl
Developing apps using Perl
 
Perl web frameworks
Perl web frameworksPerl web frameworks
Perl web frameworks
 
Mojolicious, real-time web framework
Mojolicious, real-time web frameworkMojolicious, real-time web framework
Mojolicious, real-time web framework
 
An Introduction to Windows PowerShell
An Introduction to Windows PowerShellAn Introduction to Windows PowerShell
An Introduction to Windows PowerShell
 
Node.js Express
Node.js  ExpressNode.js  Express
Node.js Express
 
Introduction to PowerShell
Introduction to PowerShellIntroduction to PowerShell
Introduction to PowerShell
 
Mojo as a_client
Mojo as a_clientMojo as a_client
Mojo as a_client
 
How to actually use promises - Jakob Mattsson, FishBrain
How to actually use promises - Jakob Mattsson, FishBrainHow to actually use promises - Jakob Mattsson, FishBrain
How to actually use promises - Jakob Mattsson, FishBrain
 
Mojolicious on Steroids
Mojolicious on SteroidsMojolicious on Steroids
Mojolicious on Steroids
 
Web Apps in Perl - HTTP 101
Web Apps in Perl - HTTP 101Web Apps in Perl - HTTP 101
Web Apps in Perl - HTTP 101
 
JSON and the APInauts
JSON and the APInautsJSON and the APInauts
JSON and the APInauts
 
Real-Time Python Web: Gevent and Socket.io
Real-Time Python Web: Gevent and Socket.ioReal-Time Python Web: Gevent and Socket.io
Real-Time Python Web: Gevent and Socket.io
 
Keeping it small: Getting to know the Slim micro framework
Keeping it small: Getting to know the Slim micro frameworkKeeping it small: Getting to know the Slim micro framework
Keeping it small: Getting to know the Slim micro framework
 
The worst Ruby codes I’ve seen in my life - RubyKaigi 2015
The worst Ruby codes I’ve seen in my life - RubyKaigi 2015The worst Ruby codes I’ve seen in my life - RubyKaigi 2015
The worst Ruby codes I’ve seen in my life - RubyKaigi 2015
 
From Node to Go
From Node to GoFrom Node to Go
From Node to Go
 
Build Lightweight Web Module
Build Lightweight Web ModuleBuild Lightweight Web Module
Build Lightweight Web Module
 
PHP, RabbitMQ, and You
PHP, RabbitMQ, and YouPHP, RabbitMQ, and You
PHP, RabbitMQ, and You
 

Semelhante a Server-Side Push: Comet, Web Sockets come of age (OSCON 2013)

Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
Tom Croucher
 
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasmineSingle Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Paulo Ragonha
 
Is HTML5 Ready? (workshop)
Is HTML5 Ready? (workshop)Is HTML5 Ready? (workshop)
Is HTML5 Ready? (workshop)
Remy Sharp
 
Is html5-ready-workshop-110727181512-phpapp02
Is html5-ready-workshop-110727181512-phpapp02Is html5-ready-workshop-110727181512-phpapp02
Is html5-ready-workshop-110727181512-phpapp02
PL dream
 
HTML5: huh, what is it good for?
HTML5: huh, what is it good for?HTML5: huh, what is it good for?
HTML5: huh, what is it good for?
Remy Sharp
 
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQueryRemedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Tatsuhiko Miyagawa
 
RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜
RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜
RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜
崇之 清水
 
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
Wesley Beary
 

Semelhante a Server-Side Push: Comet, Web Sockets come of age (OSCON 2013) (20)

Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
 
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasmineSingle Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
 
Writing Redis in Python with asyncio
Writing Redis in Python with asyncioWriting Redis in Python with asyncio
Writing Redis in Python with asyncio
 
Alexey Kupriyanenko "The State of Modern JavaScript and Web in 2020 - Real us...
Alexey Kupriyanenko "The State of Modern JavaScript and Web in 2020 - Real us...Alexey Kupriyanenko "The State of Modern JavaScript and Web in 2020 - Real us...
Alexey Kupriyanenko "The State of Modern JavaScript and Web in 2020 - Real us...
 
Is HTML5 Ready? (workshop)
Is HTML5 Ready? (workshop)Is HTML5 Ready? (workshop)
Is HTML5 Ready? (workshop)
 
Is html5-ready-workshop-110727181512-phpapp02
Is html5-ready-workshop-110727181512-phpapp02Is html5-ready-workshop-110727181512-phpapp02
Is html5-ready-workshop-110727181512-phpapp02
 
Serverless Ballerina
Serverless BallerinaServerless Ballerina
Serverless Ballerina
 
HTML5: huh, what is it good for?
HTML5: huh, what is it good for?HTML5: huh, what is it good for?
HTML5: huh, what is it good for?
 
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
 
fog or: How I Learned to Stop Worrying and Love the Cloud
fog or: How I Learned to Stop Worrying and Love the Cloudfog or: How I Learned to Stop Worrying and Love the Cloud
fog or: How I Learned to Stop Worrying and Love the Cloud
 
Sinatra for REST services
Sinatra for REST servicesSinatra for REST services
Sinatra for REST services
 
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQueryRemedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
 
RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜
RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜
RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜
 
Monitoring Your ISP Using InfluxDB Cloud and Raspberry Pi
Monitoring Your ISP Using InfluxDB Cloud and Raspberry PiMonitoring Your ISP Using InfluxDB Cloud and Raspberry Pi
Monitoring Your ISP Using InfluxDB Cloud and Raspberry Pi
 
Frontend Servers and NGINX: What, Where and How
Frontend Servers and NGINX: What, Where and HowFrontend Servers and NGINX: What, Where and How
Frontend Servers and NGINX: What, Where and How
 
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
 
Massimo Artizzu - The tricks of Houdini: a magic wand for the future of CSS -...
Massimo Artizzu - The tricks of Houdini: a magic wand for the future of CSS -...Massimo Artizzu - The tricks of Houdini: a magic wand for the future of CSS -...
Massimo Artizzu - The tricks of Houdini: a magic wand for the future of CSS -...
 
Data models in Angular 1 & 2
Data models in Angular 1 & 2Data models in Angular 1 & 2
Data models in Angular 1 & 2
 
TPSE Thailand 2015 - Rethinking Web with React and Flux
TPSE Thailand 2015 - Rethinking Web with React and FluxTPSE Thailand 2015 - Rethinking Web with React and Flux
TPSE Thailand 2015 - Rethinking Web with React and Flux
 
Crie seu sistema REST com JAX-RS e o futuro
Crie seu sistema REST com JAX-RS e o futuroCrie seu sistema REST com JAX-RS e o futuro
Crie seu sistema REST com JAX-RS e o futuro
 

Mais de Brian Sam-Bodden

Baruco 2014 - Rubymotion Workshop
Baruco 2014 - Rubymotion WorkshopBaruco 2014 - Rubymotion Workshop
Baruco 2014 - Rubymotion Workshop
Brian Sam-Bodden
 

Mais de Brian Sam-Bodden (10)

Baruco 2014 - Rubymotion Workshop
Baruco 2014 - Rubymotion WorkshopBaruco 2014 - Rubymotion Workshop
Baruco 2014 - Rubymotion Workshop
 
Ruby Metaprogramming - OSCON 2008
Ruby Metaprogramming - OSCON 2008Ruby Metaprogramming - OSCON 2008
Ruby Metaprogramming - OSCON 2008
 
RailsConf 2013: RubyMotion
RailsConf 2013: RubyMotionRailsConf 2013: RubyMotion
RailsConf 2013: RubyMotion
 
Rspec and Capybara Intro Tutorial at RailsConf 2013
Rspec and Capybara Intro Tutorial at RailsConf 2013Rspec and Capybara Intro Tutorial at RailsConf 2013
Rspec and Capybara Intro Tutorial at RailsConf 2013
 
Road to mobile w/ Sinatra, jQuery Mobile, Spine.js and Mustache
Road to mobile w/ Sinatra, jQuery Mobile, Spine.js and MustacheRoad to mobile w/ Sinatra, jQuery Mobile, Spine.js and Mustache
Road to mobile w/ Sinatra, jQuery Mobile, Spine.js and Mustache
 
Trellis Framework At RubyWebConf
Trellis Framework At RubyWebConfTrellis Framework At RubyWebConf
Trellis Framework At RubyWebConf
 
Integrallis groovy-cloud
Integrallis groovy-cloudIntegrallis groovy-cloud
Integrallis groovy-cloud
 
Ferret
FerretFerret
Ferret
 
Bitter Java, Sweeten with JRuby
Bitter Java, Sweeten with JRubyBitter Java, Sweeten with JRuby
Bitter Java, Sweeten with JRuby
 
Ruby Metaprogramming 08
Ruby Metaprogramming 08Ruby Metaprogramming 08
Ruby Metaprogramming 08
 

Último

Último (20)

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
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
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
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
A Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source MilvusA Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source Milvus
 
AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
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...
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu SubbuApidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
 
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
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
 
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
 

Server-Side Push: Comet, Web Sockets come of age (OSCON 2013)