diff options
Diffstat (limited to 'packages/meshbay-node/src/meshbay_node/roots.py')
| -rw-r--r-- | packages/meshbay-node/src/meshbay_node/roots.py | 62 |
1 files changed, 31 insertions, 31 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/roots.py b/packages/meshbay-node/src/meshbay_node/roots.py index 74ea2f6..a83b729 100644 --- a/packages/meshbay-node/src/meshbay_node/roots.py +++ b/packages/meshbay-node/src/meshbay_node/roots.py @@ -120,10 +120,10 @@ class Root: name: str path: Path kind: str = "generic" - upload: bool = False + writable: bool = False + removable: bool = False direct: bool = False - # Runtime, not configuration: set by the indexer when the directory can no - # longer be read, and cleared when it comes back. + ejected: bool = False available: bool = True @property @@ -172,8 +172,9 @@ class RootSet: """ Build from configuration, refusing anything ambiguous. - `specs` are dicts with `path`, and optionally `name`, `kind`, `upload`. - Raises RootError with a message meant for an operator reading a log. + `specs` are dicts with `path`, and optionally `name`, `kind`, `writable`, + `removable`. Raises RootError with a message meant for an operator reading + a log. """ roots: list[Root] = [] by_folded: dict[str, Root] = {} @@ -209,34 +210,18 @@ class RootSet: log.warning("root %r: unknown kind %r — using 'generic'", name, kind) kind = "generic" + # Backward compat: old configs use `upload` instead of `writable` + writable = bool(spec.get("writable", spec.get("upload", False))) root = Root(name=name, path=path, kind=kind, - upload=bool(spec.get("upload", False)), + writable=writable, + removable=bool(spec.get("removable", False)), direct=bool(spec.get("direct", False))) _refuse_nesting(root, roots) roots.append(root) by_folded[root.folded] = root - cls._settle_upload_root(roots) return cls(roots=roots) - @staticmethod - def _settle_upload_root(roots: list[Root]) -> None: - """ - Exactly one root receives uploads, and the operator picks it. - - Not guessed when several are marked, because "uploads went somewhere - else" is discovered weeks later. With none marked and a single root, the - answer is not ambiguous, so it is taken. - """ - marked = [r for r in roots if r.upload] - if len(marked) > 1: - names = ", ".join(r.name for r in marked) - raise RootError( - f"several roots are marked upload = true ({names}) — exactly one " - f"receives uploads") - if not marked and len(roots) == 1: - roots[0].upload = True - # ── Lookup ─────────────────────────────────────────────────────────────── def by_name(self, name: str) -> Root | None: @@ -247,11 +232,8 @@ class RootSet: return None @property - def upload_root(self) -> Root | None: - for root in self.roots: - if root.upload: - return root - return None + def writable_roots(self) -> list[Root]: + return [r for r in self.roots if r.writable] @property def names(self) -> list[str]: @@ -336,10 +318,23 @@ class RootSet: Called periodically and after a filesystem event that looks like a disappearance. A change here never edits the index: a root going away freezes its entries, and a root coming back triggers a rescan. + + An ejected root stays unavailable regardless of `is_live()` — the + operator must explicitly plug it back. A removable root whose path + disappears without an eject is auto-ejected as a safety net. """ changed: list[tuple[Root, bool]] = [] for root in self.roots: + if root.ejected: + if root.available: + root.available = False + changed.append((root, False)) + continue live = root.is_live() + if not live and root.removable and not root.ejected: + root.ejected = True + log.warning("Root %r auto-ejected (device disappeared): %s", + root.name, root.path) if live != root.available: root.available = live changed.append((root, live)) @@ -352,7 +347,12 @@ class RootSet: out = [] for r in self.roots: d: dict = {"name": r.name, "kind": r.kind, - "available": r.available, "upload": r.upload} + "available": r.available, + "writable": r.writable, + "removable": r.removable, + "ejected": r.ejected, + # Backward compat for MNP 1.0 clients + "upload": r.writable} if r.direct: d["direct"] = True out.append(d) |