async def connect(self) -> None: """Connect the multiplexer.""" self._loop = asyncio.get_event_loop() self.logger.debug("Multiplexer connecting...") self._connection_consistency_checks() self._set_default_connection_if_none() self._out_queue = asyncio.Queue() async with self._lock: if self.connection_status.is_connected: self.logger.debug("Multiplexer already connected.") return try: self.connection_status.set(ConnectionStates.connecting) await self._connect_all() if all(c.is_connected for c in self._connections): self.connection_status.set(ConnectionStates.connected) else: # pragma: nocover raise AEAConnectionError( "Failed to connect the multiplexer.") self._recv_loop_task = self._loop.create_task( self._receiving_loop()) self._send_loop_task = self._loop.create_task( self._send_loop()) self.logger.debug("Multiplexer connected and running.") except (CancelledError, asyncio.CancelledError): # pragma: nocover await self._stop() raise asyncio.CancelledError() except Exception: self.logger.exception("Exception on connect:") await self._stop() raise AEAConnectionError("Failed to connect the multiplexer.")
async def send(self, envelope: Envelope): """Send a message.""" if not self.connection_status.is_connected: raise AEAConnectionError( "Connection not established yet. Please use 'connect()'.") self._writer._loop.call_soon_threadsafe(self._writer.put_nowait, envelope) # type: ignore
def _check_and_set_disconnected_state(self) -> None: """Check every connection is disconnected and set disconnected state.""" if all([c.is_disconnected for c in self.connections]): self.connection_status.set(ConnectionStates.disconnected) else: raise AEAConnectionError( "Failed to disconnect multiplexer, some connections are not disconnected!" )
def try_register(self) -> bool: """Try to register to the provider.""" try: assert self._httpCall is not None self.logger.info(self.address) query = self._httpCall.register(sender_address=self.address, mailbox=True) return query["status"] == "OK" except Exception: # pragma: no cover self.logger.warning("Could not register to the provider.") raise AEAConnectionError()
async def _send(self, envelope: Envelope) -> None: """ Send an envelope. :param envelope: the envelope to send. :return: None :raises ValueError: if the connection id provided is not valid. :raises AEAConnectionError: if the connection id provided is not valid. """ connection_id = None # type: Optional[PublicId] envelope_context = envelope.context # first, try to route by context if envelope_context is not None: connection_id = envelope_context.connection_id # second, try to route by default routing if connection_id is None and envelope.protocol_id in self.default_routing: connection_id = self.default_routing[envelope.protocol_id] self.logger.debug("Using default routing: {}".format(connection_id)) if connection_id is not None and connection_id not in self._id_to_connection: raise AEAConnectionError( "No connection registered with id: {}.".format(connection_id) ) # third, if no other option route by default connection if connection_id is None: self.logger.debug( "Using default connection: {}".format(self.default_connection) ) connection = self.default_connection else: connection = self._id_to_connection[connection_id] connection = cast(Connection, connection) if ( len(connection.restricted_to_protocols) > 0 and envelope.protocol_id not in connection.restricted_to_protocols ): self.logger.warning( "Connection {} cannot handle protocol {}. Cannot send the envelope.".format( connection.connection_id, envelope.protocol_id ) ) return try: await connection.send(envelope) except Exception as e: # pylint: disable=broad-except self._handle_exception(self._send, e)
async def disconnect(self) -> None: """Disconnect the multiplexer.""" self.logger.debug("Multiplexer disconnecting...") async with self._lock: if self.connection_status.is_disconnected: self.logger.debug("Multiplexer already disconnected.") return try: self.connection_status.set(ConnectionStates.disconnecting) await asyncio.wait_for(self._stop(), timeout=60) self.logger.debug("Multiplexer disconnected.") except (CancelledError, Exception): self.logger.exception("Exception on disconnect:") raise AEAConnectionError("Failed to disconnect the multiplexer.")
async def _send(self, envelope: Envelope) -> None: """ Send an envelope. :param envelope: the envelope to send. :return: None :raises ValueError: if the connection id provided is not valid. :raises AEAConnectionError: if the connection id provided is not valid. """ connection_id = None # type: Optional[PublicId] envelope_context = envelope.context # first, try to route by context if envelope_context is not None: connection_id = envelope_context.connection_id envelope_protocol_id = self._get_protocol_id_for_envelope(envelope) # second, try to route by default routing if connection_id is None and envelope_protocol_id in self.default_routing: connection_id = self.default_routing[envelope_protocol_id] self.logger.debug( "Using default routing: {}".format(connection_id)) if connection_id is not None and connection_id not in self._id_to_connection: raise AEAConnectionError( "No connection registered with id: {}.".format(connection_id)) # third, if no other option route by default connection if connection_id is None: self.logger.debug("Using default connection: {}".format( self.default_connection)) connection = self.default_connection else: connection = self._id_to_connection[connection_id] if connection is None: self.logger.warning( f"Dropping envelope, no connection available for sending: {envelope}" ) return if not self._is_connection_supported_protocol(connection, envelope_protocol_id): return try: await connection.send(envelope) except Exception as e: # pylint: disable=broad-except self._handle_exception(self._send, e)
async def receive(self, *args, **kwargs) -> Optional["Envelope"]: """ Receive an envelope. Blocking. :return: the envelope received, or None. """ if not self.connection_status.is_connected: raise AEAConnectionError( "Connection not established yet. Please use 'connect()'.") try: assert self._reader is not None envelope = await self._reader.get() if envelope is None: logger.debug("Receiving task terminated.") return None logger.debug("Received envelope {}".format(envelope)) return envelope except Exception: return None
async def connect(self) -> None: """Connect the multiplexer.""" self.logger.debug("Multiplexer connecting...") self._connection_consistency_checks() self._set_default_connection_if_none() self._out_queue = asyncio.Queue() async with self._lock: if self.connection_status.is_connected: self.logger.debug("Multiplexer already connected.") return try: await self._connect_all() assert self.is_connected, "At least one connection failed to connect!" self._connection_status.is_connected = True self._recv_loop_task = self._loop.create_task( self._receiving_loop()) self._send_loop_task = self._loop.create_task( self._send_loop()) self.logger.debug("Multiplexer connected and running.") except (CancelledError, Exception): self.logger.exception("Exception on connect:") self._connection_status.is_connected = False await self._stop() raise AEAConnectionError("Failed to connect the multiplexer.")