0.3.9.2.a10
Restructured runtime environment variables passing to cogs
This commit is contained in:
parent
1febca2243
commit
4e77cddc92
2
bot.py
2
bot.py
@ -9,7 +9,7 @@ from modules.common.boot_notice import post_boot_notice
|
|||||||
|
|
||||||
# Version consists of:
|
# Version consists of:
|
||||||
# Major.Enhancement.Minor.Patch.Test (Test is alphanumeric; doesn’t trigger auto update)
|
# Major.Enhancement.Minor.Patch.Test (Test is alphanumeric; doesn’t trigger auto update)
|
||||||
VERSION = "0.3.9.2.a9"
|
VERSION = "0.3.9.2.a10"
|
||||||
|
|
||||||
# ---------- Env loading ----------
|
# ---------- Env loading ----------
|
||||||
|
|
||||||
|
@ -1,34 +1,119 @@
|
|||||||
# modules/common/settings.py
|
# modules/common/settings.py
|
||||||
import os
|
import os
|
||||||
|
from typing import Any, Dict, Iterable, Optional
|
||||||
|
|
||||||
|
|
||||||
|
def _clean(s: Optional[str]) -> str:
|
||||||
|
s = (s or "").strip()
|
||||||
|
# strip accidental quotes Portainer sometimes adds
|
||||||
|
if (s.startswith('"') and s.endswith('"')) or (s.startswith("'") and s.endswith("'")):
|
||||||
|
s = s[1:-1].strip()
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
def _collect_shai_env() -> Dict[str, str]:
|
||||||
|
"""
|
||||||
|
Build a {key_without_prefix_lower: cleaned_value} mapping
|
||||||
|
from all environment variables that start with SHAI_.
|
||||||
|
"""
|
||||||
|
out: Dict[str, str] = {}
|
||||||
|
for k, v in os.environ.items():
|
||||||
|
if not k.startswith("SHAI_"):
|
||||||
|
continue
|
||||||
|
key = k[5:].lower() # SHAI_MOD_CHANNEL_ID -> mod_channel_id
|
||||||
|
out[key] = _clean(v)
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
class ConfigView:
|
class ConfigView:
|
||||||
"""Unified read: ENV first, then optional bot.config['DEFAULT'], then fallback."""
|
"""
|
||||||
def __init__(self, bot):
|
Unified config view.
|
||||||
self._env = os.environ
|
- Primary: SHAI_* envs (prefix removed, lowercased keys)
|
||||||
self._default = {}
|
- Secondary: bot.config['DEFAULT'] (if present)
|
||||||
try:
|
- Helpers: get/int/bool/float/list
|
||||||
self._default = getattr(bot, "config", {}).get("DEFAULT", {}) or {}
|
- Can mirror values back into os.environ as SHAI_* (opt-in)
|
||||||
except Exception:
|
"""
|
||||||
pass
|
def __init__(self, bot=None, *, mirror_to_env: bool = False):
|
||||||
|
self._env_map = _collect_shai_env()
|
||||||
|
|
||||||
|
# Optional: also look into bot.config['DEFAULT'] as a fallback
|
||||||
|
self._default: Dict[str, Any] = {}
|
||||||
|
try:
|
||||||
|
self._default = (getattr(bot, "config", {}) or {}).get("DEFAULT", {}) or {}
|
||||||
|
except Exception:
|
||||||
|
self._default = {}
|
||||||
|
|
||||||
|
if mirror_to_env:
|
||||||
|
# Ensure os.environ has SHAI_* for everything we know (don’t clobber existing non-empty)
|
||||||
|
for k, v in self._env_map.items():
|
||||||
|
env_key = f"SHAI_{k.upper()}"
|
||||||
|
if not os.environ.get(env_key):
|
||||||
|
os.environ[env_key] = v
|
||||||
|
|
||||||
|
# ---- core accessors ----
|
||||||
def get(self, key: str, default: str = "") -> str:
|
def get(self, key: str, default: str = "") -> str:
|
||||||
v = self._env.get(key.upper(), "")
|
key = key.lower()
|
||||||
if not v:
|
if key in self._env_map:
|
||||||
|
v = _clean(self._env_map[key])
|
||||||
|
return v if v != "" else default
|
||||||
|
|
||||||
|
# Fallback to DEFAULT mapping (ConfigParser-like or our shim)
|
||||||
|
try:
|
||||||
v = self._default.get(key, "")
|
v = self._default.get(key, "")
|
||||||
v = (v or "").strip().strip('"').strip("'")
|
except Exception:
|
||||||
return v if v else default
|
v = ""
|
||||||
|
v = _clean(str(v))
|
||||||
|
return v if v != "" else default
|
||||||
|
|
||||||
def int(self, key: str, default: int = 0) -> int:
|
def int(self, key: str, default: int = 0) -> int:
|
||||||
|
s = self.get(key, "")
|
||||||
try:
|
try:
|
||||||
return int(self.get(key, ""))
|
return int(s)
|
||||||
|
except Exception:
|
||||||
|
return default
|
||||||
|
|
||||||
|
def float(self, key: str, default: float = 0.0) -> float:
|
||||||
|
s = self.get(key, "")
|
||||||
|
try:
|
||||||
|
return float(s)
|
||||||
except Exception:
|
except Exception:
|
||||||
return default
|
return default
|
||||||
|
|
||||||
def bool(self, key: str, default: bool = False) -> bool:
|
def bool(self, key: str, default: bool = False) -> bool:
|
||||||
v = self.get(key, "")
|
s = self.get(key, "")
|
||||||
if not v:
|
if s == "":
|
||||||
|
return default
|
||||||
|
s = s.lower()
|
||||||
|
if s in ("1", "true", "yes", "on", "y", "t"):
|
||||||
|
return True
|
||||||
|
if s in ("0", "false", "no", "off", "n", "f"):
|
||||||
|
return False
|
||||||
return default
|
return default
|
||||||
return v.lower() in ("1", "true", "yes", "on")
|
|
||||||
|
|
||||||
def cfg(bot) -> ConfigView:
|
def list(self, key: str, default: Optional[Iterable[str]] = None, sep: str = ",") -> Iterable[str]:
|
||||||
return ConfigView(bot)
|
s = self.get(key, "")
|
||||||
|
if s == "":
|
||||||
|
return list(default or [])
|
||||||
|
parts = [p.strip() for p in s.split(sep)]
|
||||||
|
return [p for p in parts if p]
|
||||||
|
|
||||||
|
# expose the resolved map if you ever want to dump it for debug
|
||||||
|
def to_dict(self) -> Dict[str, str]:
|
||||||
|
d = dict(self._env_map)
|
||||||
|
# Include defaults that aren’t already in env_map
|
||||||
|
for k in getattr(self._default, "keys", lambda: [])():
|
||||||
|
d.setdefault(k, _clean(str(self._default.get(k, ""))))
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
def cfg(bot=None, *, mirror_to_env: bool = False) -> ConfigView:
|
||||||
|
"""
|
||||||
|
Usage in cogs:
|
||||||
|
r = cfg(bot)
|
||||||
|
trigger_id = r.int('trigger_channel_id', 0)
|
||||||
|
prefix = r.get('vc_name_prefix', 'Room')
|
||||||
|
|
||||||
|
If you want to also ensure SHAI_* are present in os.environ at runtime:
|
||||||
|
r = cfg(bot, mirror_to_env=True)
|
||||||
|
"""
|
||||||
|
return ConfigView(bot, mirror_to_env=mirror_to_env)
|
||||||
|
Loading…
Reference in New Issue
Block a user