refactor: Move certificate config functions to file_ops.py

- Move load_certs_config, save_certs_config, add_cert_to_config,
  remove_cert_from_config from certificates.py to file_ops.py
- Add CERTS_FILE constant to config.py
- Add file locking for certificate config operations (was missing)
- Consistent pattern with servers.json handling

certificates.py: 543 → 503 lines
file_ops.py: 263 → 337 lines

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
kaffa
2026-02-02 04:26:55 +00:00
parent 79254835e9
commit 6ced2b42d4
3 changed files with 83 additions and 47 deletions

View File

@@ -9,6 +9,7 @@ from typing import Any, Optional
from .config import (
MAP_FILE,
SERVERS_FILE,
CERTS_FILE,
logger,
)
from .validation import domain_to_backend
@@ -260,3 +261,77 @@ def remove_domain_from_config(domain: str) -> None:
save_servers_config(config)
finally:
fcntl.flock(lock_file.fileno(), fcntl.LOCK_UN)
# Certificate configuration functions
def load_certs_config() -> list[str]:
"""Load certificate domain list from JSON file.
Returns:
List of domain names
"""
try:
with open(CERTS_FILE, "r", encoding="utf-8") as f:
try:
fcntl.flock(f.fileno(), fcntl.LOCK_SH)
except OSError:
pass
try:
data = json.load(f)
return data.get("domains", [])
finally:
try:
fcntl.flock(f.fileno(), fcntl.LOCK_UN)
except OSError:
pass
except FileNotFoundError:
return []
except json.JSONDecodeError as e:
logger.warning("Corrupt certificates config %s: %s", CERTS_FILE, e)
return []
def save_certs_config(domains: list[str]) -> None:
"""Save certificate domain list to JSON file atomically.
Args:
domains: List of domain names
"""
atomic_write_file(CERTS_FILE, json.dumps({"domains": sorted(domains)}, indent=2))
def add_cert_to_config(domain: str) -> None:
"""Add a domain to the certificate config.
Args:
domain: Domain name to add
"""
lock_path = f"{CERTS_FILE}.lock"
with open(lock_path, 'w') as lock_file:
fcntl.flock(lock_file.fileno(), fcntl.LOCK_EX)
try:
domains = load_certs_config()
if domain not in domains:
domains.append(domain)
save_certs_config(domains)
finally:
fcntl.flock(lock_file.fileno(), fcntl.LOCK_UN)
def remove_cert_from_config(domain: str) -> None:
"""Remove a domain from the certificate config.
Args:
domain: Domain name to remove
"""
lock_path = f"{CERTS_FILE}.lock"
with open(lock_path, 'w') as lock_file:
fcntl.flock(lock_file.fileno(), fcntl.LOCK_EX)
try:
domains = load_certs_config()
if domain in domains:
domains.remove(domain)
save_certs_config(domains)
finally:
fcntl.flock(lock_file.fileno(), fcntl.LOCK_UN)