Compare commits

..

1 Commits

Author SHA1 Message Date
Evan
3f2a49096b persist node ids in .cache
brings back EXO_CACHE_HOME as always ~/.cache/exo/, and store the node
id in there. no random copies now!
2026-02-25 18:01:39 +00:00
5 changed files with 37 additions and 8 deletions

View File

@@ -27,6 +27,7 @@ dependencies = [
"tomlkit>=0.14.0", "tomlkit>=0.14.0",
"pillow>=11.0,<12.0", # compatibility with mflux "pillow>=11.0,<12.0", # compatibility with mflux
"mflux==0.15.5", "mflux==0.15.5",
"python-multipart>=0.0.21",
"msgspec>=0.19.0", "msgspec>=0.19.0",
"zstandard>=0.23.0", "zstandard>=0.23.0",
] ]

View File

@@ -234,8 +234,6 @@ def get_node_id_keypair(
Obtains the :class:`Keypair` associated with this node-ID. Obtains the :class:`Keypair` associated with this node-ID.
Obtain the :class:`PeerId` by from it. Obtain the :class:`PeerId` by from it.
""" """
# TODO(evan): bring back node id persistence once we figure out how to deal with duplicates
return Keypair.generate()
def lock_path(path: str | bytes | PathLike[str] | PathLike[bytes]) -> Path: def lock_path(path: str | bytes | PathLike[str] | PathLike[bytes]) -> Path:
return Path(str(path) + ".lock") return Path(str(path) + ".lock")
@@ -255,6 +253,6 @@ def get_node_id_keypair(
# if no valid credentials, create new ones and persist # if no valid credentials, create new ones and persist
with open(path, "w+b") as f: with open(path, "w+b") as f:
keypair = Keypair.generate_ed25519() keypair = Keypair.generate()
f.write(keypair.to_bytes()) f.write(keypair.to_bytes())
return keypair return keypair

View File

@@ -8,12 +8,12 @@ _EXO_HOME_ENV = os.environ.get("EXO_HOME", None)
def _get_xdg_dir(env_var: str, fallback: str) -> Path: def _get_xdg_dir(env_var: str, fallback: str) -> Path:
"""Get XDG directory, prioritising EXO_HOME environment variable if its set. On non-Linux platforms, default to ~/.exo.""" """Get XDG directory, prioritising EXO_HOME environment variable if its set. On non-Linux platforms, default to ~/.exo. Cache home always prefers .cache/exo"""
if _EXO_HOME_ENV is not None: if _EXO_HOME_ENV is not None:
return Path.home() / _EXO_HOME_ENV return Path.home() / _EXO_HOME_ENV
if sys.platform != "linux": if sys.platform != "linux" and env_var != "XDG_CACHE_HOME":
return Path.home() / ".exo" return Path.home() / ".exo"
xdg_value = os.environ.get(env_var, None) xdg_value = os.environ.get(env_var, None)
@@ -54,10 +54,9 @@ DASHBOARD_DIR = (
# Log files (data/logs or cache) # Log files (data/logs or cache)
EXO_LOG_DIR = EXO_CACHE_HOME / "exo_log" EXO_LOG_DIR = EXO_CACHE_HOME / "exo_log"
EXO_LOG = EXO_LOG_DIR / "exo.log" EXO_LOG = EXO_LOG_DIR / "exo.log"
EXO_TEST_LOG = EXO_CACHE_HOME / "exo_test.log"
# Identity (config) # Identity (config)
EXO_NODE_ID_KEYPAIR = EXO_CONFIG_HOME / "node_id.keypair" EXO_NODE_ID_KEYPAIR = EXO_CACHE_HOME / "node_id.keypair"
EXO_CONFIG_FILE = EXO_CONFIG_HOME / "config.toml" EXO_CONFIG_FILE = EXO_CONFIG_HOME / "config.toml"
# libp2p topics for event forwarding # libp2p topics for event forwarding

View File

@@ -94,7 +94,27 @@ def test_macos_uses_traditional_paths():
home = Path.home() home = Path.home()
assert home / ".exo" == constants.EXO_CONFIG_HOME assert home / ".exo" == constants.EXO_CONFIG_HOME
assert home / ".exo" == constants.EXO_DATA_HOME assert home / ".exo" == constants.EXO_DATA_HOME
assert home / ".exo" == constants.EXO_CACHE_HOME assert home / ".cache" / "exo" == constants.EXO_CACHE_HOME
def test_exo_home_env():
"""Test that macOS uses traditional ~/.exo directory."""
# Remove EXO_HOME to ensure we test the default behavior
env = {k: v for k, v in os.environ.items() if k != "EXO_HOME"}
env["EXO_HOME"] = "/exo"
with (
mock.patch.dict(os.environ, env, clear=True),
mock.patch.object(sys, "platform", "darwin"),
):
import importlib
import exo.shared.constants as constants
importlib.reload(constants)
assert Path("/exo") == constants.EXO_CONFIG_HOME
assert Path("/exo") == constants.EXO_DATA_HOME
assert Path("/exo") == constants.EXO_CACHE_HOME
def test_node_id_in_config_dir(): def test_node_id_in_config_dir():

11
uv.lock generated
View File

@@ -385,6 +385,7 @@ dependencies = [
{ name = "pillow", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" }, { name = "pillow", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
{ name = "psutil", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" }, { name = "psutil", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
{ name = "pydantic", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" }, { name = "pydantic", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
{ name = "python-multipart", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
{ name = "rustworkx", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" }, { name = "rustworkx", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
{ name = "tiktoken", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" }, { name = "tiktoken", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
{ name = "tomlkit", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" }, { name = "tomlkit", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
@@ -423,6 +424,7 @@ requires-dist = [
{ name = "pillow", specifier = ">=11.0,<12.0" }, { name = "pillow", specifier = ">=11.0,<12.0" },
{ name = "psutil", specifier = ">=7.0.0" }, { name = "psutil", specifier = ">=7.0.0" },
{ name = "pydantic", specifier = ">=2.11.7" }, { name = "pydantic", specifier = ">=2.11.7" },
{ name = "python-multipart", specifier = ">=0.0.21" },
{ name = "rustworkx", specifier = ">=0.17.1" }, { name = "rustworkx", specifier = ">=0.17.1" },
{ name = "tiktoken", specifier = ">=0.12.0" }, { name = "tiktoken", specifier = ">=0.12.0" },
{ name = "tomlkit", specifier = ">=0.14.0" }, { name = "tomlkit", specifier = ">=0.14.0" },
@@ -1882,6 +1884,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" },
] ]
[[package]]
name = "python-multipart"
version = "0.0.21"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/78/96/804520d0850c7db98e5ccb70282e29208723f0964e88ffd9d0da2f52ea09/python_multipart-0.0.21.tar.gz", hash = "sha256:7137ebd4d3bbf70ea1622998f902b97a29434a9e8dc40eb203bbcf7c2a2cba92", size = 37196, upload-time = "2025-12-17T09:24:22.446Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/aa/76/03af049af4dcee5d27442f71b6924f01f3efb5d2bd34f23fcd563f2cc5f5/python_multipart-0.0.21-py3-none-any.whl", hash = "sha256:cf7a6713e01c87aa35387f4774e812c4361150938d20d232800f75ffcf266090", size = 24541, upload-time = "2025-12-17T09:24:21.153Z" },
]
[[package]] [[package]]
name = "pyyaml" name = "pyyaml"
version = "6.0.3" version = "6.0.3"