class KRPC::Client
A kRPC client, through which all Remote Procedure Calls are made. To make RPC calls client must first connect to server. This can be achieved by calling Client#connect
or Client#connect!
methods. Client
object can connect and disconnect from the server many times during it's lifetime. RPCs can be made by calling Client#execute_rpc
method. After generating the services API (with Client#generate_services_api!
call), RPCs can be also made using client.service_name.procedure_name(parameter, ...)
Example:¶ ↑
client = KRPC::Client.new(name: "my client").connect! # Notice that Client#connect! is shorthand for calling Client#connect and Client#generate_services_api! subsequently ctrl = client.space_center.active_vessel.control ctrl.activate_next_stage ctrl.throttle = 1 # Full ahead! client.close # Gracefully disconnect - and allow the spacecraft to crash ;) client.connect do # Connect to server again client.space_center.active_vessel.control.throttle = 0 # Save the spacecraft from imminent destruction ;) end # Gracefully disconnect
Constants
- DEFAULT_NAME
Attributes
Public Class Methods
Create new Client
object, optionally specifying IP address and port numbers on witch kRPC server is listening and the name for this client.
# File lib/krpc/client.rb, line 39 def initialize(name: DEFAULT_NAME, host: Connection::DEFAULT_SERVER_HOST, rpc_port: Connection::DEFAULT_SERVER_RPC_PORT, stream_port: Connection::DEFAULT_SERVER_STREAM_PORT) @name = name @rpc_connection = RPCConnection.new(name, host, rpc_port) @stream_connection = StreamConnection.new(rpc_connection, host, stream_port) @streams_manager = Streaming::StreamsManager.new(self) @services = {} @core = Services::Core.new(self) Doc.add_docstring_info(false, self.class, "core", return_type: @core.class, xmldoc: "<doc><summary>Core kRPC service, e.g. for querying for the available services. Most of this functionality is used internally by the Ruby client and therefore does not need to be used directly from application code. This service is hardcoded (in kRPC Ruby client) version of 'krpc' service, so 1) it is available even before the services API is generated, but 2) can be out of sync with 'krpc' service.</summary></doc>") end
Public Instance Methods
Build an exception from an PB::Error object.
# File lib/krpc/client.rb, line 167 def build_exception(error) msg = error.description msg = "#{error.service}.#{error.name}: #{msg}" unless error.field_empty?(:service) || error.field_empty?(:name) msg += "\nServer stack trace:\n#{error.stack_trace}" unless error.field_empty?(:stack_trace) RPCError.new(msg) end
Build an PB::ProcedureCall object.
# File lib/krpc/client.rb, line 153 def build_procedure_call(service, procedure, args=[], kwargs={}, param_names=[], param_types=[], param_default=[]) begin raise(ArgumentError, "param_names and param_types should be equal length\n\tparam_names = #{param_names}\n\tparam_types = #{param_types}") unless param_names.length == param_types.length raise(ArgumentError, "param_names and param_default should be equal length\n\tparam_names = #{param_names}\n\tparam_default = #{param_default}") unless param_names.length == param_default.length required_params_count = param_default.take_while{|pd| pd == :no_default_value}.count raise ArgumentsNumberErrorSig.new(args.count, required_params_count..param_names.count) unless args.count <= param_names.count call_args = construct_arguments(args, kwargs, param_names, param_types, param_default, required_params_count) rescue ArgumentErrorSig => err raise err.with_signature(Doc.docstring_for_procedure(service, procedure, false)) end PB::ProcedureCall.new(service: service, procedure: procedure, arguments: call_args) end
Build an PB::Request object.
# File lib/krpc/client.rb, line 147 def build_request(service, procedure, args=[], kwargs={}, param_names=[], param_types=[], param_default=[]) call = build_procedure_call(service, procedure, args, kwargs, param_names, param_types, param_default) PB::Request.new(calls: [call]) end
Close connection to kRPC server. Returns true
if the connection has closed or false
if the client had been already disconnected.
# File lib/krpc/client.rb, line 73 def close streams_manager.remove_all_streams streams_manager.stop_streaming_thread stream_connection.close rpc_connection.close end
Connect to a kRPC server on the IP address and port numbers specified during this client object creation and return self
. Calling this method while the client is already connected will raise an exception. If the block is given, then it's called passing self
and the connection to kRPC server is closed at the end of the block.
# File lib/krpc/client.rb, line 53 def connect(&block) rpc_connection.connect stream_connection.connect streams_manager.start_streaming_thread call_block_and_close(block) if block_given? self end
Connect to a kRPC server, generate the services API and return self
. Shorthand for calling Client#connect
and Client#generate_services_api!
subsequently. If the block is given, then it's called passing self
and the connection to kRPC server is closed at the end of the block.
# File lib/krpc/client.rb, line 64 def connect!(&block) connect generate_services_api! call_block_and_close(block) if block_given? self end
Returns true
if the client is connected to a server, false
otherwise.
# File lib/krpc/client.rb, line 81 def connected? rpc_connection.connected? end
Execute an RPC.
# File lib/krpc/client.rb, line 132 def execute_rpc(service, procedure, args=[], kwargs={}, param_names=[], param_types=[], param_default=[], return_type: nil) send_request(service, procedure, args, kwargs, param_names, param_types, param_default) result = receive_result raise build_exception(result.error) unless result.field_empty? :error unless return_type.nil? Decoder.decode(result.value, return_type, self) else nil end rescue IOError => e raise(Error, "RPC call attempt while not connected to a server -- call Client#connect first") if not connected? raise e end
Interrogates the server to find out what functionality it provides and dynamically creates all of the classes and methods that form the services API. For each service that server provides:
-
Class
KRPC::Services::{service name here}
, and moduleKRPC::Gen::{service name here}
are created. -
KRPC::Gen::{service name here}
module is filled with dynamically created classes. -
Those classes in turn are filled with dynamically created methods, which form the API for this service.
-
Instance method
{service name here}
is created in this client object that returnsKRPC::Services::{service name here}
object. This object is entry point for accessing functionality provided by{service name here}
service.
Returns self
. Invoking this method the second and subsequent times doesn't regenerate the API. To regenerate the API create new Client
object and call generate_services_api!
on it.
Example¶ ↑
client = KRPC::Client.new(name: "my client").connect # Notice that it is 'Client#connect' being called, not 'Client#connect!' sc = client.space_center # => Exception (undefined method "space_center") client.generate_services_api! sc = client.space_center # => KRPC::Services::SpaceCenter object v = sc.active_vessel # => KRPC::Gen::SpaceCenter::Vessel object v.mass # => {some number here} client.close
# File lib/krpc/client.rb, line 108 def generate_services_api! return self if services_api_generated? raise(Error, "Can't generate the services API while not connected to a server -- call Client#connect! to connect to server and generate the services API in one call") if not connected? resp = core.get_services resp.services.each do |service_msg| service_class = Services.create_service(service_msg) method_name = service_class.class_name.underscore self.class.instance_eval do define_method method_name do @services[service_class.class_name] ||= service_class.new(self) end end Doc.add_docstring_info(false, self.class, method_name, return_type: service_class, xmldoc: service_msg.documentation) end self end
Returns true
if the services API has been already generated, false
otherwise.
# File lib/krpc/client.rb, line 127 def services_api_generated? respond_to? :space_center or respond_to? :test_service end