Class: Goliath::Rack::SimpleAroundwareFactory

Inherits:
Object
  • Object
show all
Includes:
Validator
Defined in:
lib/goliath/rack/simple_aroundware_factory.rb

Overview

Include this to enable middleware that can perform pre- and post-processing.

For internal reasons, you can’t do the following as you would in Rack:

def call(env)
  # ... do pre-processing
  status, headers, body = @app.call(env)
  new_body = make_totally_awesome(body) ## !! BROKEN !!
  [status, headers, new_body]
end

This class creates a “aroundware” helper to do that kind of processing. Goliath proceeds asynchronously, but will still “unwind” the request by walking up the callback chain. Delegating out to the aroundware also lets you carry state around – the ban on instance variables no longer applies, as each aroundware is unique per request.

Direct Known Subclasses

BarrierAroundwareFactory

Instance Method Summary collapse

Methods included from Validator

safely, validation_error

Constructor Details

#initialize(app, aroundware_klass, *args) ⇒ Goliath::Rack::AroundwareFactory

Called by the framework to create the middleware.

Any extra args passed to the use statement are sent to each aroundware_klass as it is created.

Examples:

class Awesomizer2011
  include Goliath::Rack::SimpleAroundware
  def initialize(env, aq)
    @awesomeness_quotient = aq
    super(env)
  end
  # ... define pre_process and post_process ...
end

class AwesomeApiWithShortening < Goliath::API
  use Goliath::Rack::SimpleAroundwareFactory, Awesomizer2011, 3
  # ... stuff ...
end

Parameters:

  • app (#call)

    the downstream app

  • aroundware_klass

    a class that quacks like a Goliath::Rack::SimpleAroundware and an EM::Deferrable

  • *args (Array)

    extra args to pass to the aroundware



54
55
56
57
58
# File 'lib/goliath/rack/simple_aroundware_factory.rb', line 54

def initialize app, aroundware_klass, *args
  @app = app
  @aroundware_klass = aroundware_klass
  @aroundware_args  = args
end

Instance Method Details

#call(env) ⇒ Array

Coordinates aroundware to process a request.

We hook the aroundware in the middle of the async_callback chain:

  • send the downstream response to the aroundware, whether received directly from @app.call or via async callback

  • have the upstream callback chain be invoked when the aroundware completes

Parameters:

Returns:

  • (Array)

    The [status_code, headers, body] tuple



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/goliath/rack/simple_aroundware_factory.rb', line 69

def call(env)
  aroundware = new_aroundware(env)

  aroundware_resp = aroundware.pre_process
  return aroundware_resp if final_response?(aroundware_resp)

  hook_into_callback_chain(env, aroundware)

  downstream_resp = @app.call(env)

  # if downstream resp is final, pass it to the aroundware; it will invoke
  # the callback chain at its leisure. Our response is *always* async.
  if final_response?(downstream_resp)
    aroundware.accept_response(:downstream_resp, true, downstream_resp)
  end
  return Goliath::Connection::AsyncResponse
end

#final_response?(resp) ⇒ Boolean

Returns:

  • (Boolean)


106
107
108
# File 'lib/goliath/rack/simple_aroundware_factory.rb', line 106

def final_response?(resp)
  resp != Goliath::Connection::AsyncResponse
end

#hook_into_callback_chain(env, aroundware) ⇒ Object

Put aroundware in the middle of the async_callback chain:

  • save the old callback chain;

  • have the downstream callback send results to the aroundware (possibly completing it)

  • set the old callback chain to fire when the aroundware completes



92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/goliath/rack/simple_aroundware_factory.rb', line 92

def hook_into_callback_chain(env, aroundware)
  async_callback = env['async.callback']

  # The response from the downstream app is accepted by the aroundware...
  # ... and we immediately call post_process and hand it upstream
  downstream_callback = Proc.new do |resp|
    safely(env){ aroundware.accept_response(:downstream_resp, true, resp) }
    new_resp = safely(env){ aroundware.post_process }
    async_callback.call(new_resp)
  end

  env['async.callback'] = downstream_callback
end

#new_aroundware(env) ⇒ Goliath::Rack::SimpleAroundware

Generate a aroundware to process the request, using request env & any args passed to this AroundwareFactory at creation

Parameters:

Returns:



115
116
117
# File 'lib/goliath/rack/simple_aroundware_factory.rb', line 115

def new_aroundware(env)
  @aroundware_klass.new(env, *@aroundware_args)
end