Class: Volt::Dispatcher

Inherits:
Object show all
Includes:
DRb::DRbUndumped
Defined in:
lib/volt/tasks/dispatcher.rb

Overview

The task dispatcher is responsible for taking incoming messages from the socket channel and dispatching them to the proper handler.

Instance Method Summary collapse

Instance Method Details

#dispatch(channel, message) ⇒ Object

Dispatch takes an incoming Task from the client and runs it on the server, returning the result to the client. Tasks returning a promise will wait to return.



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/volt/tasks/dispatcher.rb', line 15

def dispatch(channel, message)
  callback_id, class_name, method_name, , *args = message
  method_name = method_name.to_sym

  # Get the class
  klass = Object.send(:const_get, class_name)

  promise = Promise.new

  start_time = Time.now.to_f

  # Check that we are calling on a Task class and a method provide at
  # Task or above in the ancestor chain. (so no :send or anything)
  if safe_method?(klass, method_name)
    promise.resolve(nil)

    # Init and send the method
    promise = promise.then do
      Thread.current['meta'] = 

      # # Profile the code
      # RubyProf.start

      result = klass.new(channel, self).send(method_name, *args)

      # res = RubyProf.stop
      #
      # # Print a flat profile to text
      # printer = RubyProf::FlatPrinter.new(res)
      # printer.print(STDOUT)

      Thread.current['meta'] = nil

      result
    end

  else
    # Unsafe method
    promise.reject(RuntimeError.new("unsafe method: #{method_name}"))
  end

  # Called after task runs or fails
  finish = proc do |error|
    run_time = ((Time.now.to_f - start_time) * 1000).round(3)
    Volt.logger.log_dispatch(class_name, method_name, run_time, args, error)
  end

    # Run the promise and pass the return value/error back to the client
  promise.then do |result|
    channel.send_message('response', callback_id, result, nil)

    finish.call
  end.fail do |error|
    finish.call(error)
    channel.send_message('response', callback_id, nil, error)
  end
end

#safe_method?(klass, method_name) ⇒ Boolean

Check if it is safe to use this method

Returns:



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/volt/tasks/dispatcher.rb', line 74

def safe_method?(klass, method_name)
  # Make sure the class being called is a Task.
  return false unless klass.ancestors.include?(Task)

  # Make sure the method is defined on the klass we're using and not up the hiearchy.
  #   ^ This check prevents methods like #send, #eval, #instance_eval, #class_eval, etc...
  klass.ancestors.each do |ancestor_klass|
    if ancestor_klass.instance_methods(false).include?(method_name)
      return true
    elsif ancestor_klass == Task
      # We made it to Task and didn't find the method, that means it
      # was defined above Task, so we reject the call.
      return false
    end
  end

  false
end