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
@@ -0,0 +1,175 @@
1
+ #pragma once
2
+
3
+ /**
4
+ * @file pubsub.h
5
+ * @brief Topic-based publish/subscribe — a GossipSub implementation over PeerNetwork.
6
+ *
7
+ * This is the real GossipSub, not plain floodsub. Each subscribed topic maintains
8
+ * a bounded *mesh* of full-message peers (formed and torn down with GRAFT/PRUNE),
9
+ * published messages are eagerly pushed along the mesh, and a lazy-pull gossip
10
+ * layer (IHAVE/IWANT, driven by the heartbeat) lets a peer recover a message it
11
+ * missed. Publishing to a topic we are not subscribed to uses a short-lived
12
+ * *fanout* set instead of a mesh. A node-id+sequence dedup key stops a message
13
+ * looping around the mesh, and a message cache keeps recent payloads so IWANT can
14
+ * be answered with real content.
15
+ *
16
+ * It depends on nothing but PeerNetwork — no Node, no reactor internals, no
17
+ * `friend`. A background heartbeat thread (started by start(), joined by stop())
18
+ * runs mesh maintenance and gossip emission once per interval.
19
+ *
20
+ * Wire format (MessageType::Gossip payload), all integers big-endian. The first
21
+ * byte is the op; a 40-byte message id is origin(32 id-bytes) || seqno(u64 BE):
22
+ * PUBLISH [0][origin:32][seqno:u64][topic_len:u16][topic][data]
23
+ * SUBSCRIBE [1][topic_len:u16][topic]
24
+ * UNSUBSCRIBE [2][topic_len:u16][topic]
25
+ * GRAFT [3][topic_len:u16][topic] // "add me to your mesh for topic"
26
+ * PRUNE [4][topic_len:u16][topic] // "drop me from your mesh for topic"
27
+ * IHAVE [5][topic_len:u16][topic][count:u16][id:40]* // "I hold these message ids"
28
+ * IWANT [6][count:u16][id:40]* // "send me these message ids"
29
+ */
30
+
31
+ #include "librats/util/rats_export.h"
32
+ #include "librats/node/peer_network.h"
33
+ #include "librats/peer/peer.h"
34
+ #include "librats/core/bytes.h"
35
+ #include "librats/peer/peer_id.h"
36
+
37
+ #include <atomic>
38
+ #include <chrono>
39
+ #include <condition_variable>
40
+ #include <cstdint>
41
+ #include <deque>
42
+ #include <functional>
43
+ #include <mutex>
44
+ #include <random>
45
+ #include <string>
46
+ #include <thread>
47
+ #include <unordered_map>
48
+ #include <unordered_set>
49
+ #include <utility>
50
+ #include <vector>
51
+
52
+ namespace librats {
53
+
54
+ /// Outcome of validating an inbound published message before it is delivered or
55
+ /// forwarded. REJECT drops it (and would penalise the sender in a scored build);
56
+ /// IGNORE drops it silently; ACCEPT delivers locally and forwards along the mesh.
57
+ enum class ValidationResult { Accept, Reject, Ignore };
58
+
59
+ class RATS_API PubSub final : public Subsystem {
60
+ public:
61
+ using Handler = std::function<void(const PeerId& from, const std::string& topic, ByteView data)>;
62
+ using Validator = std::function<ValidationResult(const PeerId& from, const std::string& topic, ByteView data)>;
63
+
64
+ /// GossipSub tuning. Defaults mirror the libp2p reference (D=6, D_low=4,
65
+ /// D_high=12) and are sensible for small-to-medium meshes.
66
+ struct Config {
67
+ int mesh_target = 6; ///< D — desired mesh degree per topic
68
+ int mesh_low = 4; ///< D_low — graft more peers below this
69
+ int mesh_high = 12; ///< D_high— prune peers above this
70
+ int fanout_size = 6; ///< peers used to publish to a topic we are not subscribed to
71
+ int gossip_factor = 6; ///< D_lazy— peers we emit IHAVE to per heartbeat per topic
72
+ std::chrono::milliseconds fanout_ttl{60000}; ///< drop a fanout set idle this long
73
+ std::chrono::milliseconds heartbeat_interval{1000}; ///< mesh maintenance + gossip cadence
74
+ int history_length = 5; ///< heartbeat windows the message cache keeps (for IWANT)
75
+ int history_gossip = 3; ///< of those, how many windows IHAVE advertises
76
+ size_t seen_limit = 8192; ///< dedup ids remembered
77
+ };
78
+
79
+ PubSub();
80
+ explicit PubSub(Config config);
81
+ ~PubSub() override;
82
+
83
+ /// Subscribe to a topic and deliver matching messages to `handler`.
84
+ void subscribe(const std::string& topic, Handler handler);
85
+ void unsubscribe(const std::string& topic);
86
+
87
+ /// Publish `data` on `topic`: along the mesh if we are subscribed, else via fanout.
88
+ void publish(const std::string& topic, ByteView data);
89
+
90
+ bool is_subscribed(const std::string& topic) const;
91
+ std::vector<std::string> subscribed_topics() const;
92
+ std::vector<PeerId> peers_for_topic(const std::string& topic) const; ///< known subscribers
93
+ std::vector<PeerId> mesh_peers(const std::string& topic) const; ///< our mesh for topic
94
+
95
+ /// Gate inbound messages for a topic; `topic == ""` installs a global validator
96
+ /// used when no per-topic validator is registered.
97
+ void set_validator(const std::string& topic, Validator validator);
98
+
99
+ // Subsystem.
100
+ void attach(NodeContext& ctx) override;
101
+ void start() override; ///< launch the heartbeat thread
102
+ void stop() override; ///< stop and join it
103
+
104
+ private:
105
+ struct Topic {
106
+ std::unordered_set<PeerId, PeerId::Hash> subscribers; ///< peers that announced interest
107
+ std::unordered_set<PeerId, PeerId::Hash> mesh; ///< full-message peering (we subscribe)
108
+ std::unordered_set<PeerId, PeerId::Hash> fanout; ///< publish targets when not subscribed
109
+ std::chrono::steady_clock::time_point last_fanout{};
110
+ };
111
+
112
+ struct CachedMessage {
113
+ std::string topic;
114
+ Bytes frame; ///< the whole PUBLISH frame, resent verbatim to answer IWANT
115
+ };
116
+
117
+ // Inbound dispatch (all run on a reactor thread).
118
+ void on_new_peer(const Peer& peer);
119
+ void on_peer_gone(const PeerId& id);
120
+ void on_gossip(const Peer& peer, ByteView payload);
121
+
122
+ void recv_subscription(const PeerId& from, const std::string& topic, bool subscribe);
123
+ void recv_graft(const PeerId& from, const std::string& topic);
124
+ void recv_prune(const PeerId& from, const std::string& topic);
125
+ void recv_publish(const PeerId& from, ByteView frame, const PeerId& origin, uint64_t seqno,
126
+ const std::string& topic, ByteView data);
127
+ void recv_ihave(const PeerId& from, const std::string& topic, const std::vector<std::string>& ids);
128
+ void recv_iwant(const PeerId& from, const std::vector<std::string>& ids);
129
+
130
+ // Heartbeat (background thread).
131
+ void heartbeat_loop();
132
+ void do_heartbeat();
133
+
134
+ /// Bring `topic`'s mesh toward [mesh_low, mesh_high] around mesh_target, queuing
135
+ /// the GRAFT/PRUNE control messages to send after the lock is released. Requires
136
+ /// `mutex_` held; a no-op unless we are subscribed to `topic`.
137
+ using CtrlList = std::vector<std::pair<PeerId, std::string>>;
138
+ void maintain_mesh_locked(const std::string& topic, CtrlList& grafts, CtrlList& prunes);
139
+
140
+ // Helpers.
141
+ void send_ctrl(const PeerId& to, uint8_t op, const std::string& topic);
142
+ void broadcast_ctrl(uint8_t op, const std::string& topic);
143
+ void deliver_local(const PeerId& from, const std::string& topic, ByteView data);
144
+ Handler handler_for(const std::string& topic) const;
145
+ ValidationResult validate(const PeerId& from, const std::string& topic, ByteView data);
146
+ bool mark_seen(const std::string& id); ///< false if already seen
147
+ void cache_message(const std::string& id, const std::string& topic, const Bytes& frame);
148
+ std::vector<PeerId> random_sample(std::vector<PeerId> in, int n);
149
+
150
+ PeerNetwork* network_ = nullptr;
151
+ Config config_;
152
+
153
+ mutable std::mutex mutex_; ///< guards subscriptions_, topics_, validators_, seqno_
154
+ uint64_t seqno_ = 0;
155
+ std::unordered_map<std::string, Handler> subscriptions_; ///< topic -> local handler
156
+ std::unordered_map<std::string, Topic> topics_; ///< topic -> peering state
157
+ std::unordered_map<std::string, Validator> validators_; ///< topic -> validator
158
+ Validator global_validator_;
159
+
160
+ mutable std::mutex mcache_mutex_; ///< guards mcache_, history_, seen_*
161
+ std::unordered_map<std::string, CachedMessage> mcache_; ///< id -> cached frame (for IWANT)
162
+ std::deque<std::vector<std::string>> history_; ///< gossip windows of ids (front = newest)
163
+ std::unordered_set<std::string> seen_; ///< dedup set
164
+ std::deque<std::string> seen_order_; ///< FIFO eviction order for seen_
165
+
166
+ std::mutex rng_mutex_;
167
+ std::mt19937 rng_;
168
+
169
+ std::atomic<bool> running_{false};
170
+ std::thread heartbeat_thread_;
171
+ std::mutex hb_mutex_;
172
+ std::condition_variable hb_cv_;
173
+ };
174
+
175
+ } // namespace librats
@@ -0,0 +1,239 @@
1
+ #include "librats/subsystems/reconnection.h"
2
+ #include "librats/node/node_context.h"
3
+ #include "librats/util/logger.h"
4
+
5
+ #include <algorithm>
6
+ #include <chrono>
7
+ #include <unordered_set>
8
+ #include <vector>
9
+
10
+ namespace librats {
11
+
12
+ namespace {
13
+ // Wall clock at the edge, kept out of PeerBook so the book stays pure/testable.
14
+ uint64_t now_secs() {
15
+ return static_cast<uint64_t>(std::chrono::duration_cast<std::chrono::seconds>(
16
+ std::chrono::system_clock::now().time_since_epoch()).count());
17
+ }
18
+ } // namespace
19
+
20
+ ReconnectionService::ReconnectionService() : ReconnectionService(Config()) {}
21
+
22
+ ReconnectionService::ReconnectionService(Config config) : config_(std::move(config)) {
23
+ // Build the book up front so the pointer is fixed for the object's life (no race
24
+ // with reactor-thread reads in on_connected) and so add() before start() records
25
+ // into an already-loaded book rather than clobbering it.
26
+ if (!config_.store_path.empty()) {
27
+ book_ = std::make_unique<PeerBook>(config_.store_path);
28
+ book_->load();
29
+ // Age out the long tail and cap the archive immediately on load.
30
+ book_->prune(now_secs(), static_cast<uint64_t>(config_.archive_max_age.count()), config_.archive_max);
31
+ book_->save();
32
+ }
33
+ }
34
+
35
+ ReconnectionService::~ReconnectionService() { stop(); }
36
+
37
+ void ReconnectionService::add(const Address& address) {
38
+ {
39
+ std::lock_guard<std::mutex> lock(mutex_);
40
+ if (targets_.count(address)) return;
41
+ if (targets_.size() >= config_.max_targets) {
42
+ LOG_WARN("reconnect", "Active-target cap (" << config_.max_targets
43
+ << ") reached; dropping " << address.to_string());
44
+ return;
45
+ }
46
+ Target& t = targets_[address];
47
+ t.address = address;
48
+ t.next_attempt = std::chrono::steady_clock::now();
49
+ }
50
+ if (book_) { book_->note_seen(address, now_secs()); book_->save(); }
51
+ wake_.notify_all();
52
+ }
53
+
54
+ void ReconnectionService::remove(const Address& address) {
55
+ bool erased;
56
+ {
57
+ std::lock_guard<std::mutex> lock(mutex_);
58
+ erased = targets_.erase(address) > 0;
59
+ }
60
+ if (book_ && book_->remove(address)) book_->save();
61
+ if (erased) LOG_DEBUG("reconnect", "Stopped reconnecting to " << address.to_string());
62
+ }
63
+
64
+ size_t ReconnectionService::target_count() const {
65
+ std::lock_guard<std::mutex> lock(mutex_);
66
+ return targets_.size();
67
+ }
68
+
69
+ std::vector<Address> ReconnectionService::known_peers(size_t n) const {
70
+ if (!book_) return {};
71
+ return book_->best(n, now_secs(), static_cast<uint64_t>(config_.archive_max_age.count()));
72
+ }
73
+
74
+ void ReconnectionService::attach(NodeContext& ctx) {
75
+ network_ = &ctx.network;
76
+ network_->on_peer_connected([this](const Peer& peer) { on_connected(peer); });
77
+ network_->on_peer_disconnected([this](const PeerId& id) { on_disconnected(id); });
78
+ network_->on_dial_failed([this](const Address& addr) { on_dial_failed(addr); });
79
+ }
80
+
81
+ void ReconnectionService::start() {
82
+ if (running_.exchange(true)) return;
83
+
84
+ // Seed the active set with the most promising peers from the book — the
85
+ // working set is "best N recent", the rest of the book stays a passive
86
+ // reserve pool reachable via known_peers().
87
+ if (book_) {
88
+ const auto recent = book_->best(config_.startup_targets, now_secs(),
89
+ static_cast<uint64_t>(config_.archive_max_age.count()));
90
+ std::lock_guard<std::mutex> lock(mutex_);
91
+ for (const Address& addr : recent) {
92
+ if (targets_.size() >= config_.max_targets) break;
93
+ auto [it, inserted] = targets_.try_emplace(addr);
94
+ if (inserted) { it->second.address = addr; it->second.next_attempt = std::chrono::steady_clock::now(); }
95
+ }
96
+ }
97
+ thread_ = std::thread(&ReconnectionService::loop, this);
98
+ }
99
+
100
+ void ReconnectionService::stop() {
101
+ if (!running_.exchange(false)) return;
102
+ wake_.notify_all();
103
+ if (thread_.joinable()) thread_.join();
104
+ if (book_) book_->save();
105
+ }
106
+
107
+ // A successful connection. Two jobs: record the address in the book, and — the
108
+ // success-side mirror of on_dial_failed — clear this target's in-flight dial state
109
+ // right now. We must NOT wait for the loop to reconcile from the live-peer snapshot:
110
+ // a peer that connects and then drops again BETWEEN ticks would otherwise leave its
111
+ // dial flagged in-flight until dial_timeout, needlessly stalling the redial for
112
+ // seconds even though the address is plainly reachable. (For an inbound peer
113
+ // info->addresses is still empty at this point — its dialable address arrives later
114
+ // via identify — so an inbound link matches no target here and is reconciled by the
115
+ // loop's live snapshot instead; inbound links are thus not auto-persisted either.)
116
+ void ReconnectionService::on_connected(const Peer& peer) {
117
+ auto info = peer.info();
118
+ if (!info) return;
119
+
120
+ const uint64_t now = now_secs();
121
+ const auto steady_now = std::chrono::steady_clock::now();
122
+ bool book_changed = false;
123
+ {
124
+ std::lock_guard<std::mutex> lock(mutex_);
125
+ for (const Address& addr : info->addresses) {
126
+ auto it = targets_.find(addr);
127
+ if (it == targets_.end()) {
128
+ if (!config_.persist_discovered) continue;
129
+ if (targets_.size() >= config_.max_targets) continue; // bound active growth
130
+ it = targets_.emplace(addr, Target{}).first;
131
+ it->second.address = addr;
132
+ }
133
+ it->second.mark_connected(steady_now); // resolve the in-flight dial now
134
+ if (book_) { book_->note_connected(addr, peer.id(), now); book_changed = true; }
135
+ }
136
+ }
137
+ if (book_ && book_changed) book_->save();
138
+ }
139
+
140
+ // A peer dropped. The loop reconciles which targets are live from the directory
141
+ // snapshot, so there is no per-target state to clear here — just wake it so the
142
+ // re-dial happens at once rather than waiting out a tick.
143
+ void ReconnectionService::on_disconnected(const PeerId& /*id*/) {
144
+ wake_.notify_all();
145
+ }
146
+
147
+ // An outbound dial we asked for closed before establishing. Clear the in-flight
148
+ // flag so the target becomes eligible again — it then re-dials on its own backoff
149
+ // schedule (next_attempt, set when we dispatched the dial). Without this signal
150
+ // the target would stay "dialing" until the dial_deadline backstop, needlessly
151
+ // stretching every retry to that timeout.
152
+ void ReconnectionService::on_dial_failed(const Address& address) {
153
+ std::lock_guard<std::mutex> lock(mutex_);
154
+ auto it = targets_.find(address);
155
+ if (it != targets_.end()) it->second.dialing = false;
156
+ }
157
+
158
+ std::chrono::milliseconds ReconnectionService::backoff_for(int attempts) const {
159
+ // base * 2^(attempts-1), capped at max.
160
+ auto delay = config_.base_backoff;
161
+ for (int i = 1; i < attempts && delay < config_.max_backoff; ++i) delay *= 2;
162
+ return (std::min)(delay, config_.max_backoff); // parenthesized: dodge windows.h min macro
163
+ }
164
+
165
+ void ReconnectionService::loop() {
166
+ std::unordered_set<Address> live; // reused across ticks to avoid re-allocating
167
+ while (running_.load()) {
168
+ const auto now = std::chrono::steady_clock::now();
169
+
170
+ // Ground truth for "this target is already connected": the union of every
171
+ // live peer's dialable addresses, identify-learned ones included. Matching
172
+ // on this — instead of a flag set only on the on_peer_connected event — is
173
+ // what lets us recognise a peer reached over a route we did not dial (an
174
+ // inbound link, or a cross-connect the directory resolved to the other
175
+ // connection). Without it such a peer is never seen as connected and we
176
+ // re-dial it forever, each dial torn down by the node as a duplicate.
177
+ live.clear();
178
+ for (const PeerInfo& p : network_->peers())
179
+ for (const Address& a : p.addresses)
180
+ live.insert(a);
181
+
182
+ std::vector<Address> to_dial, gave_up;
183
+ {
184
+ std::lock_guard<std::mutex> lock(mutex_);
185
+ for (auto it = targets_.begin(); it != targets_.end();) {
186
+ Target& target = it->second;
187
+
188
+ // Connected right now (over any route): keep the retry state armed
189
+ // so a later drop re-dials promptly, and never dial a live peer.
190
+ if (live.count(it->first)) {
191
+ target.mark_connected(now);
192
+ ++it;
193
+ continue;
194
+ }
195
+
196
+ // A dial is already in flight: don't pile on a duplicate while the
197
+ // handshake completes. We clear `dialing` on dial failure; the next
198
+ // tick clears it once the peer shows up live; dial_deadline is only a
199
+ // backstop for the case where neither signal ever arrives.
200
+ if (target.dialing && now < target.dial_deadline) { ++it; continue; }
201
+ if (target.next_attempt > now) { ++it; continue; }
202
+
203
+ // Give up actively dialing a persistently-dead target: drop it from
204
+ // the active set (it stays in the book as history, ranked down by its
205
+ // failure streak, until it ages out). A reconnect resets attempts, so
206
+ // only addresses that never came back are reaped.
207
+ if (config_.max_attempts > 0 && target.attempts >= static_cast<int>(config_.max_attempts)) {
208
+ gave_up.push_back(target.address);
209
+ it = targets_.erase(it);
210
+ continue;
211
+ }
212
+
213
+ to_dial.push_back(target.address);
214
+ target.attempts++;
215
+ target.dialing = true;
216
+ target.dial_deadline = now + config_.dial_timeout;
217
+ target.next_attempt = now + backoff_for(target.attempts);
218
+ ++it;
219
+ }
220
+ }
221
+ if (book_ && !gave_up.empty()) {
222
+ const uint64_t ts = now_secs();
223
+ for (const Address& addr : gave_up) book_->note_failure(addr, ts);
224
+ book_->save();
225
+ }
226
+ for (const Address& addr : gave_up)
227
+ LOG_DEBUG("reconnect", "Giving up on " << addr.to_string() << " after "
228
+ << config_.max_attempts << " attempts");
229
+ for (const Address& addr : to_dial) {
230
+ LOG_DEBUG("reconnect", "Dialing " << addr.to_string());
231
+ network_->connect(addr);
232
+ }
233
+
234
+ std::unique_lock<std::mutex> lock(wait_mutex_);
235
+ wake_.wait_for(lock, config_.tick, [this] { return !running_.load(); });
236
+ }
237
+ }
238
+
239
+ } // namespace librats
@@ -0,0 +1,126 @@
1
+ #pragma once
2
+
3
+ /**
4
+ * @file reconnection.h
5
+ * @brief Keeps connections to a set of peer addresses alive with backoff.
6
+ *
7
+ * A Subsystem that remembers peer addresses (optionally persisted via PeerBook)
8
+ * and re-dials them when they drop, using exponential backoff. Built only on
9
+ * PeerNetwork: it dials via connect() and, each tick, reconciles its targets
10
+ * against the set of currently-connected peers (PeerNetwork::peers(), whose
11
+ * addresses include the dialable endpoints learned via identify). A target whose
12
+ * address is served by a live peer — over ANY route, inbound or outbound — is
13
+ * left alone; only the rest are dialed. Reconciling against this snapshot, rather
14
+ * than trusting a flag toggled on the connect event, is what stops us from
15
+ * endlessly re-dialing a peer already connected over a link we did not initiate
16
+ * (an inbound link, or a cross-connect the directory resolved to the other side).
17
+ *
18
+ * A target is dropped when the app calls remove(), or — if Config::max_attempts
19
+ * is set — after that many consecutive failed dials without ever connecting (it
20
+ * "gives up", freeing memory and pruning the store). A successful connection
21
+ * resets the attempt counter, so only persistently-dead addresses are reaped.
22
+ */
23
+
24
+ #include "librats/util/rats_export.h"
25
+ #include "librats/node/peer_network.h"
26
+ #include "librats/peer/peer.h"
27
+ #include "librats/core/address.h"
28
+ #include "librats/peer/peer_id.h"
29
+ #include "librats/peer/peer_book.h"
30
+
31
+ #include <atomic>
32
+ #include <chrono>
33
+ #include <condition_variable>
34
+ #include <memory>
35
+ #include <mutex>
36
+ #include <string>
37
+ #include <thread>
38
+ #include <unordered_map>
39
+
40
+ namespace librats {
41
+
42
+ class RATS_API ReconnectionService final : public Subsystem {
43
+ public:
44
+ struct Config {
45
+ std::string store_path = ""; ///< persist the peer book here (empty = memory only)
46
+ bool persist_discovered = true; ///< remember dialed peers automatically
47
+ size_t max_targets = 1024; ///< cap on ACTIVE re-dial targets (bounds memory + dial fan-out)
48
+ size_t max_attempts = 0; ///< give up actively dialing a target after this many consecutive failures; 0 = retry forever
49
+ size_t startup_targets = 32; ///< on start, actively re-dial this many best peers from the book
50
+ size_t archive_max = 4096; ///< cap on the persistent peer book (history of everyone we met)
51
+ std::chrono::seconds archive_max_age{std::chrono::hours(24 * 30)}; ///< forget peers unseen this long (30 days)
52
+ std::chrono::milliseconds base_backoff{1000};
53
+ std::chrono::milliseconds max_backoff{60000};
54
+ std::chrono::milliseconds tick{1000};
55
+ std::chrono::milliseconds dial_timeout{15000}; ///< assume an in-flight dial is dead after this if no connect/fail event arrives (backstop only)
56
+ };
57
+
58
+ ReconnectionService();
59
+ explicit ReconnectionService(Config config);
60
+ ~ReconnectionService() override;
61
+
62
+ /// Register an address to keep connected. Persists it if a store is configured.
63
+ void add(const Address& address);
64
+
65
+ /// Stop reconnecting to an address: drops it as a target and from the store.
66
+ /// Use when the application intentionally parts with a peer and does not want
67
+ /// it re-dialed. (A later fresh connection to it may re-learn it if
68
+ /// persist_discovered is on.)
69
+ void remove(const Address& address);
70
+
71
+ size_t target_count() const;
72
+
73
+ /// The passive reserve pool: up to n best-known peer addresses from the book
74
+ /// (history of everyone we have connected to), most promising first. Not dialed
75
+ /// automatically beyond the startup seed — exposed for the app / discovery to
76
+ /// use as a bootstrap source when peer count is low.
77
+ std::vector<Address> known_peers(size_t n) const;
78
+
79
+ void attach(NodeContext& ctx) override;
80
+ void start() override;
81
+ void stop() override;
82
+
83
+ private:
84
+ struct Target {
85
+ Address address;
86
+ bool dialing = false; ///< a connect() is in flight; don't pile on a duplicate
87
+ int attempts = 0; ///< failed dials since the target was last seen connected
88
+ std::chrono::steady_clock::time_point next_attempt; ///< earliest time to (re)dial
89
+ std::chrono::steady_clock::time_point dial_deadline; ///< backstop: give up waiting on the in-flight dial after this
90
+
91
+ /// Record that this target is connected as of `now`: no dial is in flight
92
+ /// any more and the failure streak resets, so a later drop re-dials at once
93
+ /// (an address that just worked earns no backoff penalty). Used by BOTH the
94
+ /// loop's live-snapshot reconciliation and the on_connected event, so the
95
+ /// two paths that clear an in-flight dial can never drift apart.
96
+ void mark_connected(std::chrono::steady_clock::time_point now) {
97
+ dialing = false;
98
+ attempts = 0;
99
+ next_attempt = now;
100
+ }
101
+ };
102
+
103
+ void on_connected(const Peer& peer);
104
+ void on_disconnected(const PeerId& id);
105
+ void on_dial_failed(const Address& address);
106
+ void loop();
107
+ std::chrono::milliseconds backoff_for(int attempts) const;
108
+
109
+ Config config_;
110
+ PeerNetwork* network_ = nullptr;
111
+ // Built once in the constructor (when store_path is set) and never reassigned,
112
+ // so the pointer is safe to read from any thread; PeerBook is itself internally
113
+ // synchronized. (Creating it in start() raced reads from on_connected, which can
114
+ // fire on a reactor thread before this subsystem's start() returns.)
115
+ std::unique_ptr<PeerBook> book_;
116
+
117
+ std::thread thread_;
118
+ std::atomic<bool> running_{false};
119
+ std::mutex wait_mutex_;
120
+ std::condition_variable wake_;
121
+
122
+ mutable std::mutex mutex_;
123
+ std::unordered_map<Address, Target> targets_; ///< keyed by the peer Address
124
+ };
125
+
126
+ } // namespace librats