100 lines
3.5 KiB
Python
100 lines
3.5 KiB
Python
from __future__ import annotations
|
|
|
|
import os
|
|
from typing import Any
|
|
|
|
_ENV_VAR_MAP: dict[str, str] = {
|
|
"MATRIX_HOMESERVER": "homeserver",
|
|
"MATRIX_USER_ID": "user_id",
|
|
"MATRIX_ACCESS_TOKEN": "access_token",
|
|
"MATRIX_PASSWORD": "password",
|
|
"MATRIX_DEVICE_ID": "device_id",
|
|
"MATRIX_DEVICE_NAME": "deviceName",
|
|
"MATRIX_CRYPTO_STORE_DIR": "crypto_store_dir",
|
|
"MATRIX_DM_POLICY": "dm.policy",
|
|
"MATRIX_GROUP_POLICY": "groupPolicy",
|
|
"MATRIX_PROXY": "proxy",
|
|
"MATRIX_AUTO_JOIN": "autoJoin",
|
|
"MATRIX_SYNC_TIMEOUT_MS": "sync_timeout_ms",
|
|
"MATRIX_DISPLAY_NAME": "display_name",
|
|
"MATRIX_AVATAR_URL": "avatarUrl",
|
|
"MATRIX_RESPONSE_PREFIX": "responsePrefix",
|
|
"MATRIX_MEDIA_MAX_MB": "mediaMaxMb",
|
|
}
|
|
|
|
_NESTED_KEY_MAP: dict[str, tuple[str, str]] = {
|
|
"dm.policy": ("dm", "policy"),
|
|
"groupPolicy": (None, "groupPolicy"),
|
|
}
|
|
|
|
|
|
def resolve_env_vars(config: dict[str, Any], account_id: str = "") -> dict[str, Any]:
|
|
result = dict(config)
|
|
|
|
for env_var, config_key in _ENV_VAR_MAP.items():
|
|
env_value = os.environ.get(env_var)
|
|
if env_value is not None:
|
|
if "." in config_key:
|
|
_set_nested(result, config_key, env_value)
|
|
else:
|
|
result[config_key] = _coerce_type(env_value, config.get(config_key))
|
|
|
|
if account_id:
|
|
prefix = f"MATRIX_{account_id.upper()}_"
|
|
for env_name, env_value in os.environ.items():
|
|
if env_name.startswith(prefix):
|
|
config_key = env_name[len(prefix) :].lower()
|
|
result[config_key] = _coerce_type(env_value, config.get(config_key))
|
|
|
|
return result
|
|
|
|
|
|
def _set_nested(config: dict[str, Any], key: str, value: Any) -> None:
|
|
parts = key.split(".")
|
|
if len(parts) == 2:
|
|
parent, child = parts
|
|
if parent not in config or not isinstance(config[parent], dict):
|
|
config[parent] = {}
|
|
config[parent][child] = value
|
|
|
|
|
|
def _coerce_type(value: str, existing: Any) -> Any:
|
|
if existing is None:
|
|
return value
|
|
|
|
if isinstance(existing, bool):
|
|
return value.lower() in ("true", "1", "yes")
|
|
if isinstance(existing, int):
|
|
try:
|
|
return int(value)
|
|
except ValueError:
|
|
return value
|
|
if isinstance(existing, float):
|
|
try:
|
|
return float(value)
|
|
except ValueError:
|
|
return value
|
|
|
|
return value
|
|
|
|
|
|
def get_env_var_descriptions() -> dict[str, str]:
|
|
return {
|
|
"MATRIX_HOMESERVER": "Matrix homeserver URL (e.g. https://matrix.org)",
|
|
"MATRIX_USER_ID": "Matrix user ID (e.g. @bot:matrix.org)",
|
|
"MATRIX_ACCESS_TOKEN": "Matrix access token (alternative to password)",
|
|
"MATRIX_PASSWORD": "Matrix account password",
|
|
"MATRIX_DEVICE_ID": "Device ID for this session",
|
|
"MATRIX_DEVICE_NAME": "Display name for this device",
|
|
"MATRIX_CRYPTO_STORE_DIR": "Directory for E2EE key storage",
|
|
"MATRIX_DM_POLICY": "DM access policy: open/disabled/allowlist/pairing",
|
|
"MATRIX_GROUP_POLICY": "Group access policy: open/disabled/allowlist",
|
|
"MATRIX_PROXY": "HTTP(S) proxy URL",
|
|
"MATRIX_AUTO_JOIN": "Auto-join policy: off/always/allowlist/invites",
|
|
"MATRIX_SYNC_TIMEOUT_MS": "Sync timeout in milliseconds",
|
|
"MATRIX_DISPLAY_NAME": "Bot display name",
|
|
"MATRIX_AVATAR_URL": "Bot avatar URL (mxc:// or https://)",
|
|
"MATRIX_RESPONSE_PREFIX": "Prefix added to all bot responses",
|
|
"MATRIX_MEDIA_MAX_MB": "Maximum media file size in MB",
|
|
}
|