def _run_test_decode_value(self, typ, cases): for decoded, encoded in cases: value = Decoder.decode(binascii.unhexlify(encoded), Types().as_type(typ)) if typ in ('float','double'): self.assertEqual(str(decoded)[0:8], str(value)[0:8]) else: self.assertEqual(decoded, value)
def _invoke(self, service, procedure, args=[], kwargs={}, param_names=[], param_types=[], return_type=None): """ Execute an RPC """ def encode_argument(i, value): typ = param_types[i] if type(value) != typ.python_type: # Try coercing to the correct type try: value = self._types.coerce_to(value, typ) except ValueError: raise TypeError('%s.%s() argument %d must be a %s, got a %s' % (service, procedure, i, typ.python_type, type(value))) return _Encoder.encode(value, typ) if len(args) > len(param_types): raise TypeError('%s.%s() takes exactly %d arguments (%d given)' % (service, procedure, len(param_types), len(args))) # Encode positional arguments arguments = [] for i,arg in enumerate(args): argument = krpc.schema.KRPC.Argument() argument.position = i argument.value = encode_argument(i, arg) arguments.append(argument) # Encode keyword arguments for key,arg in kwargs.items(): try: i = param_names.index(key) except ValueError: raise TypeError('%s.%s() got an unexpected keyword argument \'%s\'' % (service, procedure, key)) if i < len(args): raise TypeError('%s.%s() got multiple values for keyword argument \'%s\'' % (service, procedure, key)) argument = krpc.schema.KRPC.Argument() argument.position = i argument.value = encode_argument(i, arg) arguments.append(argument) # Build the request object request = krpc.schema.KRPC.Request() request.service = service request.procedure = procedure request.arguments.extend(arguments) # Send the request with self._connection_lock: self._send_request(request) response = self._receive_response() # Check for an error response if response.HasField('error'): raise RPCError(response.error) # Decode the response and return the (optional) result result = None if return_type is not None: result = _Decoder.decode(response.return_value, return_type) return result
def update_thread(connection): stream_message_type = _Types().as_type('KRPC.StreamMessage') response_type = _Types().as_type('KRPC.Response') while True: # Read the size and position of the response message data = b'' while True: try: data += connection.partial_receive(1) size,position = _Decoder.decode_size_and_position(data) break except IndexError: pass except socket.error: return # Read and decode the response message try: data = connection.receive(size) except socket.error: return response = _Decoder.decode(data, stream_message_type) # Add the data to the cache with _stream_cache_lock: for response in response.responses: id = response.id if id not in _stream_cache: continue # Check for an error response if response.response.HasField('error'): _stream_cache[id].value = RPCError(response.response.error) continue # Decode the return value and store it in the cache typ = _stream_cache[id].return_type value = _Decoder.decode(response.response.return_value, typ) _stream_cache[id].update(value)
def _receive_response(self): """ Receive data from the server and decode it into a KRPC.Response object """ # Read the size and position of the response message data = b'' while True: try: data += self._rpc_connection.partial_receive(1) size,position = _Decoder.decode_size_and_position(data) break except IndexError: pass # Read and decode the response message data = self._rpc_connection.receive(size) return _Decoder.decode(data, self._response_type)
def _invoke(self, service, procedure, args=[], kwargs={}, param_names=[], param_types=[], return_type=None): """ Execute an RPC """ # Build the request request = self._build_request(service, procedure, args, kwargs, param_names, param_types, return_type) # Send the request with self._rpc_connection_lock: self._send_request(request) response = self._receive_response() # Check for an error response if response.HasField('error'): raise RPCError(response.error) # Decode the response and return the (optional) result result = None if return_type is not None: result = _Decoder.decode(response.return_value, return_type) return result
def test_decode_class_none(self): typ = Types().as_type('Class(ServiceName.ClassName)') value = Decoder.decode(binascii.unhexlify('00'), typ) self.assertIsNone(value)
def test_decode_class(self): typ = Types().as_type('Class(ServiceName.ClassName)') value = Decoder.decode(binascii.unhexlify('ac02'), typ) self.assertTrue(isinstance(value, typ.python_type)) self.assertEqual(300, value._object_id)
def test_decode_value(self): value = Decoder.decode(binascii.unhexlify('ac02'), Types().as_type('int32')) self.assertEquals(int(300), value)
def test_decode_message(self): typ = krpc.schema.KRPC.Request message = '0a0b536572766963654e616d65120d50726f6365647572654e616d65' request = Decoder.decode(binascii.unhexlify(message), Types().as_type('KRPC.Request')) self.assertEquals('ServiceName', request.service) self.assertEquals('ProcedureName', request.procedure)