f
This commit is contained in:
@@ -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.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user