Class: RJR::Dispatcher

Inherits:
Object show all
Defined in:
lib/rjr/dispatcher.rb

Overview

Primary RJR JSON-RPC method dispatcher.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(args = {}) ⇒ Dispatcher

RJR::Dispatcher intializer



37
38
39
40
41
42
# File 'lib/rjr/dispatcher.rb', line 37

def initialize(args = {})
  @keep_requests = args[:keep_requests] || false

  clear!
  @requests_lock = Mutex.new
end

Instance Attribute Details

#environmentsObject (readonly)

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



21
22
23
# File 'lib/rjr/dispatcher.rb', line 21

def environments
  @environments
end

#handlersObject (readonly)

Registered json-rpc request signatures and corresponding handlers



18
19
20
# File 'lib/rjr/dispatcher.rb', line 18

def handlers
  @handlers
end

#keep_requestsObject

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



24
25
26
# File 'lib/rjr/dispatcher.rb', line 24

def keep_requests
  @keep_requests
end

Instance Method Details

#add_module(name) ⇒ Object Also known as: add_modules

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.

Parameters:

  • name (String)

    location which to load module(s) from, may be a file, directory, or path specification (dirs seperated with ‘:’)

Returns:

  • self



59
60
61
62
63
64
65
66
# 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

#clear!Object

Return dispatcher to its initial state



45
46
47
48
49
# File 'lib/rjr/dispatcher.rb', line 45

def clear!
  @handlers      = {}
  @environments  = {}
  @requests      = []
end

#dispatch(args = {}) ⇒ Object

Dispatch received request. (used internally by nodes).

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



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# 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.extend(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) ⇒ Object

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

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

Parameters:

  • signature (String, Regex)

    request signature to match

  • environment (Module)

    module which to extend requests with

Returns:

  • self



117
118
119
120
121
122
123
124
# 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) ⇒ Object

Return the environment registered for the specified method



127
128
129
130
131
132
133
134
135
# 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) ⇒ Object

Register json-rpc handler with dispatcher

Parameters:

  • signature (String, Regex)

    request signature to match

  • callback (Callable) (defaults to: nil)

    callable object which to bind to signature

  • bl (Callable)

    block parameter will be set to callback if specified

Returns:

  • self



75
76
77
78
79
80
81
82
83
# 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) ⇒ Object

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

Returns return-value of method handler or raises error



177
178
179
180
181
182
183
184
185
186
187
# 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
       raise Exception, result.error_msg
     #end
   end
   return result.result
end

#handler_for(rjr_method) ⇒ Callable?

Return handler for specified method.

Currently we match method name string or regex against signature

Parameters:

  • rjr_method (String)

    string rjr method to match

Returns:

  • (Callable, nil)

    callback proc registered to handle rjr_method or nil if not found



91
92
93
94
95
96
97
98
99
# 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) ⇒ true, false

Return boolean indicating if dispatcher can handle method

Parameters:

  • rjr_method (String)

    string rjr method to match

Returns:

  • (true, false)

    indicating if requests to specified method will be matched



105
106
107
# File 'lib/rjr/dispatcher.rb', line 105

def handles?(rjr_method)
  !handler_for(rjr_method).nil?
end

#requestsObject

Requests which have been dispatched



27
28
29
# File 'lib/rjr/dispatcher.rb', line 27

def requests
  @requests_lock.synchronize { Array.new(@requests) }
end

#store_request(request) ⇒ Object

Store request if configured to do so



32
33
34
# File 'lib/rjr/dispatcher.rb', line 32

def store_request(request)
  @requests_lock.synchronize { @requests << request } if @keep_requests
end