Architecture Documentation for Pterodisbot v1.1.0
345
Architecture.md
Normal file
345
Architecture.md
Normal file
@@ -0,0 +1,345 @@
|
||||
# Architecture Overview
|
||||
|
||||
The bot follows a modular, async-first architecture designed for reliability, performance, and maintainability.
|
||||
|
||||
### System Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Discord Interface │
|
||||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||||
│ │ Slash │ │ Button │ │ Status │ │
|
||||
│ │ Commands │ │ Interactions │ │ Embeds │ │
|
||||
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
|
||||
└─────────┼──────────────────┼──────────────────┼─────────────┘
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ PterodactylBot (Core Orchestrator) │
|
||||
│ ┌────────────────────────────────────────────────────┐ │
|
||||
│ │ • Command routing and validation │ │
|
||||
│ │ • Embed lifecycle management │ │
|
||||
│ │ • State tracking and change detection │ │
|
||||
│ │ • Background task scheduling │ │
|
||||
│ └────────────────────────────────────────────────────┘ │
|
||||
└───────┬───────────────────────┬─────────────────┬───────────┘
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌──────────────┐ ┌──────────────────┐ ┌──────────────┐
|
||||
│ Pterodactyl │ │ Metrics Manager │ │ Storage │
|
||||
│ API │ │ │ │ Layer │
|
||||
│ │ │ • Data tracking │ │ │
|
||||
│ • Client API │ │ • Graph gen. │ │ • Embed loc. │
|
||||
│ • App API │ │ • Trend analysis │ │ • State data │
|
||||
│ • Resource │ │ • FIFO queues │ │ • JSON pers. │
|
||||
│ monitoring │ │ • Multi-vCPU │ │ │
|
||||
└──────────────┘ └──────────────────┘ └──────────────┘
|
||||
│ │
|
||||
▼ ▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ External Systems & Data Stores │
|
||||
│ ┌──────────────┐ ┌──────────────┐ │
|
||||
│ │ Pterodactyl │ │ File │ │
|
||||
│ │ Panel │ │ System │ │
|
||||
│ └──────────────┘ └──────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Core Components
|
||||
|
||||
#### 1. **PterodactylBot** (`pterodisbot.py`)
|
||||
Main orchestrator class that coordinates all bot operations.
|
||||
|
||||
**Responsibilities:**
|
||||
- Discord.py bot initialization and lifecycle
|
||||
- Slash command routing and validation
|
||||
- Embed creation, tracking, and lifecycle management
|
||||
- Background task scheduling and execution
|
||||
- State management and change detection
|
||||
- Error handling and recovery
|
||||
|
||||
**Key Methods:**
|
||||
- `setup_hook()`: Initializes API clients and background tasks
|
||||
- `get_server_status_embed()`: Generates Discord embeds with current server data
|
||||
- `update_status()`: Background task for intelligent embed updates
|
||||
- `refresh_all_embeds()`: Complete embed refresh across all channels
|
||||
- `track_new_embed()`: Persists embed location data
|
||||
|
||||
**Design Patterns:**
|
||||
- **Observer Pattern**: Monitors server state changes
|
||||
- **Strategy Pattern**: Different update strategies based on state changes
|
||||
- **Factory Pattern**: Creates embeds and views dynamically
|
||||
|
||||
#### 2. **PterodactylAPI** (`pterodisbot.py`)
|
||||
Abstraction layer for all Pterodactyl Panel API interactions.
|
||||
|
||||
**Responsibilities:**
|
||||
- HTTP request management with aiohttp
|
||||
- API authentication (dual key support)
|
||||
- Request/response serialization
|
||||
- Error handling and retry logic
|
||||
- Rate limit management
|
||||
|
||||
**API Coverage:**
|
||||
- **Client API** (`ptlc_*`): Server resources, power actions
|
||||
- **Application API** (`ptla_*`): Server lists, allocations, details
|
||||
|
||||
**Key Features:**
|
||||
- Async/await throughout for non-blocking I/O
|
||||
- Request locking to prevent race conditions
|
||||
- Automatic retry with exponential backoff
|
||||
- Comprehensive error response handling
|
||||
|
||||
#### 3. **ServerMetricsGraphs** (`server_metrics_graphs.py`)
|
||||
Time-series data tracking and visualization for individual servers.
|
||||
|
||||
**Responsibilities:**
|
||||
- Historical data collection (1-minute sliding window)
|
||||
- FIFO queue management (6 data points max)
|
||||
- Graph generation using matplotlib
|
||||
- Multi-vCPU scaling calculations
|
||||
- Trend analysis and statistics
|
||||
|
||||
**Graph Features:**
|
||||
- **CPU Graph**: Dynamic scaling for multi-vCPU servers
|
||||
- **Memory Graph**: Adaptive Y-axis based on usage
|
||||
- **Combined Graph**: Dual subplot for comprehensive view
|
||||
- **Discord Optimized**: Dark theme matching Discord's interface
|
||||
|
||||
**Data Structure:**
|
||||
```python
|
||||
# Each data point: (timestamp, cpu_percent, memory_mb)
|
||||
deque([
|
||||
(datetime(...), 45.5, 1024.0),
|
||||
(datetime(...), 50.2, 1100.0),
|
||||
# ... up to 6 points
|
||||
], maxlen=6)
|
||||
```
|
||||
|
||||
#### 4. **ServerMetricsManager** (`server_metrics_graphs.py`)
|
||||
Global coordinator for all server metrics tracking.
|
||||
|
||||
**Responsibilities:**
|
||||
- Lifecycle management of ServerMetricsGraphs instances
|
||||
- Server discovery and cleanup
|
||||
- Bulk operations across all tracked servers
|
||||
- Memory management
|
||||
|
||||
**Key Features:**
|
||||
- Lazy initialization of graph instances
|
||||
- Automatic cleanup of removed servers
|
||||
- Summary statistics generation
|
||||
- Thread-safe operations
|
||||
|
||||
#### 5. **ServerStatusView** (`pterodisbot.py`)
|
||||
Discord UI component providing interactive server controls.
|
||||
|
||||
**Responsibilities:**
|
||||
- Button state management
|
||||
- User authorization and validation
|
||||
- Power action execution
|
||||
- Connection info display
|
||||
|
||||
**Buttons:**
|
||||
- 🟢 **Start**: Sends `start` signal to server
|
||||
- 🔴 **Stop**: Sends `stop` signal to server
|
||||
- 🔵 **Restart**: Sends `restart` signal to server
|
||||
- 📍 **Show Address**: Displays IP and port
|
||||
|
||||
**Security:**
|
||||
- Guild ID validation
|
||||
- Role-based access control
|
||||
- Interaction-level authorization checks
|
||||
- Ephemeral responses for sensitive data
|
||||
|
||||
### Data Flow
|
||||
|
||||
#### Server Status Update Flow
|
||||
|
||||
```
|
||||
1. Background Task (every 10s)
|
||||
├─> Fetch all servers from Pterodactyl
|
||||
├─> Update server cache
|
||||
└─> For each tracked embed:
|
||||
├─> Get current resources
|
||||
├─> Check state changes:
|
||||
│ ├─> Power state changed? → UPDATE
|
||||
│ ├─> CPU change >50%? → UPDATE
|
||||
│ ├─> First check? → UPDATE
|
||||
│ └─> 10min force update? → UPDATE
|
||||
├─> If running: Collect metrics
|
||||
├─> Generate embed + view
|
||||
├─> Update Discord message
|
||||
└─> Update state tracking
|
||||
|
||||
2. Metrics Collection (running servers only)
|
||||
├─> Extract CPU/memory data
|
||||
├─> Add to ServerMetricsGraphs
|
||||
├─> Check sufficient data (6 points)
|
||||
└─> Generate graph if available
|
||||
|
||||
3. State Tracking
|
||||
├─> Store: (state, cpu_usage, last_force_update)
|
||||
├─> Compare with previous state
|
||||
└─> Determine if update needed
|
||||
```
|
||||
|
||||
#### User Interaction Flow
|
||||
|
||||
```
|
||||
1. User Types /server_status
|
||||
├─> Guild validation
|
||||
├─> Fetch all servers
|
||||
├─> Generate statistics
|
||||
├─> Create dropdown menu
|
||||
└─> Send ephemeral response
|
||||
|
||||
2. User Selects Server
|
||||
├─> Validate selection
|
||||
├─> Check for existing embed
|
||||
├─> Delete old embed if exists
|
||||
├─> Create new status embed
|
||||
├─> Track embed location
|
||||
└─> Persist to JSON
|
||||
|
||||
3. User Clicks Power Button
|
||||
├─> Interaction check
|
||||
│ ├─> Verify guild ID
|
||||
│ └─> Check user role
|
||||
├─> Send power action to API
|
||||
├─> Await confirmation
|
||||
└─> Send ephemeral response
|
||||
```
|
||||
|
||||
### Configuration System
|
||||
|
||||
The bot uses a multi-layer configuration system:
|
||||
|
||||
```python
|
||||
1. Environment Variables (Docker/container environments)
|
||||
↓
|
||||
2. config.ini file (traditional deployments)
|
||||
↓
|
||||
3. Validation layer (startup checks)
|
||||
↓
|
||||
4. Runtime constants
|
||||
```
|
||||
|
||||
**Validation Checks:**
|
||||
- Required sections and keys present
|
||||
- API key prefix validation (`ptlc_` and `ptla_`)
|
||||
- Guild ID format (valid integer)
|
||||
- URL format (includes protocol)
|
||||
- Raises `ConfigValidationError` on failure
|
||||
|
||||
### Persistent Storage
|
||||
|
||||
#### Embed Locations (`embed/embed_locations.json`)
|
||||
```json
|
||||
{
|
||||
"server_abc123": {
|
||||
"channel_id": "123456789",
|
||||
"message_id": "987654321"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Operations:**
|
||||
- **Load**: On bot startup
|
||||
- **Save**: After each embed create/delete
|
||||
- **Cleanup**: Automatic on missing messages
|
||||
|
||||
#### Server State Tracking (in-memory)
|
||||
```python
|
||||
{
|
||||
"server_abc123": (
|
||||
"running", # Current state
|
||||
45.5, # Last CPU usage
|
||||
1699123456.0 # Last force update timestamp
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
**Purpose:**
|
||||
- Change detection for smart updates
|
||||
- Reduces unnecessary Discord API calls
|
||||
- Tracks force update intervals
|
||||
|
||||
### Async Architecture
|
||||
|
||||
The bot is built on asyncio for concurrent operations:
|
||||
|
||||
```python
|
||||
# Concurrent API requests
|
||||
async with asyncio.gather(*[
|
||||
api.get_server_resources(id1),
|
||||
api.get_server_resources(id2),
|
||||
api.get_server_resources(id3)
|
||||
]):
|
||||
# Process results
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- Non-blocking I/O operations
|
||||
- Concurrent server status checks
|
||||
- Responsive to Discord interactions
|
||||
- Efficient resource utilization
|
||||
|
||||
**Synchronization:**
|
||||
- `asyncio.Lock()` for API rate limiting
|
||||
- `asyncio.Lock()` for embed update cycles
|
||||
- No blocking operations in event loop
|
||||
|
||||
### Error Handling Strategy
|
||||
|
||||
**Levels:**
|
||||
1. **Graceful Degradation**: Continue operating with reduced functionality
|
||||
2. **Automatic Retry**: Retry failed operations with backoff
|
||||
3. **User Notification**: Inform users of transient errors
|
||||
4. **Logging**: Comprehensive error logging for debugging
|
||||
5. **Crash Prevention**: Catch and handle all exceptions
|
||||
|
||||
**Example:**
|
||||
```python
|
||||
try:
|
||||
resources = await api.get_server_resources(server_id)
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to fetch resources: {e}")
|
||||
# Use cached data or display offline state
|
||||
return {'attributes': {'current_state': 'offline'}}
|
||||
```
|
||||
|
||||
### Performance Optimizations
|
||||
|
||||
#### 1. Smart Update Logic
|
||||
Only updates embeds when necessary:
|
||||
- Power state changes (always)
|
||||
- Significant CPU changes (>50% delta)
|
||||
- Force update interval (every 10 minutes)
|
||||
- Initial server checks
|
||||
|
||||
**Impact**: ~90% reduction in Discord API calls
|
||||
|
||||
#### 2. FIFO Metric Queues
|
||||
`collections.deque(maxlen=6)` automatically rotates old data:
|
||||
- O(1) append operations
|
||||
- Automatic memory management
|
||||
- No manual cleanup needed
|
||||
|
||||
#### 3. Request Locking
|
||||
Prevents concurrent API access:
|
||||
```python
|
||||
async with self.lock:
|
||||
# Only one request at a time
|
||||
response = await self.session.request(...)
|
||||
```
|
||||
|
||||
**Benefits**:
|
||||
- Avoids rate limits
|
||||
- Prevents race conditions
|
||||
- Ensures ordered operations
|
||||
|
||||
#### 4. Caching Strategy
|
||||
- Server list cached between updates
|
||||
- State tracking prevents redundant checks
|
||||
- Embed locations loaded once at startup
|
||||
Reference in New Issue
Block a user