/* piece.h — download state: block requests, piece assembly, verify, persist. * * A piece is assembled in memory as its blocks arrive, verified against the * metainfo hash (SHA-1 for v1/hybrid), then written to storage in one shot — * so a corrupt piece never reaches disk. */ #ifndef NAUT_PIECE_H #define NAUT_PIECE_H #include "naut/common.h" #include "naut/metainfo.h" #include "naut/storage.h" #include "naut/bitfield.h" #include "naut/worker.h" #include typedef struct naut_download naut_download; naut_download *naut_download_create(const naut_metainfo *mi, naut_storage *st); void naut_download_destroy(naut_download *d); /* Scan existing storage and mark SHA-1 verified pieces complete before * requesting from peers. Invalid or missing pieces are left for download. */ naut_err naut_download_resume(naut_download *d); /* Optional hash offload. Completed-piece SHA-1 jobs run on the worker pool; * naut_download_poll() finalizes verified pieces on the owning engine thread. * The pool must outlive the download. */ void naut_download_set_worker_pool(naut_download *d, naut_worker_pool *pool); naut_err naut_download_poll(naut_download *d, uint32_t *pieces_completed); /* ---- multi-peer swarm interface (Phase 4) ------------------------------- * * Availability: report what each peer has so rarest-first can rank pieces. A * peer's bitfield is added on connect (BITFIELD) and removed on disconnect; a * single HAVE bumps one piece. */ void naut_download_add_bitfield(naut_download *d, const naut_bitfield *peer_have); void naut_download_remove_bitfield(naut_download *d, const naut_bitfield *peer_have); void naut_download_inc_avail(naut_download *d, uint32_t piece); /* Pick the next block to request for a peer with `peer_have`. Uses rarest-first, * prefers finishing in-progress pieces, and switches to endgame (allowing a * block to be requested from multiple peers) when few blocks remain. Returns * false if this peer has nothing useful to request right now. */ bool naut_download_pick(naut_download *d, const naut_bitfield *peer_have, uint32_t *index, uint32_t *begin, uint32_t *length); /* Endgame may duplicate a block across peers, but never back to the same peer. * `peer_has_request` lets the caller expose that peer's current request set. * Outside endgame this behaves exactly like naut_download_pick(). */ typedef bool (*naut_request_active_cb)(void *ctx, uint32_t index, uint32_t begin); bool naut_download_pick_for_peer(naut_download *d, const naut_bitfield *peer_have, naut_request_active_cb peer_has_request, void *ctx, uint32_t *index, uint32_t *begin, uint32_t *length); /* Release a request (peer disconnected, or cancel) so the block can be re-picked. */ void naut_download_unrequest(naut_download *d, uint32_t index, uint32_t begin); bool naut_download_have(const naut_download *d, uint32_t piece); bool naut_download_in_endgame(const naut_download *d); /* Per-file completion: fired the moment the last piece overlapping a file's byte * range verifies (so the file's bytes on disk are final and it is safe to move). * This is the engine seam for the user's "move files as they finish" feature — * the scripting layer (Phase 7) forwards this to an on_file_complete hook and may * then call naut_storage_relocate(). The callback runs on the engine thread; a * script must marshal any action back through the command queue. * * NOTE: fires during naut_download_on_block(); a single block may complete * several files (small files packed into one piece). Empty files are reported as * complete via naut_download_file_complete() but do not fire the callback. */ typedef void (*naut_file_complete_cb)(void *ctx, uint32_t file_index, const char *path); void naut_download_set_file_cb(naut_download *d, naut_file_complete_cb cb, void *ctx); bool naut_download_file_complete(const naut_download *d, uint32_t file_index); /* Optional owner-thread notification after a piece verifies and is persisted. */ typedef void (*naut_piece_complete_cb)(void *ctx, uint32_t piece_index); void naut_download_set_piece_cb(naut_download *d, naut_piece_complete_cb cb, void *ctx); /* Hand out the next block to request. false => nothing left to hand out right * now (all blocks have been requested). */ bool naut_download_next_request(naut_download *d, uint32_t *index, uint32_t *begin, uint32_t *length); /* Feed a received PIECE block. *piece_done is set true iff this block completed * a piece that then verified and was written to storage. With a worker pool, * completion is reported later through naut_download_poll(). */ naut_err naut_download_on_block(naut_download *d, uint32_t index, uint32_t begin, const uint8_t *data, uint32_t len, bool *piece_done); bool naut_download_complete(const naut_download *d); uint32_t naut_download_num_pieces(const naut_download *d); uint32_t naut_download_pieces_done(const naut_download *d); uint64_t naut_download_bytes_done(const naut_download *d); size_t naut_download_piece_states(const naut_download *d, uint8_t *out, size_t capacity); /* Diagnostic: write a human-readable dump of block-assembly state to `out` — * overall progress plus, for every piece not yet verified, how many of its * blocks have arrived and how many requests are outstanding. Pairs with * engine_dump_torrent() (which covers piece selection across peers) to * investigate pieces that never finish downloading. */ void naut_download_dump(const naut_download *d, FILE *out); #endif /* NAUT_PIECE_H */