import threading from typing import Callable, Optional, Union from amqpstorm.base import Stateful from amqpstorm import Connection, Channel, AMQPError OnErrorCallback = Union[ None, Callable[[Exception], None] ] class AMQPConnection: def __init__( self, host: str, username: str, password: str, port: int = 5672, heartbeat: int = 60, virtual_host: str = "/", on_error: OnErrorCallback = None, ) -> None: self.host = host self.port = port self.username = username self.password = password self.virtual_host = virtual_host self.heartbeat = heartbeat self._on_error = on_error self._connection_lock = threading.Lock() self.channel: Optional[Channel] = None self._protocol: Optional[Connection] = None @property def connection_parameters(self): return { "hostname": self.host, "port": self.port, "username": self.username, "password": self.password, "virtual_host": self.virtual_host, # "on_error": self._on_error, "heartbeat": self.heartbeat, } @property def is_connected(self) -> bool: return self._protocol and self._protocol.current_state == Stateful.OPEN def has_channel_ready(self): return self.channel and self.channel.is_open def close(self) -> None: if not self.is_connected: return None self._protocol.close() def _connect(self) -> None: with self._connection_lock: if self.is_connected and self.has_channel_ready(): return try: if self._protocol: self.channel = self._protocol.channel() return except AMQPError as e: # Se não conseguirmos pegar um channel novo # a conexão atual deve mesmo ser renovada e isso # será feito logo abaixo. pass self._protocol = Connection(**self.connection_parameters) self.channel = self._protocol.channel()