summaryrefslogtreecommitdiffstats
path: root/packages/meshbay-node/src/meshbay_node
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-node/src/meshbay_node')
-rw-r--r--packages/meshbay-node/src/meshbay_node/daemon.py58
-rw-r--r--packages/meshbay-node/src/meshbay_node/ui/app.py10
2 files changed, 62 insertions, 6 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/daemon.py b/packages/meshbay-node/src/meshbay_node/daemon.py
index f7c1b33..e1cab61 100644
--- a/packages/meshbay-node/src/meshbay_node/daemon.py
+++ b/packages/meshbay-node/src/meshbay_node/daemon.py
@@ -1826,8 +1826,9 @@ def main() -> None:
"| chat status|rotate|encrypt-history|prune "
"| denylist show|clear "
"| stun list|add|remove|reset "
- "| transfers show|set: live transfer slots, and "
- "the node-wide download/upload caps "
+ "| transfers show|set|per-member: live transfer "
+ "slots, the node-wide caps, and how many one "
+ "member may run at once in a group "
"| reload: re-read node.toml (hot; systemd or the "
"loopback API) | restart-daemon: restart the node "
"(systemd unit, the Windows autostart launcher, or the "
@@ -1845,7 +1846,7 @@ def main() -> None:
"init|rotate for gek; "
"list|rm for file; rematch for video; show|clear for "
"denylist; list|add|remove|reset for stun; "
- "show|set for transfers; "
+ "show|set|per-member for transfers; "
"install|remove|start|stop|status for autostart and "
"for service")
parser.add_argument("target", nargs="?",
@@ -2586,8 +2587,20 @@ def main() -> None:
out = _daemon_api(cfg, "/api/transfers")
for kind, pool in out.get("pools", {}).items():
print(f" {kind:<9} {pool['in_use']}/{pool['cap']} in use, "
- f"{pool['queued']} queued, "
- f"{pool['per_member']} per member")
+ f"{pool['queued']} queued (node-wide)")
+ # Per group, because that is the cap that decides how many one
+ # person runs at once — and it is not the node-wide number. An
+ # operator raising `transfers set 8 8` and still seeing two at a
+ # time is looking at this line, which used to print the node's
+ # default and say nothing about where it came from.
+ groups = out.get("groups") or []
+ if groups:
+ print("\n per member, per group "
+ "(meshbay-node transfers per-member <dl> <ul> --group X):")
+ for g in groups:
+ how = "set" if g["set"] else "default"
+ print(f" {g['name']:<20} {g['download']} download(s), "
+ f"{g['upload']} upload(s) [{how}]")
leases = out.get("leases", [])
if not leases:
print("\n nothing transferring")
@@ -2624,7 +2637,40 @@ def main() -> None:
f"(applied now, and kept in node.toml)")
return
- print("usage: meshbay-node transfers show|set <downloads> <uploads>")
+ if sub == "per-member":
+ # How many transfers ONE member may run at once in this group. Not
+ # the same knob as `set`, which is the machine's total — and the
+ # reason "I set 8 8 and still only get two" is the commonest
+ # confusion here: per-member is checked first, by design.
+ values = [v for v in (args.target, args.value) if v]
+ if len(values) != 2:
+ print("usage: meshbay-node transfers per-member <downloads> "
+ "<uploads> [--group NAME]")
+ sys.exit(1)
+ try:
+ downloads, uploads = int(values[0]), int(values[1])
+ except ValueError:
+ print("error: both values must be whole numbers")
+ sys.exit(1)
+ if downloads < 1 or uploads < 1:
+ print("error: a cap below 1 is not 'unlimited'; it would stop "
+ "every transfer for that member. Revoke them instead.")
+ sys.exit(1)
+ group_id = _resolve_group(cfg, args.group)
+ out = _daemon_api(cfg, f"/api/groups/{group_id}/transfer-limits",
+ method="PUT",
+ body={"downloads": downloads, "uploads": uploads})
+ got = out.get("limits", {})
+ started = out.get("started") or []
+ print(f"each member of this group may now run "
+ f"{got.get('download')} download(s) and "
+ f"{got.get('upload')} upload(s) at once")
+ if started:
+ print(f"{len(started)} waiting transfer(s) started at once")
+ return
+
+ print("usage: meshbay-node transfers show|set <downloads> <uploads>|"
+ "per-member <downloads> <uploads> [--group NAME]")
sys.exit(1)
if args.command == "file":
diff --git a/packages/meshbay-node/src/meshbay_node/ui/app.py b/packages/meshbay-node/src/meshbay_node/ui/app.py
index 9b9307d..4ad3787 100644
--- a/packages/meshbay-node/src/meshbay_node/ui/app.py
+++ b/packages/meshbay-node/src/meshbay_node/ui/app.py
@@ -515,4 +515,14 @@ def create_ui_app(state: dict) -> FastAPI:
async def get_transfers():
return await _op(lambda: ops.list_transfers(state))
+ @app.put("/api/groups/{group_id}/transfer-limits")
+ async def set_transfer_limits(group_id: str, payload: dict):
+ # The same `ops.set_transfer_limits` the signed MNP handler calls. The
+ # op existed with only that one door, and nothing anywhere opened it —
+ # so the per-member cap sat at its default of 2 with no way to change
+ # it, which from outside is indistinguishable from a hardcoded 2.
+ return await _op(lambda: ops.set_transfer_limits(
+ state, group_id,
+ int(payload.get("downloads", 0)), int(payload.get("uploads", 0))))
+
return app