Module: Protobuf::Rpc::Server
- Included in:
- EventedServer, SocketServer, Protobuf::Rpc::SocketServer::Worker
- Defined in:
- lib/protobuf/rpc/server.rb
Instance Method Summary collapse
-
#handle_client ⇒ Object
Invoke the service method dictated by the proto wrapper request object.
-
#handle_error(error) ⇒ Object
Client error handler.
-
#invoke_rpc_method ⇒ Object
Assuming all things check out, we can call the service method.
- #log_signature ⇒ Object
-
#parse_request_from_buffer ⇒ Object
Parse the incoming request object into our expected request object.
-
#parse_response_from_service(response) ⇒ Object
Read out the response from the service method, setting it on the pb request, and serializing the response to the protobuf response wrapper.
-
#parse_service_info ⇒ Object
Parses and returns the service and method name from the request wrapper proto.
-
#send_response ⇒ Object
Write the response wrapper to the client.
- #serialize_response(response) ⇒ Object
Instance Method Details
#handle_client ⇒ Object
Invoke the service method dictated by the proto wrapper request object
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/protobuf/rpc/server.rb', line 13 def handle_client @stats.request_size = @buffer.size # Setup the initial request and response @request = Protobuf::Socketrpc::Request.new @response = Protobuf::Socketrpc::Response.new # Parse the protobuf request from the socket log_debug "[#{log_signature}] Parsing request from client" parse_request_from_buffer # Determine the service class and method name from the request log_debug "[#{log_signature}] Extracting procedure call info from request" parse_service_info # Call the service method log_debug "[#{log_signature}] Dispatching client request to service" invoke_rpc_method rescue => error # Ensure we're handling any errors that try to slip out the back door log_error error. log_error error.backtrace.join("\n") handle_error(error) send_response end |
#handle_error(error) ⇒ Object
Client error handler. Receives an exception object and writes it into the @response
40 41 42 43 44 45 46 47 48 49 |
# File 'lib/protobuf/rpc/server.rb', line 40 def handle_error(error) log_debug "[#{log_signature}] handle_error: %s" % error.inspect if error.respond_to?(:to_response) error.to_response(@response) else = error.respond_to?(:message) ? error. : error.to_s code = error.respond_to?(:code) ? error.code.to_s : "RPC_ERROR" PbError.new(, code).to_response(@response) end end |
#invoke_rpc_method ⇒ Object
Assuming all things check out, we can call the service method
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/protobuf/rpc/server.rb', line 52 def invoke_rpc_method # Get a new instance of the service @service = @klass.new # Define our response callback to perform the "successful" response to our client # This decouples the service's rpc method from our response to the client, # allowing the service to be the dictator for when the response should be sent back. # # In other words, we don't send the response once the service method finishes executing # since the service may perform it's own operations asynchronously. @service.on_send_response do |response| unless @did_respond parse_response_from_service(response) send_response end end @service.on_rpc_failed do |error| unless @did_respond handle_error(error) send_response end end # Call the service method log_debug "[#{log_signature}] Invoking %s#%s with request %s" % [@klass.name, @method, @request.inspect] @service.__send__(@method, @request) end |
#log_signature ⇒ Object
81 82 83 |
# File 'lib/protobuf/rpc/server.rb', line 81 def log_signature @log_signature ||= "server-#{self.class}" end |
#parse_request_from_buffer ⇒ Object
Parse the incoming request object into our expected request object
86 87 88 89 90 91 92 93 |
# File 'lib/protobuf/rpc/server.rb', line 86 def parse_request_from_buffer log_debug "[#{log_signature}] parsing request from buffer: %s" % @buffer.data.inspect @request.parse_from_string(@buffer.data) rescue => error exc = BadRequestData.new 'Unable to parse request: %s' % error. log_error exc. raise exc end |
#parse_response_from_service(response) ⇒ Object
Read out the response from the service method, setting it on the pb request, and serializing the response to the protobuf response wrapper
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/protobuf/rpc/server.rb', line 98 def parse_response_from_service(response) expected = @klass.rpcs[@klass][@method].response_type # Cannibalize the response if it's a Hash response = expected.new(response) if response.is_a?(Hash) actual = response.class log_debug "[#{log_signature}] response (should/actual): %s/%s" % [expected.name, actual.name] # Determine if the service tried to change response types on us if expected == actual serialize_response(response) else # response types do not match, throw the appropriate error raise BadResponseProto, 'Response proto changed from %s to %s' % [expected.name, actual.name] end rescue => error log_error error. log_error error.backtrace.join("\n") handle_error(error) end |
#parse_service_info ⇒ Object
Parses and returns the service and method name from the request wrapper proto
120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/protobuf/rpc/server.rb', line 120 def parse_service_info @klass = Util.constantize(@request.service_name) @method = Util.underscore(@request.method_name).to_sym unless @klass.instance_methods.include?(@method) raise MethodNotFound, "Service method #{@request.method_name} is not defined by the service" end @stats.service = @klass.name @stats.method = @method rescue NameError raise ServiceNotFound, "Service class #{@request.service_name} is not found" end |
#send_response ⇒ Object
Write the response wrapper to the client
135 136 137 138 139 140 141 142 143 144 |
# File 'lib/protobuf/rpc/server.rb', line 135 def send_response raise 'Response already sent to client' if @did_respond log_debug "[#{log_signature}] Sending response to client: %s" % @response.inspect response_buffer = Protobuf::Rpc::Buffer.new(:write, @response) send_data(response_buffer.write) @stats.response_size = response_buffer.size @stats.end @stats.log_stats @did_respond = true end |
#serialize_response(response) ⇒ Object
146 147 148 149 150 151 |
# File 'lib/protobuf/rpc/server.rb', line 146 def serialize_response(response) log_debug "[#{log_signature}] serializing response: %s" % response.inspect @response.response_proto = response.serialize_to_string rescue raise BadResponseProto, $!. end |