diff options
Diffstat (limited to 'packages/meshbay-node/src/meshbay_node/ops.py')
| -rw-r--r-- | packages/meshbay-node/src/meshbay_node/ops.py | 47 |
1 files changed, 24 insertions, 23 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/ops.py b/packages/meshbay-node/src/meshbay_node/ops.py index c3a3f9c..13a7250 100644 --- a/packages/meshbay-node/src/meshbay_node/ops.py +++ b/packages/meshbay-node/src/meshbay_node/ops.py @@ -390,7 +390,7 @@ async def list_groups(state: dict) -> dict: async def attach_group(state: dict, name: str, shared_dir: str, - upload_dir: str = "") -> dict: + upload_dir: str = "", writable: bool = True) -> dict: """ Write a new [[groups]] block into node.toml. @@ -448,7 +448,7 @@ async def attach_group(state: dict, name: str, shared_dir: str, # Forward slashes: a Windows path in a TOML basic string is a # parse error (`\U`, `\a`, ... are escapes). pathlib reads `/`. f' path = "{path.as_posix()}"\n' - f' writable = true\n') + f' writable = {"true" if writable else "false"}\n') try: with conf_path.open("a", encoding="utf-8", newline="\n") as f: f.write(block) @@ -457,6 +457,7 @@ async def attach_group(state: dict, name: str, shared_dir: str, result = {"group_id": group["id"], "name": group["name"], "shared_dir": str(path), "config": str(conf_path), + "writable": writable, "note": "restart the node to pick it up"} return result @@ -629,7 +630,7 @@ def _remove_roots_block(conf_path: Path, group_id: str, conf_path.write_text("\n".join(new_lines), encoding="utf-8", newline="\n") return - raise OpError(f"Root path not found in config", status=404) + raise OpError("Root path not found in config", status=404) async def add_root(state: dict, group_id: str, path: str, *, @@ -670,9 +671,9 @@ async def add_root(state: dict, group_id: str, path: str, *, if kind != "generic": root_block += f'\n kind = "{added.kind}"' if writable: - root_block += f'\n writable = true' + root_block += '\n writable = true' if removable: - root_block += f'\n removable = true' + root_block += '\n removable = true' _insert_roots_block(conf_path, group_id, root_block) from meshbay_node.config import RootSpec @@ -822,18 +823,17 @@ async def eject_root(state: dict, group_id: str, root_name: str) -> dict: return {"status": "already_ejected", "name": root_name, "group_id": group_id, "roots": roots.describe()} - root.ejected = True - root.available = False - - roster = _roster(state) - if roster: - await roster.set_setting( - group_id, f"root_ejected:{fold(root_name)}", "1", - set_by=state.get("node_user_id", "")) - + # The indexer stops its watchdog and freezes the entries; it holds the same + # RootSet object, but the flags are set here too so a context whose indexer + # was replaced by a retarget cannot be left disagreeing with the roster. indexer = state.get("indexers", {}).get(group_id) if indexer: indexer.eject_root(root_name) + root.ejected = True + root.available = False + + await _roster(state).set_root_ejected( + group_id, root_name, True, set_by=state.get("node_user_id", "")) log.info("Root ejected: %s from group %s", root_name, group_id[:8]) return {"status": "ejected", "name": root_name, "group_id": group_id, @@ -869,18 +869,17 @@ async def plug_root(state: dict, group_id: str, root_name: str) -> dict: f"Directory not found: {root.path}. Is the device connected?", status=409) - root.ejected = False - root.available = True - - roster = _roster(state) - if roster: - await roster.set_setting( - group_id, f"root_ejected:{fold(root_name)}", "0", - set_by=state.get("node_user_id", "")) + # Persisted before the rescan, which can take minutes on a large library: + # a crash halfway through must leave the root plugged, not ejected with + # entries half rebuilt. + await _roster(state).set_root_ejected( + group_id, root_name, False, set_by=state.get("node_user_id", "")) indexer = state.get("indexers", {}).get(group_id) if indexer: await indexer.plug_root(root_name) + root.ejected = False + root.available = root.is_live() log.info("Root plugged: %s in group %s", root_name, group_id[:8]) return {"status": "plugged", "name": root_name, "group_id": group_id, @@ -947,7 +946,7 @@ def _update_root_field(conf_path: Path, group_id: str, conf_path.write_text("\n".join(lines), encoding="utf-8", newline="\n") return - raise OpError(f"Root path not found in config", status=404) + raise OpError("Root path not found in config", status=404) # ── Files ──────────────────────────────────────────────────────────────────── @@ -1125,6 +1124,8 @@ async def set_enabled_apps(state: dict, group_id: str, apps: list[str]) -> dict: """ roster = _roster(state) ctx = _group_ctx(state, group_id) + # See the same guard in webrtc_server._do_apps_enabled: Files cannot be + # turned off, and both writers put it at the front so the two agree. if "files" not in apps: apps = ["files"] + list(apps) await roster.set_enabled_apps(group_id, apps, |