148 lines
4.1 KiB
Python
148 lines
4.1 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Configuration file handler for QLPyCon
|
|
Supports loading from ~/.qlpycon.conf or ./qlpycon.conf
|
|
"""
|
|
|
|
import os
|
|
import configparser
|
|
import logging
|
|
|
|
logger = logging.getLogger('config_loader')
|
|
|
|
|
|
class ConfigLoader:
|
|
"""Load configuration from INI file"""
|
|
|
|
def __init__(self):
|
|
self.config = configparser.ConfigParser()
|
|
self.config_loaded = False
|
|
|
|
def load(self):
|
|
"""
|
|
Try to load config from (in order):
|
|
1. ./qlpycon.conf (current directory)
|
|
2. ~/.qlpycon.conf (home directory)
|
|
"""
|
|
config_paths = [
|
|
'qlpycon.conf',
|
|
os.path.expanduser('~/.qlpycon.conf')
|
|
]
|
|
|
|
for path in config_paths:
|
|
if os.path.exists(path):
|
|
try:
|
|
self.config.read(path)
|
|
self.config_loaded = True
|
|
logger.info(f'Loaded configuration from: {path}')
|
|
return True
|
|
except Exception as e:
|
|
logger.warning(f'Failed to load config from {path}: {e}')
|
|
|
|
logger.debug('No configuration file found, using defaults')
|
|
return False
|
|
|
|
def get(self, section, key, fallback=None):
|
|
"""Get a configuration value"""
|
|
if not self.config_loaded:
|
|
return fallback
|
|
|
|
try:
|
|
return self.config.get(section, key, fallback=fallback)
|
|
except (configparser.NoSectionError, configparser.NoOptionError):
|
|
return fallback
|
|
|
|
def get_int(self, section, key, fallback=0):
|
|
"""Get an integer configuration value"""
|
|
value = self.get(section, key)
|
|
if value is None:
|
|
return fallback
|
|
|
|
try:
|
|
return int(value)
|
|
except ValueError:
|
|
logger.warning(f'Invalid integer value for [{section}] {key}: {value}')
|
|
return fallback
|
|
|
|
def get_bool(self, section, key, fallback=False):
|
|
"""Get a boolean configuration value"""
|
|
value = self.get(section, key)
|
|
if value is None:
|
|
return fallback
|
|
|
|
return value.lower() in ('true', 'yes', '1', 'on')
|
|
|
|
def get_host(self):
|
|
"""Get connection host"""
|
|
return self.get('connection', 'host')
|
|
|
|
def get_password(self):
|
|
"""Get connection password (supports ${ENV_VAR} syntax)"""
|
|
password = self.get('connection', 'password')
|
|
if not password:
|
|
return None
|
|
|
|
# Support environment variable substitution: ${VAR_NAME}
|
|
if password.startswith('${') and password.endswith('}'):
|
|
env_var = password[2:-1]
|
|
return os.environ.get(env_var)
|
|
|
|
return password
|
|
|
|
def get_log_level(self):
|
|
"""Get logging level"""
|
|
level_str = self.get('logging', 'level', 'INFO')
|
|
levels = {
|
|
'DEBUG': logging.DEBUG,
|
|
'INFO': logging.INFO,
|
|
'WARNING': logging.WARNING,
|
|
'ERROR': logging.ERROR,
|
|
'CRITICAL': logging.CRITICAL
|
|
}
|
|
return levels.get(level_str.upper(), logging.INFO)
|
|
|
|
|
|
def create_example_config():
|
|
"""Create an example configuration file"""
|
|
config_content = """# QLPyCon Configuration File
|
|
# Place this file as ~/.qlpycon.conf or ./qlpycon.conf
|
|
|
|
[connection]
|
|
# Server connection settings
|
|
host = tcp://10.13.12.93:28969
|
|
# Use ${ENV_VAR} to read from environment
|
|
password = ${QLPYCON_PASSWORD}
|
|
|
|
[logging]
|
|
# Log level: DEBUG, INFO, WARNING, ERROR, CRITICAL
|
|
level = INFO
|
|
|
|
[ui]
|
|
# Max command history entries
|
|
max_history = 10
|
|
# Color scheme (future feature)
|
|
color_scheme = quake
|
|
|
|
[behavior]
|
|
# Quit confirmation timeout (seconds)
|
|
quit_timeout = 3.0
|
|
# Player respawn delay (seconds)
|
|
respawn_delay = 3.0
|
|
"""
|
|
|
|
example_path = os.path.expanduser('~/.qlpycon.conf.example')
|
|
try:
|
|
with open(example_path, 'w') as f:
|
|
f.write(config_content)
|
|
print(f'Created example config: {example_path}')
|
|
print(f'Copy to ~/.qlpycon.conf and edit as needed')
|
|
return True
|
|
except Exception as e:
|
|
print(f'Failed to create example config: {e}')
|
|
return False
|
|
|
|
|
|
if __name__ == '__main__':
|
|
# Create example config when run directly
|
|
create_example_config()
|