Petbot/install_prerequisites.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

344 lines
No EOL
10 KiB
Python

#!/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)