diff --git a/build/lib/evolutionapi/client.py b/build/lib/evolutionapi/client.py index 7bfdbd7..237f925 100644 --- a/build/lib/evolutionapi/client.py +++ b/build/lib/evolutionapi/client.py @@ -9,6 +9,8 @@ from .services.chat import ChatService from .services.label import LabelService from .services.profile import ProfileService from .services.group import GroupService +from .services.websocket import WebSocketService, WebSocketManager + class EvolutionClient: """ Cliente para interagir com a API Evolution. @@ -29,6 +31,7 @@ class EvolutionClient: self.label = LabelService(self) self.profile = ProfileService(self) self.group = GroupService(self) + self.websocket = WebSocketService(self) def _get_headers(self, instance_token: str = None): return { @@ -112,3 +115,24 @@ class EvolutionClient: url = self._get_full_url(endpoint) response = requests.delete(url, headers=self._get_headers(instance_token)) return self._handle_response(response) + + def create_websocket(self, instance_id: str, api_token: str, max_retries: int = 5, retry_delay: float = 1.0) -> WebSocketManager: + """ + Create a WebSocket manager for the specified instance. + + Args: + instance_id (str): The instance ID + api_token (str): The API token + max_retries (int): Maximum number of reconnection attempts + retry_delay (float): Initial delay between attempts in seconds + + Returns: + WebSocketManager: The WebSocket manager instance + """ + return WebSocketManager( + base_url=self.base_url, + instance_id=instance_id, + api_token=api_token, + max_retries=max_retries, + retry_delay=retry_delay + ) diff --git a/build/lib/evolutionapi/models/websocket.py b/build/lib/evolutionapi/models/websocket.py new file mode 100644 index 0000000..56fbea3 --- /dev/null +++ b/build/lib/evolutionapi/models/websocket.py @@ -0,0 +1,20 @@ +from typing import List, Optional +from dataclasses import dataclass + +@dataclass +class WebSocketConfig: + enabled: bool + events: List[str] + + def __init__(self, enabled: bool, events: List[str]): + self.enabled = enabled + self.events = events + +@dataclass +class WebSocketInfo: + enabled: bool + events: List[str] + + def __init__(self, **kwargs): + self.enabled = kwargs.get('enabled', False) + self.events = kwargs.get('events', []) \ No newline at end of file diff --git a/build/lib/evolutionapi/services/websocket.py b/build/lib/evolutionapi/services/websocket.py index d3e89af..6839881 100644 --- a/build/lib/evolutionapi/services/websocket.py +++ b/build/lib/evolutionapi/services/websocket.py @@ -1,21 +1,60 @@ import socketio from typing import Callable, Dict, Any import logging -import ssl import time from typing import Optional +from ..models.websocket import WebSocketConfig, WebSocketInfo + +class WebSocketService: + def __init__(self, client): + self.client = client + + def set_websocket(self, instance_id: str, config: WebSocketConfig, instance_token: str): + """ + Configure WebSocket settings for an instance + + Args: + instance_id (str): The instance ID + config (WebSocketConfig): The WebSocket configuration + instance_token (str): The instance token + + Returns: + dict: The response from the API + """ + return self.client.post( + f'websocket/set/{instance_id}', + data=config.__dict__, + instance_token=instance_token + ) + + def find_websocket(self, instance_id: str, instance_token: str) -> WebSocketInfo: + """ + Get WebSocket settings for an instance + + Args: + instance_id (str): The instance ID + instance_token (str): The instance token + + Returns: + WebSocketInfo: The WebSocket information + """ + response = self.client.get( + f'websocket/find/{instance_id}', + instance_token=instance_token + ) + return WebSocketInfo(**response) class WebSocketManager: def __init__(self, base_url: str, instance_id: str, api_token: str, max_retries: int = 5, retry_delay: float = 1.0): """ - Inicializa o gerenciador de WebSocket + Initialize the WebSocket manager Args: - base_url (str): URL base da API - instance_id (str): ID da instância - api_token (str): Token de autenticação da API - max_retries (int): Número máximo de tentativas de reconexão - retry_delay (float): Delay inicial entre tentativas em segundos + base_url (str): Base URL of the API + instance_id (str): Instance ID + api_token (str): API authentication token + max_retries (int): Maximum number of reconnection attempts + retry_delay (float): Initial delay between attempts in seconds """ self.base_url = base_url.rstrip('/') self.instance_id = instance_id @@ -25,85 +64,85 @@ class WebSocketManager: self.retry_count = 0 self.should_reconnect = True - # Configuração do Socket.IO + # Socket.IO configuration self.sio = socketio.Client( - ssl_verify=False, # Para desenvolvimento local + ssl_verify=False, # For local development logger=False, engineio_logger=False, request_timeout=30 ) - # Configura o logger da classe para INFO + # Configure class logger to INFO self.logger = logging.getLogger(__name__) self.logger.setLevel(logging.INFO) - # Dicionário para armazenar os handlers registrados + # Dictionary to store registered handlers self._handlers = {} - # Configuração dos handlers de eventos + # Configure event handlers self.sio.on('connect', self._on_connect) self.sio.on('disconnect', self._on_disconnect) self.sio.on('error', self._on_error) - # Registra o handler global no namespace específico da instância + # Register global handler in instance-specific namespace self.sio.on('*', self._handle_event, namespace=f'/{self.instance_id}') def _on_connect(self): - """Handler para evento de conexão""" - self.logger.info("Socket.IO conectado") - self.retry_count = 0 # Reseta o contador de retry após conexão bem-sucedida + """Handler for connection event""" + self.logger.info("Socket.IO connected") + self.retry_count = 0 # Reset retry counter after successful connection def _on_disconnect(self): - """Handler para evento de desconexão""" - self.logger.warning(f"Socket.IO desconectado. Tentativa {self.retry_count + 1}/{self.max_retries}") + """Handler for disconnection event""" + self.logger.warning(f"Socket.IO disconnected. Attempt {self.retry_count + 1}/{self.max_retries}") if self.should_reconnect and self.retry_count < self.max_retries: self._attempt_reconnect() else: - self.logger.error("Número máximo de tentativas de reconexão atingido") + self.logger.error("Maximum number of reconnection attempts reached") def _on_error(self, error): - """Handler para eventos de erro""" - self.logger.error(f"Erro no Socket.IO: {str(error)}", exc_info=True) + """Handler for error events""" + self.logger.error(f"Socket.IO error: {str(error)}", exc_info=True) def _attempt_reconnect(self): - """Tenta reconectar com backoff exponencial""" + """Attempt to reconnect with exponential backoff""" try: - delay = self.retry_delay * (2 ** self.retry_count) # Backoff exponencial - self.logger.info(f"Tentando reconectar em {delay:.2f} segundos...") + delay = self.retry_delay * (2 ** self.retry_count) # Exponential backoff + self.logger.info(f"Attempting to reconnect in {delay:.2f} seconds...") time.sleep(delay) self.connect() self.retry_count += 1 except Exception as e: - self.logger.error(f"Erro durante tentativa de reconexão: {str(e)}", exc_info=True) + self.logger.error(f"Error during reconnection attempt: {str(e)}", exc_info=True) if self.retry_count < self.max_retries: self._attempt_reconnect() else: - self.logger.error("Todas as tentativas de reconexão falharam") + self.logger.error("All reconnection attempts failed") def _handle_event(self, event, *args): - """Handler global para todos os eventos""" - # Só processa eventos que foram registrados + """Global handler for all events""" + # Only process registered events if event in self._handlers: - self.logger.debug(f"Evento recebido no namespace /{self.instance_id}: {event}") - self.logger.debug(f"Dados do evento: {args}") + self.logger.debug(f"Event received in namespace /{self.instance_id}: {event}") + self.logger.debug(f"Event data: {args}") try: - # Extrai os dados do evento + # Extract event data raw_data = args[0] if args else {} - # Garante que estamos passando o objeto correto para o callback + # Ensure we're passing the correct object to the callback if isinstance(raw_data, dict): - self.logger.debug(f"Chamando handler para {event} com dados: {raw_data}") + self.logger.debug(f"Calling handler for {event} with data: {raw_data}") self._handlers[event](raw_data) else: - self.logger.error(f"Dados inválidos recebidos para evento {event}: {raw_data}") + self.logger.error(f"Invalid data received for event {event}: {raw_data}") except Exception as e: - self.logger.error(f"Erro ao processar evento {event}: {str(e)}", exc_info=True) + self.logger.error(f"Error processing event {event}: {str(e)}", exc_info=True) def connect(self): - """Conecta ao servidor Socket.IO""" + """Connect to Socket.IO server""" try: - # Conecta apenas ao namespace da instância com o header de autenticação + # Connect only to instance namespace with authentication header self.sio.connect( f"{self.base_url}?apikey={self.api_token}", transports=['websocket'], @@ -111,25 +150,25 @@ class WebSocketManager: wait_timeout=30 ) - # Entra na sala específica da instância + # Join instance-specific room self.sio.emit('subscribe', {'instance': self.instance_id}, namespace=f'/{self.instance_id}') except Exception as e: - self.logger.error(f"Erro ao conectar ao Socket.IO: {str(e)}", exc_info=True) + self.logger.error(f"Error connecting to Socket.IO: {str(e)}", exc_info=True) raise def disconnect(self): - """Desconecta do servidor Socket.IO""" - self.should_reconnect = False # Impede tentativas de reconexão + """Disconnect from Socket.IO server""" + self.should_reconnect = False # Prevent reconnection attempts if self.sio.connected: self.sio.disconnect() def on(self, event: str, callback: Callable): """ - Registra um callback para um evento específico + Register a callback for a specific event Args: - event (str): Nome do evento - callback (Callable): Função a ser chamada quando o evento ocorrer + event (str): Event name + callback (Callable): Function to be called when the event occurs """ self._handlers[event] = callback \ No newline at end of file