93 lines
5 KiB
C
93 lines
5 KiB
C
/* 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"
|
|
|
|
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);
|
|
|
|
/* 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);
|
|
|
|
#endif /* NAUT_PIECE_H */
|