diff options
Diffstat (limited to 'packages/meshbay-common/src/meshbay_common/protocol.py')
| -rw-r--r-- | packages/meshbay-common/src/meshbay_common/protocol.py | 24 |
1 files changed, 24 insertions, 0 deletions
diff --git a/packages/meshbay-common/src/meshbay_common/protocol.py b/packages/meshbay-common/src/meshbay_common/protocol.py index 8a521bb..5bd2903 100644 --- a/packages/meshbay-common/src/meshbay_common/protocol.py +++ b/packages/meshbay-common/src/meshbay_common/protocol.py @@ -501,6 +501,22 @@ def file_upload_payload(gek: bytes, group_id: str, msg: dict) -> dict: return unseal(gek, PURPOSE_UPLOAD, MNP.FILE_UPLOAD, group_id, msg) +# "Where am I?", asked as an ordinary sealed upload chunk rather than as a new +# message. +# +# The node identifies an upload by (member, directory, filename), so a client +# resuming one has to name the file — and `transfer_open`, the obvious place to +# ask, travels in clear. Naming it there would undo exactly what sealing the +# upload path bought: before MNP 2.0 the same file was ciphertext leaving a node +# and plaintext arriving at one. +# +# So the question is asked inside the seal that already exists, as a chunk with +# no bytes and this index. The node writes nothing, changes nothing, and answers +# with `resume_from`. A node that predates this refuses the index, which the +# client reads as "start from the beginning" — the behaviour it had anyway. +UPLOAD_PROBE_INDEX = -1 + + def file_upload_ack_wire( gek: bytes, group_id: str, @@ -510,6 +526,7 @@ def file_upload_ack_wire( filename: str, stored_as: str, dir: str = "", + resume_from: int | None = None, ) -> dict: """ The node's answer to one chunk, sealed the same way. @@ -518,8 +535,15 @@ def file_upload_ack_wire( replacing anything — and `dir` is where it landed. Both name the operator's content, so both belong inside the seal; only `upload_id` and `chunk_index` stay out, because the client matches on them. + + `resume_from` answers the probe chunk (`UPLOAD_PROBE_INDEX`): how many + chunks of this file the node already holds. Inside the seal like the rest — + it is a fact about the operator's disk — and absent from an ordinary ack, so + a client can tell the two apart without looking at `chunk_index`. """ payload = {"filename": filename, "stored_as": stored_as, "dir": dir} + if resume_from is not None: + payload["resume_from"] = int(resume_from) return { "type": MNP.FILE_UPLOAD_ACK, "v": MNP_VERSION, |