RepositoryExportReader
Class: warmhub.RepositoryExportReader
RepositoryExportReader()Verifies one logical export, across one or more transport segments.
Row lines are hashed as they are consumed and each segment’s trailer is checked against that segment’s digest, so a tampered row fails on the line that follows the last one, not on a second pass over a buffered file. A second digest runs the length of the export and never resets, and that one is the caller’s whole-stream receipt.
Methods
Section titled “Methods”restart
Section titled “restart”restart()Discard everything and return to the pre-first-byte state.
Resuming is not always on offer. An export redeemed from a token
arrives as one presigned object download, and a transfer that dies
halfway has no cursor to continue from — the only recovery is to fetch
the object again from the top. begin_segment is the wrong tool
there: it deliberately preserves the rolling digest, the record count
and after_durable_id, which is exactly the state a fresh
download must not carry. Equivalent to constructing a new reader, and
used so that a caller already holding this one keeps a live handle.
The reader is left open on a fresh first segment, so feeding may begin
immediately without a begin_segment of its own.
begin_segment
Section titled “begin_segment”begin_segment()Start a new transport segment.
The first segment opens with the header. A resumed one does not: the
client asked for afterDurableId, so the server replies with rows and
a trailer for that segment alone. “Resumed” is derived from
after_durable_id rather than passed in, because that is the
exact condition under which the request carried the parameter.
feed(chunk: bytes)Consume some bytes of the current segment, yielding whole rows.
Chunk-at-a-time rather than iterable-at-a-time because the async
transport hands bytes over an async for, and both adapters must
drive the same state machine rather than two copies of it.
end_segment
Section titled “end_segment”end_segment()Close the current segment, keeping the digest for the next one.
read_segment
Section titled “read_segment”read_segment(chunks: Iterable[bytes])Consume one transport segment, yielding its validated rows.
A segment that ends without a trailer is not an error here — that is
the resumable case, and after_durable_id is the key to continue
from. Call finish when no further segment is coming.
finish
Section titled “finish”finish()The final segment’s trailer, or raise because it never arrived.
A segment that ends with a trailer is the whole remainder the server meant to send, so a trailer is also the end of the export.
Properties and attributes
Section titled “Properties and attributes”header
Section titled “header”headerThe header, once the first line of the first segment is read.
trailer
Section titled “trailer”trailerThe final segment’s verified trailer, or None while incomplete.
A trailer describes the segment that carried it, not the export: a
resumed segment’s recordCount and contentSha256 cover only the
rows that segment sent, because the server cannot know how much the
client already holds. record_count and content_sha256
are the whole-stream figures.
record_count
Section titled “record_count”record_countRows consumed so far, across every segment.
content_sha256
Section titled “content_sha256”content_sha256The rolling digest of every row line read so far, across segments.
This is the whole-stream integrity value. No trailer claims it once an export has been resumed, so it is the client’s own receipt: hash it again from the rows you stored and the two must agree.
after_durable_id
Section titled “after_durable_id”after_durable_idResume key: the durable identity of the last row already verified.
is_complete
Section titled “is_complete”is_completeDocumentation is not yet available.