Files
Meraki_QRCodeSccaner/webhook_handler.py
2025-02-04 10:42:57 -06:00

126 lines
4.5 KiB
Python

import requests
import logging
import time
from typing import Dict, Any
from dataclasses import dataclass, asdict
from datetime import datetime
@dataclass
class WebhookConfig:
url: str
method: str
headers: Dict[str, str]
retry: Dict[str, int]
class WebhookError(Exception):
"""Clase para errores relacionados con webhooks"""
pass
class WebhookHandler:
def __init__(self, webhook_config: dict):
self.config = webhook_config
self.logger = logging.getLogger(__name__)
self.session = requests.Session()
def prepare_payload(self, qr_data: dict, scan_count: int) -> dict:
"""Prepara el payload para el webhook"""
return {
"event_type": "qr_detected",
"timestamp": datetime.now().isoformat(),
"qr_data": {
"content": qr_data.get('data'),
"type": qr_data.get('code_type'),
"scan_count": scan_count,
"coordinates": qr_data.get('coordinates'),
"detection_timestamp": qr_data.get('timestamp')
},
"device_info": {
"id": "qr_detector_01", # Puedes configurar esto
"location": "main_entrance" # Puedes configurar esto
}
}
def send_webhook(self, endpoint: WebhookConfig, payload: dict) -> bool:
"""Envía el webhook con reintentos"""
max_attempts = endpoint.retry['max_attempts']
delay = endpoint.retry['delay_seconds']
for attempt in range(max_attempts):
try:
response = self.session.request(
method=endpoint.method,
url=endpoint.url,
json=payload,
headers=endpoint.headers,
timeout=10
)
if response.ok:
self.logger.info(f"Webhook enviado exitosamente a {endpoint.url}")
return True
self.logger.warning(
f"Intento {attempt + 1}/{max_attempts} fallido. "
f"Status: {response.status_code}, "
f"Response: {response.text[:100]}"
)
except requests.RequestException as e:
self.logger.error(f"Error en intento {attempt + 1}/{max_attempts}: {e}")
if attempt < max_attempts - 1:
time.sleep(delay)
self.logger.error(f"Todos los intentos de webhook fallaron para {endpoint.url}")
return False
def notify(self, qr_data: dict, scan_count: int) -> None:
"""Maneja el envío de notificaciones basado en las reglas configuradas"""
try:
# Verificar reglas de notificación
is_new = scan_count == 1
should_notify = (
(is_new and self.config['notification_rules']['send_on_new']) or
(not is_new and self.config['notification_rules']['send_on_repeat'])
)
if not should_notify:
return
payload = self.prepare_payload(qr_data, scan_count)
for endpoint_config in self.config['endpoints']:
endpoint = WebhookConfig(
url=endpoint_config['url'],
method=endpoint_config['method'],
headers=endpoint_config['headers'],
retry=endpoint_config['retry']
)
self.send_webhook(endpoint, payload)
except Exception as e:
self.logger.error(f"Error procesando notificación: {e}")
raise WebhookError(f"Error en notificación: {e}")
def test_connection(self) -> bool:
"""Prueba las conexiones a todos los endpoints configurados"""
test_payload = {
"event_type": "connection_test",
"timestamp": datetime.now().isoformat()
}
all_successful = True
for endpoint_config in self.config['endpoints']:
endpoint = WebhookConfig(
url=endpoint_config['url'],
method=endpoint_config['method'],
headers=endpoint_config['headers'],
retry=endpoint_config['retry']
)
if not self.send_webhook(endpoint, test_payload):
all_successful = False
return all_successful