librats 1.0.2 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (319) hide show
  1. package/README.md +145 -331
  2. package/binding.gyp +16 -3
  3. package/lib/index.d.ts +288 -696
  4. package/lib/index.js +407 -44
  5. package/native-src/3rdparty/android/ifaddrs-android.c +1 -0
  6. package/native-src/3rdparty/android/ifaddrs-android.h +1 -0
  7. package/native-src/CMakeLists.txt +404 -179
  8. package/native-src/LICENSE +1 -1
  9. package/native-src/src/librats/bindings/rats.cpp +762 -0
  10. package/native-src/src/librats/bindings/rats.h +380 -0
  11. package/native-src/src/librats/bittorrent/bencode.cpp +437 -0
  12. package/native-src/src/librats/bittorrent/bencode.h +176 -0
  13. package/native-src/src/librats/bittorrent/bitfield.cpp +97 -0
  14. package/native-src/src/librats/bittorrent/bitfield.h +76 -0
  15. package/native-src/src/librats/bittorrent/byte_io.h +58 -0
  16. package/native-src/src/librats/bittorrent/choker.cpp +25 -0
  17. package/native-src/src/librats/bittorrent/choker.h +46 -0
  18. package/native-src/src/librats/bittorrent/client.cpp +413 -0
  19. package/native-src/src/librats/bittorrent/client.h +227 -0
  20. package/native-src/src/librats/bittorrent/disk_io.cpp +209 -0
  21. package/native-src/src/librats/bittorrent/disk_io.h +150 -0
  22. package/native-src/src/librats/bittorrent/extensions.cpp +191 -0
  23. package/native-src/src/librats/bittorrent/extensions.h +94 -0
  24. package/native-src/src/librats/bittorrent/file_storage.cpp +77 -0
  25. package/native-src/src/librats/bittorrent/file_storage.h +79 -0
  26. package/native-src/src/librats/bittorrent/log.h +42 -0
  27. package/native-src/src/librats/bittorrent/magnet_uri.cpp +98 -0
  28. package/native-src/src/librats/bittorrent/magnet_uri.h +35 -0
  29. package/native-src/src/librats/bittorrent/peer_connection.cpp +502 -0
  30. package/native-src/src/librats/bittorrent/peer_connection.h +194 -0
  31. package/native-src/src/librats/bittorrent/peer_list.cpp +68 -0
  32. package/native-src/src/librats/bittorrent/peer_list.h +75 -0
  33. package/native-src/src/librats/bittorrent/piece_picker.cpp +352 -0
  34. package/native-src/src/librats/bittorrent/piece_picker.h +201 -0
  35. package/native-src/src/librats/bittorrent/reactor.cpp +97 -0
  36. package/native-src/src/librats/bittorrent/reactor.h +89 -0
  37. package/native-src/src/librats/bittorrent/resume_data.cpp +72 -0
  38. package/native-src/src/librats/bittorrent/resume_data.h +41 -0
  39. package/native-src/src/librats/bittorrent/store_buffer.cpp +48 -0
  40. package/native-src/src/librats/bittorrent/store_buffer.h +47 -0
  41. package/native-src/src/librats/bittorrent/torrent.cpp +870 -0
  42. package/native-src/src/librats/bittorrent/torrent.h +260 -0
  43. package/native-src/src/librats/bittorrent/torrent_creator.cpp +129 -0
  44. package/native-src/src/librats/bittorrent/torrent_creator.h +58 -0
  45. package/native-src/src/librats/bittorrent/torrent_info.cpp +314 -0
  46. package/native-src/src/librats/bittorrent/torrent_info.h +118 -0
  47. package/native-src/src/librats/bittorrent/tracker.cpp +374 -0
  48. package/native-src/src/librats/bittorrent/tracker.h +108 -0
  49. package/native-src/src/librats/bittorrent/types.cpp +206 -0
  50. package/native-src/src/librats/bittorrent/types.h +86 -0
  51. package/native-src/src/librats/core/address.cpp +35 -0
  52. package/native-src/src/librats/core/address.h +78 -0
  53. package/native-src/src/librats/core/bytes.h +69 -0
  54. package/native-src/src/librats/core/chained_send_buffer.cpp +172 -0
  55. package/native-src/src/librats/core/chained_send_buffer.h +183 -0
  56. package/native-src/src/librats/core/endpoint_parse.cpp +41 -0
  57. package/native-src/src/librats/core/endpoint_parse.h +31 -0
  58. package/native-src/src/librats/core/event_bus.h +70 -0
  59. package/native-src/src/librats/core/host_endpoint.h +56 -0
  60. package/native-src/src/{io_poller.cpp → librats/core/io_poller.cpp} +520 -65
  61. package/native-src/src/{io_poller.h → librats/core/io_poller.h} +12 -6
  62. package/native-src/src/librats/core/ip_address.cpp +120 -0
  63. package/native-src/src/librats/core/ip_address.h +109 -0
  64. package/native-src/src/librats/core/mpsc_queue.h +47 -0
  65. package/native-src/src/librats/core/notifier.h +74 -0
  66. package/native-src/src/librats/core/receive_buffer.cpp +219 -0
  67. package/native-src/src/librats/core/receive_buffer.h +171 -0
  68. package/native-src/src/librats/core/service_registry.h +58 -0
  69. package/native-src/src/{socket.cpp → librats/core/socket.cpp} +625 -118
  70. package/native-src/src/librats/core/socket.h +496 -0
  71. package/native-src/src/librats/core/timer_queue.h +105 -0
  72. package/native-src/src/librats/core/types.cpp +43 -0
  73. package/native-src/src/librats/core/types.h +103 -0
  74. package/native-src/src/librats/core/wakeup_pipe.h +83 -0
  75. package/native-src/src/{crypto → librats/crypto}/blake2_endian.h +21 -23
  76. package/native-src/src/{crypto → librats/crypto}/blake2b.c +34 -33
  77. package/native-src/src/{crypto → librats/crypto}/blake2b.h +7 -6
  78. package/native-src/src/{crypto → librats/crypto}/blake2s.c +55 -54
  79. package/native-src/src/{crypto → librats/crypto}/blake2s.h +13 -12
  80. package/native-src/src/{crypto → librats/crypto}/chacha.c +22 -21
  81. package/native-src/src/{crypto → librats/crypto}/chacha.h +14 -13
  82. package/native-src/src/{crypto → librats/crypto}/chachapoly.c +56 -56
  83. package/native-src/src/{crypto → librats/crypto}/chachapoly.h +24 -17
  84. package/native-src/src/{crc32.cpp → librats/crypto/crc32.cpp} +1 -1
  85. package/native-src/src/{crc32.h → librats/crypto/crc32.h} +3 -1
  86. package/native-src/src/{crypto → librats/crypto}/curve25519.c +6 -4
  87. package/native-src/src/{crypto → librats/crypto}/curve25519.h +6 -3
  88. package/native-src/src/librats/crypto/hkdf.c +266 -0
  89. package/native-src/src/{crypto → librats/crypto}/hkdf.h +19 -19
  90. package/native-src/src/{noise.cpp → librats/crypto/noise.cpp} +84 -73
  91. package/native-src/src/{noise.h → librats/crypto/noise.h} +18 -8
  92. package/native-src/src/{crypto → librats/crypto}/poly1305.c +47 -46
  93. package/native-src/src/librats/crypto/poly1305.h +37 -0
  94. package/native-src/src/{sha1.cpp → librats/crypto/sha1.cpp} +33 -1
  95. package/native-src/src/{sha1.h → librats/crypto/sha1.h} +14 -6
  96. package/native-src/src/{crypto → librats/crypto}/sha256.c +15 -14
  97. package/native-src/src/{crypto → librats/crypto}/sha256.h +8 -7
  98. package/native-src/src/{crypto → librats/crypto}/sha512.c +15 -14
  99. package/native-src/src/{crypto → librats/crypto}/sha512.h +8 -7
  100. package/native-src/src/librats/dht/announce.cpp +37 -0
  101. package/native-src/src/librats/dht/announce.h +41 -0
  102. package/native-src/src/librats/dht/bep42.cpp +109 -0
  103. package/native-src/src/librats/dht/bep42.h +48 -0
  104. package/native-src/src/librats/dht/dht.cpp +501 -0
  105. package/native-src/src/librats/dht/dht.h +119 -0
  106. package/native-src/src/librats/dht/dht_runner.cpp +103 -0
  107. package/native-src/src/librats/dht/dht_runner.h +71 -0
  108. package/native-src/src/librats/dht/dos_blocker.cpp +42 -0
  109. package/native-src/src/librats/dht/dos_blocker.h +47 -0
  110. package/native-src/src/librats/dht/find_peers.cpp +52 -0
  111. package/native-src/src/librats/dht/find_peers.h +73 -0
  112. package/native-src/src/librats/dht/id.h +167 -0
  113. package/native-src/src/{krpc.cpp → librats/dht/krpc.cpp} +32 -81
  114. package/native-src/src/{krpc.h → librats/dht/krpc.h} +19 -23
  115. package/native-src/src/librats/dht/log.h +38 -0
  116. package/native-src/src/librats/dht/node.cpp +473 -0
  117. package/native-src/src/librats/dht/node.h +164 -0
  118. package/native-src/src/librats/dht/node_entry.h +81 -0
  119. package/native-src/src/librats/dht/observer.h +72 -0
  120. package/native-src/src/librats/dht/persistence.cpp +90 -0
  121. package/native-src/src/librats/dht/persistence.h +32 -0
  122. package/native-src/src/librats/dht/routing_table.cpp +559 -0
  123. package/native-src/src/librats/dht/routing_table.h +185 -0
  124. package/native-src/src/librats/dht/rpc_manager.cpp +127 -0
  125. package/native-src/src/librats/dht/rpc_manager.h +77 -0
  126. package/native-src/src/librats/dht/storage.cpp +92 -0
  127. package/native-src/src/librats/dht/storage.h +74 -0
  128. package/native-src/src/librats/dht/transport.h +27 -0
  129. package/native-src/src/librats/dht/traversal.cpp +326 -0
  130. package/native-src/src/librats/dht/traversal.h +120 -0
  131. package/native-src/src/librats/dht/udp_transport.cpp +49 -0
  132. package/native-src/src/librats/dht/udp_transport.h +51 -0
  133. package/native-src/src/librats/mdns/log.h +22 -0
  134. package/native-src/src/{mdns.cpp → librats/mdns/mdns.cpp} +75 -40
  135. package/native-src/src/{mdns.h → librats/mdns/mdns.h} +9 -8
  136. package/native-src/src/{natpmp.cpp → librats/nat/natpmp.cpp} +12 -9
  137. package/native-src/src/{natpmp.h → librats/nat/natpmp.h} +3 -3
  138. package/native-src/src/{port_mapping.h → librats/nat/port_mapping.h} +3 -2
  139. package/native-src/src/{stun.cpp → librats/nat/stun.cpp} +4 -4
  140. package/native-src/src/{stun.h → librats/nat/stun.h} +1 -1
  141. package/native-src/src/{upnp.cpp → librats/nat/upnp.cpp} +6 -6
  142. package/native-src/src/{upnp.h → librats/nat/upnp.h} +2 -2
  143. package/native-src/src/librats/node/circuit_service.h +84 -0
  144. package/native-src/src/librats/node/config.h +110 -0
  145. package/native-src/src/librats/node/dial_service.h +54 -0
  146. package/native-src/src/librats/node/dialer.cpp +264 -0
  147. package/native-src/src/librats/node/dialer.h +188 -0
  148. package/native-src/src/librats/node/host_events.h +26 -0
  149. package/native-src/src/librats/node/identify.cpp +130 -0
  150. package/native-src/src/librats/node/identify.h +71 -0
  151. package/native-src/src/librats/node/nat_status.cpp +103 -0
  152. package/native-src/src/librats/node/nat_status.h +118 -0
  153. package/native-src/src/librats/node/node.cpp +865 -0
  154. package/native-src/src/librats/node/node.h +344 -0
  155. package/native-src/src/librats/node/node_context.h +33 -0
  156. package/native-src/src/librats/node/peer_network.h +91 -0
  157. package/native-src/src/librats/peer/peer.h +49 -0
  158. package/native-src/src/librats/peer/peer_book.cpp +181 -0
  159. package/native-src/src/librats/peer/peer_book.h +88 -0
  160. package/native-src/src/librats/peer/peer_id.cpp +72 -0
  161. package/native-src/src/librats/peer/peer_id.h +62 -0
  162. package/native-src/src/librats/peer/peer_info.h +37 -0
  163. package/native-src/src/librats/peer/peer_table.cpp +170 -0
  164. package/native-src/src/librats/peer/peer_table.h +148 -0
  165. package/native-src/src/librats/security/handshaker.h +66 -0
  166. package/native-src/src/librats/security/identity.h +43 -0
  167. package/native-src/src/librats/security/noise_security.cpp +122 -0
  168. package/native-src/src/librats/security/noise_security.h +37 -0
  169. package/native-src/src/librats/security/plaintext_security.h +106 -0
  170. package/native-src/src/librats/security/session.h +37 -0
  171. package/native-src/src/{storage.cpp → librats/storage/storage.cpp} +369 -522
  172. package/native-src/src/{storage.h → librats/storage/storage.h} +135 -299
  173. package/native-src/src/librats/subsystems/bittorrent.cpp +211 -0
  174. package/native-src/src/librats/subsystems/bittorrent.h +136 -0
  175. package/native-src/src/librats/subsystems/dht_discovery.cpp +202 -0
  176. package/native-src/src/librats/subsystems/dht_discovery.h +123 -0
  177. package/native-src/src/librats/subsystems/dht_service.h +36 -0
  178. package/native-src/src/librats/subsystems/file_transfer.cpp +972 -0
  179. package/native-src/src/librats/subsystems/file_transfer.h +367 -0
  180. package/native-src/src/librats/subsystems/hole_punch.cpp +605 -0
  181. package/native-src/src/librats/subsystems/hole_punch.h +290 -0
  182. package/native-src/src/librats/subsystems/hole_punch_service.h +38 -0
  183. package/native-src/src/librats/subsystems/mdns_discovery.cpp +66 -0
  184. package/native-src/src/librats/subsystems/mdns_discovery.h +55 -0
  185. package/native-src/src/librats/subsystems/message_json.cpp +112 -0
  186. package/native-src/src/librats/subsystems/message_json.h +88 -0
  187. package/native-src/src/librats/subsystems/peer_exchange.cpp +241 -0
  188. package/native-src/src/librats/subsystems/peer_exchange.h +136 -0
  189. package/native-src/src/librats/subsystems/ping_service.cpp +98 -0
  190. package/native-src/src/librats/subsystems/ping_service.h +66 -0
  191. package/native-src/src/librats/subsystems/port_mapping_service.cpp +192 -0
  192. package/native-src/src/librats/subsystems/port_mapping_service.h +84 -0
  193. package/native-src/src/librats/subsystems/pubsub.cpp +567 -0
  194. package/native-src/src/librats/subsystems/pubsub.h +175 -0
  195. package/native-src/src/librats/subsystems/reconnection.cpp +239 -0
  196. package/native-src/src/librats/subsystems/reconnection.h +126 -0
  197. package/native-src/src/librats/subsystems/relay.cpp +1142 -0
  198. package/native-src/src/librats/subsystems/relay.h +211 -0
  199. package/native-src/src/librats/subsystems/relay_service.h +46 -0
  200. package/native-src/src/librats/transport/connection.cpp +343 -0
  201. package/native-src/src/librats/transport/connection.h +283 -0
  202. package/native-src/src/librats/transport/link.h +96 -0
  203. package/native-src/src/librats/transport/reactor.cpp +588 -0
  204. package/native-src/src/librats/transport/reactor.h +262 -0
  205. package/native-src/src/librats/transport/reactor_pool.h +81 -0
  206. package/native-src/src/librats/transport/relay_link.cpp +208 -0
  207. package/native-src/src/librats/transport/relay_link.h +303 -0
  208. package/native-src/src/librats/transport/tcp_link.cpp +49 -0
  209. package/native-src/src/librats/transport/tcp_link.h +43 -0
  210. package/native-src/src/librats/transport/udp_mux.cpp +617 -0
  211. package/native-src/src/librats/transport/udp_mux.h +363 -0
  212. package/native-src/src/librats/transport/udp_packet.cpp +121 -0
  213. package/native-src/src/librats/transport/udp_packet.h +190 -0
  214. package/native-src/src/librats/transport/udp_stream.cpp +1194 -0
  215. package/native-src/src/librats/transport/udp_stream.h +614 -0
  216. package/native-src/src/librats/util/features.h.in +51 -0
  217. package/native-src/src/{fs.cpp → librats/util/fs.cpp} +51 -3
  218. package/native-src/src/librats/util/fs.h +136 -0
  219. package/native-src/src/librats/util/json.cpp +1002 -0
  220. package/native-src/src/librats/util/json.h +444 -0
  221. package/native-src/src/{logger.cpp → librats/util/logger.cpp} +1 -1
  222. package/native-src/src/{logger.h → librats/util/logger.h} +43 -31
  223. package/native-src/src/{network_monitor.cpp → librats/util/network_monitor.cpp} +12 -4
  224. package/native-src/src/{network_monitor.h → librats/util/network_monitor.h} +2 -1
  225. package/native-src/src/{network_utils.cpp → librats/util/network_utils.cpp} +38 -23
  226. package/native-src/src/{network_utils.h → librats/util/network_utils.h} +15 -8
  227. package/native-src/src/{os.cpp → librats/util/os.cpp} +48 -18
  228. package/native-src/src/librats/util/rats_export.h +69 -0
  229. package/native-src/src/{version.cpp → librats/util/version.cpp} +2 -2
  230. package/native-src/src/{version.h.in → librats/util/version.h.in} +1 -1
  231. package/native-src/src/librats/wire/frame.cpp +76 -0
  232. package/native-src/src/librats/wire/frame.h +111 -0
  233. package/native-src/src/librats/wire/message_router.cpp +45 -0
  234. package/native-src/src/librats/wire/message_router.h +47 -0
  235. package/package.json +5 -4
  236. package/scripts/build-librats.js +1 -0
  237. package/scripts/postinstall.js +3 -3
  238. package/scripts/prepare-package.js +4 -4
  239. package/scripts/verify-installation.js +63 -105
  240. package/src/librats_node.cpp +1067 -1323
  241. package/native-src/src/bencode.cpp +0 -485
  242. package/native-src/src/bencode.h +0 -145
  243. package/native-src/src/bittorrent.cpp +0 -14
  244. package/native-src/src/bittorrent.h +0 -74
  245. package/native-src/src/bt_bitfield.cpp +0 -372
  246. package/native-src/src/bt_bitfield.h +0 -316
  247. package/native-src/src/bt_choker.cpp +0 -228
  248. package/native-src/src/bt_choker.h +0 -147
  249. package/native-src/src/bt_client.cpp +0 -1047
  250. package/native-src/src/bt_client.h +0 -445
  251. package/native-src/src/bt_create_torrent.cpp +0 -677
  252. package/native-src/src/bt_create_torrent.h +0 -473
  253. package/native-src/src/bt_extension.cpp +0 -469
  254. package/native-src/src/bt_extension.h +0 -309
  255. package/native-src/src/bt_file_storage.cpp +0 -261
  256. package/native-src/src/bt_file_storage.h +0 -298
  257. package/native-src/src/bt_handshake.cpp +0 -134
  258. package/native-src/src/bt_handshake.h +0 -157
  259. package/native-src/src/bt_messages.cpp +0 -364
  260. package/native-src/src/bt_messages.h +0 -324
  261. package/native-src/src/bt_network.cpp +0 -1007
  262. package/native-src/src/bt_network.h +0 -417
  263. package/native-src/src/bt_peer_connection.cpp +0 -742
  264. package/native-src/src/bt_peer_connection.h +0 -592
  265. package/native-src/src/bt_piece_picker.cpp +0 -786
  266. package/native-src/src/bt_piece_picker.h +0 -473
  267. package/native-src/src/bt_resume_data.cpp +0 -410
  268. package/native-src/src/bt_resume_data.h +0 -249
  269. package/native-src/src/bt_torrent.cpp +0 -2120
  270. package/native-src/src/bt_torrent.h +0 -641
  271. package/native-src/src/bt_torrent_info.cpp +0 -659
  272. package/native-src/src/bt_torrent_info.h +0 -418
  273. package/native-src/src/bt_types.h +0 -621
  274. package/native-src/src/chained_send_buffer.cpp +0 -75
  275. package/native-src/src/chained_send_buffer.h +0 -137
  276. package/native-src/src/crypto/hkdf.c +0 -266
  277. package/native-src/src/crypto/poly1305.h +0 -36
  278. package/native-src/src/dht.cpp +0 -3311
  279. package/native-src/src/dht.h +0 -717
  280. package/native-src/src/disk_io.cpp +0 -632
  281. package/native-src/src/disk_io.h +0 -315
  282. package/native-src/src/file_transfer.cpp +0 -1415
  283. package/native-src/src/file_transfer.h +0 -286
  284. package/native-src/src/fs.h +0 -108
  285. package/native-src/src/gossipsub.cpp +0 -1139
  286. package/native-src/src/gossipsub.h +0 -403
  287. package/native-src/src/ice.cpp +0 -893
  288. package/native-src/src/ice.h +0 -559
  289. package/native-src/src/json.hpp +0 -25526
  290. package/native-src/src/librats.cpp +0 -2378
  291. package/native-src/src/librats.h +0 -2324
  292. package/native-src/src/librats_bittorrent.cpp +0 -601
  293. package/native-src/src/librats_c.cpp +0 -1557
  294. package/native-src/src/librats_c.h +0 -323
  295. package/native-src/src/librats_discovery.cpp +0 -402
  296. package/native-src/src/librats_encryption.cpp +0 -275
  297. package/native-src/src/librats_file_transfer.cpp +0 -144
  298. package/native-src/src/librats_gossipsub.cpp +0 -289
  299. package/native-src/src/librats_ice.cpp +0 -213
  300. package/native-src/src/librats_log_macros.h +0 -36
  301. package/native-src/src/librats_logging.cpp +0 -173
  302. package/native-src/src/librats_mdns.cpp +0 -166
  303. package/native-src/src/librats_persistence.cpp +0 -796
  304. package/native-src/src/librats_portmap.cpp +0 -419
  305. package/native-src/src/librats_reconnection.cpp +0 -218
  306. package/native-src/src/librats_statistic.cpp +0 -105
  307. package/native-src/src/librats_storage.cpp +0 -189
  308. package/native-src/src/rats_export.h +0 -17
  309. package/native-src/src/receive_buffer.cpp +0 -82
  310. package/native-src/src/receive_buffer.h +0 -127
  311. package/native-src/src/socket.h +0 -228
  312. package/native-src/src/threadmanager.cpp +0 -105
  313. package/native-src/src/threadmanager.h +0 -53
  314. package/native-src/src/tracker.cpp +0 -1264
  315. package/native-src/src/tracker.h +0 -319
  316. package/native-src/src/turn.cpp +0 -762
  317. package/native-src/src/turn.h +0 -460
  318. package/native-src/src/wakeup_pipe.h +0 -60
  319. /package/native-src/src/{os.h → librats/util/os.h} +0 -0
@@ -1,786 +0,0 @@
1
- #include "bt_piece_picker.h"
2
- #include "logger.h"
3
- #include <algorithm>
4
- #include <random>
5
- #include <chrono>
6
-
7
- namespace librats {
8
-
9
- //=============================================================================
10
- // Constructors
11
- //=============================================================================
12
-
13
- PiecePicker::PiecePicker(uint32_t num_pieces, uint32_t piece_length, uint32_t last_piece_length)
14
- : num_pieces_(num_pieces)
15
- , piece_length_(piece_length)
16
- , last_piece_length_(last_piece_length)
17
- , mode_(PickerMode::RarestFirst)
18
- , endgame_enabled_(true)
19
- , in_endgame_(false)
20
- , max_downloading_pieces_(DEFAULT_MAX_DOWNLOADING_PIECES)
21
- , pieces_(num_pieces)
22
- , num_have_(0)
23
- , num_downloading_(0)
24
- , sequential_cursor_(0) {
25
- }
26
-
27
- PiecePicker::~PiecePicker() = default;
28
-
29
- PiecePicker::PiecePicker(PiecePicker&& other) noexcept
30
- : num_pieces_(other.num_pieces_)
31
- , piece_length_(other.piece_length_)
32
- , last_piece_length_(other.last_piece_length_)
33
- , mode_(other.mode_)
34
- , endgame_enabled_(other.endgame_enabled_)
35
- , in_endgame_(other.in_endgame_)
36
- , max_downloading_pieces_(other.max_downloading_pieces_)
37
- , pieces_(std::move(other.pieces_))
38
- , downloading_(std::move(other.downloading_))
39
- , peer_pieces_(std::move(other.peer_pieces_))
40
- , num_have_(other.num_have_)
41
- , num_downloading_(other.num_downloading_)
42
- , sequential_cursor_(other.sequential_cursor_) {
43
- }
44
-
45
- PiecePicker& PiecePicker::operator=(PiecePicker&& other) noexcept {
46
- if (this != &other) {
47
- std::lock_guard<std::mutex> lock(mutex_);
48
- num_pieces_ = other.num_pieces_;
49
- piece_length_ = other.piece_length_;
50
- last_piece_length_ = other.last_piece_length_;
51
- mode_ = other.mode_;
52
- endgame_enabled_ = other.endgame_enabled_;
53
- in_endgame_ = other.in_endgame_;
54
- max_downloading_pieces_ = other.max_downloading_pieces_;
55
- pieces_ = std::move(other.pieces_);
56
- downloading_ = std::move(other.downloading_);
57
- peer_pieces_ = std::move(other.peer_pieces_);
58
- num_have_ = other.num_have_;
59
- num_downloading_ = other.num_downloading_;
60
- sequential_cursor_ = other.sequential_cursor_;
61
- }
62
- return *this;
63
- }
64
-
65
- //=============================================================================
66
- // Configuration
67
- //=============================================================================
68
-
69
- void PiecePicker::set_mode(PickerMode mode) {
70
- std::lock_guard<std::mutex> lock(mutex_);
71
- mode_ = mode;
72
- }
73
-
74
- PickerMode PiecePicker::mode() const {
75
- std::lock_guard<std::mutex> lock(mutex_);
76
- return mode_;
77
- }
78
-
79
- void PiecePicker::set_piece_priority(uint32_t piece, PiecePriority priority) {
80
- std::lock_guard<std::mutex> lock(mutex_);
81
- if (piece < num_pieces_) {
82
- pieces_[piece].priority = priority;
83
- }
84
- }
85
-
86
- PiecePriority PiecePicker::piece_priority(uint32_t piece) const {
87
- std::lock_guard<std::mutex> lock(mutex_);
88
- if (piece < num_pieces_) {
89
- return pieces_[piece].priority;
90
- }
91
- return PiecePriority::Normal;
92
- }
93
-
94
- void PiecePicker::set_piece_priority_range(uint32_t start, uint32_t end, PiecePriority priority) {
95
- std::lock_guard<std::mutex> lock(mutex_);
96
- end = (std::min)(end, num_pieces_);
97
- for (uint32_t i = start; i < end; ++i) {
98
- pieces_[i].priority = priority;
99
- }
100
- }
101
-
102
- //=============================================================================
103
- // Piece State Management
104
- //=============================================================================
105
-
106
- void PiecePicker::mark_have(uint32_t piece) {
107
- std::lock_guard<std::mutex> lock(mutex_);
108
- if (piece >= num_pieces_) return;
109
-
110
- if (!pieces_[piece].have) {
111
- pieces_[piece].have = true;
112
- ++num_have_;
113
-
114
- // Remove from downloading if present
115
- if (pieces_[piece].downloading) {
116
- remove_downloading(piece);
117
- }
118
- }
119
- }
120
-
121
- void PiecePicker::mark_have_all() {
122
- std::lock_guard<std::mutex> lock(mutex_);
123
-
124
- // Mark all pieces as have
125
- for (uint32_t i = 0; i < num_pieces_; ++i) {
126
- if (!pieces_[i].have) {
127
- pieces_[i].have = true;
128
-
129
- // Clear downloading state if present
130
- if (pieces_[i].downloading) {
131
- pieces_[i].downloading = false;
132
- }
133
- }
134
- }
135
-
136
- // Set count to total
137
- num_have_ = num_pieces_;
138
-
139
- // Clear all downloading state
140
- downloading_.clear();
141
- num_downloading_ = 0;
142
- }
143
-
144
- bool PiecePicker::have_piece(uint32_t piece) const {
145
- std::lock_guard<std::mutex> lock(mutex_);
146
- if (piece >= num_pieces_) return false;
147
- return pieces_[piece].have;
148
- }
149
-
150
- Bitfield PiecePicker::get_have_bitfield() const {
151
- std::lock_guard<std::mutex> lock(mutex_);
152
- Bitfield bf(num_pieces_);
153
- for (uint32_t i = 0; i < num_pieces_; ++i) {
154
- if (pieces_[i].have) {
155
- bf.set_bit(i);
156
- }
157
- }
158
- return bf;
159
- }
160
-
161
- void PiecePicker::set_have_bitfield(const Bitfield& have) {
162
- std::lock_guard<std::mutex> lock(mutex_);
163
- num_have_ = 0;
164
- for (uint32_t i = 0; i < num_pieces_ && i < have.size(); ++i) {
165
- pieces_[i].have = have.get_bit(i);
166
- if (pieces_[i].have) {
167
- ++num_have_;
168
- }
169
- }
170
- }
171
-
172
- uint32_t PiecePicker::num_have() const {
173
- std::lock_guard<std::mutex> lock(mutex_);
174
- return num_have_;
175
- }
176
-
177
- uint32_t PiecePicker::num_want() const {
178
- std::lock_guard<std::mutex> lock(mutex_);
179
- return num_pieces_ - num_have_;
180
- }
181
-
182
- bool PiecePicker::is_complete() const {
183
- std::lock_guard<std::mutex> lock(mutex_);
184
- return num_have_ == num_pieces_;
185
- }
186
-
187
- //=============================================================================
188
- // Peer Availability
189
- //=============================================================================
190
-
191
- void PiecePicker::add_peer(void* peer_id, const Bitfield& bitfield) {
192
- std::lock_guard<std::mutex> lock(mutex_);
193
-
194
- // Store peer's bitfield
195
- peer_pieces_[peer_id] = bitfield;
196
-
197
- // Update availability counts
198
- for (size_t i = 0; i < bitfield.size() && i < num_pieces_; ++i) {
199
- if (bitfield.get_bit(i)) {
200
- ++pieces_[i].availability;
201
- }
202
- }
203
- }
204
-
205
- void PiecePicker::remove_peer(void* peer_id) {
206
- std::lock_guard<std::mutex> lock(mutex_);
207
-
208
- auto it = peer_pieces_.find(peer_id);
209
- if (it == peer_pieces_.end()) return;
210
-
211
- // Decrease availability for pieces this peer had
212
- const Bitfield& bitfield = it->second;
213
- for (size_t i = 0; i < bitfield.size() && i < num_pieces_; ++i) {
214
- if (bitfield.get_bit(i) && pieces_[i].availability > 0) {
215
- --pieces_[i].availability;
216
- }
217
- }
218
-
219
- // Cancel any requests to this peer
220
- for (auto& dp : downloading_) {
221
- for (auto& block : dp.blocks) {
222
- if (block.peer == peer_id && block.state == BlockState::Requested) {
223
- block.state = BlockState::None;
224
- block.peer = nullptr;
225
- }
226
- }
227
- }
228
-
229
- peer_pieces_.erase(it);
230
- }
231
-
232
- void PiecePicker::peer_has_piece(void* peer_id, uint32_t piece) {
233
- std::lock_guard<std::mutex> lock(mutex_);
234
-
235
- if (piece >= num_pieces_) return;
236
-
237
- auto it = peer_pieces_.find(peer_id);
238
- if (it == peer_pieces_.end()) {
239
- // Create empty bitfield for this peer
240
- peer_pieces_[peer_id] = Bitfield(num_pieces_);
241
- it = peer_pieces_.find(peer_id);
242
- }
243
-
244
- if (!it->second.get_bit(piece)) {
245
- it->second.set_bit(piece);
246
- ++pieces_[piece].availability;
247
- }
248
- }
249
-
250
- uint32_t PiecePicker::availability(uint32_t piece) const {
251
- std::lock_guard<std::mutex> lock(mutex_);
252
- if (piece >= num_pieces_) return 0;
253
- return pieces_[piece].availability;
254
- }
255
-
256
- //=============================================================================
257
- // Piece Picking
258
- //=============================================================================
259
-
260
- std::vector<BlockRequest> PiecePicker::pick_pieces(
261
- const Bitfield& peer_bitfield,
262
- size_t num_blocks,
263
- void* peer_id) {
264
-
265
- std::lock_guard<std::mutex> lock(mutex_);
266
- std::vector<BlockRequest> result;
267
-
268
- if (num_blocks == 0) return result;
269
-
270
- // First, try to complete pieces already being downloaded
271
- for (auto& dp : downloading_) {
272
- if (result.size() >= num_blocks) break;
273
-
274
- uint32_t piece = dp.piece_index;
275
- if (!peer_bitfield.get_bit(piece)) continue;
276
-
277
- // Find unrequested blocks in this piece
278
- for (size_t i = 0; i < dp.blocks.size() && result.size() < num_blocks; ++i) {
279
- auto& block = dp.blocks[i];
280
-
281
- bool can_request = false;
282
- if (block.state == BlockState::None) {
283
- can_request = true;
284
- } else if (in_endgame_ && block.state == BlockState::Requested && block.peer != peer_id) {
285
- // In endgame, request from multiple peers
286
- can_request = true;
287
- }
288
-
289
- if (can_request) {
290
- BlockInfo info(piece, static_cast<uint32_t>(i) * BT_BLOCK_SIZE,
291
- block_size(piece, static_cast<uint32_t>(i)));
292
- result.emplace_back(info, peer_id);
293
-
294
- block.state = BlockState::Requested;
295
- block.peer = peer_id;
296
- }
297
- }
298
- }
299
-
300
- // Then, pick new pieces (if we're not at the limit)
301
- // Note: In endgame mode, we ignore the limit to finish faster
302
- while (result.size() < num_blocks) {
303
- // Check if we can start a new piece (respect max_downloading_pieces_ limit)
304
- if (!in_endgame_ && downloading_.size() >= max_downloading_pieces_) {
305
- LOG_DEBUG("PiecePicker", "At max downloading pieces limit (" +
306
- std::to_string(max_downloading_pieces_) + "), not starting new pieces");
307
- break;
308
- }
309
-
310
- uint32_t piece = UINT32_MAX;
311
-
312
- switch (mode_) {
313
- case PickerMode::RarestFirst:
314
- piece = pick_rarest(peer_bitfield);
315
- break;
316
- case PickerMode::Sequential:
317
- piece = pick_sequential(peer_bitfield);
318
- break;
319
- case PickerMode::Random:
320
- piece = pick_random(peer_bitfield);
321
- break;
322
- }
323
-
324
- if (piece == UINT32_MAX) break; // No more pieces available
325
-
326
- // Start downloading this piece
327
- auto* dp = get_or_create_downloading(piece);
328
- if (!dp) break;
329
-
330
- // Pick blocks from this piece
331
- for (size_t i = 0; i < dp->blocks.size() && result.size() < num_blocks; ++i) {
332
- auto& block = dp->blocks[i];
333
- if (block.state == BlockState::None) {
334
- BlockInfo info(piece, static_cast<uint32_t>(i) * BT_BLOCK_SIZE,
335
- block_size(piece, static_cast<uint32_t>(i)));
336
- result.emplace_back(info, peer_id);
337
-
338
- block.state = BlockState::Requested;
339
- block.peer = peer_id;
340
- }
341
- }
342
- }
343
-
344
- return result;
345
- }
346
-
347
- std::optional<uint32_t> PiecePicker::pick_piece(const Bitfield& peer_bitfield) {
348
- std::lock_guard<std::mutex> lock(mutex_);
349
-
350
- uint32_t piece = UINT32_MAX;
351
-
352
- switch (mode_) {
353
- case PickerMode::RarestFirst:
354
- piece = pick_rarest(peer_bitfield);
355
- break;
356
- case PickerMode::Sequential:
357
- piece = pick_sequential(peer_bitfield);
358
- break;
359
- case PickerMode::Random:
360
- piece = pick_random(peer_bitfield);
361
- break;
362
- }
363
-
364
- if (piece == UINT32_MAX) {
365
- return std::nullopt;
366
- }
367
- return piece;
368
- }
369
-
370
- bool PiecePicker::is_interesting(const Bitfield& peer_bitfield) const {
371
- std::lock_guard<std::mutex> lock(mutex_);
372
-
373
- for (uint32_t i = 0; i < num_pieces_; ++i) {
374
- if (!pieces_[i].have &&
375
- pieces_[i].priority != PiecePriority::Skip &&
376
- peer_bitfield.get_bit(i)) {
377
- return true;
378
- }
379
- }
380
- return false;
381
- }
382
-
383
- //=============================================================================
384
- // Block Management
385
- //=============================================================================
386
-
387
- void PiecePicker::mark_requested(const BlockInfo& block, void* peer_id) {
388
- std::lock_guard<std::mutex> lock(mutex_);
389
-
390
- auto* dp = get_or_create_downloading(block.piece_index);
391
- if (!dp) return;
392
-
393
- size_t block_idx = block.offset / BT_BLOCK_SIZE;
394
- if (block_idx < dp->blocks.size()) {
395
- dp->blocks[block_idx].state = BlockState::Requested;
396
- dp->blocks[block_idx].peer = peer_id;
397
- }
398
- }
399
-
400
- void PiecePicker::mark_writing(const BlockInfo& block) {
401
- std::lock_guard<std::mutex> lock(mutex_);
402
-
403
- auto* dp = find_downloading(block.piece_index);
404
- if (!dp) return;
405
-
406
- size_t block_idx = block.offset / BT_BLOCK_SIZE;
407
- if (block_idx < dp->blocks.size()) {
408
- dp->blocks[block_idx].state = BlockState::Writing;
409
- }
410
- }
411
-
412
- bool PiecePicker::mark_finished(const BlockInfo& block) {
413
- std::lock_guard<std::mutex> lock(mutex_);
414
-
415
- auto* dp = find_downloading(block.piece_index);
416
- if (!dp) {
417
- LOG_WARN("PiecePicker", "mark_finished: piece " + std::to_string(block.piece_index) +
418
- " not in downloading list!");
419
- return false;
420
- }
421
-
422
- size_t block_idx = block.offset / BT_BLOCK_SIZE;
423
- if (block_idx >= dp->blocks.size()) {
424
- LOG_WARN("PiecePicker", "mark_finished: block index " + std::to_string(block_idx) +
425
- " >= blocks.size " + std::to_string(dp->blocks.size()));
426
- return false;
427
- }
428
-
429
- dp->blocks[block_idx].state = BlockState::Finished;
430
- dp->blocks[block_idx].peer = nullptr;
431
-
432
- // Check if piece is complete
433
- size_t finished_count = 0;
434
- for (const auto& b : dp->blocks) {
435
- if (b.state == BlockState::Finished) {
436
- ++finished_count;
437
- }
438
- }
439
-
440
- bool complete = (finished_count == dp->blocks.size());
441
-
442
- LOG_DEBUG("PiecePicker", "mark_finished: piece=" + std::to_string(block.piece_index) +
443
- " block=" + std::to_string(block_idx) +
444
- " finished=" + std::to_string(finished_count) + "/" + std::to_string(dp->blocks.size()) +
445
- (complete ? " COMPLETE!" : ""));
446
-
447
- if (complete) {
448
- check_endgame();
449
- }
450
-
451
- return complete;
452
- }
453
-
454
- void PiecePicker::cancel_request(const BlockInfo& block, void* peer_id) {
455
- std::lock_guard<std::mutex> lock(mutex_);
456
-
457
- auto* dp = find_downloading(block.piece_index);
458
- if (!dp) return;
459
-
460
- size_t block_idx = block.offset / BT_BLOCK_SIZE;
461
- if (block_idx < dp->blocks.size()) {
462
- auto& b = dp->blocks[block_idx];
463
- if (b.state == BlockState::Requested && b.peer == peer_id) {
464
- b.state = BlockState::None;
465
- b.peer = nullptr;
466
- }
467
- }
468
- }
469
-
470
- void PiecePicker::cancel_peer_requests(void* peer_id) {
471
- std::lock_guard<std::mutex> lock(mutex_);
472
-
473
- for (auto& dp : downloading_) {
474
- for (auto& b : dp.blocks) {
475
- if (b.peer == peer_id && b.state == BlockState::Requested) {
476
- b.state = BlockState::None;
477
- b.peer = nullptr;
478
- }
479
- }
480
- }
481
- }
482
-
483
- void PiecePicker::abort_download(const BlockInfo& block, void* peer_id) {
484
- std::lock_guard<std::mutex> lock(mutex_);
485
-
486
- auto* dp = find_downloading(block.piece_index);
487
- if (!dp) return;
488
-
489
- // Find the block within the piece
490
- uint32_t block_index = block.offset / BT_BLOCK_SIZE;
491
- if (block_index >= dp->blocks.size()) return;
492
-
493
- auto& b = dp->blocks[block_index];
494
-
495
- // Only abort if it matches the peer (or peer_id is null)
496
- if (b.state == BlockState::Requested &&
497
- (peer_id == nullptr || b.peer == peer_id)) {
498
- b.state = BlockState::None;
499
- b.peer = nullptr;
500
- }
501
- }
502
-
503
- BlockState PiecePicker::block_state(const BlockInfo& block) const {
504
- std::lock_guard<std::mutex> lock(mutex_);
505
-
506
- const auto* dp = find_downloading(block.piece_index);
507
- if (!dp) {
508
- // If piece is marked as have, all blocks are finished
509
- if (block.piece_index < num_pieces_ && pieces_[block.piece_index].have) {
510
- return BlockState::Finished;
511
- }
512
- return BlockState::None;
513
- }
514
-
515
- size_t block_idx = block.offset / BT_BLOCK_SIZE;
516
- if (block_idx < dp->blocks.size()) {
517
- return dp->blocks[block_idx].state;
518
- }
519
- return BlockState::None;
520
- }
521
-
522
- //=============================================================================
523
- // Endgame Mode
524
- //=============================================================================
525
-
526
- bool PiecePicker::in_endgame_mode() const {
527
- std::lock_guard<std::mutex> lock(mutex_);
528
- return in_endgame_;
529
- }
530
-
531
- void PiecePicker::set_endgame_mode(bool enable) {
532
- std::lock_guard<std::mutex> lock(mutex_);
533
- endgame_enabled_ = enable;
534
- if (!enable) {
535
- in_endgame_ = false;
536
- }
537
- }
538
-
539
- void PiecePicker::check_endgame() {
540
- // Called with lock held
541
- if (!endgame_enabled_ || in_endgame_) return;
542
-
543
- // Enter endgame when we have most pieces and only a few blocks left
544
- uint32_t remaining_pieces = num_pieces_ - num_have_;
545
-
546
- // Endgame threshold: less than 5% of pieces remaining, or less than 10 pieces
547
- if (remaining_pieces <= num_pieces_ / 20 || remaining_pieces <= 10) {
548
- in_endgame_ = true;
549
- }
550
- }
551
-
552
- //=============================================================================
553
- // Statistics
554
- //=============================================================================
555
-
556
- size_t PiecePicker::num_downloading() const {
557
- std::lock_guard<std::mutex> lock(mutex_);
558
- return downloading_.size();
559
- }
560
-
561
- std::vector<DownloadingPiece> PiecePicker::downloading_pieces() const {
562
- std::lock_guard<std::mutex> lock(mutex_);
563
-
564
- std::vector<DownloadingPiece> result;
565
- result.reserve(downloading_.size());
566
-
567
- for (const auto& dp : downloading_) {
568
- DownloadingPiece info;
569
- info.piece_index = dp.piece_index;
570
- info.blocks_total = static_cast<uint16_t>(dp.blocks.size());
571
-
572
- for (const auto& b : dp.blocks) {
573
- switch (b.state) {
574
- case BlockState::Requested:
575
- ++info.blocks_requested;
576
- break;
577
- case BlockState::Writing:
578
- ++info.blocks_writing;
579
- break;
580
- case BlockState::Finished:
581
- ++info.blocks_finished;
582
- break;
583
- default:
584
- break;
585
- }
586
- }
587
-
588
- result.push_back(info);
589
- }
590
-
591
- return result;
592
- }
593
-
594
- std::optional<DownloadingPiece> PiecePicker::get_downloading_piece(uint32_t piece) const {
595
- std::lock_guard<std::mutex> lock(mutex_);
596
-
597
- const auto* dp = find_downloading(piece);
598
- if (!dp) return std::nullopt;
599
-
600
- DownloadingPiece info;
601
- info.piece_index = dp->piece_index;
602
- info.blocks_total = static_cast<uint16_t>(dp->blocks.size());
603
-
604
- for (const auto& b : dp->blocks) {
605
- switch (b.state) {
606
- case BlockState::Requested:
607
- ++info.blocks_requested;
608
- break;
609
- case BlockState::Writing:
610
- ++info.blocks_writing;
611
- break;
612
- case BlockState::Finished:
613
- ++info.blocks_finished;
614
- break;
615
- default:
616
- break;
617
- }
618
- }
619
-
620
- return info;
621
- }
622
-
623
- //=============================================================================
624
- // Utility
625
- //=============================================================================
626
-
627
- uint32_t PiecePicker::blocks_in_piece(uint32_t piece) const {
628
- if (piece >= num_pieces_) return 0;
629
-
630
- uint32_t piece_size = (piece == num_pieces_ - 1) ? last_piece_length_ : piece_length_;
631
- return (piece_size + BT_BLOCK_SIZE - 1) / BT_BLOCK_SIZE;
632
- }
633
-
634
- uint32_t PiecePicker::block_size(uint32_t piece, uint32_t block_index) const {
635
- if (piece >= num_pieces_) return 0;
636
-
637
- uint32_t piece_size = (piece == num_pieces_ - 1) ? last_piece_length_ : piece_length_;
638
- uint32_t offset = block_index * BT_BLOCK_SIZE;
639
-
640
- if (offset >= piece_size) return 0;
641
- return (std::min)(BT_BLOCK_SIZE, piece_size - offset);
642
- }
643
-
644
- //=============================================================================
645
- // Internal Methods
646
- //=============================================================================
647
-
648
- uint32_t PiecePicker::pick_rarest(const Bitfield& peer_bitfield) const {
649
- // Find rarest piece that peer has and we don't
650
- uint32_t best_piece = UINT32_MAX;
651
- uint32_t best_availability = UINT32_MAX;
652
-
653
- // Add some randomization among pieces with same availability
654
- std::vector<uint32_t> candidates;
655
-
656
- for (uint32_t i = 0; i < num_pieces_; ++i) {
657
- const auto& piece = pieces_[i];
658
-
659
- // Skip pieces we have, are downloading, or don't want
660
- if (piece.have || piece.downloading || piece.priority == PiecePriority::Skip) {
661
- continue;
662
- }
663
-
664
- // Skip pieces peer doesn't have
665
- if (!peer_bitfield.get_bit(i)) {
666
- continue;
667
- }
668
-
669
- if (piece.availability < best_availability) {
670
- best_availability = piece.availability;
671
- candidates.clear();
672
- candidates.push_back(i);
673
- } else if (piece.availability == best_availability) {
674
- candidates.push_back(i);
675
- }
676
- }
677
-
678
- if (candidates.empty()) {
679
- return UINT32_MAX;
680
- }
681
-
682
- // Return random piece among equally rare ones
683
- if (candidates.size() == 1) {
684
- return candidates[0];
685
- }
686
-
687
- static thread_local std::mt19937 gen(
688
- static_cast<unsigned>(std::chrono::high_resolution_clock::now().time_since_epoch().count()));
689
- std::uniform_int_distribution<size_t> dis(0, candidates.size() - 1);
690
- return candidates[dis(gen)];
691
- }
692
-
693
- uint32_t PiecePicker::pick_sequential(const Bitfield& peer_bitfield) const {
694
- // Start from cursor and find next available piece
695
- for (uint32_t i = 0; i < num_pieces_; ++i) {
696
- uint32_t piece = (sequential_cursor_ + i) % num_pieces_;
697
- const auto& ps = pieces_[piece];
698
-
699
- if (ps.have || ps.downloading || ps.priority == PiecePriority::Skip) {
700
- continue;
701
- }
702
-
703
- if (peer_bitfield.get_bit(piece)) {
704
- return piece;
705
- }
706
- }
707
-
708
- return UINT32_MAX;
709
- }
710
-
711
- uint32_t PiecePicker::pick_random(const Bitfield& peer_bitfield) const {
712
- std::vector<uint32_t> candidates;
713
-
714
- for (uint32_t i = 0; i < num_pieces_; ++i) {
715
- const auto& piece = pieces_[i];
716
-
717
- if (piece.have || piece.downloading || piece.priority == PiecePriority::Skip) {
718
- continue;
719
- }
720
-
721
- if (peer_bitfield.get_bit(i)) {
722
- candidates.push_back(i);
723
- }
724
- }
725
-
726
- if (candidates.empty()) {
727
- return UINT32_MAX;
728
- }
729
-
730
- static thread_local std::mt19937 gen(
731
- static_cast<unsigned>(std::chrono::high_resolution_clock::now().time_since_epoch().count()));
732
- std::uniform_int_distribution<size_t> dis(0, candidates.size() - 1);
733
- return candidates[dis(gen)];
734
- }
735
-
736
- PiecePicker::DownloadingPieceState* PiecePicker::get_or_create_downloading(uint32_t piece) {
737
- // Called with lock held
738
- if (piece >= num_pieces_) return nullptr;
739
-
740
- // Check if already downloading
741
- for (auto& dp : downloading_) {
742
- if (dp.piece_index == piece) {
743
- return &dp;
744
- }
745
- }
746
-
747
- // Create new downloading piece
748
- uint32_t num_blocks = blocks_in_piece(piece);
749
- downloading_.emplace_back(piece, num_blocks);
750
- pieces_[piece].downloading = true;
751
- ++num_downloading_;
752
-
753
- return &downloading_.back();
754
- }
755
-
756
- PiecePicker::DownloadingPieceState* PiecePicker::find_downloading(uint32_t piece) {
757
- for (auto& dp : downloading_) {
758
- if (dp.piece_index == piece) {
759
- return &dp;
760
- }
761
- }
762
- return nullptr;
763
- }
764
-
765
- const PiecePicker::DownloadingPieceState* PiecePicker::find_downloading(uint32_t piece) const {
766
- for (const auto& dp : downloading_) {
767
- if (dp.piece_index == piece) {
768
- return &dp;
769
- }
770
- }
771
- return nullptr;
772
- }
773
-
774
- void PiecePicker::remove_downloading(uint32_t piece) {
775
- // Called with lock held
776
- auto it = std::find_if(downloading_.begin(), downloading_.end(),
777
- [piece](const DownloadingPieceState& dp) { return dp.piece_index == piece; });
778
-
779
- if (it != downloading_.end()) {
780
- pieces_[piece].downloading = false;
781
- downloading_.erase(it);
782
- if (num_downloading_ > 0) --num_downloading_;
783
- }
784
- }
785
-
786
- } // namespace librats