engine: add engine_peer_list for per-peer status

Enumerates a torrent's connected peers (ip/port/state/rate/bytes/have)
for the UI's peer list — the per-peer detail lost in the engine swap.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
ookami125 2026-06-22 00:35:23 -04:00
parent d8208685a2
commit f85278fcf2
2 changed files with 47 additions and 0 deletions

View file

@ -139,6 +139,24 @@ uint32_t engine_loop_count(engine *e);
void engine_torrent_status(engine *e, uint32_t torrent_id, torrent_status *out);
/* One connected peer's live state, for the UI's per-peer list. */
typedef struct {
char ip[64];
uint16_t port;
int32_t state; /* peer_state */
int32_t unchoked; /* peer has unchoked us */
uint64_t bytes_received; /* total payload bytes from this peer */
double rate_bps; /* current download rate from this peer */
uint32_t have_pieces; /* pieces this peer advertises */
uint32_t num_pieces; /* torrent piece count (for progress ratio) */
} engine_peer_info;
/* Fill `out` with up to `max` connected peers (handshake completed) of a
* torrent; returns the number written. Best-effort snapshot read on the caller
* thread (like engine_torrent_status), so fine for status, not control. */
uint32_t engine_peer_list(engine *e, uint32_t torrent_id, engine_peer_info *out,
uint32_t max);
/* Diagnostic: write a human-readable dump of one torrent's piece-selection and
* per-connection state to `out`. Reports, for every still-wanted piece
* (priority > 0), whether a peer has claimed it (requested), how many connected

View file

@ -461,6 +461,35 @@ void engine_torrent_status(engine *e, uint32_t torrent_id, torrent_status *out)
out->rtt_min_ms = rttmin;
}
uint32_t engine_peer_list(engine *e, uint32_t torrent_id, engine_peer_info *out,
uint32_t max) {
if (!e || !out || max == 0) return 0;
torrent *t = find_locked(e, torrent_id);
if (!t) return 0;
loop *lp = t->lp;
uint32_t n = 0;
for (conn *c = lp->conns; c && n < max; c = c->next) {
if (c->tor != t) continue;
int st = atomic_load_explicit(&c->astate, memory_order_relaxed);
if (st != PEER_STATE_RUNNING && st != PEER_STATE_CHOKED) continue;
engine_peer_info *p = &out[n++];
snprintf(p->ip, sizeof p->ip, "%s", c->ip);
p->port = c->port;
p->state = st;
p->unchoked = c->unchoked;
p->bytes_received =
atomic_load_explicit(&c->bytes_received, memory_order_relaxed);
p->rate_bps = c->rate_bps;
p->num_pieces = t->num_pieces;
uint32_t have = 0;
if (c->have_bits)
for (uint32_t i = 0; i < t->num_pieces; i++)
if (have_bit(c->have_bits, i)) have++;
p->have_pieces = have;
}
return n;
}
static const char *peer_state_name(int state) {
switch (state) {
case PEER_STATE_IDLE: return "idle";