def test_bytes(self): self.assertEqual(bencode(b''), b'0:') self.assertEqual(bencode(b'spam'), b'4:spam') self.assertEqual(bencode(b'4:spam'), b'6:4:spam') self.assertEqual(bencode(bytearray(b'spam')), b'4:spam') self.assertEqual(bdecode(b'0:'), b'') self.assertEqual(bdecode(b'4:spam'), b'spam') self.assertEqual(bdecode(b'6:4:spam'), b'4:spam')
def _sendResponse(self, contact, rpcID, response): """ Send a RPC response to the specified contact """ msg = msgtypes.ResponseMessage(rpcID, self._node.node_id, response) msgPrimitive = self._translator.toPrimitive(msg) encodedMsg = encoding.bencode(msgPrimitive) self._send(encodedMsg, rpcID, (contact.address, contact.port))
def test_mixed(self): self.assertEqual( bencode([[b'abc', b'127.0.0.1', 1919], [b'def', b'127.0.0.1', 1921]]), b'll3:abc9:127.0.0.1i1919eel3:def9:127.0.0.1i1921eee') self.assertEqual( bdecode(b'll3:abc9:127.0.0.1i1919eel3:def9:127.0.0.1i1921eee'), [[b'abc', b'127.0.0.1', 1919], [b'def', b'127.0.0.1', 1921]])
def _sendError(self, contact, rpcID, exceptionType, exceptionMessage): """ Send an RPC error message to the specified contact """ exceptionMessage = exceptionMessage.encode() msg = msgtypes.ErrorMessage(rpcID, self._node.node_id, exceptionType, exceptionMessage) msgPrimitive = self._translator.toPrimitive(msg) encodedMsg = encoding.bencode(msgPrimitive) self._send(encodedMsg, rpcID, (contact.address, contact.port))
def test_dict(self): self.assertEqual(bencode({ b'foo': 42, b'bar': b'spam' }), b'd3:bar4:spam3:fooi42ee') self.assertEqual(bdecode(b'd3:bar4:spam3:fooi42ee'), { b'foo': 42, b'bar': b'spam' })
def test_integer(self): self.assertEqual(bencode(42), b'i42e') self.assertEqual(bdecode(b'i42e'), 42)
def test_list(self): self.assertEqual(bencode([b'spam', 42]), b'l4:spami42ee') self.assertEqual(bdecode(b'l4:spami42ee'), [b'spam', 42])
def test_string(self): self.assertEqual(bencode(''), b'0:') self.assertEqual(bencode('spam'), b'4:spam') self.assertEqual(bencode('4:spam'), b'6:4:spam')
def _sendRPC(self, contact, method, args): """ Sends an RPC to the specified contact @param contact: The contact (remote node) to send the RPC to @type contact: kademlia.contacts.Contact @param method: The name of remote method to invoke @type method: str @param args: A list of (non-keyword) arguments to pass to the remote method, in the correct order @type args: tuple @return: This immediately returns a deferred object, which will return the result of the RPC call, or raise the relevant exception if the remote node raised one. If C{rawResponse} is set to C{True}, however, it will always return the actual response message (which may be a C{ResponseMessage} or an C{ErrorMessage}). @rtype: twisted.internet.defer.Deferred """ msg = msgtypes.RequestMessage( self._node.node_id, method, self._migrate_outgoing_rpc_args(contact, method, *args)) msgPrimitive = self._translator.toPrimitive(msg) encodedMsg = encoding.bencode(msgPrimitive) if args: log.debug("%s:%i SEND CALL %s(%s) TO %s:%i", self._node.externalIP, self._node.port, method, hexlify(args[0]), contact.address, contact.port) else: log.debug("%s:%i SEND CALL %s TO %s:%i", self._node.externalIP, self._node.port, method, contact.address, contact.port) df = defer.Deferred() def _remove_contact( failure ): # remove the contact from the routing table and track the failure contact.update_last_failed() try: if not contact.contact_is_good: self._node.removeContact(contact) except (ValueError, IndexError): pass return failure def _update_contact( result): # refresh the contact in the routing table contact.update_last_replied() if method == b'findValue': if b'token' in result: contact.update_token(result[b'token']) if b'protocolVersion' not in result: contact.update_protocol_version(0) else: contact.update_protocol_version( result.pop(b'protocolVersion')) d = self._node.addContact(contact) d.addCallback(lambda _: result) return d df.addCallbacks(_update_contact, _remove_contact) # Set the RPC timeout timer timeoutCall, cancelTimeout = self._node.reactor_callLater( constants.rpcTimeout, self._msgTimeout, msg.id) # Transmit the data self._send(encodedMsg, msg.id, (contact.address, contact.port)) self._sentMessages[msg.id] = (contact, df, timeoutCall, cancelTimeout, method, args) df.addErrback(cancelTimeout) return df