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
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file torrent.h
|
|
5
|
+
* @brief One active torrent: ties the piece picker, peers, disk and choker
|
|
6
|
+
* together and drives a download (or seed) to completion.
|
|
7
|
+
*
|
|
8
|
+
* A Torrent is a PeerConnection::Observer — every wire event lands here and is
|
|
9
|
+
* turned into picker/disk work. The flow is event-driven, not polled:
|
|
10
|
+
*
|
|
11
|
+
* peer unchokes / has new pieces → refill its request pipeline
|
|
12
|
+
* block arrives → write to disk → (piece done) hash & verify
|
|
13
|
+
* piece verified → mark have, announce `have` to peers
|
|
14
|
+
* peer interested → recompute the choker and (un)choke
|
|
15
|
+
*
|
|
16
|
+
* A 1 s tick only handles periodic chores (connect more peers, re-run the
|
|
17
|
+
* choker). All of this runs on the reactor thread, so there are no locks.
|
|
18
|
+
*
|
|
19
|
+
* Connections are owned by the host (Client); the Torrent holds raw pointers it
|
|
20
|
+
* learns at handshake and drops at close.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
#include "librats/util/rats_export.h"
|
|
24
|
+
#include "librats/bittorrent/choker.h"
|
|
25
|
+
#include "librats/bittorrent/disk_io.h"
|
|
26
|
+
#include "librats/bittorrent/extensions.h"
|
|
27
|
+
#include "librats/bittorrent/peer_connection.h"
|
|
28
|
+
#include "librats/bittorrent/peer_list.h"
|
|
29
|
+
#include "librats/bittorrent/piece_picker.h"
|
|
30
|
+
#include "librats/bittorrent/reactor.h"
|
|
31
|
+
#include "librats/bittorrent/resume_data.h"
|
|
32
|
+
#include "librats/bittorrent/torrent_info.h"
|
|
33
|
+
#include "librats/bittorrent/tracker.h"
|
|
34
|
+
#include "librats/bittorrent/types.h"
|
|
35
|
+
#include "librats/core/types.h"
|
|
36
|
+
|
|
37
|
+
#include <atomic>
|
|
38
|
+
#include <chrono>
|
|
39
|
+
#include <cstdint>
|
|
40
|
+
#include <functional>
|
|
41
|
+
#include <memory>
|
|
42
|
+
#include <optional>
|
|
43
|
+
#include <string>
|
|
44
|
+
#include <unordered_map>
|
|
45
|
+
#include <unordered_set>
|
|
46
|
+
#include <vector>
|
|
47
|
+
|
|
48
|
+
namespace librats::bittorrent {
|
|
49
|
+
|
|
50
|
+
class Torrent;
|
|
51
|
+
|
|
52
|
+
/// What a Torrent needs from its owning Client: outgoing connects and our id.
|
|
53
|
+
class RATS_API TorrentHost {
|
|
54
|
+
public:
|
|
55
|
+
virtual ~TorrentHost() = default;
|
|
56
|
+
virtual void connect_peer(Torrent& torrent, const std::string& ip, std::uint16_t port) = 0;
|
|
57
|
+
virtual const PeerId& peer_id() const = 0;
|
|
58
|
+
virtual std::uint16_t listen_port() const = 0;
|
|
59
|
+
/// Discover peers for @p info_hash via the DHT (if the host has one); each
|
|
60
|
+
/// found peer is delivered to @p on_peer on the reactor thread. Default no-op.
|
|
61
|
+
virtual void find_peers_via_dht(const InfoHash& /*info_hash*/,
|
|
62
|
+
std::function<void(const std::string& ip, std::uint16_t port)> /*on_peer*/) {}
|
|
63
|
+
/// Announce ourselves to the DHT for @p info_hash on @p port so other clients
|
|
64
|
+
/// doing get_peers can find us (BEP 5). Default no-op (no DHT attached).
|
|
65
|
+
virtual void announce_to_dht(const InfoHash& /*info_hash*/, std::uint16_t /*port*/) {}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
class RATS_API Torrent final : public PeerConnection::Observer {
|
|
69
|
+
public:
|
|
70
|
+
enum class State { Stopped, Metadata, Checking, Downloading, Seeding };
|
|
71
|
+
|
|
72
|
+
Torrent(Reactor& reactor, TorrentHost& host, TorrentInfo info, std::string save_path);
|
|
73
|
+
~Torrent() override;
|
|
74
|
+
|
|
75
|
+
Torrent(const Torrent&) = delete;
|
|
76
|
+
Torrent& operator=(const Torrent&) = delete;
|
|
77
|
+
|
|
78
|
+
void start();
|
|
79
|
+
void stop();
|
|
80
|
+
|
|
81
|
+
/// Pause a running torrent: drop its peers and stop dialing/serving, but keep
|
|
82
|
+
/// the piece picker and disk state so resume() does not re-hash. No-op if not
|
|
83
|
+
/// running or already paused.
|
|
84
|
+
void pause();
|
|
85
|
+
/// Resume a paused torrent: start reconnecting to peers again. No-op if not
|
|
86
|
+
/// running or not paused.
|
|
87
|
+
void resume();
|
|
88
|
+
bool is_paused() const noexcept { return paused_; }
|
|
89
|
+
|
|
90
|
+
/// Queue a peer to connect to (deduplicated). Connects promptly if running.
|
|
91
|
+
void add_peer(const std::string& ip, std::uint16_t port);
|
|
92
|
+
|
|
93
|
+
// ---- info / progress ----
|
|
94
|
+
const InfoHash& info_hash() const { return info_.info_hash(); }
|
|
95
|
+
const TorrentInfo& torrent_info()const { return info_; }
|
|
96
|
+
std::uint32_t num_pieces() const { return info_.num_pieces(); }
|
|
97
|
+
State state() const noexcept { return state_; }
|
|
98
|
+
bool is_complete() const { return picker_ && picker_->is_finished(); }
|
|
99
|
+
double progress() const;
|
|
100
|
+
std::size_t num_peers() const noexcept { return peers_.size(); }
|
|
101
|
+
/// Total block requests currently in flight across all peers.
|
|
102
|
+
std::size_t num_outstanding_requests() const noexcept;
|
|
103
|
+
/// Override how long a peer may hold requests without delivering before it is
|
|
104
|
+
/// snubbed and its blocks freed. Defaults to kRequestTimeout (30 s).
|
|
105
|
+
void set_request_timeout(std::chrono::milliseconds t) noexcept { request_timeout_ = t; }
|
|
106
|
+
std::uint64_t bytes_downloaded() const noexcept { return bytes_downloaded_; }
|
|
107
|
+
std::uint64_t bytes_uploaded() const noexcept { return bytes_uploaded_; }
|
|
108
|
+
|
|
109
|
+
/// True once we hold the full metadata (always true unless started from a magnet).
|
|
110
|
+
bool has_metadata() const noexcept { return has_metadata_; }
|
|
111
|
+
|
|
112
|
+
/// Fired once when a download reaches 100% (not for torrents that start complete).
|
|
113
|
+
void set_complete_callback(std::function<void()> cb) { on_complete_ = std::move(cb); }
|
|
114
|
+
/// Fired once when metadata is obtained for a magnet torrent (with the completed info).
|
|
115
|
+
void set_metadata_callback(std::function<void(const TorrentInfo&)> cb) { on_metadata_ = std::move(cb); }
|
|
116
|
+
|
|
117
|
+
// ---- fast resume ----
|
|
118
|
+
/// Apply saved resume state. Call before start(): the recorded have-bitfield
|
|
119
|
+
/// is trusted (those pieces skip the hash check), and an embedded info dict
|
|
120
|
+
/// completes a magnet torrent. Ignored if the info-hash doesn't match.
|
|
121
|
+
void load_resume_data(const ResumeData& rd);
|
|
122
|
+
/// Load resume state from the default on-disk path (see default_resume_path).
|
|
123
|
+
/// Like load_resume_data(), call before start(). Returns false if no resume
|
|
124
|
+
/// file exists or it fails to decode.
|
|
125
|
+
bool try_load_resume_data();
|
|
126
|
+
ResumeData generate_resume_data() const;
|
|
127
|
+
/// Write resume data to @p path (default: {save_path}/.resume/{info_hash}.resume).
|
|
128
|
+
bool save_resume_data() const;
|
|
129
|
+
bool save_resume_data(const std::string& path) const;
|
|
130
|
+
|
|
131
|
+
/// Called by the host when an outgoing connect attempt fails.
|
|
132
|
+
void on_connect_failed(const std::string& ip, std::uint16_t port);
|
|
133
|
+
|
|
134
|
+
// ---- PeerConnection::Observer ----
|
|
135
|
+
void on_handshake(PeerConnection&, const InfoHash&, const PeerId&) override;
|
|
136
|
+
void on_bitfield(PeerConnection&, const Bitfield&) override;
|
|
137
|
+
void on_have(PeerConnection&, std::uint32_t piece) override;
|
|
138
|
+
void on_choke(PeerConnection&, bool peer_choking) override;
|
|
139
|
+
void on_interest(PeerConnection&, bool peer_interested) override;
|
|
140
|
+
void on_request(PeerConnection&, std::uint32_t piece, std::uint32_t offset, std::uint32_t length) override;
|
|
141
|
+
void on_piece(PeerConnection&, std::uint32_t piece, std::uint32_t offset, ByteView data) override;
|
|
142
|
+
void on_extended(PeerConnection&, std::uint8_t ext_id, ByteView payload) override;
|
|
143
|
+
void on_closed(PeerConnection&, const std::string& reason) override;
|
|
144
|
+
|
|
145
|
+
private:
|
|
146
|
+
/// Post @p fn to the reactor, guarded by alive_ so it is dropped if this
|
|
147
|
+
/// torrent has since been destroyed. Disk and tracker completions run on their
|
|
148
|
+
/// own worker threads and marshal back through here; a completion that a worker
|
|
149
|
+
/// posts while stop() is joining it can land in the reactor queue *after* the
|
|
150
|
+
/// torrent is erased, so the raw `this` those callbacks capture would dangle
|
|
151
|
+
/// (use-after-free). The guard is the only thing keeping that pointer live-safe.
|
|
152
|
+
void post(std::function<void()> fn);
|
|
153
|
+
|
|
154
|
+
void on_check_complete(Bitfield have);
|
|
155
|
+
|
|
156
|
+
// Extension protocol / metadata (BEP 10 / BEP 9).
|
|
157
|
+
void send_extended_handshake(PeerConnection& pc);
|
|
158
|
+
void handle_ext_handshake(PeerConnection& pc, ByteView payload);
|
|
159
|
+
void handle_ut_metadata(PeerConnection& pc, ByteView payload);
|
|
160
|
+
void ensure_metadata_buffer(std::uint32_t total_size);
|
|
161
|
+
void request_metadata(PeerConnection& pc);
|
|
162
|
+
void on_metadata_piece(std::uint32_t piece, std::uint32_t total_size, ByteView block);
|
|
163
|
+
void try_complete_metadata();
|
|
164
|
+
void promote_to_downloading();
|
|
165
|
+
void schedule_tick();
|
|
166
|
+
void tick();
|
|
167
|
+
void try_connect();
|
|
168
|
+
void update_interest(PeerConnection& pc);
|
|
169
|
+
void refill(PeerConnection& pc);
|
|
170
|
+
void recompute_choker();
|
|
171
|
+
/// Rotate the optimistic-unchoke slot to give a currently-choked interested
|
|
172
|
+
/// peer a chance to prove itself (so newcomers can bootstrap). ~30 s cadence.
|
|
173
|
+
void rotate_optimistic();
|
|
174
|
+
void handle_pex(PeerConnection& pc, ByteView payload);
|
|
175
|
+
void send_pex();
|
|
176
|
+
std::optional<ext::PexPeer> dialable(PeerConnection& pc) const;
|
|
177
|
+
void announce_trackers(TrackerEvent event);
|
|
178
|
+
TrackerRequest make_tracker_request(TrackerEvent event) const;
|
|
179
|
+
std::string default_resume_path() const;
|
|
180
|
+
/// Free blocks stuck on peers that have made no progress within
|
|
181
|
+
/// kRequestTimeout so other peers can re-request them (prevents a silent /
|
|
182
|
+
/// keep-alive-only peer from stalling pieces forever). Runs on the 1 s tick.
|
|
183
|
+
void check_request_timeouts();
|
|
184
|
+
/// Refill every peer whose pipeline has room (used to resume requesting once
|
|
185
|
+
/// disk write backpressure clears).
|
|
186
|
+
void refill_all();
|
|
187
|
+
void on_block_written(PieceBlock block, bool ok);
|
|
188
|
+
void verify_piece(std::uint32_t piece);
|
|
189
|
+
void on_piece_hashed(std::uint32_t piece, bool ok, std::array<std::uint8_t, 20> hash);
|
|
190
|
+
bool alive(PeerConnection* pc) const;
|
|
191
|
+
void remove_peer(PeerConnection* pc);
|
|
192
|
+
|
|
193
|
+
static constexpr int kPipelineDepth = 16;
|
|
194
|
+
static constexpr std::size_t kMaxPeers = 50;
|
|
195
|
+
/// A peer that holds outstanding requests but delivers no block for this long
|
|
196
|
+
/// is snubbed: its blocks are freed for other peers. Kept well under the 120 s
|
|
197
|
+
/// idle timeout so a keep-alive-only peer can't stall pieces indefinitely.
|
|
198
|
+
static constexpr std::chrono::seconds kRequestTimeout{30};
|
|
199
|
+
std::chrono::milliseconds request_timeout_{kRequestTimeout};
|
|
200
|
+
/// Stop requesting new blocks while the disk has more than this many bytes of
|
|
201
|
+
/// writes still pending, so a fast swarm can't grow the write queue without
|
|
202
|
+
/// bound when the disk is slow (D-2). Requesting resumes as the queue drains.
|
|
203
|
+
static constexpr std::size_t kDiskWriteHighWater = 32 * 1024 * 1024;
|
|
204
|
+
|
|
205
|
+
/// Liveness token shared with every reactor task this torrent posts (directly
|
|
206
|
+
/// or via a disk/tracker completion poster). Cleared in the destructor; the
|
|
207
|
+
/// shared_ptr keeps the flag readable after the torrent is gone, so a task
|
|
208
|
+
/// still queued on the reactor drops itself instead of touching freed memory.
|
|
209
|
+
std::shared_ptr<std::atomic<bool>> alive_ = std::make_shared<std::atomic<bool>>(true);
|
|
210
|
+
|
|
211
|
+
Reactor& reactor_;
|
|
212
|
+
TorrentHost& host_;
|
|
213
|
+
TorrentInfo info_;
|
|
214
|
+
std::string save_path_;
|
|
215
|
+
std::unique_ptr<PiecePicker> picker_;
|
|
216
|
+
std::unique_ptr<DiskIo> disk_;
|
|
217
|
+
std::unique_ptr<TrackerAnnouncer> trackers_;
|
|
218
|
+
Choker choker_;
|
|
219
|
+
State state_ = State::Stopped;
|
|
220
|
+
bool running_ = false;
|
|
221
|
+
bool paused_ = false;
|
|
222
|
+
bool has_metadata_ = false;
|
|
223
|
+
bool completed_announced_ = false;
|
|
224
|
+
bool write_stalled_ = false; ///< requesting paused for disk backpressure
|
|
225
|
+
Bitfield resume_have_; ///< trusted have-set from resume data
|
|
226
|
+
|
|
227
|
+
std::vector<PeerConnection*> peers_;
|
|
228
|
+
std::unordered_map<PeerConnection*, int> outstanding_;
|
|
229
|
+
/// Time of the last progress with each peer (a block received, or the moment
|
|
230
|
+
/// we started waiting on a fresh batch). Drives the request-timeout snub.
|
|
231
|
+
std::unordered_map<PeerConnection*, std::chrono::steady_clock::time_point> request_time_;
|
|
232
|
+
std::unordered_map<PeerConnection*, std::uint64_t> recent_down_; // bytes recv this choke window (leech score)
|
|
233
|
+
std::unordered_map<PeerConnection*, std::uint64_t> recent_up_; // bytes served this choke window (seed score)
|
|
234
|
+
PeerConnection* optimistic_ = nullptr; // current optimistic-unchoke peer
|
|
235
|
+
std::unordered_set<PeerConnection*> seed_peers_; // counted via the picker's O(1) seed counter
|
|
236
|
+
std::unordered_map<PeerConnection*, ext::PeerExtensions> peer_ext_;
|
|
237
|
+
std::unordered_map<PeerConnection*, std::unordered_set<std::string>> pex_sent_;
|
|
238
|
+
std::unordered_map<PeerConnection*, int> pex_last_tick_; ///< tick of last PEX to peer (BEP11 ≥60 s gap)
|
|
239
|
+
PeerList peer_list_;
|
|
240
|
+
int tick_count_ = 0;
|
|
241
|
+
int next_announce_tick_ = 300; ///< tick to re-announce (driven by tracker interval)
|
|
242
|
+
int progress_logged_ = -1; ///< last download %-decile logged at INFO (avoids per-piece spam)
|
|
243
|
+
|
|
244
|
+
// ut_metadata (BEP 9) assembly state, used while we lack metadata.
|
|
245
|
+
Bytes metadata_buf_;
|
|
246
|
+
std::uint32_t metadata_size_ = 0;
|
|
247
|
+
std::uint32_t metadata_pieces_ = 0;
|
|
248
|
+
std::uint32_t metadata_received_ = 0;
|
|
249
|
+
std::vector<bool> metadata_have_;
|
|
250
|
+
|
|
251
|
+
std::uint64_t bytes_downloaded_ = 0; ///< cumulative payload downloaded (tracker stat / resume)
|
|
252
|
+
std::uint64_t bytes_uploaded_ = 0;
|
|
253
|
+
std::uint64_t verified_bytes_ = 0; ///< payload currently present & verified on disk (drives `left`)
|
|
254
|
+
|
|
255
|
+
TimerId tick_timer_ = kInvalidTimerId;
|
|
256
|
+
std::function<void()> on_complete_;
|
|
257
|
+
std::function<void(const TorrentInfo&)> on_metadata_;
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
} // namespace librats::bittorrent
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
#include "librats/bittorrent/torrent_creator.h"
|
|
2
|
+
|
|
3
|
+
#include "librats/bittorrent/bencode.h"
|
|
4
|
+
#include "librats/bittorrent/file_storage.h"
|
|
5
|
+
#include "librats/crypto/sha1.h"
|
|
6
|
+
#include "librats/util/fs.h"
|
|
7
|
+
|
|
8
|
+
#include <ctime>
|
|
9
|
+
|
|
10
|
+
namespace librats::bittorrent {
|
|
11
|
+
|
|
12
|
+
namespace {
|
|
13
|
+
|
|
14
|
+
struct SourceFile {
|
|
15
|
+
std::vector<std::string> components; ///< path relative to the torrent root
|
|
16
|
+
std::int64_t size = 0;
|
|
17
|
+
std::string disk_path; ///< where to read the bytes from
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/// Recursively collect the regular files under @p dir, accumulating the path
|
|
21
|
+
/// components relative to the torrent root.
|
|
22
|
+
void scan_directory(const std::string& dir, std::vector<std::string> prefix,
|
|
23
|
+
std::vector<SourceFile>& out) {
|
|
24
|
+
std::vector<DirectoryEntry> entries;
|
|
25
|
+
if (!list_directory(dir.c_str(), entries)) return;
|
|
26
|
+
for (const auto& e : entries) {
|
|
27
|
+
if (e.name == "." || e.name == "..") continue;
|
|
28
|
+
std::vector<std::string> comps = prefix;
|
|
29
|
+
comps.push_back(e.name);
|
|
30
|
+
const std::string child = combine_paths(dir, e.name);
|
|
31
|
+
if (e.is_directory) scan_directory(child, std::move(comps), out);
|
|
32
|
+
else out.push_back(SourceFile{std::move(comps), std::int64_t(get_file_size(child.c_str())), child});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
} // namespace
|
|
37
|
+
|
|
38
|
+
std::optional<TorrentInfo> TorrentCreator::create_from_path(const std::string& path, std::string* error,
|
|
39
|
+
const PieceHashProgress& on_progress) {
|
|
40
|
+
auto fail = [&](const char* m) -> std::optional<TorrentInfo> { if (error) *error = m; return std::nullopt; };
|
|
41
|
+
|
|
42
|
+
const std::string root_name = name_.empty() ? get_filename_from_path(path) : name_;
|
|
43
|
+
if (root_name.empty()) return fail("empty torrent name");
|
|
44
|
+
|
|
45
|
+
// Gather the source files and lay them out (the layout also drives reading).
|
|
46
|
+
std::vector<SourceFile> sources;
|
|
47
|
+
bool single_file = false;
|
|
48
|
+
if (is_directory(path.c_str())) {
|
|
49
|
+
scan_directory(path, {}, sources);
|
|
50
|
+
} else if (is_file(path.c_str())) {
|
|
51
|
+
single_file = true;
|
|
52
|
+
sources.push_back(SourceFile{{root_name}, std::int64_t(get_file_size(path.c_str())), path});
|
|
53
|
+
} else {
|
|
54
|
+
return fail("path is neither a file nor a directory");
|
|
55
|
+
}
|
|
56
|
+
if (sources.empty()) return fail("no files to add");
|
|
57
|
+
|
|
58
|
+
FileStorage layout;
|
|
59
|
+
layout.set_piece_length(piece_length_);
|
|
60
|
+
layout.set_name(root_name);
|
|
61
|
+
std::vector<std::string> disk_paths;
|
|
62
|
+
for (const auto& s : sources) {
|
|
63
|
+
std::string rel = root_name;
|
|
64
|
+
if (!single_file)
|
|
65
|
+
for (const auto& c : s.components) { rel += '/'; rel += c; }
|
|
66
|
+
if (!layout.add_file(rel, s.size)) return fail("file size overflow");
|
|
67
|
+
disk_paths.push_back(s.disk_path);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Hash every piece by reading the bytes it spans across the source files.
|
|
71
|
+
const std::uint32_t total_pieces = layout.num_pieces();
|
|
72
|
+
std::string pieces;
|
|
73
|
+
pieces.reserve(std::size_t(total_pieces) * 20);
|
|
74
|
+
for (std::uint32_t p = 0; p < total_pieces; ++p) {
|
|
75
|
+
Bytes buf;
|
|
76
|
+
buf.reserve(layout.piece_size(p));
|
|
77
|
+
for (const auto& slice : layout.map_block(p, 0, layout.piece_size(p))) {
|
|
78
|
+
Bytes chunk(std::size_t(slice.size));
|
|
79
|
+
if (!read_file_chunk(disk_paths[slice.file_index], std::uint64_t(slice.offset),
|
|
80
|
+
chunk.data(), chunk.size()))
|
|
81
|
+
return fail("failed to read source file");
|
|
82
|
+
buf.insert(buf.end(), chunk.begin(), chunk.end());
|
|
83
|
+
}
|
|
84
|
+
auto h = SHA1::hash_raw(buf.data(), buf.size());
|
|
85
|
+
pieces.append(reinterpret_cast<const char*>(h.data()), 20);
|
|
86
|
+
if (on_progress) on_progress(p + 1, total_pieces);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Build the info dictionary.
|
|
90
|
+
librats::BencodeValue info = librats::BencodeValue::create_dict();
|
|
91
|
+
info["name"] = librats::BencodeValue(root_name);
|
|
92
|
+
info["piece length"] = librats::BencodeValue(std::int64_t(piece_length_));
|
|
93
|
+
info["pieces"] = librats::BencodeValue(pieces);
|
|
94
|
+
if (private_) info["private"] = librats::BencodeValue(std::int64_t(1));
|
|
95
|
+
if (single_file) {
|
|
96
|
+
info["length"] = librats::BencodeValue(std::int64_t(sources[0].size));
|
|
97
|
+
} else {
|
|
98
|
+
librats::BencodeValue files = librats::BencodeValue::create_list();
|
|
99
|
+
for (const auto& s : sources) {
|
|
100
|
+
librats::BencodeValue f = librats::BencodeValue::create_dict();
|
|
101
|
+
f["length"] = librats::BencodeValue(std::int64_t(s.size));
|
|
102
|
+
librats::BencodeValue comps = librats::BencodeValue::create_list();
|
|
103
|
+
for (const auto& c : s.components) comps.push_back(librats::BencodeValue(c));
|
|
104
|
+
f["path"] = comps;
|
|
105
|
+
files.push_back(f);
|
|
106
|
+
}
|
|
107
|
+
info["files"] = files;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Wrap into a full .torrent with the optional top-level fields.
|
|
111
|
+
librats::BencodeValue root = librats::BencodeValue::create_dict();
|
|
112
|
+
if (!trackers_.empty()) {
|
|
113
|
+
root["announce"] = librats::BencodeValue(trackers_.front());
|
|
114
|
+
librats::BencodeValue tier = librats::BencodeValue::create_list();
|
|
115
|
+
for (const auto& t : trackers_) tier.push_back(librats::BencodeValue(t));
|
|
116
|
+
librats::BencodeValue al = librats::BencodeValue::create_list();
|
|
117
|
+
al.push_back(tier);
|
|
118
|
+
root["announce-list"] = al;
|
|
119
|
+
}
|
|
120
|
+
if (!comment_.empty()) root["comment"] = librats::BencodeValue(comment_);
|
|
121
|
+
if (!created_by_.empty()) root["created by"] = librats::BencodeValue(created_by_);
|
|
122
|
+
root["creation date"] = librats::BencodeValue(std::int64_t(std::time(nullptr)));
|
|
123
|
+
root["info"] = info;
|
|
124
|
+
|
|
125
|
+
torrent_bytes_ = root.encode();
|
|
126
|
+
return TorrentInfo::from_bytes(torrent_bytes_);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
} // namespace librats::bittorrent
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file torrent_creator.h
|
|
5
|
+
* @brief Build a .torrent from files on disk.
|
|
6
|
+
*
|
|
7
|
+
* Point it at a file or directory; it lays the files end-to-end, hashes every
|
|
8
|
+
* piece (SHA-1), and emits both a parsed TorrentInfo and the bencoded .torrent
|
|
9
|
+
* bytes. The resulting metadata is exactly what a downloader would receive, so
|
|
10
|
+
* the creator can immediately seed via Client::add_torrent_for_seeding.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
#include "librats/bittorrent/torrent_info.h"
|
|
14
|
+
#include "librats/bittorrent/types.h"
|
|
15
|
+
#include "librats/core/bytes.h"
|
|
16
|
+
|
|
17
|
+
#include <cstdint>
|
|
18
|
+
#include <functional>
|
|
19
|
+
#include <optional>
|
|
20
|
+
#include <string>
|
|
21
|
+
#include <vector>
|
|
22
|
+
|
|
23
|
+
namespace librats::bittorrent {
|
|
24
|
+
|
|
25
|
+
/// Reports piece-hashing progress during create_from_path: (pieces_hashed,
|
|
26
|
+
/// total_pieces). Called once per piece as it is hashed; total_pieces is fixed
|
|
27
|
+
/// for the whole run and the final call always has pieces_hashed == total_pieces.
|
|
28
|
+
using PieceHashProgress = std::function<void(std::uint32_t pieces_hashed, std::uint32_t total_pieces)>;
|
|
29
|
+
|
|
30
|
+
class TorrentCreator {
|
|
31
|
+
public:
|
|
32
|
+
void set_piece_length(std::uint32_t length) { piece_length_ = length; }
|
|
33
|
+
void set_name(std::string name) { name_ = std::move(name); }
|
|
34
|
+
void add_tracker(std::string url) { trackers_.push_back(std::move(url)); }
|
|
35
|
+
void set_private(bool is_private) { private_ = is_private; }
|
|
36
|
+
void set_comment(std::string comment) { comment_ = std::move(comment); }
|
|
37
|
+
void set_created_by(std::string creator) { created_by_ = std::move(creator); }
|
|
38
|
+
|
|
39
|
+
/// Hash @p path (a file or directory) and build the torrent. On success the
|
|
40
|
+
/// bencoded form is available via torrent_file(). Returns nullopt (and sets
|
|
41
|
+
/// @p error, if given) on I/O or layout problems. If @p on_progress is set it
|
|
42
|
+
/// is invoked once per hashed piece so callers can drive a progress bar.
|
|
43
|
+
std::optional<TorrentInfo> create_from_path(const std::string& path, std::string* error = nullptr,
|
|
44
|
+
const PieceHashProgress& on_progress = {});
|
|
45
|
+
|
|
46
|
+
const Bytes& torrent_file() const noexcept { return torrent_bytes_; }
|
|
47
|
+
|
|
48
|
+
private:
|
|
49
|
+
std::uint32_t piece_length_ = kDefaultPieceLength;
|
|
50
|
+
std::string name_;
|
|
51
|
+
std::string comment_;
|
|
52
|
+
std::string created_by_;
|
|
53
|
+
bool private_ = false;
|
|
54
|
+
std::vector<std::string> trackers_;
|
|
55
|
+
Bytes torrent_bytes_;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
} // namespace librats::bittorrent
|