Class: Rack::Remote
- Inherits:
-
Object
- Object
- Rack::Remote
- Defined in:
- lib/rack/remote.rb,
lib/rack/remote/railtie.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.
Defined Under Namespace
Classes: ChainedError, Railtie, RemoteCallFailed, RemoteError
Constant Summary collapse
- VERSION =
'1.1.0'
Class Method Summary collapse
-
.add(name, options = {}) ⇒ Object
Add a new remote to be used in ‘invoke` by symbolic reference.
-
.calls ⇒ Object
Return hash with registered calls.
-
.clear ⇒ Object
Removes all registered calls.
-
.invoke(remote, call, params = {}, headers = {}) ⇒ Object
Invoke remote call.
-
.register(name, &block) ⇒ Object
Register a new remote call.
- .remotes ⇒ Object
Instance Method Summary collapse
- #call(env) ⇒ Object
-
#initialize(app) ⇒ Remote
constructor
A new instance of Remote.
Constructor Details
#initialize(app) ⇒ Remote
Returns a new instance of Remote.
45 46 47 |
# File 'lib/rack/remote.rb', line 45 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.
106 107 108 109 |
# File 'lib/rack/remote.rb', line 106 def add(name, = {}) raise ArgumentError unless [:url] remotes[name.to_sym] = end |
.calls ⇒ Object
Return hash with registered calls.
94 95 96 |
# File 'lib/rack/remote.rb', line 94 def calls @calls ||= {} end |
.clear ⇒ Object
Removes all registered calls.
99 100 101 102 |
# File 'lib/rack/remote.rb', line 99 def clear calls.clear remotes.clear end |
.invoke(remote, call, params = {}, headers = {}) ⇒ Object
Invoke remote call.
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/rack/remote.rb', line 122 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['Content-Type'] = 'application/json' request.body = MultiJson.dump(params) response = http.request request if response.code.to_i == 500 and response['Content-Type'] == 'application/json' json = MultiJson.load(response.body) if json['error'] && json['backtrace'] && json['class'] remote_error = RemoteError.new class: json['class'], error: json['error'], backtrace: json['backtrace'] raise Rack::Remote::RemoteCallFailed.new("Remote call returned error code #{response.code}", cause: remote_error) end end raise StandardError, "Rack Remote Error Response: #{response.code}: #{response.body}" if response.code.to_i != 200 if response['Content-Type'] == 'application/json' response.body.empty? ? {} : 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.
88 89 90 |
# File 'lib/rack/remote.rb', line 88 def register(name, &block) calls[name.to_s] = block end |
.remotes ⇒ Object
111 112 113 |
# File 'lib/rack/remote.rb', line 111 def remotes @remotes ||= {} end |
Instance Method Details
#call(env) ⇒ Object
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/rack/remote.rb', line 49 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]) begin # First rewind request body before read request.body.rewind data = request.body.read json = data.empty? ? {} : MultiJson.load(data) response = cb.call(json, env, request) if response.is_a?(Array) && response.size == 3 return response else [200, {'Content-Type' => 'application/json'}, StringIO.new(MultiJson.dump response) ] end rescue => err [500, {'Content-Type' => 'application/json'}, StringIO.new(MultiJson.dump error: err., backtrace: err.backtrace, class: err.class.name) ] end else [404, {'Content-Type' => 'application/json'}, StringIO.new(MultiJson.dump error: 'remote call not defined', calls: call, list: self.class.calls.keys) ] end end |