Code Rewrite to support multi instances

This commit is contained in:
Benjamin Harder
2024-08-20 23:28:20 +02:00
parent 2041337914
commit 1663703186
80 changed files with 4560 additions and 2954 deletions

View File

@@ -0,0 +1,138 @@
import os
import yaml
from src.utils.log_setup import logger
CONFIG_MAPPING = {
"general": [
"LOG_LEVEL",
"TEST_RUN",
"TIMER",
"SSL_VERIFICATION",
"IGNORED_DOWNLOAD_CLIENTS",
],
"job_defaults": [
"MAX_STRIKES",
"MIN_DAYS_BETWEEN_SEARCHES",
"MAX_CONCURRENT_SEARCHES",
],
"jobs": [
"REMOVE_BAD_FILES",
"REMOVE_FAILED_DOWNLOADS",
"REMOVE_FAILED_IMPORTS",
"REMOVE_METADATA_MISSING",
"REMOVE_MISSING_FILES",
"REMOVE_ORPHANS",
"REMOVE_SLOW",
"REMOVE_STALLED",
"REMOVE_UNMONITORED",
"SEARCH_UNMET_CUTOFF_CONTENT",
"SEARCH_MISSING_CONTENT",
],
"instances": ["SONARR", "RADARR", "READARR", "LIDARR", "WHISPARR"],
"download_clients": ["QBITTORRENT"],
}
def get_user_config(settings):
"""Checks if data is read from enviornment variables, or from yaml file.
Reads from environment variables if in docker, unless in docker-compose "USE_CONFIG_YAML" is set to true.
Then the config file is read.
"""
config = {}
if _config_file_exists(settings):
config = _load_from_yaml_file(settings)
settings.envs.use_config_yaml = True
elif settings.envs.in_docker:
config = _load_from_env()
# Ensure all top-level keys exist, even if empty
for section in CONFIG_MAPPING:
if config.get(section) is None:
config[section] = {}
return config
def _parse_env_var(key: str) -> dict | list | str | int | None:
"""Helper function to parse one setting input key"""
raw_value = os.getenv(key)
if raw_value is None:
return None
try:
parsed = yaml.safe_load(raw_value)
return _lowercase(parsed)
except yaml.YAMLError as e:
logger.error(f"Failed to parse environment variable {key} as YAML:\n{e}")
return {}
def _load_section(keys: list[str]) -> dict:
"""Helper function to parse one section of expected config"""
section_config = {}
for key in keys:
parsed = _parse_env_var(key)
if parsed is not None:
section_config[key.lower()] = parsed
return section_config
def _load_from_env() -> dict:
"""Main function to load settings from env"""
config = {}
for section, keys in CONFIG_MAPPING.items():
config[section] = _load_section(keys)
return config
def _load_from_env() -> dict:
config = {}
for section, keys in CONFIG_MAPPING.items():
section_config = {}
for key in keys:
raw_value = os.getenv(key)
if raw_value is None:
continue
try:
parsed_value = yaml.safe_load(raw_value)
parsed_value = _lowercase(parsed_value)
except yaml.YAMLError as e:
logger.error(
f"Failed to parse environment variable {key} as YAML:\n{e}"
)
parsed_value = {}
section_config[key.lower()] = parsed_value
config[section] = section_config
return config
def _lowercase(data):
"""Translates recevied keys (for instance setting-keys of jobs) to lower case"""
if isinstance(data, dict):
return {str(k).lower(): _lowercase(v) for k, v in data.items()}
elif isinstance(data, list):
return [_lowercase(item) for item in data]
else:
# Leave strings and other types unchanged
return data
def _config_file_exists(settings):
config_path = settings.paths.config_file
return os.path.exists(config_path)
def _load_from_yaml_file(settings):
"""Reads config from YAML file and returns a dict."""
config_path = settings.paths.config_file
try:
with open(config_path, "r", encoding="utf-8") as file:
config = yaml.safe_load(file) or {}
return config
except yaml.YAMLError as e:
logger.error("Error reading YAML file: %s", e)
return {}