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,410 +0,0 @@
|
|
|
1
|
-
#include "bt_resume_data.h"
|
|
2
|
-
#include "fs.h"
|
|
3
|
-
#include "logger.h"
|
|
4
|
-
|
|
5
|
-
#include <fstream>
|
|
6
|
-
#include <sstream>
|
|
7
|
-
|
|
8
|
-
namespace librats {
|
|
9
|
-
|
|
10
|
-
//=============================================================================
|
|
11
|
-
// Constants
|
|
12
|
-
//=============================================================================
|
|
13
|
-
|
|
14
|
-
static constexpr const char* RESUME_FILE_FORMAT = "librats resume file";
|
|
15
|
-
static constexpr int RESUME_FILE_VERSION = 1;
|
|
16
|
-
|
|
17
|
-
//=============================================================================
|
|
18
|
-
// Write Resume Data
|
|
19
|
-
//=============================================================================
|
|
20
|
-
|
|
21
|
-
std::vector<uint8_t> write_resume_data(const TorrentResumeData& data) {
|
|
22
|
-
BencodeValue dict = BencodeValue::create_dict();
|
|
23
|
-
|
|
24
|
-
// File format identification
|
|
25
|
-
dict["file-format"] = BencodeValue(std::string(RESUME_FILE_FORMAT));
|
|
26
|
-
dict["file-version"] = BencodeValue(static_cast<int64_t>(RESUME_FILE_VERSION));
|
|
27
|
-
dict["librats-version"] = BencodeValue(std::string("1.0.0"));
|
|
28
|
-
|
|
29
|
-
// Info hash (as raw 20-byte string)
|
|
30
|
-
std::string hash_str(reinterpret_cast<const char*>(data.info_hash.data()),
|
|
31
|
-
data.info_hash.size());
|
|
32
|
-
dict["info-hash"] = BencodeValue(hash_str);
|
|
33
|
-
|
|
34
|
-
// Name and save path
|
|
35
|
-
if (!data.name.empty()) {
|
|
36
|
-
dict["name"] = BencodeValue(data.name);
|
|
37
|
-
}
|
|
38
|
-
dict["save_path"] = BencodeValue(data.save_path);
|
|
39
|
-
|
|
40
|
-
// Have pieces bitfield
|
|
41
|
-
// Store as a string where each byte represents one piece:
|
|
42
|
-
// 0 = don't have, 1 = have (verified)
|
|
43
|
-
if (data.have_pieces.size() > 0) {
|
|
44
|
-
std::string pieces_str;
|
|
45
|
-
pieces_str.resize(data.have_pieces.size());
|
|
46
|
-
for (size_t i = 0; i < data.have_pieces.size(); ++i) {
|
|
47
|
-
pieces_str[i] = data.have_pieces.get_bit(static_cast<uint32_t>(i)) ? 1 : 0;
|
|
48
|
-
}
|
|
49
|
-
dict["pieces"] = BencodeValue(pieces_str);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Unfinished pieces (partial downloads)
|
|
53
|
-
if (!data.unfinished_pieces.empty()) {
|
|
54
|
-
BencodeValue unfinished_list = BencodeValue::create_list();
|
|
55
|
-
|
|
56
|
-
for (const auto& [piece_idx, blocks] : data.unfinished_pieces) {
|
|
57
|
-
BencodeValue piece_dict = BencodeValue::create_dict();
|
|
58
|
-
piece_dict["piece"] = BencodeValue(static_cast<int64_t>(piece_idx));
|
|
59
|
-
|
|
60
|
-
// Pack blocks bitfield into bytes
|
|
61
|
-
// Each bit represents a 16KB block
|
|
62
|
-
size_t num_bytes = (blocks.size() + 7) / 8;
|
|
63
|
-
std::string bitmask;
|
|
64
|
-
bitmask.resize(num_bytes, 0);
|
|
65
|
-
|
|
66
|
-
for (size_t i = 0; i < blocks.size(); ++i) {
|
|
67
|
-
if (blocks.get_bit(static_cast<uint32_t>(i))) {
|
|
68
|
-
bitmask[i / 8] |= static_cast<char>(0x80 >> (i % 8));
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
piece_dict["bitmask"] = BencodeValue(bitmask);
|
|
73
|
-
piece_dict["num_blocks"] = BencodeValue(static_cast<int64_t>(blocks.size()));
|
|
74
|
-
|
|
75
|
-
unfinished_list.push_back(piece_dict);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
dict["unfinished"] = unfinished_list;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Statistics
|
|
82
|
-
dict["total_uploaded"] = BencodeValue(static_cast<int64_t>(data.total_uploaded));
|
|
83
|
-
dict["total_downloaded"] = BencodeValue(static_cast<int64_t>(data.total_downloaded));
|
|
84
|
-
dict["active_time"] = BencodeValue(data.active_time);
|
|
85
|
-
dict["seeding_time"] = BencodeValue(data.seeding_time);
|
|
86
|
-
dict["added_time"] = BencodeValue(data.added_time);
|
|
87
|
-
dict["completed_time"] = BencodeValue(data.completed_time);
|
|
88
|
-
|
|
89
|
-
// Configuration
|
|
90
|
-
dict["sequential_download"] = BencodeValue(data.sequential_download ? int64_t(1) : int64_t(0));
|
|
91
|
-
if (data.max_connections >= 0) {
|
|
92
|
-
dict["max_connections"] = BencodeValue(static_cast<int64_t>(data.max_connections));
|
|
93
|
-
}
|
|
94
|
-
if (data.max_uploads >= 0) {
|
|
95
|
-
dict["max_uploads"] = BencodeValue(static_cast<int64_t>(data.max_uploads));
|
|
96
|
-
}
|
|
97
|
-
if (data.download_limit >= 0) {
|
|
98
|
-
dict["download_rate_limit"] = BencodeValue(data.download_limit);
|
|
99
|
-
}
|
|
100
|
-
if (data.upload_limit >= 0) {
|
|
101
|
-
dict["upload_rate_limit"] = BencodeValue(data.upload_limit);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Optional: info dict (for magnet links that downloaded metadata)
|
|
105
|
-
if (!data.info_dict.empty()) {
|
|
106
|
-
std::string info_str(reinterpret_cast<const char*>(data.info_dict.data()),
|
|
107
|
-
data.info_dict.size());
|
|
108
|
-
dict["info"] = BencodeValue(info_str);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Optional: peers cache
|
|
112
|
-
if (!data.peers.empty()) {
|
|
113
|
-
// IPv4 peers: 6 bytes each (4 byte IP + 2 byte port)
|
|
114
|
-
std::string peers_str;
|
|
115
|
-
for (const auto& [ip, port] : data.peers) {
|
|
116
|
-
// Parse IP address to 4 bytes
|
|
117
|
-
uint32_t ip_num = 0;
|
|
118
|
-
int a, b, c, d;
|
|
119
|
-
if (sscanf(ip.c_str(), "%d.%d.%d.%d", &a, &b, &c, &d) == 4) {
|
|
120
|
-
ip_num = (static_cast<uint32_t>(a) << 24) |
|
|
121
|
-
(static_cast<uint32_t>(b) << 16) |
|
|
122
|
-
(static_cast<uint32_t>(c) << 8) |
|
|
123
|
-
static_cast<uint32_t>(d);
|
|
124
|
-
|
|
125
|
-
peers_str.push_back(static_cast<char>((ip_num >> 24) & 0xFF));
|
|
126
|
-
peers_str.push_back(static_cast<char>((ip_num >> 16) & 0xFF));
|
|
127
|
-
peers_str.push_back(static_cast<char>((ip_num >> 8) & 0xFF));
|
|
128
|
-
peers_str.push_back(static_cast<char>(ip_num & 0xFF));
|
|
129
|
-
peers_str.push_back(static_cast<char>((port >> 8) & 0xFF));
|
|
130
|
-
peers_str.push_back(static_cast<char>(port & 0xFF));
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
if (!peers_str.empty()) {
|
|
134
|
-
dict["peers"] = BencodeValue(peers_str);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
return dict.encode();
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
bool write_resume_data_file(const TorrentResumeData& data, const std::string& path) {
|
|
142
|
-
auto encoded = write_resume_data(data);
|
|
143
|
-
if (encoded.empty()) {
|
|
144
|
-
LOG_ERROR("ResumeData", "Failed to encode resume data");
|
|
145
|
-
return false;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// Create parent directory if needed
|
|
149
|
-
std::string parent = get_parent_directory(path);
|
|
150
|
-
if (!parent.empty() && !directory_exists(parent.c_str())) {
|
|
151
|
-
LOG_DEBUG("ResumeData", "Creating resume directory: " + parent);
|
|
152
|
-
if (!create_directories(parent.c_str())) {
|
|
153
|
-
LOG_ERROR("ResumeData", "Failed to create resume directory: " + parent);
|
|
154
|
-
return false;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
std::ofstream file(path, std::ios::binary);
|
|
159
|
-
if (!file) {
|
|
160
|
-
LOG_ERROR("ResumeData", "Failed to open resume file for writing: " + path);
|
|
161
|
-
return false;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
file.write(reinterpret_cast<const char*>(encoded.data()),
|
|
165
|
-
static_cast<std::streamsize>(encoded.size()));
|
|
166
|
-
|
|
167
|
-
if (!file) {
|
|
168
|
-
LOG_ERROR("ResumeData", "Failed to write resume file: " + path);
|
|
169
|
-
return false;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
LOG_DEBUG("ResumeData", "Saved resume data to " + path +
|
|
173
|
-
" (" + std::to_string(encoded.size()) + " bytes)");
|
|
174
|
-
|
|
175
|
-
return true;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
//=============================================================================
|
|
179
|
-
// Read Resume Data
|
|
180
|
-
//=============================================================================
|
|
181
|
-
|
|
182
|
-
std::optional<TorrentResumeData> read_resume_data(
|
|
183
|
-
const std::vector<uint8_t>& buffer,
|
|
184
|
-
std::string* error_out) {
|
|
185
|
-
|
|
186
|
-
BencodeValue decoded;
|
|
187
|
-
try {
|
|
188
|
-
decoded = BencodeDecoder::decode(buffer);
|
|
189
|
-
} catch (const std::exception& e) {
|
|
190
|
-
if (error_out) *error_out = std::string("Failed to decode bencode: ") + e.what();
|
|
191
|
-
return std::nullopt;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
if (!decoded.is_dict()) {
|
|
195
|
-
if (error_out) *error_out = "Resume data is not a dictionary";
|
|
196
|
-
return std::nullopt;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
const auto& dict = decoded.as_dict();
|
|
200
|
-
|
|
201
|
-
// Verify file format
|
|
202
|
-
auto format_it = dict.find("file-format");
|
|
203
|
-
if (format_it == dict.end() || !format_it->second.is_string()) {
|
|
204
|
-
if (error_out) *error_out = "Missing or invalid file-format";
|
|
205
|
-
return std::nullopt;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
if (format_it->second.as_string() != RESUME_FILE_FORMAT) {
|
|
209
|
-
if (error_out) *error_out = "Unknown resume file format: " + format_it->second.as_string();
|
|
210
|
-
return std::nullopt;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// Check version
|
|
214
|
-
auto version_it = dict.find("file-version");
|
|
215
|
-
if (version_it != dict.end() && version_it->second.is_integer()) {
|
|
216
|
-
int version = static_cast<int>(version_it->second.as_integer());
|
|
217
|
-
if (version > RESUME_FILE_VERSION) {
|
|
218
|
-
if (error_out) *error_out = "Resume file version too new: " + std::to_string(version);
|
|
219
|
-
return std::nullopt;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
TorrentResumeData data;
|
|
224
|
-
|
|
225
|
-
// Info hash (required)
|
|
226
|
-
auto hash_it = dict.find("info-hash");
|
|
227
|
-
if (hash_it == dict.end() || !hash_it->second.is_string()) {
|
|
228
|
-
if (error_out) *error_out = "Missing info-hash";
|
|
229
|
-
return std::nullopt;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
const auto& hash_str = hash_it->second.as_string();
|
|
233
|
-
if (hash_str.size() != 20) {
|
|
234
|
-
if (error_out) *error_out = "Invalid info-hash size";
|
|
235
|
-
return std::nullopt;
|
|
236
|
-
}
|
|
237
|
-
std::copy(hash_str.begin(), hash_str.end(), data.info_hash.begin());
|
|
238
|
-
|
|
239
|
-
// Name
|
|
240
|
-
auto name_it = dict.find("name");
|
|
241
|
-
if (name_it != dict.end() && name_it->second.is_string()) {
|
|
242
|
-
data.name = name_it->second.as_string();
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// Save path
|
|
246
|
-
auto path_it = dict.find("save_path");
|
|
247
|
-
if (path_it != dict.end() && path_it->second.is_string()) {
|
|
248
|
-
data.save_path = path_it->second.as_string();
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// Have pieces
|
|
252
|
-
auto pieces_it = dict.find("pieces");
|
|
253
|
-
if (pieces_it != dict.end() && pieces_it->second.is_string()) {
|
|
254
|
-
const auto& pieces_str = pieces_it->second.as_string();
|
|
255
|
-
data.have_pieces = Bitfield(static_cast<uint32_t>(pieces_str.size()));
|
|
256
|
-
|
|
257
|
-
for (size_t i = 0; i < pieces_str.size(); ++i) {
|
|
258
|
-
if (pieces_str[i] & 1) {
|
|
259
|
-
data.have_pieces.set_bit(static_cast<uint32_t>(i));
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// Unfinished pieces
|
|
265
|
-
auto unfinished_it = dict.find("unfinished");
|
|
266
|
-
if (unfinished_it != dict.end() && unfinished_it->second.is_list()) {
|
|
267
|
-
const auto& unfinished_list = unfinished_it->second.as_list();
|
|
268
|
-
|
|
269
|
-
for (const auto& entry : unfinished_list) {
|
|
270
|
-
if (!entry.is_dict()) continue;
|
|
271
|
-
|
|
272
|
-
const auto& piece_dict = entry.as_dict();
|
|
273
|
-
|
|
274
|
-
auto piece_it = piece_dict.find("piece");
|
|
275
|
-
if (piece_it == piece_dict.end() || !piece_it->second.is_integer()) {
|
|
276
|
-
continue;
|
|
277
|
-
}
|
|
278
|
-
uint32_t piece_idx = static_cast<uint32_t>(piece_it->second.as_integer());
|
|
279
|
-
|
|
280
|
-
auto bitmask_it = piece_dict.find("bitmask");
|
|
281
|
-
if (bitmask_it == piece_dict.end() || !bitmask_it->second.is_string()) {
|
|
282
|
-
continue;
|
|
283
|
-
}
|
|
284
|
-
const auto& bitmask = bitmask_it->second.as_string();
|
|
285
|
-
|
|
286
|
-
// Get number of blocks (optional, for accurate size)
|
|
287
|
-
size_t num_blocks = bitmask.size() * 8;
|
|
288
|
-
auto num_blocks_it = piece_dict.find("num_blocks");
|
|
289
|
-
if (num_blocks_it != piece_dict.end() && num_blocks_it->second.is_integer()) {
|
|
290
|
-
num_blocks = static_cast<size_t>(num_blocks_it->second.as_integer());
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
Bitfield blocks(static_cast<uint32_t>(num_blocks));
|
|
294
|
-
for (size_t i = 0; i < num_blocks; ++i) {
|
|
295
|
-
if (i / 8 < bitmask.size()) {
|
|
296
|
-
if (bitmask[i / 8] & (0x80 >> (i % 8))) {
|
|
297
|
-
blocks.set_bit(static_cast<uint32_t>(i));
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
data.unfinished_pieces[piece_idx] = blocks;
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// Statistics
|
|
307
|
-
auto read_int = [&dict](const char* key, int64_t default_val = 0) -> int64_t {
|
|
308
|
-
auto it = dict.find(key);
|
|
309
|
-
if (it != dict.end() && it->second.is_integer()) {
|
|
310
|
-
return it->second.as_integer();
|
|
311
|
-
}
|
|
312
|
-
return default_val;
|
|
313
|
-
};
|
|
314
|
-
|
|
315
|
-
data.total_uploaded = static_cast<uint64_t>(read_int("total_uploaded"));
|
|
316
|
-
data.total_downloaded = static_cast<uint64_t>(read_int("total_downloaded"));
|
|
317
|
-
data.active_time = read_int("active_time");
|
|
318
|
-
data.seeding_time = read_int("seeding_time");
|
|
319
|
-
data.added_time = read_int("added_time");
|
|
320
|
-
data.completed_time = read_int("completed_time");
|
|
321
|
-
|
|
322
|
-
// Configuration
|
|
323
|
-
data.sequential_download = read_int("sequential_download") != 0;
|
|
324
|
-
data.max_connections = static_cast<int>(read_int("max_connections", -1));
|
|
325
|
-
data.max_uploads = static_cast<int>(read_int("max_uploads", -1));
|
|
326
|
-
data.download_limit = read_int("download_rate_limit", -1);
|
|
327
|
-
data.upload_limit = read_int("upload_rate_limit", -1);
|
|
328
|
-
|
|
329
|
-
// Optional: info dict
|
|
330
|
-
auto info_it = dict.find("info");
|
|
331
|
-
if (info_it != dict.end() && info_it->second.is_string()) {
|
|
332
|
-
const auto& info_str = info_it->second.as_string();
|
|
333
|
-
data.info_dict.assign(info_str.begin(), info_str.end());
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
// Optional: peers
|
|
337
|
-
auto peers_it = dict.find("peers");
|
|
338
|
-
if (peers_it != dict.end() && peers_it->second.is_string()) {
|
|
339
|
-
const auto& peers_str = peers_it->second.as_string();
|
|
340
|
-
|
|
341
|
-
// Each peer is 6 bytes: 4 byte IP + 2 byte port
|
|
342
|
-
for (size_t i = 0; i + 6 <= peers_str.size(); i += 6) {
|
|
343
|
-
uint8_t a = static_cast<uint8_t>(peers_str[i]);
|
|
344
|
-
uint8_t b = static_cast<uint8_t>(peers_str[i + 1]);
|
|
345
|
-
uint8_t c = static_cast<uint8_t>(peers_str[i + 2]);
|
|
346
|
-
uint8_t d = static_cast<uint8_t>(peers_str[i + 3]);
|
|
347
|
-
uint16_t port = (static_cast<uint16_t>(static_cast<uint8_t>(peers_str[i + 4])) << 8) |
|
|
348
|
-
static_cast<uint16_t>(static_cast<uint8_t>(peers_str[i + 5]));
|
|
349
|
-
|
|
350
|
-
std::string ip = std::to_string(a) + "." + std::to_string(b) + "." +
|
|
351
|
-
std::to_string(c) + "." + std::to_string(d);
|
|
352
|
-
data.peers.emplace_back(ip, port);
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
return data;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
std::optional<TorrentResumeData> read_resume_data_file(
|
|
360
|
-
const std::string& path,
|
|
361
|
-
std::string* error_out) {
|
|
362
|
-
|
|
363
|
-
std::ifstream file(path, std::ios::binary);
|
|
364
|
-
if (!file) {
|
|
365
|
-
if (error_out) *error_out = "Failed to open resume file: " + path;
|
|
366
|
-
return std::nullopt;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
// Read entire file
|
|
370
|
-
file.seekg(0, std::ios::end);
|
|
371
|
-
size_t size = static_cast<size_t>(file.tellg());
|
|
372
|
-
file.seekg(0, std::ios::beg);
|
|
373
|
-
|
|
374
|
-
std::vector<uint8_t> buffer(size);
|
|
375
|
-
file.read(reinterpret_cast<char*>(buffer.data()), static_cast<std::streamsize>(size));
|
|
376
|
-
|
|
377
|
-
if (!file) {
|
|
378
|
-
if (error_out) *error_out = "Failed to read resume file: " + path;
|
|
379
|
-
return std::nullopt;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
LOG_DEBUG("ResumeData", "Read resume file: " + path +
|
|
383
|
-
" (" + std::to_string(size) + " bytes)");
|
|
384
|
-
|
|
385
|
-
return read_resume_data(buffer, error_out);
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
//=============================================================================
|
|
389
|
-
// Helper Functions
|
|
390
|
-
//=============================================================================
|
|
391
|
-
|
|
392
|
-
std::string get_resume_file_path(const std::string& save_path, const BtInfoHash& info_hash) {
|
|
393
|
-
std::string hash_hex = info_hash_to_hex(info_hash);
|
|
394
|
-
|
|
395
|
-
// Use save_path/.resume/{hash}.resume
|
|
396
|
-
std::string resume_dir = save_path;
|
|
397
|
-
if (!resume_dir.empty() && resume_dir.back() != '/' && resume_dir.back() != '\\') {
|
|
398
|
-
resume_dir += '/';
|
|
399
|
-
}
|
|
400
|
-
resume_dir += ".resume";
|
|
401
|
-
|
|
402
|
-
return resume_dir + "/" + hash_hex + ".resume";
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
bool resume_file_exists(const std::string& save_path, const BtInfoHash& info_hash) {
|
|
406
|
-
std::string path = get_resume_file_path(save_path, info_hash);
|
|
407
|
-
return file_exists(path.c_str());
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
} // namespace librats
|
|
@@ -1,249 +0,0 @@
|
|
|
1
|
-
#pragma once
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @file bt_resume_data.h
|
|
5
|
-
* @brief BitTorrent torrent resume data for fast resumption
|
|
6
|
-
*
|
|
7
|
-
* Resume data allows a torrent to quickly resume downloading from where
|
|
8
|
-
* it left off, without re-checking all downloaded data. It stores:
|
|
9
|
-
* - Which pieces have been verified and are complete
|
|
10
|
-
* - Partially downloaded pieces and which blocks are complete
|
|
11
|
-
* - Download statistics
|
|
12
|
-
* - Configuration settings
|
|
13
|
-
*
|
|
14
|
-
* This is similar to libtorrent's fast-resume feature.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
#include "bt_types.h"
|
|
18
|
-
#include "bt_bitfield.h"
|
|
19
|
-
#include "bt_torrent_info.h"
|
|
20
|
-
#include "bencode.h"
|
|
21
|
-
|
|
22
|
-
#include <string>
|
|
23
|
-
#include <vector>
|
|
24
|
-
#include <map>
|
|
25
|
-
#include <cstdint>
|
|
26
|
-
#include <optional>
|
|
27
|
-
|
|
28
|
-
namespace librats {
|
|
29
|
-
|
|
30
|
-
//=============================================================================
|
|
31
|
-
// Resume Data Structure
|
|
32
|
-
//=============================================================================
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* @brief Stores the state of a partially downloaded piece
|
|
36
|
-
*
|
|
37
|
-
* For each piece that is partially downloaded, we track which 16KB blocks
|
|
38
|
-
* have been written to disk. This allows resuming without losing progress
|
|
39
|
-
* on pieces that were in-flight when the client stopped.
|
|
40
|
-
*/
|
|
41
|
-
struct UnfinishedPiece {
|
|
42
|
-
uint32_t piece_index; ///< Index of the piece
|
|
43
|
-
Bitfield blocks_have; ///< Which blocks are written to disk
|
|
44
|
-
|
|
45
|
-
UnfinishedPiece() : piece_index(0) {}
|
|
46
|
-
UnfinishedPiece(uint32_t idx, const Bitfield& blocks)
|
|
47
|
-
: piece_index(idx), blocks_have(blocks) {}
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* @brief Resume data for a torrent
|
|
52
|
-
*
|
|
53
|
-
* This structure contains all the information needed to resume a torrent
|
|
54
|
-
* download without re-checking existing data.
|
|
55
|
-
*/
|
|
56
|
-
struct TorrentResumeData {
|
|
57
|
-
//=========================================================================
|
|
58
|
-
// Identification
|
|
59
|
-
//=========================================================================
|
|
60
|
-
|
|
61
|
-
/// Info hash of the torrent (for verification)
|
|
62
|
-
BtInfoHash info_hash;
|
|
63
|
-
|
|
64
|
-
/// Torrent name (for display)
|
|
65
|
-
std::string name;
|
|
66
|
-
|
|
67
|
-
//=========================================================================
|
|
68
|
-
// Paths
|
|
69
|
-
//=========================================================================
|
|
70
|
-
|
|
71
|
-
/// Directory where files are saved
|
|
72
|
-
std::string save_path;
|
|
73
|
-
|
|
74
|
-
//=========================================================================
|
|
75
|
-
// Progress - Complete Pieces
|
|
76
|
-
//=========================================================================
|
|
77
|
-
|
|
78
|
-
/// Bitfield indicating which pieces we have verified and complete
|
|
79
|
-
Bitfield have_pieces;
|
|
80
|
-
|
|
81
|
-
//=========================================================================
|
|
82
|
-
// Progress - Partial Pieces
|
|
83
|
-
//=========================================================================
|
|
84
|
-
|
|
85
|
-
/// Map of piece index to bitfield of blocks we have for incomplete pieces
|
|
86
|
-
/// Key: piece_index, Value: bitfield of blocks that are written to disk
|
|
87
|
-
std::map<uint32_t, Bitfield> unfinished_pieces;
|
|
88
|
-
|
|
89
|
-
//=========================================================================
|
|
90
|
-
// Statistics
|
|
91
|
-
//=========================================================================
|
|
92
|
-
|
|
93
|
-
/// Total bytes uploaded (all-time)
|
|
94
|
-
uint64_t total_uploaded = 0;
|
|
95
|
-
|
|
96
|
-
/// Total bytes downloaded (all-time)
|
|
97
|
-
uint64_t total_downloaded = 0;
|
|
98
|
-
|
|
99
|
-
/// Time spent actively downloading (seconds)
|
|
100
|
-
int64_t active_time = 0;
|
|
101
|
-
|
|
102
|
-
/// Time spent seeding (seconds)
|
|
103
|
-
int64_t seeding_time = 0;
|
|
104
|
-
|
|
105
|
-
/// Timestamp when torrent was added (Unix time)
|
|
106
|
-
int64_t added_time = 0;
|
|
107
|
-
|
|
108
|
-
/// Timestamp when download completed (Unix time, 0 if not complete)
|
|
109
|
-
int64_t completed_time = 0;
|
|
110
|
-
|
|
111
|
-
//=========================================================================
|
|
112
|
-
// Configuration
|
|
113
|
-
//=========================================================================
|
|
114
|
-
|
|
115
|
-
/// Download pieces in order (for streaming)
|
|
116
|
-
bool sequential_download = false;
|
|
117
|
-
|
|
118
|
-
/// Maximum connections for this torrent
|
|
119
|
-
int max_connections = -1;
|
|
120
|
-
|
|
121
|
-
/// Maximum upload slots for this torrent
|
|
122
|
-
int max_uploads = -1;
|
|
123
|
-
|
|
124
|
-
/// Download rate limit (bytes/sec, -1 = unlimited)
|
|
125
|
-
int64_t download_limit = -1;
|
|
126
|
-
|
|
127
|
-
/// Upload rate limit (bytes/sec, -1 = unlimited)
|
|
128
|
-
int64_t upload_limit = -1;
|
|
129
|
-
|
|
130
|
-
//=========================================================================
|
|
131
|
-
// Optional: Torrent metadata (for magnet links that completed metadata)
|
|
132
|
-
//=========================================================================
|
|
133
|
-
|
|
134
|
-
/// Raw info dictionary (optional, for torrents added via magnet)
|
|
135
|
-
std::vector<uint8_t> info_dict;
|
|
136
|
-
|
|
137
|
-
//=========================================================================
|
|
138
|
-
// Optional: Cached peer information
|
|
139
|
-
//=========================================================================
|
|
140
|
-
|
|
141
|
-
/// List of peers to try connecting to (ip:port pairs)
|
|
142
|
-
std::vector<std::pair<std::string, uint16_t>> peers;
|
|
143
|
-
|
|
144
|
-
//=========================================================================
|
|
145
|
-
// Validation
|
|
146
|
-
//=========================================================================
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* @brief Check if resume data is valid for use
|
|
150
|
-
* @return true if all required fields are set correctly
|
|
151
|
-
*/
|
|
152
|
-
bool is_valid() const {
|
|
153
|
-
// Must have info_hash
|
|
154
|
-
bool has_hash = false;
|
|
155
|
-
for (uint8_t b : info_hash) {
|
|
156
|
-
if (b != 0) { has_hash = true; break; }
|
|
157
|
-
}
|
|
158
|
-
return has_hash;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* @brief Check if resume data matches a torrent info
|
|
163
|
-
* @param info TorrentInfo to check against
|
|
164
|
-
* @return true if the resume data is compatible
|
|
165
|
-
*/
|
|
166
|
-
bool matches(const TorrentInfo& info) const {
|
|
167
|
-
return info_hash == info.info_hash();
|
|
168
|
-
}
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
//=============================================================================
|
|
172
|
-
// Resume Data Serialization (Bencoding)
|
|
173
|
-
//=============================================================================
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* @brief Write resume data to a bencoded format
|
|
177
|
-
*
|
|
178
|
-
* The bencoded format is compatible with libtorrent's resume file format:
|
|
179
|
-
* - "file-format": "librats resume file"
|
|
180
|
-
* - "file-version": 1
|
|
181
|
-
* - "info-hash": 20-byte SHA1 hash
|
|
182
|
-
* - "save_path": string
|
|
183
|
-
* - "pieces": string (one byte per piece: 0=don't have, 1=have)
|
|
184
|
-
* - "unfinished": list of dicts with "piece" and "bitmask"
|
|
185
|
-
* - "total_uploaded": integer
|
|
186
|
-
* - "total_downloaded": integer
|
|
187
|
-
* - etc.
|
|
188
|
-
*
|
|
189
|
-
* @param data Resume data to serialize
|
|
190
|
-
* @return Bencoded data as byte vector
|
|
191
|
-
*/
|
|
192
|
-
std::vector<uint8_t> write_resume_data(const TorrentResumeData& data);
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* @brief Write resume data to a file
|
|
196
|
-
*
|
|
197
|
-
* @param data Resume data to save
|
|
198
|
-
* @param path Path to save file
|
|
199
|
-
* @return true on success
|
|
200
|
-
*/
|
|
201
|
-
bool write_resume_data_file(const TorrentResumeData& data, const std::string& path);
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* @brief Read resume data from bencoded format
|
|
205
|
-
*
|
|
206
|
-
* @param buffer Bencoded data
|
|
207
|
-
* @param error_out Optional error message on failure
|
|
208
|
-
* @return Resume data if successful, nullopt on error
|
|
209
|
-
*/
|
|
210
|
-
std::optional<TorrentResumeData> read_resume_data(
|
|
211
|
-
const std::vector<uint8_t>& buffer,
|
|
212
|
-
std::string* error_out = nullptr);
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* @brief Read resume data from a file
|
|
216
|
-
*
|
|
217
|
-
* @param path Path to resume file
|
|
218
|
-
* @param error_out Optional error message on failure
|
|
219
|
-
* @return Resume data if successful, nullopt on error
|
|
220
|
-
*/
|
|
221
|
-
std::optional<TorrentResumeData> read_resume_data_file(
|
|
222
|
-
const std::string& path,
|
|
223
|
-
std::string* error_out = nullptr);
|
|
224
|
-
|
|
225
|
-
//=============================================================================
|
|
226
|
-
// Resume Data Helper Functions
|
|
227
|
-
//=============================================================================
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* @brief Generate default resume file path for a torrent
|
|
231
|
-
*
|
|
232
|
-
* Creates a path in the form: {save_path}/{info_hash_hex}.resume
|
|
233
|
-
*
|
|
234
|
-
* @param save_path Torrent save directory
|
|
235
|
-
* @param info_hash Torrent info hash
|
|
236
|
-
* @return Path to resume file
|
|
237
|
-
*/
|
|
238
|
-
std::string get_resume_file_path(const std::string& save_path, const BtInfoHash& info_hash);
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* @brief Check if a resume file exists for a torrent
|
|
242
|
-
*
|
|
243
|
-
* @param save_path Torrent save directory
|
|
244
|
-
* @param info_hash Torrent info hash
|
|
245
|
-
* @return true if resume file exists
|
|
246
|
-
*/
|
|
247
|
-
bool resume_file_exists(const std::string& save_path, const BtInfoHash& info_hash);
|
|
248
|
-
|
|
249
|
-
} // namespace librats
|