def send_async( self, receiver_address: typing.Address, queue_name: bytes, message: Message, ) -> AsyncResult: if not self._running: return self.log.debug( 'SEND ASYNC', receiver_address=to_normalized_address(receiver_address), message=message, queue_name=queue_name, ) if not is_binary_address(receiver_address): raise ValueError('Invalid address {}'.format(pex(receiver_address))) # These are not protocol messages, but transport specific messages if isinstance(message, (Delivered, Ping, Pong)): raise ValueError( 'Do not use send_async for {} messages'.format(message.__class__.__name__), ) if isinstance(message, SignedMessage) and not message.sender: # FIXME: This can't be right message.sender = self._client.user_id # Ignore duplicated messages message_id = message.message_identifier if message_id not in self._messageids_to_asyncresult: async_result = self._messageids_to_asyncresult[message_id] = AsyncResult() self._send_with_retry(receiver_address, async_result, json.dumps(message.to_dict())) return self._messageids_to_asyncresult[message_id]
def send_async( self, receiver_address: Address, queue_name: bytes, message: Message, ): if not self._running: return self.log.info( 'SEND ASYNC', receiver_address=to_normalized_address(receiver_address), message=message, queue_name=queue_name, ) if not is_binary_address(receiver_address): raise ValueError('Invalid address {}'.format( pex(receiver_address))) # These are not protocol messages, but transport specific messages if isinstance(message, (Delivered, Ping, Pong)): raise ValueError( 'Do not use send_async for {} messages'.format( message.__class__.__name__), ) message_id = message.message_identifier async_result = AsyncResult() if isinstance(message, Processed): async_result.set( True) # processed messages shouldn't get a Delivered reply self._send_immediate(receiver_address, json.dumps(message.to_dict())) else: self._messageids_to_asyncresult[message_id] = async_result self._send_with_retry(receiver_address, async_result, json.dumps(message.to_dict()))
def send_async( self, receiver_address: Address, queue_name: bytes, message: Message, ): if not self._running: return self.log.info( 'SEND ASYNC', receiver_address=to_normalized_address(receiver_address), message=message, queue_name=queue_name, ) if not is_binary_address(receiver_address): raise ValueError('Invalid address {}'.format(pex(receiver_address))) # These are not protocol messages, but transport specific messages if isinstance(message, (Delivered, Ping, Pong)): raise ValueError( 'Do not use send_async for {} messages'.format(message.__class__.__name__), ) message_id = message.message_identifier async_result = AsyncResult() if isinstance(message, Processed): async_result.set(True) # processed messages shouldn't get a Delivered reply self._send_immediate(receiver_address, json.dumps(message.to_dict())) else: self._messageids_to_asyncresult[message_id] = async_result self._send_with_retry(receiver_address, async_result, json.dumps(message.to_dict()))
def _send_immediate( self, queue_identifier: QueueIdentifier, message: Message, ): data = json.dumps(message.to_dict()) receiver_address = queue_identifier.recipient self._send_raw(receiver_address, data)
def maybe_send(self, recipient: typing.Address, message: Message): """ Send message to recipient if the transport is running. """ if not is_binary_address(recipient): raise InvalidAddress('Invalid address {}'.format(pex(recipient))) messagedata = message.encode() host_port = self.get_host_port(recipient) self.maybe_sendraw(host_port, messagedata)
def _send_with_retry( self, queue_identifier: QueueIdentifier, message: Message, ): data = json.dumps(message.to_dict()) message_id = message.message_identifier receiver_address = queue_identifier.recipient reachable = {UserPresence.ONLINE, UserPresence.UNAVAILABLE} def retry(): timeout_generator = udp_utils.timeout_exponential_backoff( self._config['retries_before_backoff'], self._config['retry_interval'], self._config['retry_interval'] * 10, ) for delay in timeout_generator: status = self._address_to_presence.get(receiver_address) if status in reachable: self._send_raw(receiver_address, data) else: self.log.debug( 'Skipping SEND to unreachable node', receiver=pex(receiver_address), status=status, message=message, queue=queue_identifier, ) # equivalent of gevent.sleep, but bails out when stopping if self._stop_event.wait(delay): break # retry while our queue is valid if queue_identifier not in self._queueids_to_queues: self.log.debug( 'Queue cleaned, stop retrying', message=message, queue=queue_identifier, queueids_to_queues=self._queueids_to_queues, ) break # retry while the message is in queue # Delivered and Processed messages should eventually remove them message_in_queue = any( message_id == event.message_identifier for event in self._queueids_to_queues[queue_identifier] ) if not message_in_queue: break self._spawn(retry)
def send_async( self, queue_identifier: QueueIdentifier, message: Message, ): """ Send a new ordered message to recipient. Messages that use the same `queue_identifier` are ordered. """ recipient = queue_identifier.recipient if not is_binary_address(recipient): raise ValueError('Invalid address {}'.format(pex(recipient))) # These are not protocol messages, but transport specific messages if isinstance(message, (Delivered, Ping, Pong)): raise ValueError('Do not use send for {} messages'.format( message.__class__.__name__)) messagedata = message.encode() if len(messagedata) > self.UDP_MAX_MESSAGE_SIZE: raise ValueError( 'message size exceeds the maximum {}'.format( self.UDP_MAX_MESSAGE_SIZE), ) # message identifiers must be unique message_id = message.message_identifier # ignore duplicates if message_id not in self.messageids_to_asyncresults: self.messageids_to_asyncresults[message_id] = AsyncResult() queue = self.get_queue_for(queue_identifier) queue.put((messagedata, message_id)) assert queue.is_set() self.log.debug( 'Message queued', queue_identifier=queue_identifier, queue_size=len(queue), message=message, )
def sign(self, message: Message): """ Sign message inplace. """ if not isinstance(message, SignedMessage): raise ValueError('{} is not signable.'.format(repr(message))) message.sign(self.signer)
def sign_and_inject(message: Message, signer: Signer, app: App) -> None: """Sign the message with key and inject it directly in the app transport layer.""" message.sign(signer) MessageHandler().on_message(app.raiden, message)
def sign(self, message: Message): """ Sign message inplace. """ if not isinstance(message, SignedMessage): raise ValueError('{} is not signable.'.format(repr(message))) message.sign(self.private_key)