Class: Rack::Remote

Inherits:
Object
  • Object
show all
Defined in:
lib/rack/remote.rb,
lib/rack/remote/version.rb

Overview

Rack::Remote is a Rack middleware for intercepting calls and invoking remote calls. It can be used to call remote function for test instructions in distributed systems.

Constant Summary collapse

VERSION =
'1.0.0'

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(app) ⇒ Remote

Returns a new instance of Remote.



12
13
14
# File 'lib/rack/remote.rb', line 12

def initialize(app)
  @app = app
end

Class Method Details

.add(name, options = {}) ⇒ Object

Add a new remote to be used in invoke by symbolic reference.

Raises:

  • (ArgumentError)


63
64
65
66
# File 'lib/rack/remote.rb', line 63

def add(name, options = {})
  raise ArgumentError unless options[:url]
  remotes[name.to_sym] = options
end

.callsObject

Return hash with registered calls.



51
52
53
# File 'lib/rack/remote.rb', line 51

def calls
  @calls ||= {}
end

.clearObject

Removes all registered calls.



56
57
58
59
# File 'lib/rack/remote.rb', line 56

def clear
  calls.clear
  remotes.clear
end

.invoke(remote, call, params = {}, headers = {}) ⇒ Object

Invoke remote call.

Parameters:

  • remote (Symbol, String, #to_s)

    Symbolic remote name or remote URL.

  • call (String, #to_s)

    Remote call to invoke.

  • params (Hash) (defaults to: {})

    Key-Value pairs that will be converted to json and sent to remote call.

  • headers (Hash) (defaults to: {})

    Header added to request.



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/rack/remote.rb', line 79

def invoke(remote, call, params = {}, headers = {})
  remote = remotes[remote][:url] if remote.is_a? Symbol
  uri = URI.parse remote.to_s
  uri.path = '/' if uri.path.empty?

  Net::HTTP.start uri.host, uri.port do |http|
    request = Net::HTTP::Post.new uri.path
    headers.each do |key, value|
      request[key] = value.to_s
    end

    request['X-Rack-Remote-Call'] = call.to_s
    request.form_data = params

    response = http.request request
    raise StandardError, "Rack Remote Error Response: #{response.code}: #{response.body}" if response.code.to_i != 200

    if response['Content-Type'] == 'application/json'
      MultiJson.load response.body
    else
      response.body
    end
  end
end

.register(name, &block) ⇒ Object

Register a new remote call. Used on server side to define available remote calls.

Examples:

Rack::Remote.register :factory_girl do |env, request|
  FactoryGirl.create request.params[:factory]
end


45
46
47
# File 'lib/rack/remote.rb', line 45

def register(name, &block)
  calls[name.to_s] = block
end

.remotesObject



68
69
70
# File 'lib/rack/remote.rb', line 68

def remotes
  @remotes ||= {}
end

Instance Method Details

#call(env) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/rack/remote.rb', line 16

def call(env)
  return @app.call(env) unless env['HTTP_X_RACK_REMOTE_CALL']

  request = ::Rack::Request.new(env)
  call    = env['HTTP_X_RACK_REMOTE_CALL'].to_s

  if (cb = self.class.calls[call])
    response = cb.call(request.params, env, request)
    if response.is_a?(Array) && response.size == 3
      return response
    else
      [200, {'Content-Type' => 'application/json'}, StringIO.new(MultiJson.dump response) ]
    end
  else
    [404, {'Content-Type' => 'application/json'}, StringIO.new('{"error":"remote call not defined"}') ]
  end
end