PeerList
The set of known peers for one torrent. This is the pure-Kotlin port of libtorrent's struct peer_list (include/libtorrent/peer_list.hpp, src/peer_list.cpp).
This is a pure data structure: it owns no sockets and performs no I/O. Its job is to remember every endpoint we have heard about (TorrentPeer), keep the collection deduplicated and bounded, track how many of them are worth trying to connect to right now ("connect candidates"), and hand back the next best peer to dial via connectOnePeer. The actual dialing, handshaking and transfer live in higher layers that v0 does not include.
What is ported faithfully
the connect-candidate predicate isConnectCandidate,
the candidate ranking (comparePeer, findConnectCandidates): lower failcount first, local peers first, least-recently-tried first, then source rank and BEP 40 peer rank,
dedupe-on-insert keyed by endpoint, with the peer vector kept sorted by address,
list-size weeding (erasePeers + the erase-candidate predicates),
the connect-candidate counter bookkeeping that every mutator nudges,
banPeer, setSeed, setConnected, incFailcount, setFailcount, updatePeerPort, erasePeer, reconnect back-off in candidate selection.
What is intentionally omitted
Anything that requires a live connection or session pointer: the duplicate- connection resolution dance in new_connection (which decides which of two live sockets to drop), ip/port-filter application (needs a filter + live disconnects), and i2p peers. The connection-lifecycle hooks are reduced to setConnected / onConnectionClosed, which maintain exactly the same candidate bookkeeping the upstream functions do.
Threading
libtorrent's peer_list is single_threaded; so is this. It is not safe for concurrent use and assumes a single owning torrent task.
Functions
Add (or merge) a peer learned for (host, port) from source. This is the port of the IP path of peer_list::add_peer. Returns the stored TorrentPeer (existing or freshly created), or null if the endpoint is rejected.
Ban p, the port of peer_list::ban_peer. A banned peer is removed from the connect-candidate count and can never become a candidate again. Returns true (upstream always reports the ban as applied).
Clear every cached peer rank, the port of peer_list::clear_peer_prio.
Return the single best peer to try to connect to next, or null if there is none. This is the port of peer_list::connect_one_peer. It maintains a cache of pre-ranked candidates: stale entries (no longer candidates) are dropped, the cache is refilled via findConnectCandidates when empty, and the front (best) peer is popped and returned. The returned peer is guaranteed to be a current connect candidate (not banned, not connected, connectable).
Remove p from the list, correcting every counter and cursor. This is the port of peer_list::erase_peer(torrent_peer*). The removed peer is appended to TorrentState.erased. No-op if p is not present.
True if p is in this list (peer_list::has_peer).
Increment p's failcount (saturating at 31). This is the port of peer_list::inc_failcount. Updates the candidate count if this pushes the peer past maxFailcount.
Whether p is a connect candidate. This is the port of peer_list::is_connect_candidate. A peer is not a candidate if it is already connected, banned, a web seed, not connectable, a seed while we are finished, or has failed too many times. Everything else is a candidate.
Number of current connect candidates (peer_list::num_connect_candidates).
Record that a connection to p just closed. This is the port of the bookkeeping in peer_list::connection_closed. Clears the connected flag and optimistic unchoke, optionally stamps lastConnected with sessionTime, bumps the failcount when failed, and re-counts the peer as a candidate if it now is one. If multiple-connections-per-IP is on and this was a non-connectable incoming peer, the entry is erased (we can't reliably identify it again).
Read-only snapshot of the peers, in stored (address-sorted) order.
Recompute the connect-candidate count from scratch and snapshot the finished and max-failcount state. This is the port of peer_list::recalculate_connect_candidates. Called whenever the finished state flips or the failcount threshold changes, since both alter which peers count.
Mark p as connected or not. This is the candidate-bookkeeping core of peer_list::set_connection (when connecting) and connection_closed's pointer clearing. Setting connected clears the TorrentPeer.maybeUploadOnly hint (we will soon learn the truth) and removes the peer from the candidate count; clearing it may make the peer a candidate again.
Re-evaluate the candidate count if TorrentState.maxFailcount changed.