diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-09-08 14:53:03 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-09-08 14:53:03 +0200 |
| commit | 4b94468d24913c3071b48eeefb43367f4f5cd523 (patch) | |
| tree | a0072ff4b986e6aa9c6dd14d6f54d0da51e3d72f /packages/meshbay-common | |
| parent | bdeffa448cdde9680fbf7bdda036746b101ddf75 (diff) | |
| download | meshbay-4b94468d24913c3071b48eeefb43367f4f5cd523.tar.gz | |
feat(node): make the transfer caps settable, node-wide and per group
Step 3 of ~/next/improve-downloads.md. Step 2 built the pools with constants;
this gives them to the operator, in the two scopes they belong to.
**The pools are the machine's.** `[node] max_concurrent_downloads` and
`max_concurrent_uploads`, default 8, on the §2.11 pattern: node.toml for a
fresh install, a roster.db override for immediate effect, editable from the
Node page and from `meshbay-node transfers show|set`, applied live through the
one `set_capacity` step 1 fixed.
**The per-member cap is a group's.** How many transfers one member may run at
once here — on the node like every other group setting (not the hub, which
would have authority over someone else's disk; not node.toml, which is
hand-written and needs a restart), changed by a signed operator instruction
(`OP_TRANSFER_LIMITS`, subject "d=2,u=2" so what is signed names the outcome),
broadcast to the group, and read live by the pools.
That was the one thing step 2's shape could not express: `per_member` was a
single node-wide number. `group_limits` and `member_cap(kind, member)` make it
a lookup — the group's own value if it has one, the node's default otherwise —
and it is deliberately the only dimension that is not node-wide.
Three refusals, each with a test:
- **absent means the default (2), never "unlimited".** A group that predates
the setting coming back unlimited would leave the node-wide pool as the only
control, which is the situation slots exist to end;
- **zero is not "unlimited"**, and is not "this member may not transfer"
either: the floor is one everywhere, and the CLI says to revoke the member
instead;
- **an unreadable row reads as unset**, not as zero — the same discipline the
sealed messages follow, where a payload that does not open must never become
a default state on its own.
`handshake_ack` carries this member's own caps for this group, so the interface
can say "2 of your 2 slots are busy" instead of drawing a bare spinner. Absent
reads as "no limit known" and the hint is not drawn — never as "unlimited",
which would have the interface contradicting the node.
1164 node, 793 hub, 0 failed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HCGdheDLxGReuKHga3BtST
Diffstat (limited to 'packages/meshbay-common')
| -rw-r--r-- | packages/meshbay-common/src/meshbay_common/adminop.py | 6 | ||||
| -rw-r--r-- | packages/meshbay-common/src/meshbay_common/protocol.py | 2 |
2 files changed, 8 insertions, 0 deletions
diff --git a/packages/meshbay-common/src/meshbay_common/adminop.py b/packages/meshbay-common/src/meshbay_common/adminop.py index ed6e940..5c7345b 100644 --- a/packages/meshbay-common/src/meshbay_common/adminop.py +++ b/packages/meshbay-common/src/meshbay_common/adminop.py @@ -61,6 +61,12 @@ OP_APPS_ENABLED = "apps_enabled" # security property in itself, but the pattern (every operator setting is # signed) is what keeps the authorization model simple to reason about. OP_SET_SCAN_SETTINGS = "set_scan_settings" +# How many transfers one member may run at once in this group. Signed like the +# rest: an unsigned cap is one any member can raise for themselves, which makes +# the control a suggestion. The subject is "d=2,u=2" so what the operator is +# shown before signing names the outcome and not the operation -- the same rule +# member_upload's on/off subject follows. +OP_TRANSFER_LIMITS = "transfer_limits" # Whether the node uses the operator's own API token/language instead of the # shipped default — node-wide (docs/mediacenter.md §5.5), one credential # shared by every group. Signed like the rest: it turns on outbound diff --git a/packages/meshbay-common/src/meshbay_common/protocol.py b/packages/meshbay-common/src/meshbay_common/protocol.py index 4890d3b..8a521bb 100644 --- a/packages/meshbay-common/src/meshbay_common/protocol.py +++ b/packages/meshbay-common/src/meshbay_common/protocol.py @@ -152,6 +152,8 @@ class MNP: MEMBER_UPLOAD_ACK = "member_upload_ack" APPS_ENABLED = "apps_enabled" # operator → node: which group apps to show APPS_ENABLED_ACK = "apps_enabled_ack" + TRANSFER_LIMITS = "transfer_limits" # operator → node: per-member caps for this group + TRANSFER_LIMITS_ACK = "transfer_limits_ack" # node → this group: the new caps SET_SCAN_SETTINGS = "set_scan_settings" # operator → node: reconcile/debounce timing SET_SCAN_SETTINGS_ACK = "set_scan_settings_ack" MEDIA_META_REQ = "media_meta_req" # client → node: TMDB metadata for a path |