Parent

Included Modules

Arachni::RPC::EM::Client

Simple EventMachine-based RPC client.

It's capable of:

@author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>

Constants

DEFAULT_CONNECTION_POOL_SIZE

Default amount of connections to maintain in the re-use pool.

Attributes

connection_count[R]
opts[R]

@return [Hash] Options hash.

Public Class Methods

new( opts ) click to toggle source

Starts EventMachine and connects to the remote server.

@example Example options:

{
    :host  => 'localhost',
    :port  => 7331,

    # optional authentication token, if it doesn't match the one
    # set on the server-side you'll be getting exceptions.
    :token => 'superdupersecret',

    # optional serializer (defaults to YAML)
    # see the 'serializer' method at:
    # http://eventmachine.rubyforge.org/EventMachine/Protocols/ObjectProtocol.html#M000369
    :serializer => Marshal,

    # serializer to use if the first choice fails
    :fallback_serializer => YAML,

    :max_retries => 0,

    #
    # In order to enable peer verification one must first provide
    # the following:
    #
    # SSL CA certificate
    :ssl_ca     => cwd + '/../spec/pems/cacert.pem',
    # SSL private key
    :ssl_pkey   => cwd + '/../spec/pems/client/key.pem',
    # SSL certificate
    :ssl_cert   => cwd + '/../spec/pems/client/cert.pem'
}

@param [Hash] opts @option opts [String] :host Hostname/IP address. @option opts [Integer] :port Port number. @option opts [String] :socket Path to UNIX domain socket. @option opts [Integer] :connection_pool_size (1)

Amount of connections to keep open.

@option opts [String] :token Optional authentication token. @option opts [.dump, .load] :serializer (YAML)

Serializer to use for message transmission.

@option opts [.dump, .load] :fallback_serializer

Optional fallback serializer to be used when the primary one fails.

@option opts [Integer] :max_retries

How many times to retry failed requests.

@option opts [String] :ssl_ca SSL CA certificate. @option opts [String] :ssl_pkey SSL private key. @option opts [String] :ssl_cert SSL certificate.

# File lib/arachni/rpc/em/client.rb, line 91
def initialize( opts )
    @opts  = opts.merge( role: :client )
    @token = @opts[:token]

    @host, @port = @opts[:host], @opts[:port]
    @socket = @opts[:socket]

    if !@socket && !(@host || @port)
        fail ArgumentError, 'Needs either a :socket or :host and :port options.'
    end

    @port = @port.to_i

    if @host && @port <= 0
        fail ArgumentError, "Invalid port: #{@port}"
    end

    if @socket && !File.exist?( @socket )
        fail ArgumentError, "Socket path not valid: #{@socket}"
    end

    @pool_size = @opts[:connection_pool_size] || DEFAULT_CONNECTION_POOL_SIZE

    @connections      = ::EM::Queue.new
    @connection_count = 0

    Arachni::RPC::EM.ensure_em_running
end

Public Instance Methods

call( msg, *args, &block ) click to toggle source

Calls a remote method and grabs the result.

There are 2 ways to perform a call, async (non-blocking) and sync (blocking).

@example To perform an async call you need to provide a block to handle the result.

server.call( 'handler.method', arg1, arg2 ) do |res|
    do_stuff( res )
end

@example To perform a sync (blocking), call without a block.

res = server.call( 'handler.method', arg1, arg2 )

@param [String] msg

RPC message in the form of `handler.method`.

@param [Array] args

Collection of arguments to be passed to the method.

@param [Block] block

# File lib/arachni/rpc/em/client.rb, line 213
def call( msg, *args, &block )
    req = Request.new(
        message:  msg,
        args:     args,
        callback: block,
        token:    @token
    )

    block_given? ? call_async( req ) : call_sync( req )
end
connect( &block ) click to toggle source

Connection factory, will re-use or create new connections as needed to accommodate the workload.

@param [Block] block Block to be passed a {Handler connection}.

@return [Boolean]

`true` if a new connection had to be established, `false` if an existing
one was re-used.
# File lib/arachni/rpc/em/client.rb, line 128
def connect( &block )
    if @connections.empty? && @connection_count < @pool_size
        #p 'NEW'
        #p connection_count
        begin
            opts = @socket ? @socket : [@host, @port]
            block.call ::EM.connect( *[opts, Handler, @opts.merge( client: self )].flatten )
            increment_connection_counter
        rescue => e
            block.call e
        end
        return true
    end

    pop_block = proc do |conn|
        # Some connections may have died while they were waiting in the
        # queue, get rid of them and start all over in case the queue has
        # been emptied.
        if !conn.done?
            #p 'NOT DONE'
            #p connection_count
            connection_failed conn
            connect( &block )
            next
        end

        block.call conn
    end

    #p 'REUSE'
    #p connection_count
    #p @connections.size
    @connections.pop( &pop_block )

    false
end
connection_failed( connection ) click to toggle source

Handles failed connections.

@param [Handler] connection

# File lib/arachni/rpc/em/client.rb, line 183
def connection_failed( connection )
    #p 'CON FAILED'
    #p connection_count
    #p @connections.size
    @connection_count -= 1
    connection.close_without_retry
end
increment_connection_counter() click to toggle source
# File lib/arachni/rpc/em/client.rb, line 165
def increment_connection_counter
    @connection_count += 1
end
push_connection( connection ) click to toggle source

{Handler#done? Finished} {Handler}s push themselves here to be re-used.

@param [Handler] connection

# File lib/arachni/rpc/em/client.rb, line 172
def push_connection( connection )
    #p 'PUSHING BACK'
    #p connection_count
    #p @connections.size
    #return if @pool_size <= 0 || @connections.size > @pool_size
    @connections << connection
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.