summaryrefslogtreecommitdiffstats
path: root/packages/meshbay-node/src/meshbay_node/transport
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-19 14:01:38 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-19 14:01:38 +0200
commitd2495a2c4b89fbbfc18cefec83ae96cabdd745e2 (patch)
tree463e4d11b1c742475aac07155818c9c64a1e43e5 /packages/meshbay-node/src/meshbay_node/transport
parentf8223293a211a87c92b1fed80f5ca53660f6b26c (diff)
parent933daccbcfde7705413d3a10db87d910c650ed42 (diff)
downloadmeshbay-d2495a2c4b89fbbfc18cefec83ae96cabdd745e2.tar.gz
Merge origin/main: the operator's upload ceiling beside the disk-thread work
One conflict, in §15.3's open list, and it was two changes agreeing rather than disagreeing: this side removed the rows for the third-party search bound and the node-announcement bound because both are now built (AV27, AV28), while the other side kept them and added a new one. Resolved by keeping what is genuinely still open — per-device revocation having no CLI — and leaving the two closed. `webrtc_server.py` merged without conflict but the two sides met inside one function: `_upload_chunk` gained the operator's `max_upload_gb` ceiling from there and the per-group lock and `off_disk` calls from here. Read back rather than trusted: the operator's ceiling now sits inside the critical section that keeps chunk ordering, and the unlink beside it goes to the disk thread with everything else. 2893 passed. The twelve `test_sticky_header.py[firefox]` setup errors are the open Firefox on this machine, as before.
Diffstat (limited to 'packages/meshbay-node/src/meshbay_node/transport')
-rw-r--r--packages/meshbay-node/src/meshbay_node/transport/webrtc_server.py41
1 files changed, 37 insertions, 4 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/transport/webrtc_server.py b/packages/meshbay-node/src/meshbay_node/transport/webrtc_server.py
index ba8a3e4..8a5bbff 100644
--- a/packages/meshbay-node/src/meshbay_node/transport/webrtc_server.py
+++ b/packages/meshbay-node/src/meshbay_node/transport/webrtc_server.py
@@ -256,7 +256,13 @@ _CHAT_RATE_MAX_TRACKED = 1000
# a name the client chose, overwriting whatever was already there — which both violated
# node sovereignty and defeated the delete authorization (overwrite a file, become its
# recorded uploader, then delete it legitimately).
-MAX_UPLOAD_BYTES = 4 * 1024 * 1024 * 1024 # 4 GB per file
+# The ceiling is the operator's to set (`max_upload_gb` in node.toml, the Node
+# page and `meshbay-node transfers max-size`) because it is their disk that
+# fills: this is only the default a node starts from when they have said
+# nothing. It is read from the transport context on every chunk, so a change
+# applies to an upload already in flight.
+MAX_UPLOAD_BYTES = 8 * 1024 * 1024 * 1024 # 8 GB per file
+GB_BYTES = 1024 * 1024 * 1024
# What the `tr` on a chunk request turned out to be (see `_lease_of`).
LEASE_GRANTED = "granted"
@@ -3552,7 +3558,21 @@ class WebRTCPeerSession:
"queued": len(progress.queued),
}
- # ── Transfer slots ───────────────────────────────────────────────────────
+ # ── Upload ceiling and transfer slots ────────────────────────────────────
+
+ def _max_upload_bytes(self) -> int:
+ """The per-file upload ceiling this node is running with, in bytes.
+
+ Read from the transport context rather than captured once, for the same
+ reason the transfer pools are refreshed there: the operator can change
+ it from the Node page or the CLI while an upload is running, and a
+ ceiling that only applies after a restart is not the one they were
+ shown. `None` means they have said nothing and the default stands.
+ """
+ gb = self._ctx.get("max_upload_gb")
+ if not gb:
+ return MAX_UPLOAD_BYTES
+ return max(1, int(float(gb) * GB_BYTES))
def _slots(self) -> "TransferSlots":
"""The node's transfer pools, shared across every peer and every group.
@@ -5597,7 +5617,7 @@ class WebRTCPeerSession:
_refuse("Unexpected chunk index", "bad_chunk_index")
return
- if state.bytes + len(chunk_bytes) > MAX_UPLOAD_BYTES:
+ if state.bytes + len(chunk_bytes) > self._max_upload_bytes():
uploads.drop(user_id, rel_dir, filename)
await off_disk(roots, tmp_path.unlink, True)
_refuse("Upload exceeds size limit", "too_large")
@@ -6991,6 +7011,7 @@ class WebRTCTransport:
max_concurrent_streams: int | None = None,
max_concurrent_downloads: int | None = None,
max_concurrent_uploads: int | None = None,
+ max_upload_gb: float | None = None,
transcode_incompatible_video: bool = True,
):
self._ctx: dict[str, Any] = {
@@ -7007,6 +7028,9 @@ class WebRTCTransport:
# the operator said nothing and transfers.py's defaults apply.
"max_concurrent_downloads": max_concurrent_downloads,
"max_concurrent_uploads": max_concurrent_uploads,
+ # The per-file upload ceiling, in GB. None means the operator said
+ # nothing and MAX_UPLOAD_BYTES stands.
+ "max_upload_gb": max_upload_gb,
# Operator opt-out (node.toml) for the HEVC-etc. transcode
# fallback in _stream_video_inner — real CPU cost, unlike copy.
"transcode_incompatible_video": transcode_incompatible_video,
@@ -7022,7 +7046,8 @@ class WebRTCTransport:
def set_capacity(self, *, max_concurrent_streams: int | None = None,
max_concurrent_downloads: int | None = None,
- max_concurrent_uploads: int | None = None) -> dict:
+ max_concurrent_uploads: int | None = None,
+ max_upload_gb: float | None = None) -> dict:
"""Resize a live pool without restarting the daemon.
`ops.set_node_settings` used to do this by assigning
@@ -7089,6 +7114,14 @@ class WebRTCTransport:
# prevent.
for lease in granted:
self._notify_granted(lease)
+
+ if max_upload_gb is not None:
+ gb = float(max_upload_gb)
+ if gb <= 0:
+ raise ValueError("max_upload_gb must be greater than zero")
+ self._ctx["max_upload_gb"] = gb
+ changed["max_upload_gb"] = gb
+ log.info("upload: per-file ceiling now %g GB", gb)
return changed
def _notify_granted(self, lease) -> None: