Skip to content

Latest commit

 

History

History
139 lines (107 loc) · 3.67 KB

Streaming.md

File metadata and controls

139 lines (107 loc) · 3.67 KB

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

Server-Sent Events

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

Real-world Example #1

Real-world Example #2

[ contents ↑ ]

WebSockets

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

Real-world Example

[ contents ↑ ]

Chunked Responses

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

Real-world Example