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>
This commit is contained in:
parent
f8ac661cd1
commit
915aa00bea
28 changed files with 5730 additions and 57 deletions
344
install_prerequisites.py
Normal file
344
install_prerequisites.py
Normal file
|
|
@ -0,0 +1,344 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
PetBot Prerequisites Installation Script
|
||||
This script installs all required Python packages and dependencies for running PetBot.
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
import os
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def print_header():
|
||||
"""Print installation header."""
|
||||
print("=" * 60)
|
||||
print("🐾 PetBot Prerequisites Installation Script")
|
||||
print("=" * 60)
|
||||
print()
|
||||
|
||||
|
||||
def check_python_version():
|
||||
"""Check if Python version is compatible."""
|
||||
print("🔍 Checking Python version...")
|
||||
|
||||
version = sys.version_info
|
||||
required_major = 3
|
||||
required_minor = 7
|
||||
|
||||
if version.major < required_major or (version.major == required_major and version.minor < required_minor):
|
||||
print(f"❌ Python {required_major}.{required_minor}+ required. Current version: {version.major}.{version.minor}.{version.micro}")
|
||||
print("Please upgrade Python and try again.")
|
||||
return False
|
||||
|
||||
print(f"✅ Python {version.major}.{version.minor}.{version.micro} is compatible")
|
||||
return True
|
||||
|
||||
|
||||
def check_pip_available():
|
||||
"""Check if pip is available."""
|
||||
print("\n🔍 Checking pip availability...")
|
||||
|
||||
try:
|
||||
import pip
|
||||
print("✅ pip is available")
|
||||
return True
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
# Try alternative ways to check pip
|
||||
try:
|
||||
result = subprocess.run([sys.executable, "-m", "pip", "--version"],
|
||||
capture_output=True, text=True, check=True)
|
||||
print(f"✅ pip is available: {result.stdout.strip()}")
|
||||
return True
|
||||
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||
print("❌ pip is not available")
|
||||
print("Please install pip first:")
|
||||
print(" - On Ubuntu/Debian: sudo apt install python3-pip")
|
||||
print(" - On CentOS/RHEL: sudo yum install python3-pip")
|
||||
print(" - On macOS: brew install python3")
|
||||
return False
|
||||
|
||||
|
||||
def check_package_installed(package_name):
|
||||
"""Check if a package is already installed."""
|
||||
try:
|
||||
importlib.import_module(package_name)
|
||||
return True
|
||||
except ImportError:
|
||||
return False
|
||||
|
||||
|
||||
def install_package(package_spec):
|
||||
"""Install a package using pip."""
|
||||
print(f"📦 Installing {package_spec}...")
|
||||
|
||||
try:
|
||||
result = subprocess.run([
|
||||
sys.executable, "-m", "pip", "install", package_spec
|
||||
], capture_output=True, text=True, check=True)
|
||||
|
||||
print(f"✅ Successfully installed {package_spec}")
|
||||
return True
|
||||
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"❌ Failed to install {package_spec}")
|
||||
print(f"Error output: {e.stderr}")
|
||||
return False
|
||||
|
||||
|
||||
def install_requirements():
|
||||
"""Install packages from requirements.txt if it exists."""
|
||||
print("\n📋 Installing packages from requirements.txt...")
|
||||
|
||||
requirements_file = Path("requirements.txt")
|
||||
if not requirements_file.exists():
|
||||
print("❌ requirements.txt not found")
|
||||
return False
|
||||
|
||||
try:
|
||||
result = subprocess.run([
|
||||
sys.executable, "-m", "pip", "install", "-r", "requirements.txt"
|
||||
], capture_output=True, text=True, check=True)
|
||||
|
||||
print("✅ Successfully installed packages from requirements.txt")
|
||||
return True
|
||||
|
||||
except subprocess.CalledProcessError as e:
|
||||
print("❌ Failed to install from requirements.txt")
|
||||
print(f"Error output: {e.stderr}")
|
||||
return False
|
||||
|
||||
|
||||
def install_individual_packages():
|
||||
"""Install individual packages if requirements.txt fails."""
|
||||
print("\n📦 Installing individual packages...")
|
||||
|
||||
packages = [
|
||||
("irc", "irc>=20.3.0", "IRC client library"),
|
||||
("aiosqlite", "aiosqlite>=0.19.0", "Async SQLite database interface"),
|
||||
("dotenv", "python-dotenv>=1.0.0", "Environment variable loading")
|
||||
]
|
||||
|
||||
results = []
|
||||
|
||||
for import_name, package_spec, description in packages:
|
||||
print(f"\n🔍 Checking {import_name} ({description})...")
|
||||
|
||||
if check_package_installed(import_name):
|
||||
print(f"✅ {import_name} is already installed")
|
||||
results.append(True)
|
||||
else:
|
||||
print(f"❌ {import_name} is not installed")
|
||||
success = install_package(package_spec)
|
||||
results.append(success)
|
||||
|
||||
return all(results)
|
||||
|
||||
|
||||
def verify_installation():
|
||||
"""Verify that all required packages are installed correctly."""
|
||||
print("\n🔍 Verifying installation...")
|
||||
|
||||
test_imports = [
|
||||
("irc", "IRC client library"),
|
||||
("aiosqlite", "Async SQLite database"),
|
||||
("dotenv", "Environment variable loading"),
|
||||
("asyncio", "Async programming (built-in)"),
|
||||
("sqlite3", "SQLite database (built-in)"),
|
||||
("json", "JSON handling (built-in)"),
|
||||
("socket", "Network communication (built-in)"),
|
||||
("threading", "Threading (built-in)")
|
||||
]
|
||||
|
||||
all_good = True
|
||||
|
||||
for module_name, description in test_imports:
|
||||
try:
|
||||
importlib.import_module(module_name)
|
||||
print(f"✅ {module_name}: {description}")
|
||||
except ImportError as e:
|
||||
print(f"❌ {module_name}: {description} - {e}")
|
||||
all_good = False
|
||||
|
||||
return all_good
|
||||
|
||||
|
||||
def check_directory_structure():
|
||||
"""Check if we're in the correct directory and required files exist."""
|
||||
print("\n🔍 Checking directory structure...")
|
||||
|
||||
required_files = [
|
||||
"requirements.txt",
|
||||
"src/database.py",
|
||||
"src/game_engine.py",
|
||||
"src/bot.py",
|
||||
"webserver.py",
|
||||
"run_bot_debug.py"
|
||||
]
|
||||
|
||||
missing_files = []
|
||||
|
||||
for file_path in required_files:
|
||||
if not Path(file_path).exists():
|
||||
missing_files.append(file_path)
|
||||
|
||||
if missing_files:
|
||||
print("❌ Missing required files:")
|
||||
for file_path in missing_files:
|
||||
print(f" - {file_path}")
|
||||
print("\nPlease make sure you're running this script from the PetBot project directory.")
|
||||
return False
|
||||
|
||||
print("✅ All required files found")
|
||||
return True
|
||||
|
||||
|
||||
def create_data_directory():
|
||||
"""Create data directory if it doesn't exist."""
|
||||
print("\n🔍 Checking data directory...")
|
||||
|
||||
data_dir = Path("data")
|
||||
if not data_dir.exists():
|
||||
try:
|
||||
data_dir.mkdir()
|
||||
print("✅ Created data directory")
|
||||
except Exception as e:
|
||||
print(f"❌ Failed to create data directory: {e}")
|
||||
return False
|
||||
else:
|
||||
print("✅ Data directory already exists")
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def create_backups_directory():
|
||||
"""Create backups directory if it doesn't exist."""
|
||||
print("\n🔍 Checking backups directory...")
|
||||
|
||||
backups_dir = Path("backups")
|
||||
if not backups_dir.exists():
|
||||
try:
|
||||
backups_dir.mkdir()
|
||||
print("✅ Created backups directory")
|
||||
except Exception as e:
|
||||
print(f"❌ Failed to create backups directory: {e}")
|
||||
return False
|
||||
else:
|
||||
print("✅ Backups directory already exists")
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def test_basic_imports():
|
||||
"""Test basic functionality by importing key modules."""
|
||||
print("\n🧪 Testing basic imports...")
|
||||
|
||||
try:
|
||||
# Test database import
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
from src.database import Database
|
||||
print("✅ Database module imports successfully")
|
||||
|
||||
# Test connection manager import
|
||||
from src.irc_connection_manager import IRCConnectionManager
|
||||
print("✅ IRC connection manager imports successfully")
|
||||
|
||||
# Test backup manager import
|
||||
from src.backup_manager import BackupManager
|
||||
print("✅ Backup manager imports successfully")
|
||||
|
||||
return True
|
||||
|
||||
except ImportError as e:
|
||||
print(f"❌ Import test failed: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def show_next_steps():
|
||||
"""Show next steps after successful installation."""
|
||||
print("\n🎉 Installation completed successfully!")
|
||||
print("\n📋 Next steps:")
|
||||
print("1. Review and update configuration files in the config/ directory")
|
||||
print("2. Test the bot with: python3 run_bot_debug.py")
|
||||
print("3. Or use the new reconnection system: python3 run_bot_with_reconnect.py")
|
||||
print("4. Check the web interface at: http://localhost:8080")
|
||||
print("5. Review CLAUDE.md for development guidelines")
|
||||
print("\n🔧 Available test commands:")
|
||||
print(" python3 test_backup_simple.py - Test backup system")
|
||||
print(" python3 test_reconnection.py - Test IRC reconnection")
|
||||
print("\n📚 Documentation:")
|
||||
print(" README.md - Project overview")
|
||||
print(" CLAUDE.md - Development guide")
|
||||
print(" TODO.md - Current status")
|
||||
print(" issues.txt - Security audit findings")
|
||||
print(" BACKUP_SYSTEM_INTEGRATION.md - Backup system guide")
|
||||
|
||||
|
||||
def main():
|
||||
"""Main installation function."""
|
||||
print_header()
|
||||
|
||||
# Check prerequisites
|
||||
if not check_python_version():
|
||||
return False
|
||||
|
||||
if not check_pip_available():
|
||||
return False
|
||||
|
||||
if not check_directory_structure():
|
||||
return False
|
||||
|
||||
# Create directories
|
||||
if not create_data_directory():
|
||||
return False
|
||||
|
||||
if not create_backups_directory():
|
||||
return False
|
||||
|
||||
# Install packages
|
||||
success = install_requirements()
|
||||
|
||||
if not success:
|
||||
print("\n⚠️ requirements.txt installation failed, trying individual packages...")
|
||||
success = install_individual_packages()
|
||||
|
||||
if not success:
|
||||
print("\n❌ Package installation failed")
|
||||
return False
|
||||
|
||||
# Verify installation
|
||||
if not verify_installation():
|
||||
print("\n❌ Installation verification failed")
|
||||
return False
|
||||
|
||||
# Test imports
|
||||
if not test_basic_imports():
|
||||
print("\n❌ Basic import tests failed")
|
||||
return False
|
||||
|
||||
# Show next steps
|
||||
show_next_steps()
|
||||
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
success = main()
|
||||
if success:
|
||||
print("\n✅ PetBot prerequisites installation completed successfully!")
|
||||
sys.exit(0)
|
||||
else:
|
||||
print("\n❌ Installation failed. Please check the errors above.")
|
||||
sys.exit(1)
|
||||
except KeyboardInterrupt:
|
||||
print("\n🛑 Installation interrupted by user")
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
print(f"\n💥 Unexpected error: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
Loading…
Add table
Add a link
Reference in a new issue