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.
- package/README.md +145 -331
- package/binding.gyp +16 -3
- package/lib/index.d.ts +288 -696
- package/lib/index.js +407 -44
- package/native-src/3rdparty/android/ifaddrs-android.c +1 -0
- package/native-src/3rdparty/android/ifaddrs-android.h +1 -0
- package/native-src/CMakeLists.txt +404 -179
- package/native-src/LICENSE +1 -1
- package/native-src/src/librats/bindings/rats.cpp +762 -0
- package/native-src/src/librats/bindings/rats.h +380 -0
- package/native-src/src/librats/bittorrent/bencode.cpp +437 -0
- package/native-src/src/librats/bittorrent/bencode.h +176 -0
- package/native-src/src/librats/bittorrent/bitfield.cpp +97 -0
- package/native-src/src/librats/bittorrent/bitfield.h +76 -0
- package/native-src/src/librats/bittorrent/byte_io.h +58 -0
- package/native-src/src/librats/bittorrent/choker.cpp +25 -0
- package/native-src/src/librats/bittorrent/choker.h +46 -0
- package/native-src/src/librats/bittorrent/client.cpp +413 -0
- package/native-src/src/librats/bittorrent/client.h +227 -0
- package/native-src/src/librats/bittorrent/disk_io.cpp +209 -0
- package/native-src/src/librats/bittorrent/disk_io.h +150 -0
- package/native-src/src/librats/bittorrent/extensions.cpp +191 -0
- package/native-src/src/librats/bittorrent/extensions.h +94 -0
- package/native-src/src/librats/bittorrent/file_storage.cpp +77 -0
- package/native-src/src/librats/bittorrent/file_storage.h +79 -0
- package/native-src/src/librats/bittorrent/log.h +42 -0
- package/native-src/src/librats/bittorrent/magnet_uri.cpp +98 -0
- package/native-src/src/librats/bittorrent/magnet_uri.h +35 -0
- package/native-src/src/librats/bittorrent/peer_connection.cpp +502 -0
- package/native-src/src/librats/bittorrent/peer_connection.h +194 -0
- package/native-src/src/librats/bittorrent/peer_list.cpp +68 -0
- package/native-src/src/librats/bittorrent/peer_list.h +75 -0
- package/native-src/src/librats/bittorrent/piece_picker.cpp +352 -0
- package/native-src/src/librats/bittorrent/piece_picker.h +201 -0
- package/native-src/src/librats/bittorrent/reactor.cpp +97 -0
- package/native-src/src/librats/bittorrent/reactor.h +89 -0
- package/native-src/src/librats/bittorrent/resume_data.cpp +72 -0
- package/native-src/src/librats/bittorrent/resume_data.h +41 -0
- package/native-src/src/librats/bittorrent/store_buffer.cpp +48 -0
- package/native-src/src/librats/bittorrent/store_buffer.h +47 -0
- package/native-src/src/librats/bittorrent/torrent.cpp +870 -0
- package/native-src/src/librats/bittorrent/torrent.h +260 -0
- package/native-src/src/librats/bittorrent/torrent_creator.cpp +129 -0
- package/native-src/src/librats/bittorrent/torrent_creator.h +58 -0
- package/native-src/src/librats/bittorrent/torrent_info.cpp +314 -0
- package/native-src/src/librats/bittorrent/torrent_info.h +118 -0
- package/native-src/src/librats/bittorrent/tracker.cpp +374 -0
- package/native-src/src/librats/bittorrent/tracker.h +108 -0
- package/native-src/src/librats/bittorrent/types.cpp +206 -0
- package/native-src/src/librats/bittorrent/types.h +86 -0
- package/native-src/src/librats/core/address.cpp +35 -0
- package/native-src/src/librats/core/address.h +78 -0
- package/native-src/src/librats/core/bytes.h +69 -0
- package/native-src/src/librats/core/chained_send_buffer.cpp +172 -0
- package/native-src/src/librats/core/chained_send_buffer.h +183 -0
- package/native-src/src/librats/core/endpoint_parse.cpp +41 -0
- package/native-src/src/librats/core/endpoint_parse.h +31 -0
- package/native-src/src/librats/core/event_bus.h +70 -0
- package/native-src/src/librats/core/host_endpoint.h +56 -0
- package/native-src/src/{io_poller.cpp → librats/core/io_poller.cpp} +520 -65
- package/native-src/src/{io_poller.h → librats/core/io_poller.h} +12 -6
- package/native-src/src/librats/core/ip_address.cpp +120 -0
- package/native-src/src/librats/core/ip_address.h +109 -0
- package/native-src/src/librats/core/mpsc_queue.h +47 -0
- package/native-src/src/librats/core/notifier.h +74 -0
- package/native-src/src/librats/core/receive_buffer.cpp +219 -0
- package/native-src/src/librats/core/receive_buffer.h +171 -0
- package/native-src/src/librats/core/service_registry.h +58 -0
- package/native-src/src/{socket.cpp → librats/core/socket.cpp} +625 -118
- package/native-src/src/librats/core/socket.h +496 -0
- package/native-src/src/librats/core/timer_queue.h +105 -0
- package/native-src/src/librats/core/types.cpp +43 -0
- package/native-src/src/librats/core/types.h +103 -0
- package/native-src/src/librats/core/wakeup_pipe.h +83 -0
- package/native-src/src/{crypto → librats/crypto}/blake2_endian.h +21 -23
- package/native-src/src/{crypto → librats/crypto}/blake2b.c +34 -33
- package/native-src/src/{crypto → librats/crypto}/blake2b.h +7 -6
- package/native-src/src/{crypto → librats/crypto}/blake2s.c +55 -54
- package/native-src/src/{crypto → librats/crypto}/blake2s.h +13 -12
- package/native-src/src/{crypto → librats/crypto}/chacha.c +22 -21
- package/native-src/src/{crypto → librats/crypto}/chacha.h +14 -13
- package/native-src/src/{crypto → librats/crypto}/chachapoly.c +56 -56
- package/native-src/src/{crypto → librats/crypto}/chachapoly.h +24 -17
- package/native-src/src/{crc32.cpp → librats/crypto/crc32.cpp} +1 -1
- package/native-src/src/{crc32.h → librats/crypto/crc32.h} +3 -1
- package/native-src/src/{crypto → librats/crypto}/curve25519.c +6 -4
- package/native-src/src/{crypto → librats/crypto}/curve25519.h +6 -3
- package/native-src/src/librats/crypto/hkdf.c +266 -0
- package/native-src/src/{crypto → librats/crypto}/hkdf.h +19 -19
- package/native-src/src/{noise.cpp → librats/crypto/noise.cpp} +84 -73
- package/native-src/src/{noise.h → librats/crypto/noise.h} +18 -8
- package/native-src/src/{crypto → librats/crypto}/poly1305.c +47 -46
- package/native-src/src/librats/crypto/poly1305.h +37 -0
- package/native-src/src/{sha1.cpp → librats/crypto/sha1.cpp} +33 -1
- package/native-src/src/{sha1.h → librats/crypto/sha1.h} +14 -6
- package/native-src/src/{crypto → librats/crypto}/sha256.c +15 -14
- package/native-src/src/{crypto → librats/crypto}/sha256.h +8 -7
- package/native-src/src/{crypto → librats/crypto}/sha512.c +15 -14
- package/native-src/src/{crypto → librats/crypto}/sha512.h +8 -7
- package/native-src/src/librats/dht/announce.cpp +37 -0
- package/native-src/src/librats/dht/announce.h +41 -0
- package/native-src/src/librats/dht/bep42.cpp +109 -0
- package/native-src/src/librats/dht/bep42.h +48 -0
- package/native-src/src/librats/dht/dht.cpp +501 -0
- package/native-src/src/librats/dht/dht.h +119 -0
- package/native-src/src/librats/dht/dht_runner.cpp +103 -0
- package/native-src/src/librats/dht/dht_runner.h +71 -0
- package/native-src/src/librats/dht/dos_blocker.cpp +42 -0
- package/native-src/src/librats/dht/dos_blocker.h +47 -0
- package/native-src/src/librats/dht/find_peers.cpp +52 -0
- package/native-src/src/librats/dht/find_peers.h +73 -0
- package/native-src/src/librats/dht/id.h +167 -0
- package/native-src/src/{krpc.cpp → librats/dht/krpc.cpp} +32 -81
- package/native-src/src/{krpc.h → librats/dht/krpc.h} +19 -23
- package/native-src/src/librats/dht/log.h +38 -0
- package/native-src/src/librats/dht/node.cpp +473 -0
- package/native-src/src/librats/dht/node.h +164 -0
- package/native-src/src/librats/dht/node_entry.h +81 -0
- package/native-src/src/librats/dht/observer.h +72 -0
- package/native-src/src/librats/dht/persistence.cpp +90 -0
- package/native-src/src/librats/dht/persistence.h +32 -0
- package/native-src/src/librats/dht/routing_table.cpp +559 -0
- package/native-src/src/librats/dht/routing_table.h +185 -0
- package/native-src/src/librats/dht/rpc_manager.cpp +127 -0
- package/native-src/src/librats/dht/rpc_manager.h +77 -0
- package/native-src/src/librats/dht/storage.cpp +92 -0
- package/native-src/src/librats/dht/storage.h +74 -0
- package/native-src/src/librats/dht/transport.h +27 -0
- package/native-src/src/librats/dht/traversal.cpp +326 -0
- package/native-src/src/librats/dht/traversal.h +120 -0
- package/native-src/src/librats/dht/udp_transport.cpp +49 -0
- package/native-src/src/librats/dht/udp_transport.h +51 -0
- package/native-src/src/librats/mdns/log.h +22 -0
- package/native-src/src/{mdns.cpp → librats/mdns/mdns.cpp} +75 -40
- package/native-src/src/{mdns.h → librats/mdns/mdns.h} +9 -8
- package/native-src/src/{natpmp.cpp → librats/nat/natpmp.cpp} +12 -9
- package/native-src/src/{natpmp.h → librats/nat/natpmp.h} +3 -3
- package/native-src/src/{port_mapping.h → librats/nat/port_mapping.h} +3 -2
- package/native-src/src/{stun.cpp → librats/nat/stun.cpp} +4 -4
- package/native-src/src/{stun.h → librats/nat/stun.h} +1 -1
- package/native-src/src/{upnp.cpp → librats/nat/upnp.cpp} +6 -6
- package/native-src/src/{upnp.h → librats/nat/upnp.h} +2 -2
- package/native-src/src/librats/node/circuit_service.h +84 -0
- package/native-src/src/librats/node/config.h +110 -0
- package/native-src/src/librats/node/dial_service.h +54 -0
- package/native-src/src/librats/node/dialer.cpp +264 -0
- package/native-src/src/librats/node/dialer.h +188 -0
- package/native-src/src/librats/node/host_events.h +26 -0
- package/native-src/src/librats/node/identify.cpp +130 -0
- package/native-src/src/librats/node/identify.h +71 -0
- package/native-src/src/librats/node/nat_status.cpp +103 -0
- package/native-src/src/librats/node/nat_status.h +118 -0
- package/native-src/src/librats/node/node.cpp +865 -0
- package/native-src/src/librats/node/node.h +344 -0
- package/native-src/src/librats/node/node_context.h +33 -0
- package/native-src/src/librats/node/peer_network.h +91 -0
- package/native-src/src/librats/peer/peer.h +49 -0
- package/native-src/src/librats/peer/peer_book.cpp +181 -0
- package/native-src/src/librats/peer/peer_book.h +88 -0
- package/native-src/src/librats/peer/peer_id.cpp +72 -0
- package/native-src/src/librats/peer/peer_id.h +62 -0
- package/native-src/src/librats/peer/peer_info.h +37 -0
- package/native-src/src/librats/peer/peer_table.cpp +170 -0
- package/native-src/src/librats/peer/peer_table.h +148 -0
- package/native-src/src/librats/security/handshaker.h +66 -0
- package/native-src/src/librats/security/identity.h +43 -0
- package/native-src/src/librats/security/noise_security.cpp +122 -0
- package/native-src/src/librats/security/noise_security.h +37 -0
- package/native-src/src/librats/security/plaintext_security.h +106 -0
- package/native-src/src/librats/security/session.h +37 -0
- package/native-src/src/{storage.cpp → librats/storage/storage.cpp} +369 -522
- package/native-src/src/{storage.h → librats/storage/storage.h} +135 -299
- package/native-src/src/librats/subsystems/bittorrent.cpp +211 -0
- package/native-src/src/librats/subsystems/bittorrent.h +136 -0
- package/native-src/src/librats/subsystems/dht_discovery.cpp +202 -0
- package/native-src/src/librats/subsystems/dht_discovery.h +123 -0
- package/native-src/src/librats/subsystems/dht_service.h +36 -0
- package/native-src/src/librats/subsystems/file_transfer.cpp +972 -0
- package/native-src/src/librats/subsystems/file_transfer.h +367 -0
- package/native-src/src/librats/subsystems/hole_punch.cpp +605 -0
- package/native-src/src/librats/subsystems/hole_punch.h +290 -0
- package/native-src/src/librats/subsystems/hole_punch_service.h +38 -0
- package/native-src/src/librats/subsystems/mdns_discovery.cpp +66 -0
- package/native-src/src/librats/subsystems/mdns_discovery.h +55 -0
- package/native-src/src/librats/subsystems/message_json.cpp +112 -0
- package/native-src/src/librats/subsystems/message_json.h +88 -0
- package/native-src/src/librats/subsystems/peer_exchange.cpp +241 -0
- package/native-src/src/librats/subsystems/peer_exchange.h +136 -0
- package/native-src/src/librats/subsystems/ping_service.cpp +98 -0
- package/native-src/src/librats/subsystems/ping_service.h +66 -0
- package/native-src/src/librats/subsystems/port_mapping_service.cpp +192 -0
- package/native-src/src/librats/subsystems/port_mapping_service.h +84 -0
- package/native-src/src/librats/subsystems/pubsub.cpp +567 -0
- package/native-src/src/librats/subsystems/pubsub.h +175 -0
- package/native-src/src/librats/subsystems/reconnection.cpp +239 -0
- package/native-src/src/librats/subsystems/reconnection.h +126 -0
- package/native-src/src/librats/subsystems/relay.cpp +1142 -0
- package/native-src/src/librats/subsystems/relay.h +211 -0
- package/native-src/src/librats/subsystems/relay_service.h +46 -0
- package/native-src/src/librats/transport/connection.cpp +343 -0
- package/native-src/src/librats/transport/connection.h +283 -0
- package/native-src/src/librats/transport/link.h +96 -0
- package/native-src/src/librats/transport/reactor.cpp +588 -0
- package/native-src/src/librats/transport/reactor.h +262 -0
- package/native-src/src/librats/transport/reactor_pool.h +81 -0
- package/native-src/src/librats/transport/relay_link.cpp +208 -0
- package/native-src/src/librats/transport/relay_link.h +303 -0
- package/native-src/src/librats/transport/tcp_link.cpp +49 -0
- package/native-src/src/librats/transport/tcp_link.h +43 -0
- package/native-src/src/librats/transport/udp_mux.cpp +617 -0
- package/native-src/src/librats/transport/udp_mux.h +363 -0
- package/native-src/src/librats/transport/udp_packet.cpp +121 -0
- package/native-src/src/librats/transport/udp_packet.h +190 -0
- package/native-src/src/librats/transport/udp_stream.cpp +1194 -0
- package/native-src/src/librats/transport/udp_stream.h +614 -0
- package/native-src/src/librats/util/features.h.in +51 -0
- package/native-src/src/{fs.cpp → librats/util/fs.cpp} +51 -3
- package/native-src/src/librats/util/fs.h +136 -0
- package/native-src/src/librats/util/json.cpp +1002 -0
- package/native-src/src/librats/util/json.h +444 -0
- package/native-src/src/{logger.cpp → librats/util/logger.cpp} +1 -1
- package/native-src/src/{logger.h → librats/util/logger.h} +43 -31
- package/native-src/src/{network_monitor.cpp → librats/util/network_monitor.cpp} +12 -4
- package/native-src/src/{network_monitor.h → librats/util/network_monitor.h} +2 -1
- package/native-src/src/{network_utils.cpp → librats/util/network_utils.cpp} +38 -23
- package/native-src/src/{network_utils.h → librats/util/network_utils.h} +15 -8
- package/native-src/src/{os.cpp → librats/util/os.cpp} +48 -18
- package/native-src/src/librats/util/rats_export.h +69 -0
- package/native-src/src/{version.cpp → librats/util/version.cpp} +2 -2
- package/native-src/src/{version.h.in → librats/util/version.h.in} +1 -1
- package/native-src/src/librats/wire/frame.cpp +76 -0
- package/native-src/src/librats/wire/frame.h +111 -0
- package/native-src/src/librats/wire/message_router.cpp +45 -0
- package/native-src/src/librats/wire/message_router.h +47 -0
- package/package.json +5 -4
- package/scripts/build-librats.js +1 -0
- package/scripts/postinstall.js +3 -3
- package/scripts/prepare-package.js +4 -4
- package/scripts/verify-installation.js +63 -105
- package/src/librats_node.cpp +1067 -1323
- package/native-src/src/bencode.cpp +0 -485
- package/native-src/src/bencode.h +0 -145
- package/native-src/src/bittorrent.cpp +0 -14
- package/native-src/src/bittorrent.h +0 -74
- package/native-src/src/bt_bitfield.cpp +0 -372
- package/native-src/src/bt_bitfield.h +0 -316
- package/native-src/src/bt_choker.cpp +0 -228
- package/native-src/src/bt_choker.h +0 -147
- package/native-src/src/bt_client.cpp +0 -1047
- package/native-src/src/bt_client.h +0 -445
- package/native-src/src/bt_create_torrent.cpp +0 -677
- package/native-src/src/bt_create_torrent.h +0 -473
- package/native-src/src/bt_extension.cpp +0 -469
- package/native-src/src/bt_extension.h +0 -309
- package/native-src/src/bt_file_storage.cpp +0 -261
- package/native-src/src/bt_file_storage.h +0 -298
- package/native-src/src/bt_handshake.cpp +0 -134
- package/native-src/src/bt_handshake.h +0 -157
- package/native-src/src/bt_messages.cpp +0 -364
- package/native-src/src/bt_messages.h +0 -324
- package/native-src/src/bt_network.cpp +0 -1007
- package/native-src/src/bt_network.h +0 -417
- package/native-src/src/bt_peer_connection.cpp +0 -742
- package/native-src/src/bt_peer_connection.h +0 -592
- package/native-src/src/bt_piece_picker.cpp +0 -786
- package/native-src/src/bt_piece_picker.h +0 -473
- package/native-src/src/bt_resume_data.cpp +0 -410
- package/native-src/src/bt_resume_data.h +0 -249
- package/native-src/src/bt_torrent.cpp +0 -2120
- package/native-src/src/bt_torrent.h +0 -641
- package/native-src/src/bt_torrent_info.cpp +0 -659
- package/native-src/src/bt_torrent_info.h +0 -418
- package/native-src/src/bt_types.h +0 -621
- package/native-src/src/chained_send_buffer.cpp +0 -75
- package/native-src/src/chained_send_buffer.h +0 -137
- package/native-src/src/crypto/hkdf.c +0 -266
- package/native-src/src/crypto/poly1305.h +0 -36
- package/native-src/src/dht.cpp +0 -3311
- package/native-src/src/dht.h +0 -717
- package/native-src/src/disk_io.cpp +0 -632
- package/native-src/src/disk_io.h +0 -315
- package/native-src/src/file_transfer.cpp +0 -1415
- package/native-src/src/file_transfer.h +0 -286
- package/native-src/src/fs.h +0 -108
- package/native-src/src/gossipsub.cpp +0 -1139
- package/native-src/src/gossipsub.h +0 -403
- package/native-src/src/ice.cpp +0 -893
- package/native-src/src/ice.h +0 -559
- package/native-src/src/json.hpp +0 -25526
- package/native-src/src/librats.cpp +0 -2378
- package/native-src/src/librats.h +0 -2324
- package/native-src/src/librats_bittorrent.cpp +0 -601
- package/native-src/src/librats_c.cpp +0 -1557
- package/native-src/src/librats_c.h +0 -323
- package/native-src/src/librats_discovery.cpp +0 -402
- package/native-src/src/librats_encryption.cpp +0 -275
- package/native-src/src/librats_file_transfer.cpp +0 -144
- package/native-src/src/librats_gossipsub.cpp +0 -289
- package/native-src/src/librats_ice.cpp +0 -213
- package/native-src/src/librats_log_macros.h +0 -36
- package/native-src/src/librats_logging.cpp +0 -173
- package/native-src/src/librats_mdns.cpp +0 -166
- package/native-src/src/librats_persistence.cpp +0 -796
- package/native-src/src/librats_portmap.cpp +0 -419
- package/native-src/src/librats_reconnection.cpp +0 -218
- package/native-src/src/librats_statistic.cpp +0 -105
- package/native-src/src/librats_storage.cpp +0 -189
- package/native-src/src/rats_export.h +0 -17
- package/native-src/src/receive_buffer.cpp +0 -82
- package/native-src/src/receive_buffer.h +0 -127
- package/native-src/src/socket.h +0 -228
- package/native-src/src/threadmanager.cpp +0 -105
- package/native-src/src/threadmanager.h +0 -53
- package/native-src/src/tracker.cpp +0 -1264
- package/native-src/src/tracker.h +0 -319
- package/native-src/src/turn.cpp +0 -762
- package/native-src/src/turn.h +0 -460
- package/native-src/src/wakeup_pipe.h +0 -60
- /package/native-src/src/{os.h → librats/util/os.h} +0 -0
|
@@ -1,1047 +0,0 @@
|
|
|
1
|
-
#include "bt_client.h"
|
|
2
|
-
#include "tracker.h"
|
|
3
|
-
#include "logger.h"
|
|
4
|
-
#include "fs.h"
|
|
5
|
-
|
|
6
|
-
#include <chrono>
|
|
7
|
-
#include <algorithm>
|
|
8
|
-
|
|
9
|
-
namespace librats {
|
|
10
|
-
|
|
11
|
-
//=============================================================================
|
|
12
|
-
// Constructor / Destructor
|
|
13
|
-
//=============================================================================
|
|
14
|
-
|
|
15
|
-
BtClient::BtClient()
|
|
16
|
-
: peer_id_(generate_peer_id("-LR0001-"))
|
|
17
|
-
, running_(false)
|
|
18
|
-
, dht_running_(false) {
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
BtClient::BtClient(const BtClientConfig& config)
|
|
22
|
-
: config_(config)
|
|
23
|
-
, peer_id_(generate_peer_id("-LR0001-"))
|
|
24
|
-
, running_(false)
|
|
25
|
-
, dht_running_(false) {
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
BtClient::~BtClient() {
|
|
29
|
-
stop();
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
void BtClient::set_external_dht(DhtClient* dht) {
|
|
33
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
34
|
-
if (running_) {
|
|
35
|
-
LOG_WARN("BtClient", "Cannot set external DHT while client is running");
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
external_dht_ = dht;
|
|
39
|
-
LOG_DEBUG("BtClient", "External DHT client set");
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
//=============================================================================
|
|
43
|
-
// Lifecycle
|
|
44
|
-
//=============================================================================
|
|
45
|
-
|
|
46
|
-
void BtClient::start() {
|
|
47
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
48
|
-
|
|
49
|
-
if (running_) return;
|
|
50
|
-
|
|
51
|
-
running_ = true;
|
|
52
|
-
|
|
53
|
-
// Initialize network manager
|
|
54
|
-
BtNetworkConfig net_config;
|
|
55
|
-
net_config.listen_port = config_.listen_port;
|
|
56
|
-
net_config.max_connections = config_.max_connections;
|
|
57
|
-
net_config.enable_incoming = true;
|
|
58
|
-
net_config.peer_id = peer_id_; // For incoming connections
|
|
59
|
-
|
|
60
|
-
network_manager_ = std::make_unique<BtNetworkManager>(net_config);
|
|
61
|
-
|
|
62
|
-
// Set network callbacks
|
|
63
|
-
network_manager_->set_connected_callback(
|
|
64
|
-
[this](const BtInfoHash& hash, std::shared_ptr<BtPeerConnection> conn,
|
|
65
|
-
socket_t sock, bool incoming) {
|
|
66
|
-
on_peer_connected(hash, conn, sock, incoming);
|
|
67
|
-
}
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
network_manager_->set_disconnected_callback(
|
|
71
|
-
[this](const BtInfoHash& hash, BtPeerConnection* conn) {
|
|
72
|
-
on_peer_disconnected(hash, conn);
|
|
73
|
-
}
|
|
74
|
-
);
|
|
75
|
-
|
|
76
|
-
network_manager_->set_data_callback(
|
|
77
|
-
[this](const BtInfoHash& hash, BtPeerConnection* conn, socket_t sock) {
|
|
78
|
-
on_peer_data(hash, conn, sock);
|
|
79
|
-
}
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
if (!network_manager_->start()) {
|
|
83
|
-
LOG_ERROR("BtClient", "Failed to start network manager");
|
|
84
|
-
running_ = false;
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
LOG_INFO("BtClient", "Network manager started, listening on port " +
|
|
89
|
-
std::to_string(network_manager_->listen_port()));
|
|
90
|
-
|
|
91
|
-
// Start DHT if enabled
|
|
92
|
-
if (config_.enable_dht) {
|
|
93
|
-
if (external_dht_) {
|
|
94
|
-
// Use external DHT client - check if it's already running
|
|
95
|
-
if (external_dht_->is_running()) {
|
|
96
|
-
dht_running_ = true;
|
|
97
|
-
LOG_INFO("BtClient", "Using external DHT client with " +
|
|
98
|
-
std::to_string(external_dht_->get_routing_table_size()) + " nodes");
|
|
99
|
-
} else {
|
|
100
|
-
LOG_WARN("BtClient", "External DHT client provided but not running");
|
|
101
|
-
}
|
|
102
|
-
} else {
|
|
103
|
-
// Create and start our own DHT client
|
|
104
|
-
dht_client_ = std::make_unique<DhtClient>(config_.listen_port, "");
|
|
105
|
-
|
|
106
|
-
if (dht_client_->start()) {
|
|
107
|
-
// Bootstrap with default nodes
|
|
108
|
-
auto bootstrap_nodes = DhtClient::get_default_bootstrap_nodes();
|
|
109
|
-
dht_client_->bootstrap(bootstrap_nodes);
|
|
110
|
-
dht_running_ = true;
|
|
111
|
-
|
|
112
|
-
LOG_INFO("BtClient", "DHT started with " +
|
|
113
|
-
std::to_string(bootstrap_nodes.size()) + " bootstrap nodes");
|
|
114
|
-
} else {
|
|
115
|
-
LOG_ERROR("BtClient", "Failed to start DHT");
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Initialize timing
|
|
121
|
-
last_dht_announce_ = std::chrono::steady_clock::now();
|
|
122
|
-
last_tracker_announce_ = std::chrono::steady_clock::now();
|
|
123
|
-
|
|
124
|
-
// Start tick thread
|
|
125
|
-
tick_thread_ = std::thread(&BtClient::tick_loop, this);
|
|
126
|
-
|
|
127
|
-
if (on_alert_) {
|
|
128
|
-
on_alert_("BitTorrent client started on port " +
|
|
129
|
-
std::to_string(network_manager_->listen_port()));
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
void BtClient::set_resume_data_path(const std::string& path) {
|
|
134
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
135
|
-
config_.resume_data_path = path;
|
|
136
|
-
LOG_INFO("BtClient", "Resume data path set to: " + path);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
void BtClient::stop() {
|
|
140
|
-
{
|
|
141
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
142
|
-
|
|
143
|
-
if (!running_) return;
|
|
144
|
-
|
|
145
|
-
running_ = false;
|
|
146
|
-
dht_running_ = false;
|
|
147
|
-
|
|
148
|
-
// Save resume data for all torrents before stopping
|
|
149
|
-
LOG_INFO("BtClient", "Saving resume data before shutdown...");
|
|
150
|
-
for (auto& [hash, torrent] : torrents_) {
|
|
151
|
-
if (torrent->has_metadata()) {
|
|
152
|
-
torrent->save_resume_data();
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// Stop all torrents
|
|
157
|
-
for (auto& [hash, torrent] : torrents_) {
|
|
158
|
-
torrent->stop();
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// Wait for tick thread
|
|
163
|
-
if (tick_thread_.joinable()) {
|
|
164
|
-
tick_thread_.join();
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Stop network manager
|
|
168
|
-
if (network_manager_) {
|
|
169
|
-
network_manager_->stop();
|
|
170
|
-
network_manager_.reset();
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// Stop DHT (only if we own it - not external)
|
|
174
|
-
if (dht_client_) {
|
|
175
|
-
dht_client_->stop();
|
|
176
|
-
dht_client_.reset();
|
|
177
|
-
}
|
|
178
|
-
// Note: external_dht_ is not stopped - lifecycle managed by caller
|
|
179
|
-
|
|
180
|
-
// Clear tracker managers
|
|
181
|
-
tracker_managers_.clear();
|
|
182
|
-
|
|
183
|
-
// Clear torrents (already stopped above)
|
|
184
|
-
{
|
|
185
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
186
|
-
torrents_.clear();
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// Clear pending removals
|
|
190
|
-
{
|
|
191
|
-
std::lock_guard<std::mutex> lock(removal_mutex_);
|
|
192
|
-
pending_removals_.clear();
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
if (on_alert_) {
|
|
196
|
-
on_alert_("BitTorrent client stopped");
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
//=============================================================================
|
|
201
|
-
// Torrent Management
|
|
202
|
-
//=============================================================================
|
|
203
|
-
|
|
204
|
-
Torrent::Ptr BtClient::add_torrent_file(const std::string& path,
|
|
205
|
-
const std::string& save_path) {
|
|
206
|
-
auto info = TorrentInfo::from_file(path);
|
|
207
|
-
if (!info) {
|
|
208
|
-
if (on_alert_) {
|
|
209
|
-
on_alert_("Failed to parse torrent file: " + path);
|
|
210
|
-
}
|
|
211
|
-
return nullptr;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
return add_torrent(*info, save_path);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
Torrent::Ptr BtClient::add_torrent(const TorrentInfo& info,
|
|
218
|
-
const std::string& save_path) {
|
|
219
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
220
|
-
|
|
221
|
-
// Check if already exists
|
|
222
|
-
auto it = torrents_.find(info.info_hash());
|
|
223
|
-
if (it != torrents_.end()) {
|
|
224
|
-
return it->second;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
auto torrent = create_torrent(info, save_path);
|
|
228
|
-
torrents_[info.info_hash()] = torrent;
|
|
229
|
-
|
|
230
|
-
// Register with network manager
|
|
231
|
-
if (network_manager_ && info.has_metadata()) {
|
|
232
|
-
network_manager_->register_torrent(info.info_hash(), peer_id_, info.num_pieces());
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
// Create tracker manager
|
|
236
|
-
tracker_managers_[info.info_hash()] = std::make_unique<TrackerManager>(info);
|
|
237
|
-
|
|
238
|
-
// Check if files already exist before starting - to avoid overwriting existing data
|
|
239
|
-
// This is similar to libtorrent's async_check_files behavior
|
|
240
|
-
bool files_exist = false;
|
|
241
|
-
std::string effective_save_path = save_path.empty() ? config_.download_path : save_path;
|
|
242
|
-
const auto& files = info.files().files();
|
|
243
|
-
for (const auto& f : files) {
|
|
244
|
-
std::string file_path = combine_paths(effective_save_path, f.path);
|
|
245
|
-
if (file_exists(file_path)) {
|
|
246
|
-
files_exist = true;
|
|
247
|
-
break;
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
if (running_) {
|
|
252
|
-
if (files_exist) {
|
|
253
|
-
// Files exist - check them before starting download to avoid overwriting
|
|
254
|
-
LOG_INFO("BtClient", "Files exist for " + info.name() +
|
|
255
|
-
", checking before download to avoid overwriting...");
|
|
256
|
-
torrent->check_files_async(
|
|
257
|
-
[this, hash = info.info_hash()](uint32_t have, uint32_t total) {
|
|
258
|
-
LOG_INFO("BtClient", "File check complete: " +
|
|
259
|
-
std::to_string(have) + "/" + std::to_string(total) + " pieces");
|
|
260
|
-
|
|
261
|
-
auto t = get_torrent(hash);
|
|
262
|
-
if (t) {
|
|
263
|
-
// Now start the torrent after file check completes
|
|
264
|
-
t->start();
|
|
265
|
-
|
|
266
|
-
// Announce after start
|
|
267
|
-
if (dht_running_) {
|
|
268
|
-
find_peers_dht(hash);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// Save resume data after check
|
|
272
|
-
t->save_resume_data();
|
|
273
|
-
}
|
|
274
|
-
},
|
|
275
|
-
nullptr
|
|
276
|
-
);
|
|
277
|
-
} else {
|
|
278
|
-
// No files exist - safe to start download immediately
|
|
279
|
-
torrent->start();
|
|
280
|
-
|
|
281
|
-
// Announce to DHT
|
|
282
|
-
if (dht_running_) {
|
|
283
|
-
find_peers_dht(info.info_hash());
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
// Announce to trackers (regardless of file check status)
|
|
288
|
-
auto& tracker_mgr = tracker_managers_[info.info_hash()];
|
|
289
|
-
if (tracker_mgr) {
|
|
290
|
-
TrackerRequest req;
|
|
291
|
-
req.info_hash = info.info_hash();
|
|
292
|
-
req.peer_id = peer_id_;
|
|
293
|
-
req.port = network_manager_ ? network_manager_->listen_port() : config_.listen_port;
|
|
294
|
-
req.uploaded = 0;
|
|
295
|
-
req.downloaded = 0;
|
|
296
|
-
req.left = info.total_size();
|
|
297
|
-
req.event = TrackerEvent::STARTED;
|
|
298
|
-
req.numwant = 50;
|
|
299
|
-
|
|
300
|
-
tracker_mgr->announce(req, [this, hash = info.info_hash()](
|
|
301
|
-
const TrackerResponse& response, const std::string& tracker_url) {
|
|
302
|
-
|
|
303
|
-
if (response.success && !response.peers.empty()) {
|
|
304
|
-
LOG_INFO("BtClient", "Got " + std::to_string(response.peers.size()) +
|
|
305
|
-
" peers from tracker " + tracker_url);
|
|
306
|
-
|
|
307
|
-
auto torrent = get_torrent(hash);
|
|
308
|
-
if (torrent) {
|
|
309
|
-
for (const auto& peer : response.peers) {
|
|
310
|
-
torrent->add_peer(peer.ip, peer.port);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
});
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
if (on_torrent_added_) {
|
|
319
|
-
on_torrent_added_(torrent);
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
LOG_INFO("BtClient", "Added torrent: " + info.name() + " (" +
|
|
323
|
-
info_hash_to_hex(info.info_hash()).substr(0, 8) + "...)");
|
|
324
|
-
|
|
325
|
-
return torrent;
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
Torrent::Ptr BtClient::add_magnet(const std::string& magnet_uri,
|
|
329
|
-
const std::string& save_path,
|
|
330
|
-
bool skip_dht_search) {
|
|
331
|
-
auto info = TorrentInfo::from_magnet(magnet_uri);
|
|
332
|
-
if (!info) {
|
|
333
|
-
if (on_alert_) {
|
|
334
|
-
on_alert_("Failed to parse magnet URI");
|
|
335
|
-
}
|
|
336
|
-
return nullptr;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
340
|
-
|
|
341
|
-
// Check if already exists
|
|
342
|
-
auto it = torrents_.find(info->info_hash());
|
|
343
|
-
if (it != torrents_.end()) {
|
|
344
|
-
return it->second;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
// Create torrent without full metadata
|
|
348
|
-
TorrentConfig torrent_config;
|
|
349
|
-
// For metadata-only mode (skip_dht_search=true with empty save_path), keep save_path empty
|
|
350
|
-
// Otherwise use default download path if not specified
|
|
351
|
-
if (skip_dht_search && save_path.empty()) {
|
|
352
|
-
// Metadata-only mode - keep empty save_path for proper detection
|
|
353
|
-
torrent_config.save_path = "";
|
|
354
|
-
} else {
|
|
355
|
-
torrent_config.save_path = save_path.empty() ? config_.download_path : save_path;
|
|
356
|
-
}
|
|
357
|
-
torrent_config.resume_data_path = config_.resume_data_path;
|
|
358
|
-
torrent_config.max_connections = config_.max_connections_per_torrent;
|
|
359
|
-
torrent_config.max_uploads = config_.max_uploads;
|
|
360
|
-
|
|
361
|
-
auto torrent = std::make_shared<Torrent>(
|
|
362
|
-
info->info_hash(),
|
|
363
|
-
info->name(),
|
|
364
|
-
torrent_config,
|
|
365
|
-
peer_id_
|
|
366
|
-
);
|
|
367
|
-
|
|
368
|
-
torrents_[info->info_hash()] = torrent;
|
|
369
|
-
|
|
370
|
-
if (running_) {
|
|
371
|
-
torrent->start();
|
|
372
|
-
|
|
373
|
-
// Find peers via DHT for metadata (skip if using direct peer connection)
|
|
374
|
-
if (dht_running_ && !skip_dht_search) {
|
|
375
|
-
find_peers_dht(info->info_hash());
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
if (on_torrent_added_) {
|
|
380
|
-
on_torrent_added_(torrent);
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
LOG_INFO("BtClient", "Added magnet: " + info->name() + " (" +
|
|
384
|
-
info_hash_to_hex(info->info_hash()).substr(0, 8) + "...)");
|
|
385
|
-
|
|
386
|
-
return torrent;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
Torrent::Ptr BtClient::add_torrent_with_resume(
|
|
390
|
-
const TorrentInfo& info,
|
|
391
|
-
const TorrentResumeData& resume_data,
|
|
392
|
-
const std::string& save_path) {
|
|
393
|
-
|
|
394
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
395
|
-
|
|
396
|
-
// Check if already exists
|
|
397
|
-
auto it = torrents_.find(info.info_hash());
|
|
398
|
-
if (it != torrents_.end()) {
|
|
399
|
-
return it->second;
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
// Create torrent with resume-specified or provided save path
|
|
403
|
-
std::string effective_save_path = save_path.empty()
|
|
404
|
-
? (resume_data.save_path.empty() ? config_.download_path : resume_data.save_path)
|
|
405
|
-
: save_path;
|
|
406
|
-
|
|
407
|
-
auto torrent = create_torrent(info, effective_save_path);
|
|
408
|
-
|
|
409
|
-
// Load resume data before starting
|
|
410
|
-
if (!torrent->load_resume_data(resume_data)) {
|
|
411
|
-
LOG_WARN("BtClient", "Failed to load resume data for " + info.name());
|
|
412
|
-
} else {
|
|
413
|
-
LOG_INFO("BtClient", "Loaded resume data for " + info.name() +
|
|
414
|
-
": " + std::to_string(resume_data.have_pieces.count()) + " pieces");
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
torrents_[info.info_hash()] = torrent;
|
|
418
|
-
|
|
419
|
-
// Register with network manager
|
|
420
|
-
if (network_manager_ && info.has_metadata()) {
|
|
421
|
-
network_manager_->register_torrent(info.info_hash(), peer_id_, info.num_pieces());
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
// Create tracker manager
|
|
425
|
-
tracker_managers_[info.info_hash()] = std::make_unique<TrackerManager>(info);
|
|
426
|
-
|
|
427
|
-
if (running_) {
|
|
428
|
-
torrent->start();
|
|
429
|
-
|
|
430
|
-
// Announce to DHT
|
|
431
|
-
if (dht_running_) {
|
|
432
|
-
find_peers_dht(info.info_hash());
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
if (on_torrent_added_) {
|
|
437
|
-
on_torrent_added_(torrent);
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
LOG_INFO("BtClient", "Added torrent with resume: " + info.name() + " (" +
|
|
441
|
-
info_hash_to_hex(info.info_hash()).substr(0, 8) + "...)");
|
|
442
|
-
|
|
443
|
-
return torrent;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
Torrent::Ptr BtClient::add_torrent_auto_resume(
|
|
447
|
-
const TorrentInfo& info,
|
|
448
|
-
const std::string& save_path,
|
|
449
|
-
bool check_files) {
|
|
450
|
-
|
|
451
|
-
std::string effective_save_path = save_path.empty() ? config_.download_path : save_path;
|
|
452
|
-
|
|
453
|
-
// Try to load resume data
|
|
454
|
-
std::string resume_path = get_resume_file_path(effective_save_path, info.info_hash());
|
|
455
|
-
std::string error;
|
|
456
|
-
auto resume_data = read_resume_data_file(resume_path, &error);
|
|
457
|
-
|
|
458
|
-
if (resume_data) {
|
|
459
|
-
LOG_INFO("BtClient", "Found resume data for " + info.name());
|
|
460
|
-
return add_torrent_with_resume(info, *resume_data, effective_save_path);
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
LOG_DEBUG("BtClient", "No resume data for " + info.name() + ": " + error);
|
|
464
|
-
|
|
465
|
-
// Add torrent normally
|
|
466
|
-
auto torrent = add_torrent(info, effective_save_path);
|
|
467
|
-
|
|
468
|
-
// If files might exist, check them
|
|
469
|
-
if (torrent && check_files) {
|
|
470
|
-
// Check if any files already exist
|
|
471
|
-
bool files_exist = false;
|
|
472
|
-
const auto& files = info.files().files();
|
|
473
|
-
for (const auto& f : files) {
|
|
474
|
-
std::string file_path = combine_paths(effective_save_path, f.path);
|
|
475
|
-
if (file_exists(file_path)) {
|
|
476
|
-
files_exist = true;
|
|
477
|
-
break;
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
if (files_exist) {
|
|
482
|
-
LOG_INFO("BtClient", "Files exist for " + info.name() + ", checking...");
|
|
483
|
-
torrent->check_files_async(
|
|
484
|
-
[this, hash = info.info_hash()](uint32_t have, uint32_t total) {
|
|
485
|
-
LOG_INFO("BtClient", "File check complete: " +
|
|
486
|
-
std::to_string(have) + "/" + std::to_string(total) + " pieces");
|
|
487
|
-
|
|
488
|
-
// Save resume data after check
|
|
489
|
-
auto t = get_torrent(hash);
|
|
490
|
-
if (t) {
|
|
491
|
-
t->save_resume_data();
|
|
492
|
-
}
|
|
493
|
-
},
|
|
494
|
-
nullptr
|
|
495
|
-
);
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
return torrent;
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
Torrent::Ptr BtClient::add_torrent_for_seeding(
|
|
503
|
-
const TorrentInfo& info,
|
|
504
|
-
const std::string& save_path) {
|
|
505
|
-
|
|
506
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
507
|
-
|
|
508
|
-
// Check if already exists
|
|
509
|
-
auto it = torrents_.find(info.info_hash());
|
|
510
|
-
if (it != torrents_.end()) {
|
|
511
|
-
return it->second;
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
LOG_INFO("BtClient", "Adding torrent for seeding: " + info.name());
|
|
515
|
-
|
|
516
|
-
// Create torrent with seed_mode enabled
|
|
517
|
-
TorrentConfig torrent_config;
|
|
518
|
-
torrent_config.save_path = save_path.empty() ? config_.download_path : save_path;
|
|
519
|
-
torrent_config.resume_data_path = config_.resume_data_path;
|
|
520
|
-
torrent_config.max_connections = config_.max_connections_per_torrent;
|
|
521
|
-
torrent_config.max_uploads = config_.max_uploads;
|
|
522
|
-
torrent_config.seed_mode = true; // Key difference: seed_mode enabled
|
|
523
|
-
|
|
524
|
-
auto torrent = std::make_shared<Torrent>(info, torrent_config, peer_id_);
|
|
525
|
-
torrents_[info.info_hash()] = torrent;
|
|
526
|
-
|
|
527
|
-
// Register with network manager
|
|
528
|
-
if (network_manager_ && info.has_metadata()) {
|
|
529
|
-
network_manager_->register_torrent(info.info_hash(), peer_id_, info.num_pieces());
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
// Create tracker manager
|
|
533
|
-
tracker_managers_[info.info_hash()] = std::make_unique<TrackerManager>(info);
|
|
534
|
-
|
|
535
|
-
if (running_) {
|
|
536
|
-
torrent->start();
|
|
537
|
-
|
|
538
|
-
// Announce to DHT
|
|
539
|
-
if (dht_running_) {
|
|
540
|
-
find_peers_dht(info.info_hash());
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
// Announce to trackers with completed event (since we're seeding)
|
|
544
|
-
auto& tracker_mgr = tracker_managers_[info.info_hash()];
|
|
545
|
-
if (tracker_mgr) {
|
|
546
|
-
TrackerRequest req;
|
|
547
|
-
req.info_hash = info.info_hash();
|
|
548
|
-
req.peer_id = peer_id_;
|
|
549
|
-
req.port = network_manager_ ? network_manager_->listen_port() : config_.listen_port;
|
|
550
|
-
req.uploaded = 0;
|
|
551
|
-
req.downloaded = 0;
|
|
552
|
-
req.left = 0; // 0 = seeding
|
|
553
|
-
req.event = TrackerEvent::COMPLETED;
|
|
554
|
-
req.numwant = 50;
|
|
555
|
-
|
|
556
|
-
tracker_mgr->announce(req, [this, hash = info.info_hash()](
|
|
557
|
-
const TrackerResponse& response, const std::string& tracker_url) {
|
|
558
|
-
|
|
559
|
-
if (response.success && !response.peers.empty()) {
|
|
560
|
-
LOG_INFO("BtClient", "Got " + std::to_string(response.peers.size()) +
|
|
561
|
-
" peers from tracker " + tracker_url);
|
|
562
|
-
|
|
563
|
-
auto torrent = get_torrent(hash);
|
|
564
|
-
if (torrent) {
|
|
565
|
-
for (const auto& peer : response.peers) {
|
|
566
|
-
torrent->add_peer(peer.ip, peer.port);
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
});
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
if (on_torrent_added_) {
|
|
575
|
-
on_torrent_added_(torrent);
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
LOG_INFO("BtClient", "Added torrent for seeding: " + info.name() + " (" +
|
|
579
|
-
info_hash_to_hex(info.info_hash()).substr(0, 8) + "...)");
|
|
580
|
-
|
|
581
|
-
return torrent;
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
void BtClient::save_all_resume_data() {
|
|
585
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
586
|
-
|
|
587
|
-
LOG_INFO("BtClient", "Saving resume data for " + std::to_string(torrents_.size()) + " torrents");
|
|
588
|
-
|
|
589
|
-
for (auto& [hash, torrent] : torrents_) {
|
|
590
|
-
if (torrent->has_metadata()) {
|
|
591
|
-
torrent->save_resume_data();
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
void BtClient::remove_torrent(const BtInfoHash& info_hash, bool delete_files) {
|
|
597
|
-
Torrent::Ptr torrent;
|
|
598
|
-
|
|
599
|
-
{
|
|
600
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
601
|
-
|
|
602
|
-
LOG_INFO("BtClient", "Removing torrent: " + info_hash_to_hex(info_hash).substr(0, 8) + "...");
|
|
603
|
-
|
|
604
|
-
auto it = torrents_.find(info_hash);
|
|
605
|
-
if (it == torrents_.end()) {
|
|
606
|
-
return;
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
torrent = it->second; // Keep a reference before erasing
|
|
610
|
-
torrent->stop();
|
|
611
|
-
|
|
612
|
-
// Remove tracker manager
|
|
613
|
-
tracker_managers_.erase(info_hash);
|
|
614
|
-
|
|
615
|
-
if (delete_files) {
|
|
616
|
-
// TODO: Delete downloaded files
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
torrents_.erase(it);
|
|
620
|
-
}
|
|
621
|
-
// mutex_ is now RELEASED - important to avoid deadlock!
|
|
622
|
-
// The callbacks below may try to acquire mutex_ via get_torrent()
|
|
623
|
-
|
|
624
|
-
// Unregister from network manager OUTSIDE the mutex
|
|
625
|
-
// This invokes on_disconnected_ callbacks which call on_peer_disconnected()
|
|
626
|
-
// which needs to acquire mutex_ via get_torrent()
|
|
627
|
-
if (network_manager_) {
|
|
628
|
-
network_manager_->unregister_torrent(info_hash);
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
// Cancel any active DHT searches/announces for this torrent
|
|
632
|
-
DhtClient* dht = external_dht_ ? external_dht_ : dht_client_.get();
|
|
633
|
-
if (dht) {
|
|
634
|
-
dht->cancel_search(info_hash);
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
if (on_torrent_removed_) {
|
|
638
|
-
on_torrent_removed_(info_hash);
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
LOG_INFO("BtClient", "Removed torrent: " + info_hash_to_hex(info_hash).substr(0, 8) + "...");
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
void BtClient::mark_for_removal(const BtInfoHash& info_hash) {
|
|
645
|
-
std::lock_guard<std::mutex> lock(removal_mutex_);
|
|
646
|
-
|
|
647
|
-
// Avoid duplicates
|
|
648
|
-
for (const auto& hash : pending_removals_) {
|
|
649
|
-
if (hash == info_hash) {
|
|
650
|
-
return;
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
pending_removals_.push_back(info_hash);
|
|
655
|
-
LOG_DEBUG("BtClient", "Marked torrent for removal: " +
|
|
656
|
-
info_hash_to_hex(info_hash).substr(0, 8) + "...");
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
Torrent::Ptr BtClient::get_torrent(const BtInfoHash& info_hash) {
|
|
660
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
661
|
-
|
|
662
|
-
auto it = torrents_.find(info_hash);
|
|
663
|
-
if (it != torrents_.end()) {
|
|
664
|
-
return it->second;
|
|
665
|
-
}
|
|
666
|
-
return nullptr;
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
std::vector<Torrent::Ptr> BtClient::get_torrents() {
|
|
670
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
671
|
-
|
|
672
|
-
std::vector<Torrent::Ptr> result;
|
|
673
|
-
result.reserve(torrents_.size());
|
|
674
|
-
for (const auto& [hash, torrent] : torrents_) {
|
|
675
|
-
result.push_back(torrent);
|
|
676
|
-
}
|
|
677
|
-
return result;
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
size_t BtClient::num_torrents() const {
|
|
681
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
682
|
-
return torrents_.size();
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
//=============================================================================
|
|
686
|
-
// Configuration
|
|
687
|
-
//=============================================================================
|
|
688
|
-
|
|
689
|
-
void BtClient::set_download_limit(uint64_t bytes_per_sec) {
|
|
690
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
691
|
-
config_.download_limit = bytes_per_sec;
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
void BtClient::set_upload_limit(uint64_t bytes_per_sec) {
|
|
695
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
696
|
-
config_.upload_limit = bytes_per_sec;
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
//=============================================================================
|
|
700
|
-
// Statistics
|
|
701
|
-
//=============================================================================
|
|
702
|
-
|
|
703
|
-
uint64_t BtClient::total_download_rate() const {
|
|
704
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
705
|
-
|
|
706
|
-
uint64_t total = 0;
|
|
707
|
-
for (const auto& [hash, torrent] : torrents_) {
|
|
708
|
-
total += torrent->stats().download_rate;
|
|
709
|
-
}
|
|
710
|
-
return total;
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
uint64_t BtClient::total_upload_rate() const {
|
|
714
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
715
|
-
|
|
716
|
-
uint64_t total = 0;
|
|
717
|
-
for (const auto& [hash, torrent] : torrents_) {
|
|
718
|
-
total += torrent->stats().upload_rate;
|
|
719
|
-
}
|
|
720
|
-
return total;
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
size_t BtClient::total_peers() const {
|
|
724
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
725
|
-
|
|
726
|
-
size_t total = 0;
|
|
727
|
-
for (const auto& [hash, torrent] : torrents_) {
|
|
728
|
-
total += torrent->num_peers();
|
|
729
|
-
}
|
|
730
|
-
return total;
|
|
731
|
-
}
|
|
732
|
-
|
|
733
|
-
//=============================================================================
|
|
734
|
-
// DHT
|
|
735
|
-
//=============================================================================
|
|
736
|
-
|
|
737
|
-
void BtClient::add_dht_node(const std::string& host, uint16_t port) {
|
|
738
|
-
DhtClient* dht = external_dht_ ? external_dht_ : dht_client_.get();
|
|
739
|
-
if (dht) {
|
|
740
|
-
std::vector<Peer> nodes = {{host, port}};
|
|
741
|
-
dht->bootstrap(nodes);
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
size_t BtClient::dht_node_count() const {
|
|
746
|
-
DhtClient* dht = external_dht_ ? external_dht_ : dht_client_.get();
|
|
747
|
-
if (dht) {
|
|
748
|
-
return dht->get_routing_table_size();
|
|
749
|
-
}
|
|
750
|
-
return 0;
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
void BtClient::announce_to_dht(const BtInfoHash& info_hash) {
|
|
754
|
-
DhtClient* dht = external_dht_ ? external_dht_ : dht_client_.get();
|
|
755
|
-
if (!dht || !dht_running_) {
|
|
756
|
-
return;
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
// Convert BtInfoHash to InfoHash (they're the same type)
|
|
760
|
-
InfoHash dht_hash;
|
|
761
|
-
std::copy(info_hash.begin(), info_hash.end(), dht_hash.begin());
|
|
762
|
-
|
|
763
|
-
uint16_t port = network_manager_ ? network_manager_->listen_port() : config_.listen_port;
|
|
764
|
-
|
|
765
|
-
dht->announce_peer(dht_hash, port,
|
|
766
|
-
[this, info_hash](const std::vector<Peer>& peers, const InfoHash&) {
|
|
767
|
-
on_dht_peers_found(peers, info_hash);
|
|
768
|
-
}
|
|
769
|
-
);
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
void BtClient::find_peers_dht(const BtInfoHash& info_hash) {
|
|
773
|
-
DhtClient* dht = external_dht_ ? external_dht_ : dht_client_.get();
|
|
774
|
-
if (!dht || !dht_running_) {
|
|
775
|
-
return;
|
|
776
|
-
}
|
|
777
|
-
|
|
778
|
-
InfoHash dht_hash;
|
|
779
|
-
std::copy(info_hash.begin(), info_hash.end(), dht_hash.begin());
|
|
780
|
-
|
|
781
|
-
dht->find_peers(dht_hash,
|
|
782
|
-
[this, info_hash](const std::vector<Peer>& peers, const InfoHash&) {
|
|
783
|
-
on_dht_peers_found(peers, info_hash);
|
|
784
|
-
}
|
|
785
|
-
);
|
|
786
|
-
|
|
787
|
-
LOG_DEBUG("BtClient", "Started DHT peer search for " +
|
|
788
|
-
info_hash_to_hex(info_hash).substr(0, 8) + "...");
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
void BtClient::on_dht_peers_found(const std::vector<Peer>& peers, const InfoHash& info_hash) {
|
|
792
|
-
if (peers.empty()) {
|
|
793
|
-
return;
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
// Build peer list string for logging (show up to 5 peers)
|
|
797
|
-
std::string peer_list;
|
|
798
|
-
size_t show_count = (std::min)(peers.size(), static_cast<size_t>(5));
|
|
799
|
-
for (size_t i = 0; i < show_count; ++i) {
|
|
800
|
-
if (i > 0) peer_list += ", ";
|
|
801
|
-
peer_list += peers[i].ip + ":" + std::to_string(peers[i].port);
|
|
802
|
-
}
|
|
803
|
-
if (peers.size() > 5) {
|
|
804
|
-
peer_list += ", ...";
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
LOG_INFO("BtClient", "DHT found " + std::to_string(peers.size()) + " peers for " +
|
|
808
|
-
node_id_to_hex(info_hash).substr(0, 8) + "...: " + peer_list);
|
|
809
|
-
|
|
810
|
-
BtInfoHash bt_hash;
|
|
811
|
-
std::copy(info_hash.begin(), info_hash.end(), bt_hash.begin());
|
|
812
|
-
|
|
813
|
-
auto torrent = get_torrent(bt_hash);
|
|
814
|
-
if (torrent) {
|
|
815
|
-
for (const auto& peer : peers) {
|
|
816
|
-
torrent->add_peer(peer.ip, peer.port);
|
|
817
|
-
}
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
//=============================================================================
|
|
822
|
-
// Internal Methods - Network Callbacks
|
|
823
|
-
//=============================================================================
|
|
824
|
-
|
|
825
|
-
void BtClient::on_peer_connected(const BtInfoHash& info_hash,
|
|
826
|
-
std::shared_ptr<BtPeerConnection> connection,
|
|
827
|
-
socket_t socket, bool is_incoming) {
|
|
828
|
-
auto torrent = get_torrent(info_hash);
|
|
829
|
-
if (!torrent) {
|
|
830
|
-
LOG_DEBUG("BtClient", "Peer connected for unknown torrent");
|
|
831
|
-
if (network_manager_) {
|
|
832
|
-
network_manager_->close_connection(socket);
|
|
833
|
-
}
|
|
834
|
-
return;
|
|
835
|
-
}
|
|
836
|
-
|
|
837
|
-
LOG_INFO("BtClient", "Peer connected: " + connection->ip() + ":" +
|
|
838
|
-
std::to_string(connection->port()) +
|
|
839
|
-
(is_incoming ? " (incoming)" : " (outgoing)") +
|
|
840
|
-
" state=" + peer_state_to_string(connection->state()));
|
|
841
|
-
|
|
842
|
-
// NOTE: Do NOT call set_socket() here! The socket was already set by
|
|
843
|
-
// NetworkManager when the connection was created. Calling set_socket()
|
|
844
|
-
// again would reset the state from Connected back to Handshaking,
|
|
845
|
-
// breaking the torrent download logic.
|
|
846
|
-
|
|
847
|
-
// Hand connection to torrent - it will manage from here
|
|
848
|
-
// Both network manager and torrent share ownership via shared_ptr
|
|
849
|
-
// Torrent will setup callbacks and send extension handshake
|
|
850
|
-
torrent->add_connection(connection);
|
|
851
|
-
}
|
|
852
|
-
|
|
853
|
-
void BtClient::on_peer_disconnected(const BtInfoHash& info_hash,
|
|
854
|
-
BtPeerConnection* connection) {
|
|
855
|
-
LOG_DEBUG("BtClient", "Peer disconnected: " + connection->ip());
|
|
856
|
-
|
|
857
|
-
// Remove connection from torrent
|
|
858
|
-
auto torrent = get_torrent(info_hash);
|
|
859
|
-
if (torrent) {
|
|
860
|
-
torrent->remove_connection(connection);
|
|
861
|
-
}
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
void BtClient::on_peer_data(const BtInfoHash& info_hash,
|
|
865
|
-
BtPeerConnection* connection,
|
|
866
|
-
socket_t socket) {
|
|
867
|
-
// Data is already processed by connection->process_incoming()
|
|
868
|
-
// Send data is already in connection->send_buffer() and will be
|
|
869
|
-
// sent by NetworkManager's flush_send_buffer() - no action needed here
|
|
870
|
-
(void)info_hash;
|
|
871
|
-
(void)connection;
|
|
872
|
-
(void)socket;
|
|
873
|
-
}
|
|
874
|
-
|
|
875
|
-
void BtClient::connect_pending_peers() {
|
|
876
|
-
if (!network_manager_) return;
|
|
877
|
-
|
|
878
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
879
|
-
|
|
880
|
-
for (auto& [hash, torrent] : torrents_) {
|
|
881
|
-
if (!torrent->is_active()) continue;
|
|
882
|
-
if (!torrent->has_metadata()) continue;
|
|
883
|
-
|
|
884
|
-
// Get pending peers from torrent and initiate connections
|
|
885
|
-
// The torrent stores pending_peers_ internally
|
|
886
|
-
// We need to expose them or have torrent request connections
|
|
887
|
-
|
|
888
|
-
auto info = torrent->info();
|
|
889
|
-
if (!info) continue;
|
|
890
|
-
|
|
891
|
-
// For now, we rely on torrent's add_peer which adds to pending_peers_
|
|
892
|
-
// The connection is initiated here by calling network_manager_->connect_peer
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
void BtClient::announce_torrents_to_trackers() {
|
|
897
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
898
|
-
|
|
899
|
-
for (auto& [hash, torrent] : torrents_) {
|
|
900
|
-
if (!torrent->is_active()) continue;
|
|
901
|
-
|
|
902
|
-
// Skip metadata-only torrents (empty save_path means only fetching metadata)
|
|
903
|
-
if (torrent->save_path().empty()) continue;
|
|
904
|
-
|
|
905
|
-
auto tracker_it = tracker_managers_.find(hash);
|
|
906
|
-
if (tracker_it == tracker_managers_.end()) continue;
|
|
907
|
-
|
|
908
|
-
auto& tracker_mgr = tracker_it->second;
|
|
909
|
-
if (!tracker_mgr->should_announce()) continue;
|
|
910
|
-
|
|
911
|
-
auto stats = torrent->stats();
|
|
912
|
-
auto info = torrent->info();
|
|
913
|
-
if (!info) continue;
|
|
914
|
-
|
|
915
|
-
TrackerRequest req;
|
|
916
|
-
req.info_hash = hash;
|
|
917
|
-
req.peer_id = peer_id_;
|
|
918
|
-
req.port = network_manager_ ? network_manager_->listen_port() : config_.listen_port;
|
|
919
|
-
req.uploaded = stats.total_uploaded;
|
|
920
|
-
req.downloaded = stats.total_downloaded;
|
|
921
|
-
req.left = stats.total_size - stats.bytes_done;
|
|
922
|
-
req.event = TrackerEvent::NONE;
|
|
923
|
-
req.numwant = 50;
|
|
924
|
-
|
|
925
|
-
tracker_mgr->announce(req, [this, hash](
|
|
926
|
-
const TrackerResponse& response, const std::string& tracker_url) {
|
|
927
|
-
|
|
928
|
-
if (response.success && !response.peers.empty()) {
|
|
929
|
-
LOG_INFO("BtClient", "Got " + std::to_string(response.peers.size()) +
|
|
930
|
-
" peers from tracker");
|
|
931
|
-
|
|
932
|
-
auto torrent = get_torrent(hash);
|
|
933
|
-
if (torrent) {
|
|
934
|
-
for (const auto& peer : response.peers) {
|
|
935
|
-
torrent->add_peer(peer.ip, peer.port);
|
|
936
|
-
}
|
|
937
|
-
}
|
|
938
|
-
}
|
|
939
|
-
});
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
|
|
943
|
-
//=============================================================================
|
|
944
|
-
// Internal Methods
|
|
945
|
-
//=============================================================================
|
|
946
|
-
|
|
947
|
-
void BtClient::tick_loop() {
|
|
948
|
-
LOG_INFO("BtClient", "Tick loop started");
|
|
949
|
-
|
|
950
|
-
while (running_) {
|
|
951
|
-
auto now = std::chrono::steady_clock::now();
|
|
952
|
-
|
|
953
|
-
// Process deferred removals (outside main mutex to avoid deadlocks)
|
|
954
|
-
{
|
|
955
|
-
std::vector<BtInfoHash> to_remove;
|
|
956
|
-
{
|
|
957
|
-
std::lock_guard<std::mutex> lock(removal_mutex_);
|
|
958
|
-
to_remove = std::move(pending_removals_);
|
|
959
|
-
pending_removals_.clear();
|
|
960
|
-
}
|
|
961
|
-
|
|
962
|
-
for (const auto& hash : to_remove) {
|
|
963
|
-
remove_torrent(hash);
|
|
964
|
-
}
|
|
965
|
-
}
|
|
966
|
-
|
|
967
|
-
{
|
|
968
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
969
|
-
|
|
970
|
-
// Tick all torrents
|
|
971
|
-
for (auto& [hash, torrent] : torrents_) {
|
|
972
|
-
torrent->tick();
|
|
973
|
-
}
|
|
974
|
-
|
|
975
|
-
// Connect pending peers (for both magnet and regular torrents)
|
|
976
|
-
for (auto& [hash, torrent] : torrents_) {
|
|
977
|
-
if (!torrent->is_active()) continue;
|
|
978
|
-
|
|
979
|
-
auto pending = torrent->get_pending_peers();
|
|
980
|
-
if (pending.empty()) continue;
|
|
981
|
-
|
|
982
|
-
size_t connected = torrent->num_peers();
|
|
983
|
-
size_t max_conn = config_.max_connections_per_torrent;
|
|
984
|
-
|
|
985
|
-
// Connect to pending peers
|
|
986
|
-
for (const auto& [ip, port] : pending) {
|
|
987
|
-
if (connected >= max_conn) break;
|
|
988
|
-
|
|
989
|
-
// For magnet links without metadata, num_pieces is 0
|
|
990
|
-
uint32_t num_pieces = 0;
|
|
991
|
-
if (torrent->has_metadata() && torrent->info()) {
|
|
992
|
-
num_pieces = torrent->info()->num_pieces();
|
|
993
|
-
}
|
|
994
|
-
|
|
995
|
-
if (network_manager_->connect_peer(ip, port, hash, peer_id_, num_pieces)) {
|
|
996
|
-
LOG_DEBUG("BtClient", "Connecting to peer " + ip + ":" + std::to_string(port));
|
|
997
|
-
++connected;
|
|
998
|
-
}
|
|
999
|
-
}
|
|
1000
|
-
|
|
1001
|
-
// Clear pending peers after attempting connections
|
|
1002
|
-
torrent->clear_pending_peers();
|
|
1003
|
-
}
|
|
1004
|
-
}
|
|
1005
|
-
|
|
1006
|
-
// Periodic DHT announces (every 15 minutes)
|
|
1007
|
-
// Skip metadata-only torrents (empty save_path) to avoid unnecessary network traffic
|
|
1008
|
-
auto dht_elapsed = std::chrono::duration_cast<std::chrono::minutes>(
|
|
1009
|
-
now - last_dht_announce_).count();
|
|
1010
|
-
if (dht_elapsed >= 15 && dht_running_) {
|
|
1011
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
1012
|
-
for (auto& [hash, torrent] : torrents_) {
|
|
1013
|
-
// Skip metadata-only torrents (empty save_path means only fetching metadata)
|
|
1014
|
-
if (torrent->is_active() && !torrent->save_path().empty()) {
|
|
1015
|
-
announce_to_dht(hash);
|
|
1016
|
-
}
|
|
1017
|
-
}
|
|
1018
|
-
last_dht_announce_ = now;
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
// Periodic tracker announces (handled by tracker manager's should_announce)
|
|
1022
|
-
auto tracker_elapsed = std::chrono::duration_cast<std::chrono::seconds>(
|
|
1023
|
-
now - last_tracker_announce_).count();
|
|
1024
|
-
if (tracker_elapsed >= 30) {
|
|
1025
|
-
announce_torrents_to_trackers();
|
|
1026
|
-
last_tracker_announce_ = now;
|
|
1027
|
-
}
|
|
1028
|
-
|
|
1029
|
-
// Sleep for a bit
|
|
1030
|
-
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
1031
|
-
}
|
|
1032
|
-
|
|
1033
|
-
LOG_INFO("BtClient", "Tick loop stopped");
|
|
1034
|
-
}
|
|
1035
|
-
|
|
1036
|
-
Torrent::Ptr BtClient::create_torrent(const TorrentInfo& info,
|
|
1037
|
-
const std::string& save_path) {
|
|
1038
|
-
TorrentConfig torrent_config;
|
|
1039
|
-
torrent_config.save_path = save_path.empty() ? config_.download_path : save_path;
|
|
1040
|
-
torrent_config.resume_data_path = config_.resume_data_path;
|
|
1041
|
-
torrent_config.max_connections = config_.max_connections_per_torrent;
|
|
1042
|
-
torrent_config.max_uploads = config_.max_uploads;
|
|
1043
|
-
|
|
1044
|
-
return std::make_shared<Torrent>(info, torrent_config, peer_id_);
|
|
1045
|
-
}
|
|
1046
|
-
|
|
1047
|
-
} // namespace librats
|