Petbot/modules/base_module.py
megaproxy 915aa00bea Implement comprehensive rate limiting system and item spawn configuration
Major Features Added:
- Complete token bucket rate limiting for IRC commands and web interface
- Per-user rate tracking with category-based limits (Basic, Gameplay, Management, Admin, Web)
- Admin commands for rate limit management (\!rate_stats, \!rate_user, \!rate_unban, \!rate_reset)
- Automatic violation tracking and temporary bans with cleanup
- Global item spawn multiplier system with 75% spawn rate reduction
- Central admin configuration system (config.py)
- One-command bot startup script (start_petbot.sh)

Rate Limiting:
- Token bucket algorithm with burst capacity and refill rates
- Category limits: Basic (20/min), Gameplay (10/min), Management (5/min), Web (60/min)
- Graceful violation handling with user-friendly error messages
- Admin exemption and override capabilities
- Background cleanup of old violations and expired bans

Item Spawn System:
- Added global_spawn_multiplier to config/items.json for easy adjustment
- Reduced all individual spawn rates by 75% (multiplied by 0.25)
- Admins can fine-tune both global multiplier and individual item rates
- Game engine integration applies multiplier to all spawn calculations

Infrastructure:
- Single admin user configuration in config.py
- Enhanced startup script with dependency management and verification
- Updated documentation and help system with rate limiting guide
- Comprehensive test suite for rate limiting functionality

Security:
- Rate limiting protects against command spam and abuse
- IP-based tracking for web interface requests
- Proper error handling and status codes (429 for rate limits)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-15 20:10:43 +00:00

60 lines
No EOL
2.1 KiB
Python

#!/usr/bin/env python3
"""Base module class for PetBot command modules"""
import asyncio
from abc import ABC, abstractmethod
class BaseModule(ABC):
"""Base class for all PetBot modules"""
def __init__(self, bot, database, game_engine):
self.bot = bot
self.database = database
self.game_engine = game_engine
@staticmethod
def normalize_input(user_input):
"""Normalize user input by converting to lowercase for case-insensitive command processing"""
if isinstance(user_input, str):
return user_input.lower()
elif isinstance(user_input, list):
return [item.lower() if isinstance(item, str) else item for item in user_input]
return user_input
@abstractmethod
def get_commands(self):
"""Return list of commands this module handles"""
pass
@abstractmethod
async def handle_command(self, channel, nickname, command, args):
"""Handle a command for this module"""
pass
def send_message(self, target, message):
"""Send message through the bot"""
# Use sync wrapper if available (new bot), otherwise fallback to old method
if hasattr(self.bot, 'send_message_sync'):
self.bot.send_message_sync(target, message)
else:
self.bot.send_message(target, message)
def send_pm(self, nickname, message):
"""Send private message to user"""
# Use sync wrapper if available (new bot), otherwise fallback to old method
if hasattr(self.bot, 'send_message_sync'):
self.bot.send_message_sync(nickname, message)
else:
self.bot.send_message(nickname, message)
async def get_player(self, nickname):
"""Get player from database"""
return await self.database.get_player(nickname)
async def require_player(self, channel, nickname):
"""Get player or send start message if not found"""
player = await self.get_player(nickname)
if not player:
self.send_message(channel, f"{nickname}: Use !start to begin your journey first!")
return None
return player