예제 #1
0
파일: protocol.py 프로젝트: val461/lbry
    def sendRPC(self, contact, method, args, rawResponse=False):
        """ 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
        @param rawResponse: If this is set to C{True}, the caller of this RPC
                            will receive a tuple containing the actual response
                            message object and the originating address tuple as
                            a result; in other words, it will not be
                            interpreted by this class. Unless something special
                            needs to be done with the metadata associated with
                            the message, this should remain C{False}.
        @type rawResponse: bool

        @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, args)
        msgPrimitive = self._translator.toPrimitive(msg)
        encodedMsg = self._encoder.encode(msgPrimitive)

        if args:
            log.debug("DHT SEND CALL %s(%s)", method, args[0].encode('hex'))
        else:
            log.debug("DHT SEND CALL %s", method)

        df = defer.Deferred()
        if rawResponse:
            df._rpcRawResponse = True

        # 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.id, df, timeoutCall, method,
                                      args)
        df.addErrback(cancelTimeout)
        return df
예제 #2
0
 def fromPrimitive(self, msgPrimitive):
     msgType = msgPrimitive[self.headerType]
     if msgType == self.typeRequest:
         msg = msgtypes.RequestMessage(msgPrimitive[self.headerNodeID],
                                       msgPrimitive[self.headerPayload],
                                       msgPrimitive[self.headerArgs],
                                       msgPrimitive[self.headerMsgID])
     elif msgType == self.typeResponse:
         msg = msgtypes.ResponseMessage(msgPrimitive[self.headerMsgID],
                                        msgPrimitive[self.headerNodeID],
                                        msgPrimitive[self.headerPayload])
     elif msgType == self.typeError:
         msg = msgtypes.ErrorMessage(msgPrimitive[self.headerMsgID],
                                     msgPrimitive[self.headerNodeID],
                                     msgPrimitive[self.headerPayload],
                                     msgPrimitive[self.headerArgs])
     else:
         # Unknown message, no payload
         msg = msgtypes.Message(msgPrimitive[self.headerMsgID], msgPrimitive[self.headerNodeID])
     return msg
예제 #3
0
    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 = self._encoder.encode(msgPrimitive)

        if args:
            log.debug("%s:%i SEND CALL %s(%s) TO %s:%i", self._node.externalIP,
                      self._node.port, method, args[0].encode('hex'),
                      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
            try:
                self._node.removeContact(contact)
            except (ValueError, IndexError):
                pass
            contact.update_last_failed()
            return failure

        def _update_contact(
                result):  # refresh the contact in the routing table
            contact.update_last_replied()
            if method == 'findValue':
                if 'protocolVersion' not in result:
                    contact.update_protocol_version(0)
                else:
                    contact.update_protocol_version(
                        result.pop('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