Class: Arachni::RPC::Server::Dispatcher::Handler

Inherits:
Object
  • Object
show all
Defined in:
lib/arachni/rpc/server/dispatcher/handler.rb

Overview

Base class and namespace for all RPCD/Dispatcher handlers.

# RPC accessibility

Only PUBLIC methods YOU have defined will be accessible over RPC.

# Blocking operations

Please try to avoid blocking operations as they will block the main Reactor loop.

However, if you really need to perform such operations, you can update the relevant methods to expect a block and then pass the desired return value to that block instead of returning it the usual way.

This will result in the method’s payload to be deferred into a Thread of its own.

In addition, you can use the #defer and #run_asap methods is you need more control over what gets deferred and general scheduling.

# Asynchronous operations

Methods which perform async operations should expect a block and pass their results to that block instead of returning a value.

Author:

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts, dispatcher) ⇒ Handler

Returns a new instance of Handler.



51
52
53
54
# File 'lib/arachni/rpc/server/dispatcher/handler.rb', line 51

def initialize( opts, dispatcher )
    @opts       = opts
    @dispatcher = dispatcher
end

Instance Attribute Details

#dispatcherObject (readonly)

Returns the value of attribute dispatcher.



49
50
51
# File 'lib/arachni/rpc/server/dispatcher/handler.rb', line 49

def dispatcher
  @dispatcher
end

#optsObject (readonly)

Returns the value of attribute opts.



48
49
50
# File 'lib/arachni/rpc/server/dispatcher/handler.rb', line 48

def opts
  @opts
end

Instance Method Details

#connect_to_dispatcher(url) ⇒ Client::Dispatcher

Connects to a Dispatcher by ‘url`

Parameters:

Returns:



133
134
135
136
# File 'lib/arachni/rpc/server/dispatcher/handler.rb', line 133

def connect_to_dispatcher( url )
    @dispatcher_connections ||= {}
    @dispatcher_connections[url] ||= Client::Dispatcher.new( opts, url )
end

#connect_to_instance(*args) ⇒ Client::Instance

Connects to an Instance by ‘url`.

Examples:

connect_to_instance( url, token )
connect_to_instance( url: url, token: token )
connect_to_instance( 'url' => url, 'token' => token )

Parameters:

  • args (Vararg)

Returns:



150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/arachni/rpc/server/dispatcher/handler.rb', line 150

def connect_to_instance( *args )
    url = token = nil

    if args.size == 2
        url, token = *args
    elsif args.first.is_a? Hash
        options = args.first
        url     = options['url'] || options[:url]
        token   = options['token'] || options[:token]
    end

    @instance_connections ||= {}
    @instance_connections[url] ||= Client::Instance.new( opts, url, token )
end

#defer(operation = nil, callback = nil, &block) ⇒ Object

Defers a blocking operation in order to avoid blocking the main Reactor loop.

The operation will be run in its own Thread - DO NOT block forever.

Accepts either 2 parameters (an ‘operation` and a `callback` or an operation as a block.

Parameters:

  • operation (Proc) (defaults to: nil)

    Operation to defer.

  • callback (Proc) (defaults to: nil)

    Block to call with the results of the operation.

  • block (Block)

    Operation to defer.



99
100
101
# File 'lib/arachni/rpc/server/dispatcher/handler.rb', line 99

def defer( operation = nil, callback = nil, &block )
    ::EM.defer( *[operation, callback].compact, &block )
end

#each_instance(&block) ⇒ Object

Performs an asynchronous iteration over all running instances.

Parameters:



79
80
81
82
83
84
# File 'lib/arachni/rpc/server/dispatcher/handler.rb', line 79

def each_instance( &block )
    wrap = proc do |instance, iterator|
        block.call( connect_to_instance( instance ), iterator )
    end
    iterator_for( instances ).each( &wrap )
end

#instancesArray<Hash>

Returns All running instances.

Returns:



122
123
124
# File 'lib/arachni/rpc/server/dispatcher/handler.rb', line 122

def instances
    dispatcher.jobs.select { |j| !j['proc'].empty? }
end

#iterator_for(arr, max_concurrency = 10) ⇒ ::EM::Iterator

Returns Iterator for the provided array.

Parameters:

Returns:

  • (::EM::Iterator)

    Iterator for the provided array.



117
118
119
# File 'lib/arachni/rpc/server/dispatcher/handler.rb', line 117

def iterator_for( arr, max_concurrency = 10 )
    ::EM::Iterator.new( arr, max_concurrency )
end

#map_instances(each, after) ⇒ Object

Performs an asynchronous map operation over all running instances.

Parameters:

  • each (Proc)

    Block to be passed Client::Instance and EM::Iterator.

  • after (Proc)

    Block to be passed the Array of results.



67
68
69
70
71
72
# File 'lib/arachni/rpc/server/dispatcher/handler.rb', line 67

def map_instances( each, after )
    wrap_each = proc do |instance, iterator|
        each.call( connect_to_instance( instance ), iterator )
    end
    iterator_for( instances ).map( wrap_each, after )
end

#nodeServer::Dispatcher::Node

Returns Local node.

Returns:



57
58
59
# File 'lib/arachni/rpc/server/dispatcher/handler.rb', line 57

def node
    dispatcher.instance_eval { @node }
end

#run_asap(&block) ⇒ Object

Runs a block as soon as possible in the Reactor loop.

Parameters:

  • block (Block)


108
109
110
# File 'lib/arachni/rpc/server/dispatcher/handler.rb', line 108

def run_asap( &block )
    ::EM.next_tick( &block )
end