class Rack::Remote
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.
Constants
- VERSION
Public Class Methods
add(name, options = {})
click to toggle source
Add a new remote to be used in ‘invoke` by symbolic reference.
# File lib/rack/remote.rb, line 106 def add(name, options = {}) raise ArgumentError unless options[:url] remotes[name.to_sym] = options end
calls()
click to toggle source
Return hash with registered calls.
# File lib/rack/remote.rb, line 94 def calls @calls ||= {} end
clear()
click to toggle source
Removes all registered calls.
# File lib/rack/remote.rb, line 99 def clear calls.clear remotes.clear end
invoke(remote, call, params = {}, headers = {})
click to toggle source
Invoke remote call.
@param remote [Symbol, String, to_s] Symbolic remote name or remote URL. @param call [String, to_s] Remote
call to invoke. @param params [Hash] Key-Value pairs that will be converted to json and sent to remote call. @param headers [Hash] Header added to request.
# 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
new(app)
click to toggle source
# File lib/rack/remote.rb, line 45 def initialize(app) @app = app end
register(name, &block)
click to toggle source
Register a new remote call. Used on server side to define available remote calls.
@example
Rack::Remote.register :factory_girl do |env, request| FactoryGirl.create request.params[:factory] end
@params name [String, to_s] Remote
call name
# File lib/rack/remote.rb, line 88 def register(name, &block) calls[name.to_s] = block end
remotes()
click to toggle source
# File lib/rack/remote.rb, line 111 def remotes @remotes ||= {} end
Public Instance Methods
call(env)
click to toggle source
# 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.message, 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