This commit is contained in:
2026-01-31 15:37:17 -08:00
parent ae7acd48ac
commit c854f8c6a8
5 changed files with 151 additions and 7 deletions

View File

@@ -725,6 +725,92 @@ def save(config: Dict[str, Any]) -> int:
return save_config(config)
def save_config_and_verify(config: Dict[str, Any], retries: int = 3, delay: float = 0.15) -> int:
"""Save configuration and verify crucial keys persisted to disk.
This helper performs a best-effort verification loop that reloads the
configuration from disk and confirms that modified API key entries (e.g.
AllDebrid) were written successfully. If verification fails after the
configured number of retries, a RuntimeError is raised.
"""
# Detect an API key that should be verified (provider or store-backed)
expected_key = None
try:
providers = config.get("provider", {}) if isinstance(config, dict) else {}
if isinstance(providers, dict):
entry = providers.get("alldebrid")
if entry is not None:
# _extract_api_key is a small internal helper; reuse the implementation here
if isinstance(entry, dict):
for k in ("api_key", "API_KEY", "apikey", "APIKEY"):
v = entry.get(k)
if isinstance(v, str) and v.strip():
expected_key = v.strip()
break
elif isinstance(entry, str) and entry.strip():
expected_key = entry.strip()
if not expected_key:
store_block = config.get("store", {}) if isinstance(config, dict) else {}
debrid = store_block.get("debrid") if isinstance(store_block, dict) else None
if isinstance(debrid, dict):
srv = debrid.get("all-debrid")
if isinstance(srv, dict):
for k in ("api_key", "API_KEY", "apikey", "APIKEY"):
v = srv.get(k)
if isinstance(v, str) and v.strip():
expected_key = v.strip()
break
elif isinstance(srv, str) and srv.strip():
expected_key = srv.strip()
except Exception:
expected_key = None
last_exc: Exception | None = None
for attempt in range(1, max(1, int(retries)) + 1):
try:
saved = save_config(config)
if not expected_key:
# Nothing special to verify; return success.
return saved
# Reload directly from disk and compare the canonical debrid/provider keys
clear_config_cache()
reloaded = load_config()
# Provider-level key
prov_block = reloaded.get("provider", {}) if isinstance(reloaded, dict) else {}
prov_key = None
if isinstance(prov_block, dict):
aentry = prov_block.get("alldebrid")
if isinstance(aentry, dict):
for k in ("api_key", "API_KEY", "apikey", "APIKEY"):
v = aentry.get(k)
if isinstance(v, str) and v.strip():
prov_key = v.strip()
break
elif isinstance(aentry, str) and aentry.strip():
prov_key = aentry.strip()
# Store-level key
try:
store_key = get_debrid_api_key(reloaded, service="All-debrid")
except Exception:
store_key = None
if prov_key == expected_key or store_key == expected_key:
return saved
# Not yet persisted; log and retry
log(f"Warning: Post-save verification attempt {attempt} failed (expected key not found in DB). Retrying...")
time.sleep(delay * attempt)
except Exception as exc:
last_exc = exc
log(f"Warning: save and verify attempt {attempt} failed: {exc}")
time.sleep(delay * attempt)
# All retries exhausted
raise RuntimeError(f"Post-save verification failed after {retries} attempts: {last_exc}")
def count_changed_entries(config: Dict[str, Any]) -> int:
"""Return the number of changed configuration entries compared to the last saved snapshot.