Object
Simple EventMachine-based RPC client.
It's capable of:
Performing and handling a few thousands requests per second (depending on
call size, network conditions and the like)
TLS encryption
Asynchronous and synchronous requests
Handling remote asynchronous calls that require a block
@author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
Default amount of connections to maintain in the re-use pool.
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
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
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
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
# File lib/arachni/rpc/em/client.rb, line 165 def increment_connection_counter @connection_count += 1 end
{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
Generated with the Darkfish Rdoc Generator 2.