class RJR::Dispatcher

Primary RJR JSON-RPC method dispatcher.

Attributes

environments[R]

Registered json-rpc request signatures and environments which to execute handlers in

handlers[R]

Registered json-rpc request signatures and corresponding handlers

keep_requests[RW]

Flag toggling whether or not to keep requests (& responses) around.

Public Class Methods

new(args = {}) click to toggle source

RJR::Dispatcher intializer

# File lib/rjr/dispatcher.rb, line 37
def initialize(args = {})
  @keep_requests = args[:keep_requests] || false

  clear!
  @requests_lock = Mutex.new
end

Public Instance Methods

add_module(name) click to toggle source

Loads module from fs and adds handlers defined there

Assumes module includes a ‘dispatch_<module_name>’ method which accepts a dispatcher and defines handlers on it.

@param [String] name location which to load module(s) from, may be

a file, directory, or path specification (dirs seperated with ':')

@return self

# File lib/rjr/dispatcher.rb, line 59
def add_module(name)
  require name

  m = name.downcase.gsub(File::SEPARATOR, '_')
  method("dispatch_#{m}".intern).call(self)

  self
end
Also aliased as: add_modules
add_modules(name)
Alias for: add_module
clear!() click to toggle source

Return dispatcher to its initial state

# File lib/rjr/dispatcher.rb, line 45
def clear!
  @handlers      = {}
  @environments  = {}
  @requests      = []
end
dispatch(args = {}) click to toggle source

Dispatch received request. (used internally by nodes).

Arguments should include :rjr_method and other parameters required to construct a valid Request instance

# File lib/rjr/dispatcher.rb, line 141
def dispatch(args = {})
  rjr_method = args[:rjr_method]

  # *note* not using concurrent access protection,
  # assumes all handlers/enviroments are registered
  # before first dispatch occurs
  handler     = handler_for(rjr_method)
  environment = env_for(rjr_method)

  return Result.method_not_found(rjr_method) if handler.nil?

  request = Request.new args.merge(:rjr_handler  => handler)

  # set request environment
  request.set_env(environment) unless environment.nil?

  begin
    retval = request.handle
    request.result  = Result.new(:result => retval)

  rescue Exception => e
    warning = "Exception Raised in #{rjr_method} handler #{e}"
    RJR::Logger.warn [warning] + e.backtrace

    request.result = Result.new(:error_code  => -32000,
                                :error_msg   => e.to_s,
                                :error_class => e.class)
  end

  store_request request
  return request.result
end
env(signature, environment) click to toggle source

Register environment to run json-rpc handler w/ dispatcher.

Currently environments may be set to modules which requests will extend before executing handler

@param [String,Regex] signature request signature to match @param [Module] environment module which to extend requests with @return self

# File lib/rjr/dispatcher.rb, line 117
def env(signature, environment)
  if signature.is_a?(Array)
    signature.each { |s| env(s, environment) }
    return self
  end
  @environments[signature] = environment
  self
end
env_for(rjr_method) click to toggle source

Return the environment registered for the specified method

# File lib/rjr/dispatcher.rb, line 127
def env_for(rjr_method)
   # look for exact match first
   env = @environments.find { |k,v| k == rjr_method }

   # if not found try to match regex's
   env ||= @environments.find { |k,v| k.is_a?(Regexp) && (k =~ rjr_method) }

   env.nil? ? nil : env.last
end
handle(signature, callback = nil, &bl) click to toggle source

Register json-rpc handler with dispatcher

@param [String,Regex] signature request signature to match @param [Callable] callback callable object which to bind to signature @param [Callable] bl block parameter will be set to callback if specified @return self

# File lib/rjr/dispatcher.rb, line 75
def handle(signature, callback = nil, &bl)
  if signature.is_a?(Array)
    signature.each { |s| handle(s, callback, &bl) }
    return self
  end
  @handlers[signature] = callback unless callback.nil?
  @handlers[signature] = bl       unless bl.nil?
  self
end
handle_response(result) click to toggle source

Handle responses received from rjr requests. (used internally by nodes)

Returns return-value of method handler or raises error

# File lib/rjr/dispatcher.rb, line 177
def handle_response(result)
   unless result.success
     #if result.error_class
     #  TODO needs to be constantized first (see TODO in lib/rjr/message)
     #  raise result.error_class.new(result.error_msg) unless result.success
     #else
       fail result.error_msg
     #end
   end
   return result.result
end
handler_for(rjr_method) click to toggle source

Return handler for specified method.

Currently we match method name string or regex against signature @param [String] rjr_method string rjr method to match @return [Callable, nil] callback proc registered to handle rjr_method

or nil if not found
# File lib/rjr/dispatcher.rb, line 91
def handler_for(rjr_method)
  # look for exact match first
  handler = @handlers.find { |k,v| k == rjr_method }

  # if not found try to match regex's
  handler ||= @handlers.find { |k,v| k.is_a?(Regexp) && (k =~ rjr_method) }

  handler.nil? ? nil : handler.last
end
handles?(rjr_method) click to toggle source

Return boolean indicating if dispatcher can handle method

@param [String] rjr_method string rjr method to match @return [true,false] indicating if requests to specified method will be matched

# File lib/rjr/dispatcher.rb, line 105
def handles?(rjr_method)
  !handler_for(rjr_method).nil?
end
requests() click to toggle source

Requests which have been dispatched

# File lib/rjr/dispatcher.rb, line 27
def requests
  @requests_lock.synchronize { Array.new(@requests) }
end
store_request(request) click to toggle source

Store request if configured to do so

# File lib/rjr/dispatcher.rb, line 32
def store_request(request)
  @requests_lock.synchronize { @requests << request } if @keep_requests
end