Some updates for backend thingies

This commit is contained in:
2026-03-20 15:59:07 -06:00
parent 84e9d3001a
commit 76156955b9
16 changed files with 1027 additions and 100 deletions

View File

@@ -0,0 +1 @@
"""RabbitMQ adapters for message publishing and consuming"""

View File

@@ -0,0 +1,71 @@
"""RabbitMQ message consumer base"""
import pika
import json
from typing import Callable, Dict, Any
import logging
logger = logging.getLogger(__name__)
class RabbitMQConsumer:
"""Generic RabbitMQ consumer for consuming messages from queues"""
def __init__(self, queue_name: str, host: str = 'localhost', port: int = 5672):
self.queue_name = queue_name
self.host = host
self.port = port
self.callback = None
def set_callback(self, callback: Callable[[Dict[str, Any]], None]) -> None:
"""
Sets the callback function to be called when a message is received
Args:
callback: Function that takes a message dictionary as argument
"""
self.callback = callback
def start_consuming(self) -> None:
"""
Starts consuming messages from the queue
"""
try:
connection = pika.BlockingConnection(
pika.ConnectionParameters(host=self.host, port=self.port)
)
channel = connection.channel()
# Declare queue to ensure it exists
channel.queue_declare(queue=self.queue_name, durable=True)
def callback_wrapper(ch, method, properties, body):
try:
# Decode the message
message = json.loads(body.decode('utf-8'))
logger.info(f"Received message from queue '{self.queue_name}': {message}")
# Call the user's callback function
if self.callback:
self.callback(message)
# Acknowledge the message
ch.basic_ack(delivery_tag=method.delivery_tag)
except Exception as e:
logger.error(f"Error processing message: {e}")
# Negative acknowledge to requeue the message
ch.basic_nack(delivery_tag=method.delivery_tag, requeue=True)
# Set up the consumer with manual acknowledgment
channel.basic_consume(
queue=self.queue_name,
on_message_callback=callback_wrapper,
auto_ack=False
)
logger.info(f"[*] Waiting for messages in queue '{self.queue_name}'. Ctrl+C to exit.")
channel.start_consuming()
except Exception as e:
logger.error(f"Error in consumer: {e}")
raise

View File

@@ -0,0 +1,82 @@
"""Message schemas for RabbitMQ communication"""
from dataclasses import dataclass, asdict
from datetime import datetime
from typing import Optional
from enum import Enum
import json
class UserEventType(str, Enum):
"""Types of user events"""
CREATE = "user.create"
UPDATE = "user.update"
DELETE = "user.delete"
class ReportEventType(str, Enum):
"""Types of report events"""
CREATE = "report.create"
UPDATE_VISIBILITY = "report.update_visibility"
DELETE = "report.delete"
@dataclass
class UserMessage:
"""Message for user events"""
event_type: UserEventType
user_id: Optional[int] = None
nombre: Optional[str] = None
apellido: Optional[str] = None
email: Optional[str] = None
fecha_nacimiento: Optional[str] = None # ISO format datetime string
fecha_creacion: Optional[str] = None # ISO format datetime string
calificacion: Optional[float] = None
numero_reportes: Optional[int] = None
url_foto_perfil: Optional[str] = None
biografia: Optional[str] = None
def to_dict(self):
"""Convert to dictionary"""
data = asdict(self)
data['event_type'] = self.event_type.value
return data
def to_json(self) -> str:
"""Convert to JSON string"""
return json.dumps(self.to_dict())
@staticmethod
def from_dict(data: dict) -> 'UserMessage':
"""Create from dictionary"""
data['event_type'] = UserEventType(data['event_type'])
return UserMessage(**data)
@dataclass
class ReportMessage:
"""Message for report events"""
event_type: ReportEventType
id_reporte: Optional[str] = None
id_usuario: Optional[int] = None
tipo_reporte: Optional[int] = None
descripcion: Optional[str] = None
ubicacion: Optional[str] = None
visibilidad: Optional[float] = None
fecha_creacion: Optional[str] = None # ISO format datetime string
penalize_author: Optional[bool] = None # For update_visibility event
def to_dict(self):
"""Convert to dictionary"""
data = asdict(self)
data['event_type'] = self.event_type.value
return data
def to_json(self) -> str:
"""Convert to JSON string"""
return json.dumps(self.to_dict())
@staticmethod
def from_dict(data: dict) -> 'ReportMessage':
"""Create from dictionary"""
data['event_type'] = ReportEventType(data['event_type'])
return ReportMessage(**data)

View File

@@ -0,0 +1,74 @@
"""RabbitMQ message sender"""
import pika
import json
from typing import Any, Dict
import logging
logger = logging.getLogger(__name__)
class RabbitMQSender:
"""Generic RabbitMQ sender for publishing messages to queues"""
def __init__(self, host: str = 'localhost', port: int = 5672):
self.host = host
self.port = port
def send_message(self, queue_name: str, message: Dict[str, Any]) -> bool:
"""
Sends a message to a RabbitMQ queue
Args:
queue_name: Name of the queue to send to
message: Dictionary containing the message data
Returns:
True if successful, False otherwise
"""
try:
connection = pika.BlockingConnection(
pika.ConnectionParameters(host=self.host, port=self.port)
)
channel = connection.channel()
# Declare queue to ensure it exists
channel.queue_declare(queue=queue_name, durable=True)
# Convert message to JSON
message_json = json.dumps(message)
# Publish the message
channel.basic_publish(
exchange='',
routing_key=queue_name,
body=message_json,
properties=pika.BasicProperties(
delivery_mode=pika.spec.PERSISTENT_DELIVERY_MODE
)
)
connection.close()
logger.info(f"Message sent to queue '{queue_name}': {message_json}")
return True
except Exception as e:
logger.error(f"Error sending message to RabbitMQ: {e}")
return False
def send_to_queue(queue_name: str, message: Dict[str, Any],
host: str = 'localhost', port: int = 5672) -> bool:
"""
Convenience function to send a message to RabbitMQ
Args:
queue_name: Name of the queue
message: Message dictionary
host: RabbitMQ host
port: RabbitMQ port
Returns:
True if successful, False otherwise
"""
sender = RabbitMQSender(host=host, port=port)
return sender.send_message(queue_name, message)