1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
use ;
use crateChokingAlgorithm;
use cratePeerStats;
/// BitTorrent choking algorithm manager for download-side peer selection.
///
/// This module encapsulates all download-side choke/unchoke tracking logic,
/// mirroring the original aria2 C++ architecture's separation of
/// BtLeecherStateChoke and BtSeederStateChoke.
///
/// Responsibilities:
/// - Track which peers are choking us (affects request priority)
/// - Select best peers for piece requests based on choke state and speed
/// - Detect and handle snubbed peers (unresponsive peers)
/// - Update statistics when data is received from peers
// ======================================================================
// Download-Side Choke Tracking Helpers
// ======================================================================
/// Record that a peer at the given index has sent us a Choke message.
///
/// This updates the internal `choking_algo` state so that
/// [`select_best_peer_for_request`] can deprioritize choked peers.
///
/// # Arguments
/// * `algo` - The choking algorithm instance (mutable reference)
/// * `peer_idx` - Index of the peer that sent the choke message
/// Record that a peer at the given index has sent us an Unchoke message.
///
/// # Arguments
/// * `algo` - The choking algorithm instance (mutable reference)
/// * `peer_idx` - Index of the peer that sent the unchoke message
/// Record data received from a peer (updates speed + resets snubbed status).
///
/// Should be called whenever we successfully receive a block from a peer.
///
/// # Arguments
/// * `algo` - The choking algorithm instance (mutable reference)
/// * `peer_idx` - Index of the peer we received data from
/// * `bytes` - Number of bytes received
/// Check if any tracked peer is snubbed and should be handled.
///
/// Returns indices of newly snubbed peers that may need special handling
/// (e.g., reduced priority or disconnection).
///
/// # Arguments
/// * `algo` - The choking algorithm instance (mutable reference)
///
/// # Returns
/// Vector of peer indices that are newly snubbed
/// Add a connected peer to the choking algorithm tracking.
///
/// Call this when a new peer connection is established during download phase.
///
/// # Arguments
/// * `algo` - The choking algorithm instance (mutable reference)
/// * `peer_id` - First 8 bytes of the peer's 20-byte ID (rest will be zeroed)
/// * `addr` - Socket address of the peer
///
/// # Returns
/// Index of the added peer in the algorithm's internal list,
/// or 0 if no algorithm is configured
// ======================================================================
// Peer Selection Logic
// ======================================================================
/// Select the best peer for requesting pieces, preferring unchoked peers.
///
/// Uses the choking algorithm's peer stats to score and rank peers:
/// - Unchoked peers are strongly preferred
/// - Higher download speed is better
/// - Snubbed peers are penalized
///
/// Scoring formula:
/// - Download speed contribution: 50% weight
/// - Upload speed contribution (reciprocity): 30% weight
/// - Interest bonus: +50 points if peer wants our data
///
/// # Arguments
/// * `algo` - The choking algorithm instance (immutable reference)
///
/// # Returns
/// Index of the best peer for making requests, or None if no suitable peer found
// ======================================================================
// Snubbed Peer Handling
// ======================================================================
/// Handle a peer that has been marked as snubbed.
///
/// Reduces the request frequency for this peer by increasing its
/// request interval multiplier. This avoids wasting time waiting for
/// data from unresponsive peers while keeping the connection alive
/// in case they recover.
///
/// The choking algorithm will automatically lower this peer's score
/// on next rotation due to the `is_snubbed` flag, which will cause it
/// to be choked on the upload side.
///
/// # Arguments
/// * `algo` - The choking algorithm instance (mutable reference)
/// * `peer_idx` - Index of the snubbed peer
// The unit error type is mapped to a proper Aria2Error by the caller in
// bt_download_command.rs via map_err, so the Result<_, ()> signature is kept
// to preserve the existing error-handling path.
pub async
// ======================================================================
// Piece Receive Statistics
// ======================================================================
/// Update peer statistics when piece data is received.
///
/// Should be called whenever we successfully receive a block from a peer.
/// Updates the download speed estimate via EMA and resets the snubbed timer.
///
/// # Arguments
/// * `algo` - The choking algorithm instance (mutable reference)
/// * `peer_idx` - Index of the peer we received data from
/// * `bytes` - Number of bytes received in this block