Stream with Sinatra, destination update gradually

I have a Sinatra web application that I would really like to improve with streaming updates for certain functions. Right now, however, I'm just trying to learn how to use streaming data, which I have never done before. I have the following simple test code:

In Sinatra:

get '/foo' do stream do |out| 10.times do out.puts "foo" out.flush sleep 1 end end end get '/bar' do erb :bar end 

In bar.erb :

 <body> <div class="stream"> nothing. </div> </body> <script type="text/javascript" charset="utf-8"> $(document).ready( function() { $.get('/foo', function(html) { $(".stream").html(html); }); }); </script> 

I am not surprised that this does not do what I want to match each "foo" when it is recording and refreshing the page dynamically. Instead, nothing happens for ~ 10 seconds, and then I get foo foo foo foo foo foo foo foo foo foo foo .

My question is: how in the ERB template (using Ruby, jQuery or other means) can I pull out the streaming data as provided, instead of blocking until they all come together and spit it all out at once?

+4
source share
2 answers

Sinatra’s actions carry the entire HTTP response loop — this means that it waits until the action completes before the request closes, at which point the browser considers the data “complete” and “good” to use. Everything you created in your code above is a very, very slow Sinatra action.

The technology you are looking for is Websockets, which are supported by most modern browsers and provide a two-way communication channel between each client and server. The websocket channel is created by "updating" a regular HTTP request. If clients do not support web sockets, they can be emulated using methods such as HTTP Long Polling (and the request remains open without an answer until data is available). At this point, the data will be disconnected from the response channel, the response channel is closed, and it is expected that the client will open a new request to receive any additional data).

You can configure this setting in your Ruby application using EventMachine and EM-Websocket . An alternative is Socky , which I believe provides a javascript client as well as a Ruby server.

+5
source

If you use a stream in Sinatra, regular templates are skipped, you get a blank page with only an html stream. You can get around this by manually creating and placing your layout along with the text. Here is an example.

 require 'sinatra' require "sinatra/streaming" set server: 'thin', connections: [] get '/' do stream do |out| settings.connections << out @out = out erb :stream out.callback { settings.connections.delete(out) } end end __END__ @@pre <!DOCTYPE html> <html> <head> <title>test</title> </head> <body> <h1>This is the body</h1> @@after </body> </html> @@stream <% @out.puts erb(:pre) @out.puts "<h2>test</h2>" (1..10).each do |i| @out.puts "#{i}<br>" sleep 2 end @out.puts erb(:after) @out.flush %> 
0
source

Source: https://habr.com/ru/post/1416221/


All Articles