Module: Sinatra::Streaming
- Defined in:
- lib/sinatra/streaming.rb
Overview
Sinatra::Streaming
Sinatra 1.3 introduced the stream
helper. This addon improves the streaming API by making the stream object immitate an IO object, turning it into a real Deferrable and making the body play nicer with middleware unaware of streaming.
IO-like behavior
This is useful when passing the stream object to a library expecting an IO or StringIO object.
get '/' do
stream do |out|
out.puts "Hello World!", "How are you?"
out.write "Written #{out.pos} bytes so far!\n"
out.putc(65) unless out.closed?
out.flush
end
end
Proper Deferrable
Handy when using EventMachine.
list = []
get '/' do
stream(:keep_open) do |out|
list << out
out.callback { list.delete out }
out.errback do
logger.warn "lost connection"
list.delete out
end
end
end
Better Middleware Handling
Blocks passed to #map! or #map will actually be applied when streaming takes place (as you might have suspected, #map! applies modifications to the current body, while #map creates a new one):
class StupidMiddleware
def initialize(app) @app = app end
def call(env)
status, headers, body = @app.call(env)
body.map! { |e| e.upcase }
[status, headers, body]
end
end
use StupidMiddleware
get '/' do
stream do |out|
out.puts "still"
sleep 1
out.puts "streaming"
end
end
Even works if #each is used to generate an Enumerator:
def call(env)
status, headers, body = @app.call(env)
body = body.each.map { |s| s.upcase }
[status, headers, body]
end
Note that both examples violate the Rack specification.
Setup
In a classic application:
require "sinatra"
require "sinatra/streaming"
In a modular application:
require "sinatra/base"
require "sinatra/streaming"
class MyApp < Sinatra::Base
helpers Sinatra::Streaming
end
Defined Under Namespace
Modules: Stream
Instance Method Summary collapse
Instance Method Details
#stream ⇒ Object
97 98 99 100 101 102 103 |
# File 'lib/sinatra/streaming.rb', line 97 def stream(*) stream = super stream.extend Stream stream.app = self env['async.close'].callback { stream.close } if env.key? 'async.close' stream end |