feat: resume an interrupted download instead of refetching it (#18)

Downloads buffered the whole file in memory and wrote it out only on
success, so an interrupted transfer left nothing behind and always
started over. The START_DOWNLOAD offset was hardcoded to zero on the
download side and discarded on the upload side, so neither half of the
protocol's resume support was wired up.

Bytes now stream into `<file>.part` as they arrive and it is renamed
only once the file is whole. A new attempt sends the partial file's
length as the START_DOWNLOAD offset, and `serve_file` seeks to the
offset a peer asks for rather than replaying from the start. A `.part`
at or past the expected size is treated as stale and restarted.

Partial files are kept out of the share index, since the download
directory is shared by default.
This commit is contained in:
Michel de Graaf
2026-07-26 12:51:48 +02:00
committed by GitHub
parent 3b75332e0c
commit a72dd64081
7 changed files with 515 additions and 325 deletions
+3 -1
View File
@@ -51,7 +51,9 @@ Flags: `--min-bitrate <kbps>`, `--free-slots`, `-n/--limit` (0 means all),
**`download <user> <path> [--size N]`** or **`download --stdin`** — one object
per finished transfer: `user`, `path`, `size`, `file` (the local path written).
`--stdin` consumes `search --json` output as-is.
`--stdin` consumes `search --json` output as-is. A transfer that fails leaves a
`<file>.part` behind; re-running the same command resumes from it rather than
starting over, so retrying a failed download is cheap.
**`get <query>`** — search, pick, and download in one step. `--pick
best|first|all`, `-n/--limit`, `--min-bitrate`, `--free-slots`. Prefer this