librats 1.0.2 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (319) hide show
  1. package/README.md +145 -331
  2. package/binding.gyp +16 -3
  3. package/lib/index.d.ts +288 -696
  4. package/lib/index.js +407 -44
  5. package/native-src/3rdparty/android/ifaddrs-android.c +1 -0
  6. package/native-src/3rdparty/android/ifaddrs-android.h +1 -0
  7. package/native-src/CMakeLists.txt +404 -179
  8. package/native-src/LICENSE +1 -1
  9. package/native-src/src/librats/bindings/rats.cpp +762 -0
  10. package/native-src/src/librats/bindings/rats.h +380 -0
  11. package/native-src/src/librats/bittorrent/bencode.cpp +437 -0
  12. package/native-src/src/librats/bittorrent/bencode.h +176 -0
  13. package/native-src/src/librats/bittorrent/bitfield.cpp +97 -0
  14. package/native-src/src/librats/bittorrent/bitfield.h +76 -0
  15. package/native-src/src/librats/bittorrent/byte_io.h +58 -0
  16. package/native-src/src/librats/bittorrent/choker.cpp +25 -0
  17. package/native-src/src/librats/bittorrent/choker.h +46 -0
  18. package/native-src/src/librats/bittorrent/client.cpp +413 -0
  19. package/native-src/src/librats/bittorrent/client.h +227 -0
  20. package/native-src/src/librats/bittorrent/disk_io.cpp +209 -0
  21. package/native-src/src/librats/bittorrent/disk_io.h +150 -0
  22. package/native-src/src/librats/bittorrent/extensions.cpp +191 -0
  23. package/native-src/src/librats/bittorrent/extensions.h +94 -0
  24. package/native-src/src/librats/bittorrent/file_storage.cpp +77 -0
  25. package/native-src/src/librats/bittorrent/file_storage.h +79 -0
  26. package/native-src/src/librats/bittorrent/log.h +42 -0
  27. package/native-src/src/librats/bittorrent/magnet_uri.cpp +98 -0
  28. package/native-src/src/librats/bittorrent/magnet_uri.h +35 -0
  29. package/native-src/src/librats/bittorrent/peer_connection.cpp +502 -0
  30. package/native-src/src/librats/bittorrent/peer_connection.h +194 -0
  31. package/native-src/src/librats/bittorrent/peer_list.cpp +68 -0
  32. package/native-src/src/librats/bittorrent/peer_list.h +75 -0
  33. package/native-src/src/librats/bittorrent/piece_picker.cpp +352 -0
  34. package/native-src/src/librats/bittorrent/piece_picker.h +201 -0
  35. package/native-src/src/librats/bittorrent/reactor.cpp +97 -0
  36. package/native-src/src/librats/bittorrent/reactor.h +89 -0
  37. package/native-src/src/librats/bittorrent/resume_data.cpp +72 -0
  38. package/native-src/src/librats/bittorrent/resume_data.h +41 -0
  39. package/native-src/src/librats/bittorrent/store_buffer.cpp +48 -0
  40. package/native-src/src/librats/bittorrent/store_buffer.h +47 -0
  41. package/native-src/src/librats/bittorrent/torrent.cpp +870 -0
  42. package/native-src/src/librats/bittorrent/torrent.h +260 -0
  43. package/native-src/src/librats/bittorrent/torrent_creator.cpp +129 -0
  44. package/native-src/src/librats/bittorrent/torrent_creator.h +58 -0
  45. package/native-src/src/librats/bittorrent/torrent_info.cpp +314 -0
  46. package/native-src/src/librats/bittorrent/torrent_info.h +118 -0
  47. package/native-src/src/librats/bittorrent/tracker.cpp +374 -0
  48. package/native-src/src/librats/bittorrent/tracker.h +108 -0
  49. package/native-src/src/librats/bittorrent/types.cpp +206 -0
  50. package/native-src/src/librats/bittorrent/types.h +86 -0
  51. package/native-src/src/librats/core/address.cpp +35 -0
  52. package/native-src/src/librats/core/address.h +78 -0
  53. package/native-src/src/librats/core/bytes.h +69 -0
  54. package/native-src/src/librats/core/chained_send_buffer.cpp +172 -0
  55. package/native-src/src/librats/core/chained_send_buffer.h +183 -0
  56. package/native-src/src/librats/core/endpoint_parse.cpp +41 -0
  57. package/native-src/src/librats/core/endpoint_parse.h +31 -0
  58. package/native-src/src/librats/core/event_bus.h +70 -0
  59. package/native-src/src/librats/core/host_endpoint.h +56 -0
  60. package/native-src/src/{io_poller.cpp → librats/core/io_poller.cpp} +520 -65
  61. package/native-src/src/{io_poller.h → librats/core/io_poller.h} +12 -6
  62. package/native-src/src/librats/core/ip_address.cpp +120 -0
  63. package/native-src/src/librats/core/ip_address.h +109 -0
  64. package/native-src/src/librats/core/mpsc_queue.h +47 -0
  65. package/native-src/src/librats/core/notifier.h +74 -0
  66. package/native-src/src/librats/core/receive_buffer.cpp +219 -0
  67. package/native-src/src/librats/core/receive_buffer.h +171 -0
  68. package/native-src/src/librats/core/service_registry.h +58 -0
  69. package/native-src/src/{socket.cpp → librats/core/socket.cpp} +625 -118
  70. package/native-src/src/librats/core/socket.h +496 -0
  71. package/native-src/src/librats/core/timer_queue.h +105 -0
  72. package/native-src/src/librats/core/types.cpp +43 -0
  73. package/native-src/src/librats/core/types.h +103 -0
  74. package/native-src/src/librats/core/wakeup_pipe.h +83 -0
  75. package/native-src/src/{crypto → librats/crypto}/blake2_endian.h +21 -23
  76. package/native-src/src/{crypto → librats/crypto}/blake2b.c +34 -33
  77. package/native-src/src/{crypto → librats/crypto}/blake2b.h +7 -6
  78. package/native-src/src/{crypto → librats/crypto}/blake2s.c +55 -54
  79. package/native-src/src/{crypto → librats/crypto}/blake2s.h +13 -12
  80. package/native-src/src/{crypto → librats/crypto}/chacha.c +22 -21
  81. package/native-src/src/{crypto → librats/crypto}/chacha.h +14 -13
  82. package/native-src/src/{crypto → librats/crypto}/chachapoly.c +56 -56
  83. package/native-src/src/{crypto → librats/crypto}/chachapoly.h +24 -17
  84. package/native-src/src/{crc32.cpp → librats/crypto/crc32.cpp} +1 -1
  85. package/native-src/src/{crc32.h → librats/crypto/crc32.h} +3 -1
  86. package/native-src/src/{crypto → librats/crypto}/curve25519.c +6 -4
  87. package/native-src/src/{crypto → librats/crypto}/curve25519.h +6 -3
  88. package/native-src/src/librats/crypto/hkdf.c +266 -0
  89. package/native-src/src/{crypto → librats/crypto}/hkdf.h +19 -19
  90. package/native-src/src/{noise.cpp → librats/crypto/noise.cpp} +84 -73
  91. package/native-src/src/{noise.h → librats/crypto/noise.h} +18 -8
  92. package/native-src/src/{crypto → librats/crypto}/poly1305.c +47 -46
  93. package/native-src/src/librats/crypto/poly1305.h +37 -0
  94. package/native-src/src/{sha1.cpp → librats/crypto/sha1.cpp} +33 -1
  95. package/native-src/src/{sha1.h → librats/crypto/sha1.h} +14 -6
  96. package/native-src/src/{crypto → librats/crypto}/sha256.c +15 -14
  97. package/native-src/src/{crypto → librats/crypto}/sha256.h +8 -7
  98. package/native-src/src/{crypto → librats/crypto}/sha512.c +15 -14
  99. package/native-src/src/{crypto → librats/crypto}/sha512.h +8 -7
  100. package/native-src/src/librats/dht/announce.cpp +37 -0
  101. package/native-src/src/librats/dht/announce.h +41 -0
  102. package/native-src/src/librats/dht/bep42.cpp +109 -0
  103. package/native-src/src/librats/dht/bep42.h +48 -0
  104. package/native-src/src/librats/dht/dht.cpp +501 -0
  105. package/native-src/src/librats/dht/dht.h +119 -0
  106. package/native-src/src/librats/dht/dht_runner.cpp +103 -0
  107. package/native-src/src/librats/dht/dht_runner.h +71 -0
  108. package/native-src/src/librats/dht/dos_blocker.cpp +42 -0
  109. package/native-src/src/librats/dht/dos_blocker.h +47 -0
  110. package/native-src/src/librats/dht/find_peers.cpp +52 -0
  111. package/native-src/src/librats/dht/find_peers.h +73 -0
  112. package/native-src/src/librats/dht/id.h +167 -0
  113. package/native-src/src/{krpc.cpp → librats/dht/krpc.cpp} +32 -81
  114. package/native-src/src/{krpc.h → librats/dht/krpc.h} +19 -23
  115. package/native-src/src/librats/dht/log.h +38 -0
  116. package/native-src/src/librats/dht/node.cpp +473 -0
  117. package/native-src/src/librats/dht/node.h +164 -0
  118. package/native-src/src/librats/dht/node_entry.h +81 -0
  119. package/native-src/src/librats/dht/observer.h +72 -0
  120. package/native-src/src/librats/dht/persistence.cpp +90 -0
  121. package/native-src/src/librats/dht/persistence.h +32 -0
  122. package/native-src/src/librats/dht/routing_table.cpp +559 -0
  123. package/native-src/src/librats/dht/routing_table.h +185 -0
  124. package/native-src/src/librats/dht/rpc_manager.cpp +127 -0
  125. package/native-src/src/librats/dht/rpc_manager.h +77 -0
  126. package/native-src/src/librats/dht/storage.cpp +92 -0
  127. package/native-src/src/librats/dht/storage.h +74 -0
  128. package/native-src/src/librats/dht/transport.h +27 -0
  129. package/native-src/src/librats/dht/traversal.cpp +326 -0
  130. package/native-src/src/librats/dht/traversal.h +120 -0
  131. package/native-src/src/librats/dht/udp_transport.cpp +49 -0
  132. package/native-src/src/librats/dht/udp_transport.h +51 -0
  133. package/native-src/src/librats/mdns/log.h +22 -0
  134. package/native-src/src/{mdns.cpp → librats/mdns/mdns.cpp} +75 -40
  135. package/native-src/src/{mdns.h → librats/mdns/mdns.h} +9 -8
  136. package/native-src/src/{natpmp.cpp → librats/nat/natpmp.cpp} +12 -9
  137. package/native-src/src/{natpmp.h → librats/nat/natpmp.h} +3 -3
  138. package/native-src/src/{port_mapping.h → librats/nat/port_mapping.h} +3 -2
  139. package/native-src/src/{stun.cpp → librats/nat/stun.cpp} +4 -4
  140. package/native-src/src/{stun.h → librats/nat/stun.h} +1 -1
  141. package/native-src/src/{upnp.cpp → librats/nat/upnp.cpp} +6 -6
  142. package/native-src/src/{upnp.h → librats/nat/upnp.h} +2 -2
  143. package/native-src/src/librats/node/circuit_service.h +84 -0
  144. package/native-src/src/librats/node/config.h +110 -0
  145. package/native-src/src/librats/node/dial_service.h +54 -0
  146. package/native-src/src/librats/node/dialer.cpp +264 -0
  147. package/native-src/src/librats/node/dialer.h +188 -0
  148. package/native-src/src/librats/node/host_events.h +26 -0
  149. package/native-src/src/librats/node/identify.cpp +130 -0
  150. package/native-src/src/librats/node/identify.h +71 -0
  151. package/native-src/src/librats/node/nat_status.cpp +103 -0
  152. package/native-src/src/librats/node/nat_status.h +118 -0
  153. package/native-src/src/librats/node/node.cpp +865 -0
  154. package/native-src/src/librats/node/node.h +344 -0
  155. package/native-src/src/librats/node/node_context.h +33 -0
  156. package/native-src/src/librats/node/peer_network.h +91 -0
  157. package/native-src/src/librats/peer/peer.h +49 -0
  158. package/native-src/src/librats/peer/peer_book.cpp +181 -0
  159. package/native-src/src/librats/peer/peer_book.h +88 -0
  160. package/native-src/src/librats/peer/peer_id.cpp +72 -0
  161. package/native-src/src/librats/peer/peer_id.h +62 -0
  162. package/native-src/src/librats/peer/peer_info.h +37 -0
  163. package/native-src/src/librats/peer/peer_table.cpp +170 -0
  164. package/native-src/src/librats/peer/peer_table.h +148 -0
  165. package/native-src/src/librats/security/handshaker.h +66 -0
  166. package/native-src/src/librats/security/identity.h +43 -0
  167. package/native-src/src/librats/security/noise_security.cpp +122 -0
  168. package/native-src/src/librats/security/noise_security.h +37 -0
  169. package/native-src/src/librats/security/plaintext_security.h +106 -0
  170. package/native-src/src/librats/security/session.h +37 -0
  171. package/native-src/src/{storage.cpp → librats/storage/storage.cpp} +369 -522
  172. package/native-src/src/{storage.h → librats/storage/storage.h} +135 -299
  173. package/native-src/src/librats/subsystems/bittorrent.cpp +211 -0
  174. package/native-src/src/librats/subsystems/bittorrent.h +136 -0
  175. package/native-src/src/librats/subsystems/dht_discovery.cpp +202 -0
  176. package/native-src/src/librats/subsystems/dht_discovery.h +123 -0
  177. package/native-src/src/librats/subsystems/dht_service.h +36 -0
  178. package/native-src/src/librats/subsystems/file_transfer.cpp +972 -0
  179. package/native-src/src/librats/subsystems/file_transfer.h +367 -0
  180. package/native-src/src/librats/subsystems/hole_punch.cpp +605 -0
  181. package/native-src/src/librats/subsystems/hole_punch.h +290 -0
  182. package/native-src/src/librats/subsystems/hole_punch_service.h +38 -0
  183. package/native-src/src/librats/subsystems/mdns_discovery.cpp +66 -0
  184. package/native-src/src/librats/subsystems/mdns_discovery.h +55 -0
  185. package/native-src/src/librats/subsystems/message_json.cpp +112 -0
  186. package/native-src/src/librats/subsystems/message_json.h +88 -0
  187. package/native-src/src/librats/subsystems/peer_exchange.cpp +241 -0
  188. package/native-src/src/librats/subsystems/peer_exchange.h +136 -0
  189. package/native-src/src/librats/subsystems/ping_service.cpp +98 -0
  190. package/native-src/src/librats/subsystems/ping_service.h +66 -0
  191. package/native-src/src/librats/subsystems/port_mapping_service.cpp +192 -0
  192. package/native-src/src/librats/subsystems/port_mapping_service.h +84 -0
  193. package/native-src/src/librats/subsystems/pubsub.cpp +567 -0
  194. package/native-src/src/librats/subsystems/pubsub.h +175 -0
  195. package/native-src/src/librats/subsystems/reconnection.cpp +239 -0
  196. package/native-src/src/librats/subsystems/reconnection.h +126 -0
  197. package/native-src/src/librats/subsystems/relay.cpp +1142 -0
  198. package/native-src/src/librats/subsystems/relay.h +211 -0
  199. package/native-src/src/librats/subsystems/relay_service.h +46 -0
  200. package/native-src/src/librats/transport/connection.cpp +343 -0
  201. package/native-src/src/librats/transport/connection.h +283 -0
  202. package/native-src/src/librats/transport/link.h +96 -0
  203. package/native-src/src/librats/transport/reactor.cpp +588 -0
  204. package/native-src/src/librats/transport/reactor.h +262 -0
  205. package/native-src/src/librats/transport/reactor_pool.h +81 -0
  206. package/native-src/src/librats/transport/relay_link.cpp +208 -0
  207. package/native-src/src/librats/transport/relay_link.h +303 -0
  208. package/native-src/src/librats/transport/tcp_link.cpp +49 -0
  209. package/native-src/src/librats/transport/tcp_link.h +43 -0
  210. package/native-src/src/librats/transport/udp_mux.cpp +617 -0
  211. package/native-src/src/librats/transport/udp_mux.h +363 -0
  212. package/native-src/src/librats/transport/udp_packet.cpp +121 -0
  213. package/native-src/src/librats/transport/udp_packet.h +190 -0
  214. package/native-src/src/librats/transport/udp_stream.cpp +1194 -0
  215. package/native-src/src/librats/transport/udp_stream.h +614 -0
  216. package/native-src/src/librats/util/features.h.in +51 -0
  217. package/native-src/src/{fs.cpp → librats/util/fs.cpp} +51 -3
  218. package/native-src/src/librats/util/fs.h +136 -0
  219. package/native-src/src/librats/util/json.cpp +1002 -0
  220. package/native-src/src/librats/util/json.h +444 -0
  221. package/native-src/src/{logger.cpp → librats/util/logger.cpp} +1 -1
  222. package/native-src/src/{logger.h → librats/util/logger.h} +43 -31
  223. package/native-src/src/{network_monitor.cpp → librats/util/network_monitor.cpp} +12 -4
  224. package/native-src/src/{network_monitor.h → librats/util/network_monitor.h} +2 -1
  225. package/native-src/src/{network_utils.cpp → librats/util/network_utils.cpp} +38 -23
  226. package/native-src/src/{network_utils.h → librats/util/network_utils.h} +15 -8
  227. package/native-src/src/{os.cpp → librats/util/os.cpp} +48 -18
  228. package/native-src/src/librats/util/rats_export.h +69 -0
  229. package/native-src/src/{version.cpp → librats/util/version.cpp} +2 -2
  230. package/native-src/src/{version.h.in → librats/util/version.h.in} +1 -1
  231. package/native-src/src/librats/wire/frame.cpp +76 -0
  232. package/native-src/src/librats/wire/frame.h +111 -0
  233. package/native-src/src/librats/wire/message_router.cpp +45 -0
  234. package/native-src/src/librats/wire/message_router.h +47 -0
  235. package/package.json +5 -4
  236. package/scripts/build-librats.js +1 -0
  237. package/scripts/postinstall.js +3 -3
  238. package/scripts/prepare-package.js +4 -4
  239. package/scripts/verify-installation.js +63 -105
  240. package/src/librats_node.cpp +1067 -1323
  241. package/native-src/src/bencode.cpp +0 -485
  242. package/native-src/src/bencode.h +0 -145
  243. package/native-src/src/bittorrent.cpp +0 -14
  244. package/native-src/src/bittorrent.h +0 -74
  245. package/native-src/src/bt_bitfield.cpp +0 -372
  246. package/native-src/src/bt_bitfield.h +0 -316
  247. package/native-src/src/bt_choker.cpp +0 -228
  248. package/native-src/src/bt_choker.h +0 -147
  249. package/native-src/src/bt_client.cpp +0 -1047
  250. package/native-src/src/bt_client.h +0 -445
  251. package/native-src/src/bt_create_torrent.cpp +0 -677
  252. package/native-src/src/bt_create_torrent.h +0 -473
  253. package/native-src/src/bt_extension.cpp +0 -469
  254. package/native-src/src/bt_extension.h +0 -309
  255. package/native-src/src/bt_file_storage.cpp +0 -261
  256. package/native-src/src/bt_file_storage.h +0 -298
  257. package/native-src/src/bt_handshake.cpp +0 -134
  258. package/native-src/src/bt_handshake.h +0 -157
  259. package/native-src/src/bt_messages.cpp +0 -364
  260. package/native-src/src/bt_messages.h +0 -324
  261. package/native-src/src/bt_network.cpp +0 -1007
  262. package/native-src/src/bt_network.h +0 -417
  263. package/native-src/src/bt_peer_connection.cpp +0 -742
  264. package/native-src/src/bt_peer_connection.h +0 -592
  265. package/native-src/src/bt_piece_picker.cpp +0 -786
  266. package/native-src/src/bt_piece_picker.h +0 -473
  267. package/native-src/src/bt_resume_data.cpp +0 -410
  268. package/native-src/src/bt_resume_data.h +0 -249
  269. package/native-src/src/bt_torrent.cpp +0 -2120
  270. package/native-src/src/bt_torrent.h +0 -641
  271. package/native-src/src/bt_torrent_info.cpp +0 -659
  272. package/native-src/src/bt_torrent_info.h +0 -418
  273. package/native-src/src/bt_types.h +0 -621
  274. package/native-src/src/chained_send_buffer.cpp +0 -75
  275. package/native-src/src/chained_send_buffer.h +0 -137
  276. package/native-src/src/crypto/hkdf.c +0 -266
  277. package/native-src/src/crypto/poly1305.h +0 -36
  278. package/native-src/src/dht.cpp +0 -3311
  279. package/native-src/src/dht.h +0 -717
  280. package/native-src/src/disk_io.cpp +0 -632
  281. package/native-src/src/disk_io.h +0 -315
  282. package/native-src/src/file_transfer.cpp +0 -1415
  283. package/native-src/src/file_transfer.h +0 -286
  284. package/native-src/src/fs.h +0 -108
  285. package/native-src/src/gossipsub.cpp +0 -1139
  286. package/native-src/src/gossipsub.h +0 -403
  287. package/native-src/src/ice.cpp +0 -893
  288. package/native-src/src/ice.h +0 -559
  289. package/native-src/src/json.hpp +0 -25526
  290. package/native-src/src/librats.cpp +0 -2378
  291. package/native-src/src/librats.h +0 -2324
  292. package/native-src/src/librats_bittorrent.cpp +0 -601
  293. package/native-src/src/librats_c.cpp +0 -1557
  294. package/native-src/src/librats_c.h +0 -323
  295. package/native-src/src/librats_discovery.cpp +0 -402
  296. package/native-src/src/librats_encryption.cpp +0 -275
  297. package/native-src/src/librats_file_transfer.cpp +0 -144
  298. package/native-src/src/librats_gossipsub.cpp +0 -289
  299. package/native-src/src/librats_ice.cpp +0 -213
  300. package/native-src/src/librats_log_macros.h +0 -36
  301. package/native-src/src/librats_logging.cpp +0 -173
  302. package/native-src/src/librats_mdns.cpp +0 -166
  303. package/native-src/src/librats_persistence.cpp +0 -796
  304. package/native-src/src/librats_portmap.cpp +0 -419
  305. package/native-src/src/librats_reconnection.cpp +0 -218
  306. package/native-src/src/librats_statistic.cpp +0 -105
  307. package/native-src/src/librats_storage.cpp +0 -189
  308. package/native-src/src/rats_export.h +0 -17
  309. package/native-src/src/receive_buffer.cpp +0 -82
  310. package/native-src/src/receive_buffer.h +0 -127
  311. package/native-src/src/socket.h +0 -228
  312. package/native-src/src/threadmanager.cpp +0 -105
  313. package/native-src/src/threadmanager.h +0 -53
  314. package/native-src/src/tracker.cpp +0 -1264
  315. package/native-src/src/tracker.h +0 -319
  316. package/native-src/src/turn.cpp +0 -762
  317. package/native-src/src/turn.h +0 -460
  318. package/native-src/src/wakeup_pipe.h +0 -60
  319. /package/native-src/src/{os.h → librats/util/os.h} +0 -0
@@ -1,659 +0,0 @@
1
- #include "bt_torrent_info.h"
2
- #include "sha1.h"
3
-
4
- #include <fstream>
5
- #include <algorithm>
6
- #include <cctype>
7
- #include <sstream>
8
- #include <iomanip>
9
-
10
- namespace librats {
11
-
12
- //=============================================================================
13
- // Constructors
14
- //=============================================================================
15
-
16
- TorrentInfo::TorrentInfo()
17
- : info_hash_{}
18
- , creation_date_(0)
19
- , is_private_(false)
20
- , has_metadata_(false) {
21
- }
22
-
23
- TorrentInfo::TorrentInfo(const TorrentInfo& other)
24
- : info_hash_(other.info_hash_)
25
- , name_(other.name_)
26
- , comment_(other.comment_)
27
- , created_by_(other.created_by_)
28
- , creation_date_(other.creation_date_)
29
- , is_private_(other.is_private_)
30
- , has_metadata_(other.has_metadata_)
31
- , files_(other.files_)
32
- , piece_hashes_(other.piece_hashes_)
33
- , announce_(other.announce_)
34
- , announce_list_(other.announce_list_)
35
- , web_seeds_(other.web_seeds_)
36
- , dht_nodes_(other.dht_nodes_)
37
- , info_dict_bytes_(other.info_dict_bytes_) {
38
- }
39
-
40
- TorrentInfo::TorrentInfo(TorrentInfo&& other) noexcept
41
- : info_hash_(std::move(other.info_hash_))
42
- , name_(std::move(other.name_))
43
- , comment_(std::move(other.comment_))
44
- , created_by_(std::move(other.created_by_))
45
- , creation_date_(other.creation_date_)
46
- , is_private_(other.is_private_)
47
- , has_metadata_(other.has_metadata_)
48
- , files_(std::move(other.files_))
49
- , piece_hashes_(std::move(other.piece_hashes_))
50
- , announce_(std::move(other.announce_))
51
- , announce_list_(std::move(other.announce_list_))
52
- , web_seeds_(std::move(other.web_seeds_))
53
- , dht_nodes_(std::move(other.dht_nodes_))
54
- , info_dict_bytes_(std::move(other.info_dict_bytes_)) {
55
- other.has_metadata_ = false;
56
- }
57
-
58
- TorrentInfo& TorrentInfo::operator=(const TorrentInfo& other) {
59
- if (this != &other) {
60
- info_hash_ = other.info_hash_;
61
- name_ = other.name_;
62
- comment_ = other.comment_;
63
- created_by_ = other.created_by_;
64
- creation_date_ = other.creation_date_;
65
- is_private_ = other.is_private_;
66
- has_metadata_ = other.has_metadata_;
67
- files_ = other.files_;
68
- piece_hashes_ = other.piece_hashes_;
69
- announce_ = other.announce_;
70
- announce_list_ = other.announce_list_;
71
- web_seeds_ = other.web_seeds_;
72
- dht_nodes_ = other.dht_nodes_;
73
- info_dict_bytes_ = other.info_dict_bytes_;
74
- }
75
- return *this;
76
- }
77
-
78
- TorrentInfo& TorrentInfo::operator=(TorrentInfo&& other) noexcept {
79
- if (this != &other) {
80
- info_hash_ = std::move(other.info_hash_);
81
- name_ = std::move(other.name_);
82
- comment_ = std::move(other.comment_);
83
- created_by_ = std::move(other.created_by_);
84
- creation_date_ = other.creation_date_;
85
- is_private_ = other.is_private_;
86
- has_metadata_ = other.has_metadata_;
87
- files_ = std::move(other.files_);
88
- piece_hashes_ = std::move(other.piece_hashes_);
89
- announce_ = std::move(other.announce_);
90
- announce_list_ = std::move(other.announce_list_);
91
- web_seeds_ = std::move(other.web_seeds_);
92
- dht_nodes_ = std::move(other.dht_nodes_);
93
- info_dict_bytes_ = std::move(other.info_dict_bytes_);
94
- other.has_metadata_ = false;
95
- }
96
- return *this;
97
- }
98
-
99
- TorrentInfo::~TorrentInfo() = default;
100
-
101
- //=============================================================================
102
- // Static Factory Methods
103
- //=============================================================================
104
-
105
- std::optional<TorrentInfo> TorrentInfo::from_bytes(
106
- const std::vector<uint8_t>& data,
107
- TorrentParseError* error) {
108
-
109
- if (data.empty()) {
110
- if (error) error->message = "Empty data";
111
- return std::nullopt;
112
- }
113
-
114
- // Decode bencoded data
115
- BencodeValue decoded;
116
- try {
117
- decoded = BencodeDecoder::decode(data);
118
- } catch (...) {
119
- if (error) error->message = "Failed to decode bencoded data";
120
- return std::nullopt;
121
- }
122
-
123
- if (!decoded.is_dict()) {
124
- if (error) error->message = "Root element is not a dictionary";
125
- return std::nullopt;
126
- }
127
-
128
- const auto& root = decoded.as_dict();
129
-
130
- // Info dictionary is required
131
- auto info_it = root.find("info");
132
- if (info_it == root.end() || !info_it->second.is_dict()) {
133
- if (error) error->message = "Missing or invalid 'info' dictionary";
134
- return std::nullopt;
135
- }
136
-
137
- TorrentInfo info;
138
-
139
- // Extract info dictionary bytes for hash calculation
140
- // We need to find the raw bytes of the info dict in the original data
141
- // For now, re-encode it (this is correct as bencode is canonical)
142
- info.info_dict_bytes_ = info_it->second.encode();
143
- info.info_hash_ = calculate_info_hash(info.info_dict_bytes_);
144
-
145
- // Parse info dictionary
146
- if (!info.parse_info_dict(info_it->second, error)) {
147
- return std::nullopt;
148
- }
149
-
150
- // Parse announce (primary tracker)
151
- auto announce_it = root.find("announce");
152
- if (announce_it != root.end() && announce_it->second.is_string()) {
153
- info.announce_ = announce_it->second.as_string();
154
- }
155
-
156
- // Parse announce-list (multi-tracker)
157
- auto announce_list_it = root.find("announce-list");
158
- if (announce_list_it != root.end() && announce_list_it->second.is_list()) {
159
- for (const auto& tier : announce_list_it->second.as_list()) {
160
- if (tier.is_list()) {
161
- TrackerTier tracker_tier;
162
- for (const auto& tracker : tier.as_list()) {
163
- if (tracker.is_string()) {
164
- tracker_tier.push_back(tracker.as_string());
165
- }
166
- }
167
- if (!tracker_tier.empty()) {
168
- info.announce_list_.push_back(std::move(tracker_tier));
169
- }
170
- }
171
- }
172
- }
173
-
174
- // Parse comment
175
- auto comment_it = root.find("comment");
176
- if (comment_it != root.end() && comment_it->second.is_string()) {
177
- info.comment_ = comment_it->second.as_string();
178
- }
179
-
180
- // Parse created by
181
- auto created_by_it = root.find("created by");
182
- if (created_by_it != root.end() && created_by_it->second.is_string()) {
183
- info.created_by_ = created_by_it->second.as_string();
184
- }
185
-
186
- // Parse creation date
187
- auto creation_date_it = root.find("creation date");
188
- if (creation_date_it != root.end() && creation_date_it->second.is_integer()) {
189
- info.creation_date_ = creation_date_it->second.as_integer();
190
- }
191
-
192
- // Parse url-list (web seeds)
193
- auto url_list_it = root.find("url-list");
194
- if (url_list_it != root.end()) {
195
- if (url_list_it->second.is_string()) {
196
- info.web_seeds_.push_back(url_list_it->second.as_string());
197
- } else if (url_list_it->second.is_list()) {
198
- for (const auto& url : url_list_it->second.as_list()) {
199
- if (url.is_string()) {
200
- info.web_seeds_.push_back(url.as_string());
201
- }
202
- }
203
- }
204
- }
205
-
206
- // Parse nodes (DHT bootstrap nodes)
207
- auto nodes_it = root.find("nodes");
208
- if (nodes_it != root.end() && nodes_it->second.is_list()) {
209
- for (const auto& node : nodes_it->second.as_list()) {
210
- if (node.is_list() && node.size() >= 2) {
211
- const auto& node_list = node.as_list();
212
- if (node_list[0].is_string() && node_list[1].is_integer()) {
213
- DhtNode dht_node;
214
- dht_node.host = node_list[0].as_string();
215
- dht_node.port = static_cast<uint16_t>(node_list[1].as_integer());
216
- info.dht_nodes_.push_back(std::move(dht_node));
217
- }
218
- }
219
- }
220
- }
221
-
222
- info.has_metadata_ = true;
223
- return info;
224
- }
225
-
226
- std::optional<TorrentInfo> TorrentInfo::from_file(
227
- const std::string& path,
228
- TorrentParseError* error) {
229
-
230
- std::ifstream file(path, std::ios::binary);
231
- if (!file) {
232
- if (error) error->message = "Failed to open file: " + path;
233
- return std::nullopt;
234
- }
235
-
236
- // Read entire file
237
- file.seekg(0, std::ios::end);
238
- size_t size = static_cast<size_t>(file.tellg());
239
- file.seekg(0, std::ios::beg);
240
-
241
- std::vector<uint8_t> data(size);
242
- if (!file.read(reinterpret_cast<char*>(data.data()), size)) {
243
- if (error) error->message = "Failed to read file: " + path;
244
- return std::nullopt;
245
- }
246
-
247
- return from_bytes(data, error);
248
- }
249
-
250
- std::optional<TorrentInfo> TorrentInfo::from_magnet(
251
- const std::string& magnet_uri,
252
- TorrentParseError* error) {
253
-
254
- auto parsed = MagnetUri::parse(magnet_uri);
255
- if (!parsed) {
256
- if (error) error->message = "Failed to parse magnet URI";
257
- return std::nullopt;
258
- }
259
-
260
- if (!parsed->is_valid()) {
261
- if (error) error->message = "Invalid info hash in magnet URI";
262
- return std::nullopt;
263
- }
264
-
265
- TorrentInfo info;
266
- info.info_hash_ = parsed->info_hash;
267
- info.name_ = parsed->display_name;
268
-
269
- // Add trackers
270
- for (const auto& tracker : parsed->trackers) {
271
- if (info.announce_.empty()) {
272
- info.announce_ = tracker;
273
- }
274
- // Each tracker is its own tier in announce-list
275
- info.announce_list_.push_back({tracker});
276
- }
277
-
278
- // Add web seeds
279
- info.web_seeds_ = std::move(parsed->web_seeds);
280
-
281
- // Note: has_metadata_ remains false
282
- return info;
283
- }
284
-
285
- std::optional<TorrentInfo> TorrentInfo::from_info_dict(
286
- const std::vector<uint8_t>& info_dict_bytes,
287
- const BtInfoHash& expected_hash,
288
- TorrentParseError* error) {
289
-
290
- // Calculate hash and verify
291
- BtInfoHash actual_hash = calculate_info_hash(info_dict_bytes);
292
- if (actual_hash != expected_hash) {
293
- if (error) error->message = "Info hash mismatch";
294
- return std::nullopt;
295
- }
296
-
297
- // Decode info dictionary
298
- BencodeValue decoded;
299
- try {
300
- decoded = BencodeDecoder::decode(info_dict_bytes);
301
- } catch (...) {
302
- if (error) error->message = "Failed to decode info dictionary";
303
- return std::nullopt;
304
- }
305
-
306
- if (!decoded.is_dict()) {
307
- if (error) error->message = "Failed to decode info dictionary";
308
- return std::nullopt;
309
- }
310
-
311
- TorrentInfo info;
312
- info.info_hash_ = actual_hash;
313
- info.info_dict_bytes_ = info_dict_bytes;
314
-
315
- if (!info.parse_info_dict(decoded, error)) {
316
- return std::nullopt;
317
- }
318
-
319
- info.has_metadata_ = true;
320
- return info;
321
- }
322
-
323
- //=============================================================================
324
- // Parsing Helpers
325
- //=============================================================================
326
-
327
- bool TorrentInfo::parse_info_dict(const BencodeValue& info_dict, TorrentParseError* error) {
328
- const auto& info = info_dict.as_dict();
329
-
330
- // Name is required
331
- auto name_it = info.find("name");
332
- if (name_it == info.end() || !name_it->second.is_string()) {
333
- if (error) error->message = "Missing or invalid 'name' in info dictionary";
334
- return false;
335
- }
336
- name_ = name_it->second.as_string();
337
- files_.set_name(name_);
338
-
339
- // Piece length is required
340
- auto piece_length_it = info.find("piece length");
341
- if (piece_length_it == info.end() || !piece_length_it->second.is_integer()) {
342
- if (error) error->message = "Missing or invalid 'piece length' in info dictionary";
343
- return false;
344
- }
345
- uint32_t piece_length = static_cast<uint32_t>(piece_length_it->second.as_integer());
346
- files_.set_piece_length(piece_length);
347
-
348
- // Pieces (concatenated SHA-1 hashes) is required
349
- auto pieces_it = info.find("pieces");
350
- if (pieces_it == info.end() || !pieces_it->second.is_string()) {
351
- if (error) error->message = "Missing or invalid 'pieces' in info dictionary";
352
- return false;
353
- }
354
- const std::string& pieces_str = pieces_it->second.as_string();
355
- if (pieces_str.size() % 20 != 0) {
356
- if (error) error->message = "Invalid 'pieces' length (not multiple of 20)";
357
- return false;
358
- }
359
- piece_hashes_.assign(pieces_str.begin(), pieces_str.end());
360
-
361
- // Private flag
362
- auto private_it = info.find("private");
363
- if (private_it != info.end() && private_it->second.is_integer()) {
364
- is_private_ = private_it->second.as_integer() != 0;
365
- }
366
-
367
- // Check for single-file or multi-file torrent
368
- auto files_it = info.find("files");
369
- if (files_it != info.end() && files_it->second.is_list()) {
370
- // Multi-file torrent
371
- for (const auto& file_entry : files_it->second.as_list()) {
372
- if (!file_entry.is_dict()) continue;
373
-
374
- const auto& file_dict = file_entry.as_dict();
375
-
376
- // Length is required
377
- auto length_it = file_dict.find("length");
378
- if (length_it == file_dict.end() || !length_it->second.is_integer()) {
379
- continue;
380
- }
381
- int64_t length = length_it->second.as_integer();
382
-
383
- // Path is required (list of path components)
384
- auto path_it = file_dict.find("path");
385
- if (path_it == file_dict.end() || !path_it->second.is_list()) {
386
- continue;
387
- }
388
-
389
- std::string path;
390
- for (const auto& component : path_it->second.as_list()) {
391
- if (component.is_string()) {
392
- if (!path.empty()) path += "/";
393
- path += component.as_string();
394
- }
395
- }
396
-
397
- if (path.empty()) continue;
398
-
399
- // Check for attributes
400
- bool executable = false;
401
- bool hidden = false;
402
- bool pad_file = false;
403
-
404
- auto attr_it = file_dict.find("attr");
405
- if (attr_it != file_dict.end() && attr_it->second.is_string()) {
406
- const std::string& attr = attr_it->second.as_string();
407
- executable = attr.find('x') != std::string::npos;
408
- hidden = attr.find('h') != std::string::npos;
409
- pad_file = attr.find('p') != std::string::npos;
410
- }
411
-
412
- files_.add_file(path, length, pad_file, executable, hidden);
413
- }
414
- } else {
415
- // Single-file torrent
416
- auto length_it = info.find("length");
417
- if (length_it == info.end() || !length_it->second.is_integer()) {
418
- if (error) error->message = "Missing 'length' for single-file torrent";
419
- return false;
420
- }
421
- int64_t length = length_it->second.as_integer();
422
- files_.add_file(name_, length);
423
- }
424
-
425
- files_.finalize();
426
-
427
- // Verify piece count matches
428
- size_t expected_pieces = piece_hashes_.size() / 20;
429
- if (files_.num_pieces() != expected_pieces) {
430
- if (error) {
431
- error->message = "Piece count mismatch: expected " +
432
- std::to_string(expected_pieces) + ", got " +
433
- std::to_string(files_.num_pieces());
434
- }
435
- return false;
436
- }
437
-
438
- return true;
439
- }
440
-
441
- BtInfoHash TorrentInfo::calculate_info_hash(const std::vector<uint8_t>& info_bytes) {
442
- SHA1 hasher;
443
- hasher.update(info_bytes.data(), info_bytes.size());
444
- std::string hex_hash = hasher.finalize();
445
- return hex_to_info_hash(hex_hash);
446
- }
447
-
448
- //=============================================================================
449
- // Accessors
450
- //=============================================================================
451
-
452
- std::array<uint8_t, 20> TorrentInfo::piece_hash(uint32_t index) const {
453
- std::array<uint8_t, 20> hash{};
454
- if (index >= num_pieces()) {
455
- return hash;
456
- }
457
-
458
- size_t offset = static_cast<size_t>(index) * 20;
459
- std::copy(piece_hashes_.begin() + offset,
460
- piece_hashes_.begin() + offset + 20,
461
- hash.begin());
462
- return hash;
463
- }
464
-
465
- std::vector<std::string> TorrentInfo::all_trackers() const {
466
- std::vector<std::string> result;
467
-
468
- // Add primary announce if not in announce-list
469
- if (!announce_.empty()) {
470
- result.push_back(announce_);
471
- }
472
-
473
- // Add all from announce-list
474
- for (const auto& tier : announce_list_) {
475
- for (const auto& tracker : tier) {
476
- // Avoid duplicates
477
- if (std::find(result.begin(), result.end(), tracker) == result.end()) {
478
- result.push_back(tracker);
479
- }
480
- }
481
- }
482
-
483
- return result;
484
- }
485
-
486
- //=============================================================================
487
- // Magnet URI
488
- //=============================================================================
489
-
490
- std::string TorrentInfo::to_magnet_uri(bool include_trackers) const {
491
- std::ostringstream oss;
492
-
493
- oss << "magnet:?xt=urn:btih:" << info_hash_hex();
494
-
495
- if (!name_.empty()) {
496
- oss << "&dn=" << url_encode(name_);
497
- }
498
-
499
- if (include_trackers) {
500
- for (const auto& tracker : all_trackers()) {
501
- oss << "&tr=" << url_encode(tracker);
502
- }
503
- }
504
-
505
- for (const auto& ws : web_seeds_) {
506
- oss << "&ws=" << url_encode(ws);
507
- }
508
-
509
- return oss.str();
510
- }
511
-
512
- std::string TorrentInfo::url_encode(const std::string& str) {
513
- std::ostringstream encoded;
514
- encoded << std::hex << std::uppercase;
515
-
516
- for (char c : str) {
517
- if (std::isalnum(static_cast<unsigned char>(c)) ||
518
- c == '-' || c == '_' || c == '.' || c == '~') {
519
- encoded << c;
520
- } else {
521
- encoded << '%' << std::setw(2) << std::setfill('0')
522
- << static_cast<int>(static_cast<unsigned char>(c));
523
- }
524
- }
525
-
526
- return encoded.str();
527
- }
528
-
529
- //=============================================================================
530
- // Metadata Update
531
- //=============================================================================
532
-
533
- bool TorrentInfo::set_metadata(const std::vector<uint8_t>& info_dict_bytes) {
534
- BtInfoHash actual_hash = calculate_info_hash(info_dict_bytes);
535
- if (actual_hash != info_hash_) {
536
- return false;
537
- }
538
-
539
- BencodeValue decoded;
540
- try {
541
- decoded = BencodeDecoder::decode(info_dict_bytes);
542
- } catch (...) {
543
- return false;
544
- }
545
-
546
- if (!decoded.is_dict()) {
547
- return false;
548
- }
549
-
550
- info_dict_bytes_ = info_dict_bytes;
551
-
552
- TorrentParseError error;
553
- if (!parse_info_dict(decoded, &error)) {
554
- return false;
555
- }
556
-
557
- has_metadata_ = true;
558
- return true;
559
- }
560
-
561
- //=============================================================================
562
- // MagnetUri
563
- //=============================================================================
564
-
565
- std::optional<MagnetUri> MagnetUri::parse(const std::string& uri) {
566
- // Check prefix
567
- if (uri.substr(0, 8) != "magnet:?") {
568
- return std::nullopt;
569
- }
570
-
571
- MagnetUri result;
572
-
573
- // Parse query parameters
574
- std::string query = uri.substr(8);
575
- size_t pos = 0;
576
-
577
- while (pos < query.size()) {
578
- // Find next parameter
579
- size_t eq_pos = query.find('=', pos);
580
- if (eq_pos == std::string::npos) break;
581
-
582
- std::string key = query.substr(pos, eq_pos - pos);
583
-
584
- size_t amp_pos = query.find('&', eq_pos);
585
- std::string value;
586
- if (amp_pos == std::string::npos) {
587
- value = query.substr(eq_pos + 1);
588
- pos = query.size();
589
- } else {
590
- value = query.substr(eq_pos + 1, amp_pos - eq_pos - 1);
591
- pos = amp_pos + 1;
592
- }
593
-
594
- // URL decode value
595
- std::string decoded_value;
596
- for (size_t i = 0; i < value.size(); ++i) {
597
- if (value[i] == '%' && i + 2 < value.size()) {
598
- std::string hex = value.substr(i + 1, 2);
599
- try {
600
- decoded_value += static_cast<char>(std::stoul(hex, nullptr, 16));
601
- i += 2;
602
- } catch (...) {
603
- decoded_value += value[i];
604
- }
605
- } else if (value[i] == '+') {
606
- decoded_value += ' ';
607
- } else {
608
- decoded_value += value[i];
609
- }
610
- }
611
-
612
- // Process parameter
613
- if (key == "xt") {
614
- // Extract info hash from urn:btih:HASH
615
- if (decoded_value.substr(0, 9) == "urn:btih:") {
616
- std::string hash_str = decoded_value.substr(9);
617
-
618
- if (hash_str.size() == 40) {
619
- // Hex-encoded hash
620
- result.info_hash = hex_to_info_hash(hash_str);
621
- } else if (hash_str.size() == 32) {
622
- // Base32-encoded hash
623
- // TODO: Implement base32 decoding
624
- }
625
- }
626
- } else if (key == "dn") {
627
- result.display_name = decoded_value;
628
- } else if (key == "tr") {
629
- result.trackers.push_back(decoded_value);
630
- } else if (key == "ws") {
631
- result.web_seeds.push_back(decoded_value);
632
- }
633
- }
634
-
635
- return result;
636
- }
637
-
638
- //=============================================================================
639
- // Load from data (rats-search compatibility)
640
- //=============================================================================
641
-
642
- bool TorrentInfo::load_from_data(const std::vector<uint8_t>& data) {
643
- auto result = TorrentInfo::from_bytes(data);
644
- if (result) {
645
- *this = std::move(*result);
646
- return true;
647
- }
648
- return false;
649
- }
650
-
651
- bool TorrentInfo::load_from_data(const uint8_t* data, size_t size) {
652
- if (!data || size == 0) {
653
- return false;
654
- }
655
- std::vector<uint8_t> vec(data, data + size);
656
- return load_from_data(vec);
657
- }
658
-
659
- } // namespace librats