Note: Streaming in Espresso is working only with Thin, Rainbows! and Reel(0.3 and up) web-servers.
By default Espresso will use EventMachine
as streaming backend.
If you are using Reel web server, you should instruct Espresso
to use Celluloid
as backend.
This is done via streaming_backend
method at app level:
app = E.new do
streaming_backend :Celluloid
# ...
end
As easy as:
<script type="text/javascript">
var evs = new EventSource('/subscribe');
evs.onmessage = function(e) {
$('#wall').html( e.data );
}
</script>
class App < E
map '/'
def subscribe
evented_stream :keep_open do |stream|
stream << "some string" # sending data
end
end
end
<script type="text/javascript">
var evs = new EventSource('/subscribe');
evs.addEventListener('time', function(e) {
$('#time').html( e.data );
}, false);
</script>
def subscribe
evented_stream :keep_open do |stream|
stream.event "time" # sending "time" event
stream << Time.now # sending time data
end
end
Other EventSource
related methods - id
, retry
:
def subscribe
evented_stream :keep_open do |stream|
stream.id "foo" # sending "foo" ID
stream.retry 10000 # instructing browser to reconnect every 10 seconds
end
end
[ contents ↑ ]
For now, WebSockets works out-of-the-box with Reel web-server only.
As easy as:
<script type="text/javascript">
ws = new WebSocket('ws://host:port/subscribe');
ws.onmessage = function(e) {
$('#wall').html( e.data );
}
</script>
<input type="text" id="message">
<input type="button" onClick="ws.send( $('#message').val() );" value="send message">
def subscribe
if socket = websocket?
socket << 'Welcome to the wall'
socket.on_message do |msg|
# will set #wall's HTML to current time + received message
socket << "#{Time.now}: #{msg}"
end
socket.on_error { socket.close unless socket.closed? }
socket.read_interval 1 # reading from socket every 1 second
end
end
[ contents ↑ ]
From W3.org:
The chunked encoding modifies the body of a message in order to transfer it as a series of chunks, each with its own size indicator, followed by an OPTIONAL trailer containing entity-header fields. This allows dynamically produced content to be transferred along with the information necessary for the recipient to verify that it has received the full message.
So, this is useful when your body is not yet ready in full and you want to start sending it by chunks.
Here is an example that will release the response instantly and then send body by chunks:
def some_heavy_action
chunked_stream do |socket|
ExtractDataFromDBOrSomePresumablySlowAPI.each do |data|
socket << data
end
socket.close # close it, otherwise the browser will wait for data forever
end
end