Update: Major code refactor for modular extensibility #2

Merged
k.eaven merged 7 commits from development into main 2026-10-24 15:33:41 +00:00
Showing only changes of commit 451e202832 - Show all commits
+71 -21
View File
@@ -3,6 +3,7 @@ import configparser
from pathlib import Path from pathlib import Path
from dotenv import load_dotenv from dotenv import load_dotenv
def validate_env_vars(): def validate_env_vars():
"""Validate that required environment variables are set and non-empty.""" """Validate that required environment variables are set and non-empty."""
required_vars = [ required_vars = [
@@ -17,34 +18,83 @@ def validate_env_vars():
if missing_vars: if missing_vars:
raise ValueError(f"Missing required environment variables: {', '.join(missing_vars)}") raise ValueError(f"Missing required environment variables: {', '.join(missing_vars)}")
def get_env_config():
"""Extract configuration from environment variables."""
return {
'Discord': {
'Token': os.getenv('DISCORD_TOKEN'),
'AllowedGuildID': os.getenv('ALLOWED_GUILD_ID')
},
'Pterodactyl': {
'PanelURL': os.getenv('PANEL_URL'),
'ClientAPIKey': os.getenv('CLIENT_API_KEY'),
'ApplicationAPIKey': os.getenv('APPLICATION_API_KEY')
}
}
def configs_match(existing_config, env_config):
"""Compare existing config with environment variables."""
for section, values in env_config.items():
if not existing_config.has_section(section):
return False
for key, env_value in values.items():
if env_value is None:
# Environment variable not set, don't require match
continue
existing_value = existing_config.get(section, key, fallback=None)
if existing_value != env_value:
return False
return True
def generate_config(): def generate_config():
"""Generate config.ini from environment variables.""" """
# Validate environment variables first Generate config.ini from environment variables if:
validate_env_vars() 1. No config file exists, OR
2. Config file exists but values don't match environment variables
config = configparser.ConfigParser() Environment variables always take priority.
"""
# Discord section - ensure all values are strings
config['Discord'] = {
'Token': str(os.getenv('DISCORD_TOKEN')),
'AllowedGuildID': str(os.getenv('ALLOWED_GUILD_ID'))
}
# Pterodactyl section - ensure all values are strings
config['Pterodactyl'] = {
'PanelURL': str(os.getenv('PANEL_URL')),
'ClientAPIKey': str(os.getenv('CLIENT_API_KEY')),
'ApplicationAPIKey': str(os.getenv('APPLICATION_API_KEY'))
}
# Write to file
config_path = Path(os.getenv('CONFIG_PATH', 'config.ini')) config_path = Path(os.getenv('CONFIG_PATH', 'config.ini'))
# Check if config file exists
if not config_path.exists():
print(f"No config file found at {config_path}, generating from environment variables...")
validate_env_vars()
_write_config(config_path, get_env_config())
return
# Config file exists, read it and compare with environment
existing_config = configparser.ConfigParser()
existing_config.read(config_path)
env_config = get_env_config()
if not configs_match(existing_config, env_config):
print(f"Config file at {config_path} differs from environment variables, regenerating...")
# Validate that required env vars are present for regeneration
validate_env_vars()
_write_config(config_path, env_config)
return
print(f"Config file at {config_path} matches environment variables, using existing config.")
def _write_config(config_path, config_dict):
"""Write config dictionary to file."""
config = configparser.ConfigParser()
for section, values in config_dict.items():
config[section] = {k: str(v) for k, v in values.items() if v is not None}
config_path.parent.mkdir(exist_ok=True, parents=True) config_path.parent.mkdir(exist_ok=True, parents=True)
with open(config_path, 'w') as configfile: with open(config_path, 'w') as configfile:
config.write(configfile) config.write(configfile)
print(f"Config file generated at {config_path}") print(f"Config file written to {config_path}")
if __name__ == "__main__": if __name__ == "__main__":
load_dotenv() load_dotenv()
generate_config() generate_config()