From 753653b4df62723b82d32799825135822886eac7 Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Thu, 3 Sep 2026 16:20:23 +0200 Subject: refactor(node): platform abstraction for Windows portability (W1-W2-W5-W6-W7) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Platform directories, signal handling, chmod guards, ffmpeg discovery, and platform-conditional CLI messages — all testable on Linux. See docs/WINDOWS-PORT.md §5 for the plan these implement. Co-Authored-By: Claude Opus 4.6 --- packages/meshbay-node/src/meshbay_node/platform.py | 70 ++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 packages/meshbay-node/src/meshbay_node/platform.py (limited to 'packages/meshbay-node/src/meshbay_node/platform.py') diff --git a/packages/meshbay-node/src/meshbay_node/platform.py b/packages/meshbay-node/src/meshbay_node/platform.py new file mode 100644 index 0000000..bc48169 --- /dev/null +++ b/packages/meshbay-node/src/meshbay_node/platform.py @@ -0,0 +1,70 @@ +"""Platform-specific paths and tool resolution for meshbay-node.""" + +import os +import shutil +import sys +from pathlib import Path + +# ── Directories ────────────────────────────────────────────────────────────── + + +def config_dir() -> Path: + if sys.platform == "win32": + return Path(os.environ.get("LOCALAPPDATA") or Path.home()) / "meshbay" + return Path.home() / ".config" / "meshbay" + + +def data_dir() -> Path: + if sys.platform == "win32": + return Path(os.environ.get("LOCALAPPDATA") or Path.home()) / "meshbay" / "data" + return Path.home() / ".local" / "share" / "meshbay" + + +def state_dir() -> Path: + if sys.platform == "win32": + return Path(os.environ.get("LOCALAPPDATA") or Path.home()) / "meshbay" / "state" + return Path.home() / ".local" / "state" / "meshbay" + + +# ── File permissions ───────────────────────────────────────────────────────── + + +def chmod_private(path: Path, *, mode: int = 0o600) -> None: + """Set restrictive permissions on a file. No-op on Windows (NTFS ignores mode bits).""" + if sys.platform != "win32": + path.chmod(mode) + + +# ── Media tools ────────────────────────────────────────────────────────────── + +_ffmpeg_path: str = "ffmpeg" +_ffprobe_path: str = "ffprobe" + + +def check_media_tools( + ffmpeg: str = "ffmpeg", ffprobe: str = "ffprobe", +) -> None: + """Resolve ffmpeg/ffprobe at daemon startup. Raises RuntimeError if not found.""" + global _ffmpeg_path, _ffprobe_path + resolved = shutil.which(ffmpeg) + if not resolved: + raise RuntimeError( + f"{ffmpeg!r} not found in PATH. " + "Install ffmpeg or set [node] ffmpeg_path in node.toml." + ) + _ffmpeg_path = resolved + resolved = shutil.which(ffprobe) + if not resolved: + raise RuntimeError( + f"{ffprobe!r} not found in PATH. " + "Install ffmpeg or set [node] ffprobe_path in node.toml." + ) + _ffprobe_path = resolved + + +def ffmpeg_cmd() -> str: + return _ffmpeg_path + + +def ffprobe_cmd() -> str: + return _ffprobe_path -- cgit v1.2.3