Class: Arachni::RPC::Server::Dispatcher::Service

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

Overview

Base class and namespace for all Dispatcher services.

# 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:

  • Tasos “Zapotek” Laskos <tasos.laskos@arachni-scanner.com>

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options, dispatcher) ⇒ Service

Returns a new instance of Service.



42
43
44
45
# File 'lib/arachni/rpc/server/dispatcher/service.rb', line 42

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

Instance Attribute Details

#dispatcherObject (readonly)

Returns the value of attribute dispatcher.



40
41
42
# File 'lib/arachni/rpc/server/dispatcher/service.rb', line 40

def dispatcher
  @dispatcher
end

#optionsObject (readonly)

Returns the value of attribute options.



39
40
41
# File 'lib/arachni/rpc/server/dispatcher/service.rb', line 39

def options
  @options
end

Instance Method Details

#connect_to_dispatcher(url) ⇒ Client::Dispatcher

Connects to a Dispatcher by `url`

Parameters:

Returns:



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

def connect_to_dispatcher( url )
    @dispatcher_connections ||= {}
    @dispatcher_connections[url] ||= Client::Dispatcher.new( options, 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:



136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/arachni/rpc/server/dispatcher/service.rb', line 136

def connect_to_instance( *args )
    url = token = nil

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

    @instance_connections ||= {}
    @instance_connections[url] ||= Client::Instance.new( options, 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.



91
92
93
# File 'lib/arachni/rpc/server/dispatcher/service.rb', line 91

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

#each_instance(&block) ⇒ Object

Performs an asynchronous iteration over all running instances.

Parameters:

  • block (Proc)

    Block to be passed Client::Instance and `Arachni::Reactor::Iterator`.



70
71
72
73
74
75
# File 'lib/arachni/rpc/server/dispatcher/service.rb', line 70

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 Alive instances.

Returns:



112
113
114
# File 'lib/arachni/rpc/server/dispatcher/service.rb', line 112

def instances
    dispatcher.running_jobs
end

#iterator_for(list, max_concurrency = 10) ⇒ Reactor::Iterator

Returns Iterator for the provided array.

Parameters:

Returns:

  • (Reactor::Iterator)

    Iterator for the provided array.



106
107
108
# File 'lib/arachni/rpc/server/dispatcher/service.rb', line 106

def iterator_for( list, max_concurrency = 10 )
    Reactor.global.create_iterator( list, 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 `Arachni::Reactor::Iterator`.

  • after (Proc)

    Block to be passed the Array of results.



59
60
61
62
63
64
# File 'lib/arachni/rpc/server/dispatcher/service.rb', line 59

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:



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

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)


98
99
100
# File 'lib/arachni/rpc/server/dispatcher/service.rb', line 98

def run_asap( &block )
    Reactor.global.next_tick( &block )
end