mirror of
https://github.com/pacnpal/Pac-cogs.git
synced 2025-12-20 10:51:05 -05:00
Core Systems:
Component-based architecture with lifecycle management Enhanced error handling and recovery mechanisms Comprehensive state management and tracking Event-driven architecture with monitoring Queue Management: Multiple processing strategies for different scenarios Advanced state management with recovery Comprehensive metrics and health monitoring Sophisticated cleanup system with multiple strategies Processing Pipeline: Enhanced message handling with validation Improved URL extraction and processing Better queue management and monitoring Advanced cleanup mechanisms Overall Benefits: Better code organization and maintainability Improved error handling and recovery Enhanced monitoring and reporting More robust and reliable system
This commit is contained in:
225
videoarchiver/processor/message_validator.py
Normal file
225
videoarchiver/processor/message_validator.py
Normal file
@@ -0,0 +1,225 @@
|
||||
"""Message validation functionality for video processing"""
|
||||
|
||||
import logging
|
||||
from enum import Enum
|
||||
from dataclasses import dataclass
|
||||
from typing import Dict, Optional, Tuple, List, Any, Callable, Set
|
||||
from datetime import datetime
|
||||
import discord
|
||||
|
||||
logger = logging.getLogger("VideoArchiver")
|
||||
|
||||
class ValidationResult(Enum):
|
||||
"""Possible validation results"""
|
||||
VALID = "valid"
|
||||
INVALID = "invalid"
|
||||
IGNORED = "ignored"
|
||||
|
||||
@dataclass
|
||||
class ValidationContext:
|
||||
"""Context for message validation"""
|
||||
message: discord.Message
|
||||
settings: Dict[str, Any]
|
||||
guild_id: int
|
||||
channel_id: int
|
||||
author_id: int
|
||||
roles: Set[int]
|
||||
content_length: int
|
||||
attachment_count: int
|
||||
is_bot: bool
|
||||
timestamp: datetime
|
||||
|
||||
@classmethod
|
||||
def from_message(cls, message: discord.Message, settings: Dict[str, Any]) -> 'ValidationContext':
|
||||
"""Create context from message"""
|
||||
return cls(
|
||||
message=message,
|
||||
settings=settings,
|
||||
guild_id=message.guild.id,
|
||||
channel_id=message.channel.id,
|
||||
author_id=message.author.id,
|
||||
roles={role.id for role in message.author.roles},
|
||||
content_length=len(message.content) if message.content else 0,
|
||||
attachment_count=len(message.attachments),
|
||||
is_bot=message.author.bot,
|
||||
timestamp=message.created_at
|
||||
)
|
||||
|
||||
@dataclass
|
||||
class ValidationRule:
|
||||
"""Defines a validation rule"""
|
||||
name: str
|
||||
description: str
|
||||
validate: Callable[[ValidationContext], Tuple[bool, Optional[str]]]
|
||||
enabled: bool = True
|
||||
priority: int = 0
|
||||
|
||||
class ValidationCache:
|
||||
"""Caches validation results"""
|
||||
|
||||
def __init__(self, max_size: int = 1000):
|
||||
self.max_size = max_size
|
||||
self._cache: Dict[int, Dict[str, Any]] = {}
|
||||
self._access_times: Dict[int, datetime] = {}
|
||||
|
||||
def add(self, message_id: int, result: Dict[str, Any]) -> None:
|
||||
"""Add validation result to cache"""
|
||||
if len(self._cache) >= self.max_size:
|
||||
self._cleanup_oldest()
|
||||
self._cache[message_id] = result
|
||||
self._access_times[message_id] = datetime.utcnow()
|
||||
|
||||
def get(self, message_id: int) -> Optional[Dict[str, Any]]:
|
||||
"""Get cached validation result"""
|
||||
if message_id in self._cache:
|
||||
self._access_times[message_id] = datetime.utcnow()
|
||||
return self._cache[message_id]
|
||||
return None
|
||||
|
||||
def _cleanup_oldest(self) -> None:
|
||||
"""Remove oldest cache entries"""
|
||||
if not self._access_times:
|
||||
return
|
||||
oldest = min(self._access_times.items(), key=lambda x: x[1])[0]
|
||||
del self._cache[oldest]
|
||||
del self._access_times[oldest]
|
||||
|
||||
class ValidationRuleManager:
|
||||
"""Manages validation rules"""
|
||||
|
||||
def __init__(self):
|
||||
self.rules: List[ValidationRule] = [
|
||||
ValidationRule(
|
||||
name="content_check",
|
||||
description="Check if message has content to process",
|
||||
validate=self._validate_content,
|
||||
priority=1
|
||||
),
|
||||
ValidationRule(
|
||||
name="guild_enabled",
|
||||
description="Check if archiving is enabled for guild",
|
||||
validate=self._validate_guild_enabled,
|
||||
priority=2
|
||||
),
|
||||
ValidationRule(
|
||||
name="channel_enabled",
|
||||
description="Check if channel is enabled for archiving",
|
||||
validate=self._validate_channel,
|
||||
priority=3
|
||||
),
|
||||
ValidationRule(
|
||||
name="user_roles",
|
||||
description="Check if user has required roles",
|
||||
validate=self._validate_user_roles,
|
||||
priority=4
|
||||
)
|
||||
]
|
||||
self.rules.sort(key=lambda x: x.priority)
|
||||
|
||||
def _validate_content(self, ctx: ValidationContext) -> Tuple[bool, Optional[str]]:
|
||||
"""Validate message content"""
|
||||
if not ctx.content_length and not ctx.attachment_count:
|
||||
return False, "No content or attachments"
|
||||
return True, None
|
||||
|
||||
def _validate_guild_enabled(self, ctx: ValidationContext) -> Tuple[bool, Optional[str]]:
|
||||
"""Validate guild settings"""
|
||||
if not ctx.settings.get("enabled", False):
|
||||
return False, "Video archiving disabled for guild"
|
||||
return True, None
|
||||
|
||||
def _validate_channel(self, ctx: ValidationContext) -> Tuple[bool, Optional[str]]:
|
||||
"""Validate channel settings"""
|
||||
enabled_channels = ctx.settings.get("enabled_channels", [])
|
||||
if enabled_channels and ctx.channel_id not in enabled_channels:
|
||||
return False, "Channel not enabled for archiving"
|
||||
return True, None
|
||||
|
||||
def _validate_user_roles(self, ctx: ValidationContext) -> Tuple[bool, Optional[str]]:
|
||||
"""Validate user roles"""
|
||||
allowed_roles = ctx.settings.get("allowed_roles", [])
|
||||
if allowed_roles and not (ctx.roles & set(allowed_roles)):
|
||||
return False, "User does not have required roles"
|
||||
return True, None
|
||||
|
||||
class MessageValidator:
|
||||
"""Handles validation of messages for video processing"""
|
||||
|
||||
def __init__(self):
|
||||
self.rule_manager = ValidationRuleManager()
|
||||
self.cache = ValidationCache()
|
||||
self.validation_stats: Dict[str, int] = {
|
||||
"total": 0,
|
||||
"valid": 0,
|
||||
"invalid": 0,
|
||||
"ignored": 0,
|
||||
"cached": 0
|
||||
}
|
||||
|
||||
async def validate_message(
|
||||
self,
|
||||
message: discord.Message,
|
||||
settings: Dict
|
||||
) -> Tuple[bool, Optional[str]]:
|
||||
"""Validate if a message should be processed"""
|
||||
self.validation_stats["total"] += 1
|
||||
|
||||
# Check cache
|
||||
cached = self.cache.get(message.id)
|
||||
if cached:
|
||||
self.validation_stats["cached"] += 1
|
||||
return cached["valid"], cached.get("reason")
|
||||
|
||||
# Create validation context
|
||||
ctx = ValidationContext.from_message(message, settings)
|
||||
|
||||
# Run validation rules
|
||||
for rule in self.rule_manager.rules:
|
||||
if not rule.enabled:
|
||||
continue
|
||||
|
||||
try:
|
||||
valid, reason = rule.validate(ctx)
|
||||
if not valid:
|
||||
self.validation_stats["invalid"] += 1
|
||||
# Cache result
|
||||
self.cache.add(message.id, {
|
||||
"valid": False,
|
||||
"reason": reason,
|
||||
"rule": rule.name
|
||||
})
|
||||
return False, reason
|
||||
except Exception as e:
|
||||
logger.error(f"Error in validation rule {rule.name}: {e}")
|
||||
return False, f"Validation error: {str(e)}"
|
||||
|
||||
# Message passed all rules
|
||||
self.validation_stats["valid"] += 1
|
||||
self.cache.add(message.id, {
|
||||
"valid": True,
|
||||
"reason": None
|
||||
})
|
||||
return True, None
|
||||
|
||||
def get_stats(self) -> Dict[str, Any]:
|
||||
"""Get validation statistics"""
|
||||
return {
|
||||
"validation_stats": self.validation_stats.copy(),
|
||||
"rules": [
|
||||
{
|
||||
"name": rule.name,
|
||||
"description": rule.description,
|
||||
"enabled": rule.enabled,
|
||||
"priority": rule.priority
|
||||
}
|
||||
for rule in self.rule_manager.rules
|
||||
]
|
||||
}
|
||||
|
||||
def clear_cache(self, message_id: Optional[int] = None) -> None:
|
||||
"""Clear validation cache"""
|
||||
if message_id:
|
||||
self.cache._cache.pop(message_id, None)
|
||||
self.cache._access_times.pop(message_id, None)
|
||||
else:
|
||||
self.cache = ValidationCache(self.cache.max_size)
|
||||
Reference in New Issue
Block a user