diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-09-19 14:01:38 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-09-19 14:01:38 +0200 |
| commit | d2495a2c4b89fbbfc18cefec83ae96cabdd745e2 (patch) | |
| tree | 463e4d11b1c742475aac07155818c9c64a1e43e5 /packages/meshbay-node/src/meshbay_node/transport/webrtc_server.py | |
| parent | f8223293a211a87c92b1fed80f5ca53660f6b26c (diff) | |
| parent | 933daccbcfde7705413d3a10db87d910c650ed42 (diff) | |
| download | meshbay-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/webrtc_server.py')
| -rw-r--r-- | packages/meshbay-node/src/meshbay_node/transport/webrtc_server.py | 41 |
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: |