Module: Sinatra::Async::InstanceMethods

Defined in:
lib/sinatra/async.rb

Instance Method Summary collapse

Instance Method Details

#async(method_name = nil, &block) ⇒ Object

Repond to this request asynchronously.

Can be passed a block or method name which will be queued for execution, or just aborts the current flow and presumes you’ll respond later.

The return value of the supplied block or method will be used as a response, as per a normal Sinatra route handler, unless:

* If it is an EM::Deferrable, we will respond as a succeed
  callback.

* If it is nil, is an EM::Timer or EM::PeriodicTimer we
  presume you'll respond later using #async_respond.

Raises:

  • (RuntimeError)


21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/sinatra/async.rb', line 21

def async method_name=nil, &block
  raise RuntimeError, 'Not running in async capable server -- try Thin' unless env.has_key?('async.callback')
  
  block ||= method method_name if method_name
  
  if block
    EM.next_tick do
      catch :async do
        returned = invoke { route_eval &block }
        
        if returned.is_a? EventMachine::Deferrable
          returned.callback do |*args|
            invoke { throw :halt, args.first } unless args.empty?
            async_call!
          end
        elsif returned.is_a?(EventMachine::Timer) || returned.is_a?(EventMachine::PeriodicTimer)
          returned = nil
        end
        
        async_call! unless returned.nil?
      end
    end
  end

  throw :async
end

#async_call!Object

Resumes #call! and sends an asynchronous response

To DRY this up we’d need to break up Sinatra::Base#call!



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/sinatra/async.rb', line 57

def async_call!
  invoke { error_block! response.status }

  unless @response['Content-Type']
    if body.respond_to?(:to_ary) and body.first.respond_to? :content_type
      content_type body.first.content_type
    else
      content_type :html
    end
  end

  status, header, body = @response.finish

  # Never produce a body on HEAD requests. Do retain the Content-Length
  # unless it's "0", in which case we assume it was calculated erroneously
  # for a manual HEAD response and remove it entirely.
  if @env['REQUEST_METHOD'] == 'HEAD'
    body = []
    header.delete('Content-Length') if header['Content-Length'] == '0'
  end

  env['async.callback'].call [status, header, body]
end

#async_respond(response) ⇒ Object

Respond to an existing asynchronous request.



49
50
51
52
# File 'lib/sinatra/async.rb', line 49

def async_respond response
  invoke { throw :halt, response }
  async_call!
end