librats 1.0.2 → 2.1.4

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 (313) hide show
  1. package/README.md +137 -332
  2. package/binding.gyp +16 -3
  3. package/lib/index.d.ts +271 -696
  4. package/lib/index.js +383 -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 +396 -179
  8. package/native-src/LICENSE +1 -1
  9. package/native-src/src/librats/bindings/rats.cpp +731 -0
  10. package/native-src/src/librats/bindings/rats.h +352 -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 +42 -0
  73. package/native-src/src/librats/core/types.h +93 -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/config.h +110 -0
  144. package/native-src/src/librats/node/dial_service.h +54 -0
  145. package/native-src/src/librats/node/dialer.cpp +264 -0
  146. package/native-src/src/librats/node/dialer.h +188 -0
  147. package/native-src/src/librats/node/host_events.h +26 -0
  148. package/native-src/src/librats/node/identify.cpp +130 -0
  149. package/native-src/src/librats/node/identify.h +71 -0
  150. package/native-src/src/librats/node/nat_status.cpp +103 -0
  151. package/native-src/src/librats/node/nat_status.h +118 -0
  152. package/native-src/src/librats/node/node.cpp +826 -0
  153. package/native-src/src/librats/node/node.h +333 -0
  154. package/native-src/src/librats/node/node_context.h +33 -0
  155. package/native-src/src/librats/node/peer_network.h +91 -0
  156. package/native-src/src/librats/peer/peer.h +49 -0
  157. package/native-src/src/librats/peer/peer_book.cpp +181 -0
  158. package/native-src/src/librats/peer/peer_book.h +88 -0
  159. package/native-src/src/librats/peer/peer_id.cpp +72 -0
  160. package/native-src/src/librats/peer/peer_id.h +62 -0
  161. package/native-src/src/librats/peer/peer_info.h +37 -0
  162. package/native-src/src/librats/peer/peer_table.cpp +137 -0
  163. package/native-src/src/librats/peer/peer_table.h +148 -0
  164. package/native-src/src/librats/security/handshaker.h +66 -0
  165. package/native-src/src/librats/security/identity.h +43 -0
  166. package/native-src/src/librats/security/noise_security.cpp +122 -0
  167. package/native-src/src/librats/security/noise_security.h +37 -0
  168. package/native-src/src/librats/security/plaintext_security.h +106 -0
  169. package/native-src/src/librats/security/session.h +37 -0
  170. package/native-src/src/{storage.cpp → librats/storage/storage.cpp} +369 -522
  171. package/native-src/src/{storage.h → librats/storage/storage.h} +135 -299
  172. package/native-src/src/librats/subsystems/bittorrent.cpp +211 -0
  173. package/native-src/src/librats/subsystems/bittorrent.h +136 -0
  174. package/native-src/src/librats/subsystems/dht_discovery.cpp +202 -0
  175. package/native-src/src/librats/subsystems/dht_discovery.h +123 -0
  176. package/native-src/src/librats/subsystems/dht_service.h +36 -0
  177. package/native-src/src/librats/subsystems/file_transfer.cpp +972 -0
  178. package/native-src/src/librats/subsystems/file_transfer.h +367 -0
  179. package/native-src/src/librats/subsystems/hole_punch.cpp +532 -0
  180. package/native-src/src/librats/subsystems/hole_punch.h +266 -0
  181. package/native-src/src/librats/subsystems/hole_punch_service.h +38 -0
  182. package/native-src/src/librats/subsystems/mdns_discovery.cpp +66 -0
  183. package/native-src/src/librats/subsystems/mdns_discovery.h +55 -0
  184. package/native-src/src/librats/subsystems/message_json.cpp +112 -0
  185. package/native-src/src/librats/subsystems/message_json.h +88 -0
  186. package/native-src/src/librats/subsystems/peer_exchange.cpp +241 -0
  187. package/native-src/src/librats/subsystems/peer_exchange.h +136 -0
  188. package/native-src/src/librats/subsystems/ping_service.cpp +98 -0
  189. package/native-src/src/librats/subsystems/ping_service.h +66 -0
  190. package/native-src/src/librats/subsystems/port_mapping_service.cpp +192 -0
  191. package/native-src/src/librats/subsystems/port_mapping_service.h +84 -0
  192. package/native-src/src/librats/subsystems/pubsub.cpp +567 -0
  193. package/native-src/src/librats/subsystems/pubsub.h +175 -0
  194. package/native-src/src/librats/subsystems/reconnection.cpp +239 -0
  195. package/native-src/src/librats/subsystems/reconnection.h +126 -0
  196. package/native-src/src/librats/transport/connection.cpp +343 -0
  197. package/native-src/src/librats/transport/connection.h +283 -0
  198. package/native-src/src/librats/transport/link.h +96 -0
  199. package/native-src/src/librats/transport/reactor.cpp +540 -0
  200. package/native-src/src/librats/transport/reactor.h +224 -0
  201. package/native-src/src/librats/transport/reactor_pool.h +81 -0
  202. package/native-src/src/librats/transport/tcp_link.cpp +49 -0
  203. package/native-src/src/librats/transport/tcp_link.h +43 -0
  204. package/native-src/src/librats/transport/udp_mux.cpp +617 -0
  205. package/native-src/src/librats/transport/udp_mux.h +363 -0
  206. package/native-src/src/librats/transport/udp_packet.cpp +121 -0
  207. package/native-src/src/librats/transport/udp_packet.h +190 -0
  208. package/native-src/src/librats/transport/udp_stream.cpp +1194 -0
  209. package/native-src/src/librats/transport/udp_stream.h +614 -0
  210. package/native-src/src/librats/util/features.h.in +51 -0
  211. package/native-src/src/{fs.cpp → librats/util/fs.cpp} +51 -3
  212. package/native-src/src/librats/util/fs.h +136 -0
  213. package/native-src/src/librats/util/json.cpp +1002 -0
  214. package/native-src/src/librats/util/json.h +444 -0
  215. package/native-src/src/{logger.cpp → librats/util/logger.cpp} +1 -1
  216. package/native-src/src/{logger.h → librats/util/logger.h} +43 -31
  217. package/native-src/src/{network_monitor.cpp → librats/util/network_monitor.cpp} +12 -4
  218. package/native-src/src/{network_monitor.h → librats/util/network_monitor.h} +2 -1
  219. package/native-src/src/{network_utils.cpp → librats/util/network_utils.cpp} +38 -23
  220. package/native-src/src/{network_utils.h → librats/util/network_utils.h} +15 -8
  221. package/native-src/src/{os.cpp → librats/util/os.cpp} +48 -18
  222. package/native-src/src/librats/util/rats_export.h +69 -0
  223. package/native-src/src/{version.cpp → librats/util/version.cpp} +2 -2
  224. package/native-src/src/{version.h.in → librats/util/version.h.in} +1 -1
  225. package/native-src/src/librats/wire/frame.cpp +76 -0
  226. package/native-src/src/librats/wire/frame.h +110 -0
  227. package/native-src/src/librats/wire/message_router.cpp +45 -0
  228. package/native-src/src/librats/wire/message_router.h +47 -0
  229. package/package.json +5 -4
  230. package/scripts/build-librats.js +1 -0
  231. package/scripts/postinstall.js +3 -3
  232. package/scripts/prepare-package.js +4 -4
  233. package/scripts/verify-installation.js +63 -105
  234. package/src/librats_node.cpp +1042 -1324
  235. package/native-src/src/bencode.cpp +0 -485
  236. package/native-src/src/bencode.h +0 -145
  237. package/native-src/src/bittorrent.cpp +0 -14
  238. package/native-src/src/bittorrent.h +0 -74
  239. package/native-src/src/bt_bitfield.cpp +0 -372
  240. package/native-src/src/bt_bitfield.h +0 -316
  241. package/native-src/src/bt_choker.cpp +0 -228
  242. package/native-src/src/bt_choker.h +0 -147
  243. package/native-src/src/bt_client.cpp +0 -1047
  244. package/native-src/src/bt_client.h +0 -445
  245. package/native-src/src/bt_create_torrent.cpp +0 -677
  246. package/native-src/src/bt_create_torrent.h +0 -473
  247. package/native-src/src/bt_extension.cpp +0 -469
  248. package/native-src/src/bt_extension.h +0 -309
  249. package/native-src/src/bt_file_storage.cpp +0 -261
  250. package/native-src/src/bt_file_storage.h +0 -298
  251. package/native-src/src/bt_handshake.cpp +0 -134
  252. package/native-src/src/bt_handshake.h +0 -157
  253. package/native-src/src/bt_messages.cpp +0 -364
  254. package/native-src/src/bt_messages.h +0 -324
  255. package/native-src/src/bt_network.cpp +0 -1007
  256. package/native-src/src/bt_network.h +0 -417
  257. package/native-src/src/bt_peer_connection.cpp +0 -742
  258. package/native-src/src/bt_peer_connection.h +0 -592
  259. package/native-src/src/bt_piece_picker.cpp +0 -786
  260. package/native-src/src/bt_piece_picker.h +0 -473
  261. package/native-src/src/bt_resume_data.cpp +0 -410
  262. package/native-src/src/bt_resume_data.h +0 -249
  263. package/native-src/src/bt_torrent.cpp +0 -2120
  264. package/native-src/src/bt_torrent.h +0 -641
  265. package/native-src/src/bt_torrent_info.cpp +0 -659
  266. package/native-src/src/bt_torrent_info.h +0 -418
  267. package/native-src/src/bt_types.h +0 -621
  268. package/native-src/src/chained_send_buffer.cpp +0 -75
  269. package/native-src/src/chained_send_buffer.h +0 -137
  270. package/native-src/src/crypto/hkdf.c +0 -266
  271. package/native-src/src/crypto/poly1305.h +0 -36
  272. package/native-src/src/dht.cpp +0 -3311
  273. package/native-src/src/dht.h +0 -717
  274. package/native-src/src/disk_io.cpp +0 -632
  275. package/native-src/src/disk_io.h +0 -315
  276. package/native-src/src/file_transfer.cpp +0 -1415
  277. package/native-src/src/file_transfer.h +0 -286
  278. package/native-src/src/fs.h +0 -108
  279. package/native-src/src/gossipsub.cpp +0 -1139
  280. package/native-src/src/gossipsub.h +0 -403
  281. package/native-src/src/ice.cpp +0 -893
  282. package/native-src/src/ice.h +0 -559
  283. package/native-src/src/json.hpp +0 -25526
  284. package/native-src/src/librats.cpp +0 -2378
  285. package/native-src/src/librats.h +0 -2324
  286. package/native-src/src/librats_bittorrent.cpp +0 -601
  287. package/native-src/src/librats_c.cpp +0 -1557
  288. package/native-src/src/librats_c.h +0 -323
  289. package/native-src/src/librats_discovery.cpp +0 -402
  290. package/native-src/src/librats_encryption.cpp +0 -275
  291. package/native-src/src/librats_file_transfer.cpp +0 -144
  292. package/native-src/src/librats_gossipsub.cpp +0 -289
  293. package/native-src/src/librats_ice.cpp +0 -213
  294. package/native-src/src/librats_log_macros.h +0 -36
  295. package/native-src/src/librats_logging.cpp +0 -173
  296. package/native-src/src/librats_mdns.cpp +0 -166
  297. package/native-src/src/librats_persistence.cpp +0 -796
  298. package/native-src/src/librats_portmap.cpp +0 -419
  299. package/native-src/src/librats_reconnection.cpp +0 -218
  300. package/native-src/src/librats_statistic.cpp +0 -105
  301. package/native-src/src/librats_storage.cpp +0 -189
  302. package/native-src/src/rats_export.h +0 -17
  303. package/native-src/src/receive_buffer.cpp +0 -82
  304. package/native-src/src/receive_buffer.h +0 -127
  305. package/native-src/src/socket.h +0 -228
  306. package/native-src/src/threadmanager.cpp +0 -105
  307. package/native-src/src/threadmanager.h +0 -53
  308. package/native-src/src/tracker.cpp +0 -1264
  309. package/native-src/src/tracker.h +0 -319
  310. package/native-src/src/turn.cpp +0 -762
  311. package/native-src/src/turn.h +0 -460
  312. package/native-src/src/wakeup_pipe.h +0 -60
  313. /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