81 lines
2.6 KiB
Python
81 lines
2.6 KiB
Python
"""Persistent node configuration — stored in ~/.config/meshnet/config.json."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
import stat
|
|
from pathlib import Path
|
|
|
|
_DEFAULT_CONFIG_DIR = Path.home() / ".config" / "meshnet"
|
|
_DEFAULT_CONFIG_FILE = _DEFAULT_CONFIG_DIR / "config.json"
|
|
# MESHNET_DOWNLOAD_DIR overrides the model store for every node on this
|
|
# machine (all CLI flows fall back to this default; --download-dir still wins).
|
|
_DEFAULT_DOWNLOAD_DIR = Path(
|
|
os.environ.get("MESHNET_DOWNLOAD_DIR", str(Path.home() / ".meshnet" / "models"))
|
|
)
|
|
_DEFAULT_TRACKER_URL = os.environ.get("MESHNET_TRACKER_URL", "http://localhost:8080")
|
|
_DEFAULT_WALLET_PATH = str(Path.home() / ".config" / "meshnet" / "wallet.json")
|
|
_DEFAULT_QUANTIZATION = "auto"
|
|
_DEFAULT_MODEL = os.environ.get("MESHNET_MODEL_ID") or os.environ.get("MESHNET_MODEL", "")
|
|
_DEFAULT_MODEL_HF_REPO = _DEFAULT_MODEL if "/" in _DEFAULT_MODEL else ""
|
|
_DEFAULT_MODEL_NAME = _DEFAULT_MODEL.split("/")[-1] if "/" in _DEFAULT_MODEL else _DEFAULT_MODEL
|
|
|
|
DEFAULTS = {
|
|
"model_hf_repo": _DEFAULT_MODEL_HF_REPO,
|
|
"model_name": _DEFAULT_MODEL_NAME,
|
|
"quantization": _DEFAULT_QUANTIZATION,
|
|
"download_dir": str(_DEFAULT_DOWNLOAD_DIR),
|
|
"tracker_url": _DEFAULT_TRACKER_URL,
|
|
"wallet_path": _DEFAULT_WALLET_PATH,
|
|
"shard_start": None,
|
|
"shard_end": None,
|
|
"port": 7000,
|
|
"host": "0.0.0.0",
|
|
"debug": False,
|
|
}
|
|
|
|
|
|
def config_path(override: Path | None = None) -> Path:
|
|
return override or _DEFAULT_CONFIG_FILE
|
|
|
|
|
|
def load_config(path: Path | None = None) -> dict | None:
|
|
"""Return parsed config dict, or None if no config file exists."""
|
|
p = config_path(path)
|
|
if not p.exists():
|
|
return None
|
|
try:
|
|
cfg = json.loads(p.read_text())
|
|
if not isinstance(cfg, dict):
|
|
return None
|
|
return cfg
|
|
except (json.JSONDecodeError, OSError):
|
|
return None
|
|
|
|
|
|
def save_config(cfg: dict, path: Path | None = None) -> None:
|
|
"""Write config to disk with restricted permissions (0o600)."""
|
|
p = config_path(path)
|
|
p.parent.mkdir(parents=True, exist_ok=True)
|
|
p.write_text(json.dumps(cfg, indent=2))
|
|
try:
|
|
os.chmod(p, stat.S_IRUSR | stat.S_IWUSR)
|
|
except OSError:
|
|
pass # Windows / some filesystems don't support chmod
|
|
|
|
|
|
def delete_config(path: Path | None = None) -> None:
|
|
p = config_path(path)
|
|
if p.exists():
|
|
p.unlink()
|
|
|
|
|
|
def merge_cli_overrides(cfg: dict, **cli_kwargs) -> dict:
|
|
"""Return a copy of cfg with any non-None CLI values applied on top."""
|
|
result = dict(cfg)
|
|
for key, val in cli_kwargs.items():
|
|
if val is not None:
|
|
result[key] = val
|
|
return result
|