3
Architecture
Eaven Kimura edited this page 2026-10-26 13:01:42 +00:00

Architecture

Overview

Pterodisbot is a modular, asynchronous Discord bot built with Python 3.8+ using the discord.py library. It follows a clean architecture pattern with clear separation of concerns across multiple modules.

System Architecture

┌─────────────────────────────────────────────────────────────────┐
│                        Discord Client                           │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────────┐  │
│  │ Slash Cmds  │  │  Buttons    │  │  Dropdown Menus         │  │
│  └──────┬──────┘  └──────┬──────┘  └───────────┬─────────────┘  │
└─────────┼────────────────┼──────────────────────┼───────────────┘
          │                │                      │
          ▼                ▼                      ▼
┌─────────────────────────────────────────────────────────────────┐
│                      PterodactylBot (commands.Bot)              │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │  Background Task: update_status (10s interval)            │  │
│  │  • Smart update detection (state changes, CPU, uptime)    │  │
│  │  • Rate limit protection                                  │  │
│  └───────────────────────────────────────────────────────────┘  │
└─────────────────────────────┬───────────────────────────────────┘
                              │
        ┌─────────────────────┼─────────────────────┐
        ▼                     ▼                     ▼
┌───────────────┐    ┌───────────────┐    ┌───────────────┐
│  EmbedManager │    │  PanelAPI     │    │MetricsManager │
│               │    │               │    │               │
│ • Create      │    │ • Client API  │    │ • Data points │
│ • Update      │    │ • App API     │    │ • Graphs      │
│ • Track       │    │ • Auth        │    │ • Trends      │
│ • Persist     │    │ • Rate limit  │    │               │
└───────┬───────┘    └───────┬───────┘    └───────┬───────┘
        │                    │                    │
        ▼                    ▼                    ▼
┌───────────────┐    ┌───────────────┐    ┌───────────────┐
│  JSON Storage │    │ Pterodactyl/  │    │  Matplotlib   │
│ (embed_locs)  │    │   Pelican     │    │  (PNG graphs) │
|               |    |  Panel API    |    |               |
└───────────────┘    └───────────────┘    └───────────────┘

Module Structure

Module Responsibility Key Classes
main.py Entry point, logging setup main()
config.py Configuration loading/validation Config, load_config()
bot.py Core bot, commands, background tasks PterodactylBot, setup_commands()
api.py Pterodactyl/Pelican Panel API client PanelAPI
embeds.py Embed creation, tracking, persistence EmbedManager
views.py Discord UI components (buttons, dropdowns) ServerStatusView, ServerDropdown
metrics.py Metrics collection & graph generation ServerMetricsManager, ServerMetricsGraphs
models.py Pydantic data models ServerData, ServerResources, etc.
exceptions.py Custom exception hierarchy APIError, ConfigValidationError, etc.
logging_config.py Logging configuration setup_logging()
generate_config.py Config generation from env vars generate_config_from_env()

Data Flow

1. Bot Startup

main() → load_config() → PterodactylBot() → setup_commands() → bot.start()
                                    ↓
                           setup_hook() → api.initialize()
                                    ↓
                           embed_manager.load_locations()
                                    ↓
                           update_status.start()

2. Status Update Cycle (Every 10s)

update_status() → api.get_servers() → For each tracked embed:
    → api.get_server_resources()
    → metrics_manager.add_server_data() (if running)
    → Smart update detection:
        • Power state changed? → UPDATE
        • CPU change >50%? → UPDATE
        • First time seeing server? → UPDATE
        • Running >10min? → UPDATE (uptime accuracy)
    → embed_manager.update_single_embed()
    → metrics_manager.generate_combined_graph()
    → Discord message.edit()

3. User Interaction Flow

/server_status command
    → api.get_servers()
    → Create stats embed + dropdown
    → User selects server
    → api.get_server_resources()
    → Delete old embed (if exists)
    → embed_manager.create_server_embed()
    → Send new embed with ServerStatusView
    → embed_manager.track_embed()

Button press (Start/Stop/Restart/Show Address)
    → ServerStatusView.interaction_check() (guild + role)
    → api.send_power_action() or api.get_server_default_allocation()
    → Ephemeral response to user

Concurrency Model

  • Async/await throughout for non-blocking I/O
  • asyncio.Lock in PanelAPI._request() for rate limit protection
  • asyncio.Lock in PterodactylBot.update_status for update cycle serialization
  • deque(maxlen=6) for automatic metrics rotation (1 min history)
  • Background task with @tasks.loop(seconds=10) for periodic updates

Persistence

  • Embed locations: JSON file (embed/embed_locations.json)
  • Metrics: In-memory only (last 6 data points = 1 minute)
  • Configuration: INI file (config.ini) or environment variables
  • Logs: Rotating files (5MB, 3 backups) in logs/

Security Architecture

┌────────────────────────────────────────────────────────────┐
│                    Access Control Layers                   │
├────────────────────────────────────────────────────────────┤
│  1. Guild Restriction (config.allowed_guild_id)            │
│     └─ Checked in: on_interaction, check_allowed_guild,    │
│         ServerStatusView.interaction_check                 │
├────────────────────────────────────────────────────────────┤
│  2. Role-Based Access ("Game Server User" role)            │
│     └─ Checked in: ServerStatusView.interaction_check      │
├────────────────────────────────────────────────────────────┤
│  3. Admin Permissions (Discord Administrator)              │
│     └─ Required for: /refresh_embeds, /purge_embeds        │
└────────────────────────────────────────────────────────────┘

API Integration

Dual API Key System

  • Client API Key (ptlc_ / pacc_): Server operations (power, resources)
  • Application API Key (ptla_ / papp_): Admin operations (list servers, details)

Supported Panels

  • Pterodactyl Panel (standard)
  • Pelican Panel (fork, uses pacc_/papp_ prefixes)
  • Auto-detected via Config.is_pelican_panel property

Error Handling Strategy

  1. Validation at startup - Config validation fails fast
  2. Graceful degradation - Failed embed updates don't crash the bot
  3. Structured exceptions - Custom exception types for different failure modes
  4. Comprehensive logging - DEBUG for operations, ERROR for failures
  5. Automatic cleanup - Missing embeds removed from tracking

Deployment Architectures

Traditional

Python 3.8+ → pip install -r requirements.txt → python main.py

Docker

Dockerfile → docker build → docker run -v config:/app

Kubernetes

Deployment + Secret + PVC → kubectl apply