Object
EventMachine-based RPC server.
@author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
Starts EventMachine and the RPC 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) :serializer => Marshal, # serializer to use if the first choice fails :fallback_serializer => YAML, # # 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 [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/server.rb, line 76 def initialize( opts ) @opts = opts if @opts[:ssl_pkey] && @opts[:ssl_cert] if !File.exist?( @opts[:ssl_pkey] ) raise "Could not find private key at: #{@opts[:ssl_pkey]}" end if !File.exist?( @opts[:ssl_cert] ) raise "Could not find certificate at: #{@opts[:ssl_cert]}" end end @token = @opts[:token] @logger = ::Logger.new( STDOUT ) @logger.level = Logger::INFO @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 clear_handlers end
@example
server.add_async_check do |method| # # Must return 'true' for async and 'false' for sync. # # Very simple check here... # 'async' == method.name.to_s.split( '_' )[0] end
@param [Block] block
Block to identify methods that pass their result to a block instead of simply returning them (which is the most usual operation of async methods).
# File lib/arachni/rpc/em/server.rb, line 122 def add_async_check( &block ) @async_checks << block end
@example
server.add_handler( 'myclass', MyClass.new )
@param [String] name
Name by which to make the object available over RPC.
@param [Object] obj Instantiated server object to expose.
# File lib/arachni/rpc/em/server.rb, line 135 def add_handler( name, obj ) @objects[name] = obj @methods[name] = Set.new @async_methods[name] = Set.new obj.class.public_instance_methods( false ).each do |method| @methods[name] << method.to_s @async_methods[name] << method.to_s if async_check( obj.method( method ) ) end end
@return [TrueClass]
# File lib/arachni/rpc/em/server.rb, line 224 def alive? true end
@note If the called method is asynchronous it will be sent by this method
directly, otherwise it will be handled by the {Handler}.
@param [Handler] connection
Connection with request information.
@return [Arachni::RPC::Response]
# File lib/arachni/rpc/em/server.rb, line 184 def call( connection ) req = connection.request peer_ip_addr = connection.peer_ip_addr expr, args = req.message, req.args meth_name, obj_name = parse_expr( expr ) log_call( peer_ip_addr, expr, *args ) if !object_exist?( obj_name ) msg = "Trying to access non-existent object '#{obj_name}'." @logger.error( 'Call' ){ msg + " [on behalf of #{peer_ip_addr}]" } raise InvalidObject.new( msg ) end if !public_method?( obj_name, meth_name ) msg = "Trying to access non-public method '#{meth_name}'." @logger.error( 'Call' ){ msg + " [on behalf of #{peer_ip_addr}]" } raise InvalidMethod.new( msg ) end # The handler needs to know if this is an async call because if it is # we'll have already send the response and it doesn't need to do # transmit anything. res = Response.new res.async! if async?( obj_name, meth_name ) if res.async? @objects[obj_name].send( meth_name.to_sym, *args ) do |obj| res.obj = obj connection.send_response( res ) end else res.obj = @objects[obj_name].send( meth_name.to_sym, *args ) end res end
Clears all handlers and their associated information like methods and async check blocks.
@see add_handler @see add_async_check
# File lib/arachni/rpc/em/server.rb, line 151 def clear_handlers @objects = {} @methods = {} @async_checks = [] @async_methods = {} end
Runs the server and blocks while EM ir running.
# File lib/arachni/rpc/em/server.rb, line 160 def run Arachni::RPC::EM.schedule { start } Arachni::RPC::EM.block end
Shuts down the server after 2 seconds
# File lib/arachni/rpc/em/server.rb, line 229 def shutdown wait_for = 2 @logger.info( 'System' ){ "Shutting down in #{wait_for} seconds..." } # Don't die before returning... ::EM.add_timer( wait_for ) do File.unlink( @socket ) if @socket ::EM.stop end true end
Starts the server but does not block.
# File lib/arachni/rpc/em/server.rb, line 166 def start @logger.info( 'System' ){ 'RPC Server started.' } @logger.info( 'System' ) do interface = @socket ? @socket : "#{@host}:#{@port}" "Listening on #{interface}" end opts = @socket ? @socket : [@host, @port] ::EM.start_server( *[opts, Handler, self].flatten ) end
Generated with the Darkfish Rdoc Generator 2.