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,444 @@
1
+ #pragma once
2
+
3
+ /**
4
+ * @file json.h
5
+ * @brief A small, self-contained JSON value type for librats.
6
+ *
7
+ * `librats::Json` is a dynamically-typed JSON value with a deliberately
8
+ * nlohmann-flavoured surface so existing call sites read naturally:
9
+ *
10
+ * Json j; // null
11
+ * j["name"] = "rats"; // becomes an object
12
+ * j["count"] = 42; // signed integer
13
+ * j["tags"] = Json::array(); // empty array
14
+ * j["tags"].push_back("p2p");
15
+ *
16
+ * Json cfg = { // initializer-list "object" detection,
17
+ * {"version", 1}, // exactly like nlohmann: a list whose
18
+ * {"nodes", {{"id", "ab"}}}, // every element is a [string, value] pair
19
+ * }; // is treated as an object.
20
+ *
21
+ * std::string text = j.dump(); // compact
22
+ * std::string nice = j.dump(2); // pretty, 2-space indent
23
+ * Json back = Json::parse(text); // throws on malformed input
24
+ * Json safe = Json::parse(text, nullptr, false); // never throws; see is_discarded()
25
+ *
26
+ * Design notes:
27
+ * - Numbers keep their kind (signed / unsigned / floating) so integers
28
+ * round-trip exactly and large 64-bit values are not silently truncated.
29
+ * - Objects preserve insertion order while offering O(1) average key lookup.
30
+ * - Heavy payloads (string / array / object) live behind a pointer, so a Json
31
+ * value is small (a tag plus one word) and cheap to move.
32
+ * - The parser is iterative-friendly recursive descent with a depth guard, so
33
+ * adversarial deeply-nested input fails cleanly instead of smashing the stack.
34
+ */
35
+
36
+ #include "librats/util/rats_export.h"
37
+ #include <cstdint>
38
+ #include <initializer_list>
39
+ #include <iosfwd>
40
+ #include <stdexcept>
41
+ #include <string>
42
+ #include <type_traits>
43
+ #include <utility>
44
+ #include <vector>
45
+
46
+ namespace librats {
47
+
48
+ /// Thrown by the throwing parse path and by type-mismatched accessors.
49
+ /// Derives from std::runtime_error so existing catch(const std::exception&)
50
+ /// blocks keep working unchanged.
51
+ class JsonError : public std::runtime_error {
52
+ public:
53
+ explicit JsonError(const std::string& what) : std::runtime_error(what) {}
54
+ };
55
+
56
+ class RATS_API Json {
57
+ public:
58
+ enum class Type : uint8_t {
59
+ Null,
60
+ Boolean,
61
+ Integer, // signed, stored as int64_t
62
+ Unsigned, // unsigned, stored as uint64_t
63
+ Float, // stored as double
64
+ String,
65
+ Array,
66
+ Object,
67
+ Discarded, // result of a non-throwing parse failure
68
+ };
69
+
70
+ using Array = std::vector<Json>;
71
+
72
+ /// Insertion-ordered string->Json map with O(1) average lookup.
73
+ class Object {
74
+ public:
75
+ using value_type = std::pair<std::string, Json>;
76
+ using storage = std::vector<value_type>;
77
+
78
+ Object() = default;
79
+ Object(const Object&) = default;
80
+ Object(Object&&) noexcept = default;
81
+ Object& operator=(const Object&) = default;
82
+ Object& operator=(Object&&) noexcept = default;
83
+
84
+ Json& operator[](const std::string& key); // inserts null if absent
85
+ Json& operator[](std::string&& key); // ditto, moves key on insert
86
+ const Json* find(const std::string& key) const; // nullptr if absent
87
+ Json* find(const std::string& key); // nullptr if absent
88
+ bool contains(const std::string& key) const { return find(key) != nullptr; }
89
+ bool erase(const std::string& key);
90
+
91
+ std::size_t size() const { return items_.size(); }
92
+ bool empty() const { return items_.empty(); }
93
+ void clear() { items_.clear(); index_ = {}; }
94
+
95
+ storage::iterator begin() { return items_.begin(); }
96
+ storage::iterator end() { return items_.end(); }
97
+ storage::const_iterator begin() const { return items_.begin(); }
98
+ storage::const_iterator end() const { return items_.end(); }
99
+
100
+ bool operator==(const Object& other) const; // order-independent
101
+
102
+ private:
103
+ // Small objects (the common case — a peer record, a config node) keep
104
+ // only the insertion-ordered vector and find keys with a linear scan,
105
+ // which beats hashing for a handful of entries and costs no allocation.
106
+ // Past the threshold we build an open-addressing index that stores *only*
107
+ // 1-based positions into items_ (a 0 slot means empty) — so it copies no
108
+ // keys and is one small vector instead of a node-per-key hash map. items_
109
+ // stays the single source of truth; every probe reads the key back from
110
+ // it. The index is non-empty exactly while the object is indexed.
111
+ static constexpr std::size_t kIndexThreshold = 16;
112
+
113
+ static std::size_t hash_key(const std::string& key);
114
+ void rebuild_index(); // size the table for items_ and fill it from scratch
115
+ void reindex(); // after erase: rebuild while large, else drop the index
116
+ bool indexed() const { return !index_.empty(); }
117
+
118
+ // Shared find-or-insert for both operator[] overloads. K is deduced as
119
+ // `const std::string&` or `std::string&&`, so the key is copied or moved
120
+ // into storage to match how the caller supplied it.
121
+ template <typename K>
122
+ Json& emplace_key(K&& key);
123
+
124
+ storage items_;
125
+ // Open-addressing slots: value 0 is an empty slot, otherwise it is
126
+ // (items_ index + 1). uint32_t positions cap an object at ~4 billion
127
+ // keys — far beyond any real JSON document.
128
+ std::vector<std::uint32_t> index_;
129
+ };
130
+
131
+ // ── Construction ────────────────────────────────────────────────────────
132
+
133
+ Json() noexcept : type_(Type::Null) {}
134
+ Json(std::nullptr_t) noexcept : type_(Type::Null) {}
135
+ Json(bool b) noexcept : type_(Type::Boolean) { bool_ = b; }
136
+
137
+ template <typename T,
138
+ typename std::enable_if<std::is_integral<T>::value &&
139
+ !std::is_same<T, bool>::value,
140
+ int>::type = 0>
141
+ Json(T v) noexcept {
142
+ if (std::is_signed<T>::value) {
143
+ type_ = Type::Integer;
144
+ int_ = static_cast<int64_t>(v);
145
+ } else {
146
+ type_ = Type::Unsigned;
147
+ uint_ = static_cast<uint64_t>(v);
148
+ }
149
+ }
150
+
151
+ template <typename T,
152
+ typename std::enable_if<std::is_floating_point<T>::value, int>::type = 0>
153
+ Json(T v) noexcept : type_(Type::Float) { float_ = static_cast<double>(v); }
154
+
155
+ Json(const char* s) : type_(Type::String) { str_ = new std::string(s ? s : ""); }
156
+ Json(const std::string& s) : type_(Type::String) { str_ = new std::string(s); }
157
+ Json(std::string&& s) : type_(Type::String) { str_ = new std::string(std::move(s)); }
158
+
159
+ /// nlohmann-style brace initialisation. A list whose every element is a
160
+ /// two-element array with a string first element is read as an object;
161
+ /// otherwise it is an array.
162
+ Json(std::initializer_list<Json> init);
163
+
164
+ Json(const Json& other) { copy_from(other); }
165
+ Json(Json&& other) noexcept { move_from(other); }
166
+
167
+ Json& operator=(const Json& other);
168
+ Json& operator=(Json&& other) noexcept;
169
+
170
+ ~Json() { destroy(); }
171
+
172
+ /// Explicit empties (also handy to force kind on an otherwise-null value).
173
+ static Json array() { Json j; j.type_ = Type::Array; j.arr_ = new Array(); return j; }
174
+ static Json object() { Json j; j.type_ = Type::Object; j.obj_ = new Object(); return j; }
175
+
176
+ // ── Parsing ─────────────────────────────────────────────────────────────
177
+ //
178
+ // The second argument exists only for nlohmann call-site compatibility
179
+ // (a parser callback, which this implementation ignores). When
180
+ // allow_exceptions is false a malformed document yields a Discarded value
181
+ // (see is_discarded()) instead of throwing.
182
+
183
+ static Json parse(const std::string& text, std::nullptr_t = nullptr,
184
+ bool allow_exceptions = true);
185
+ static Json parse(const char* text, std::nullptr_t = nullptr,
186
+ bool allow_exceptions = true);
187
+
188
+ template <typename InputIt>
189
+ static Json parse(InputIt first, InputIt last, std::nullptr_t = nullptr,
190
+ bool allow_exceptions = true) {
191
+ // std::string's range constructor copies [first, last), converting each
192
+ // element to char — this handles const char*, const uint8_t*, etc.
193
+ std::string buf(first, last);
194
+ return parse(buf, nullptr, allow_exceptions);
195
+ }
196
+
197
+ // ── Serialisation ───────────────────────────────────────────────────────
198
+ //
199
+ // indent < 0 (the default) produces the most compact form. indent >= 0
200
+ // pretty-prints with that many spaces per level.
201
+ std::string dump(int indent = -1) const;
202
+
203
+ // ── Type inspection ─────────────────────────────────────────────────────
204
+
205
+ Type type() const noexcept { return type_; }
206
+ bool is_null() const noexcept { return type_ == Type::Null; }
207
+ bool is_boolean() const noexcept { return type_ == Type::Boolean; }
208
+ bool is_number() const noexcept {
209
+ return type_ == Type::Integer || type_ == Type::Unsigned || type_ == Type::Float;
210
+ }
211
+ bool is_number_integer() const noexcept {
212
+ return type_ == Type::Integer || type_ == Type::Unsigned;
213
+ }
214
+ bool is_number_unsigned() const noexcept { return type_ == Type::Unsigned; }
215
+ bool is_number_float() const noexcept { return type_ == Type::Float; }
216
+ bool is_string() const noexcept { return type_ == Type::String; }
217
+ bool is_array() const noexcept { return type_ == Type::Array; }
218
+ bool is_object() const noexcept { return type_ == Type::Object; }
219
+ bool is_discarded() const noexcept { return type_ == Type::Discarded; }
220
+ bool is_primitive() const noexcept {
221
+ return is_null() || is_boolean() || is_number() || is_string();
222
+ }
223
+ bool is_structured() const noexcept { return is_array() || is_object(); }
224
+
225
+ /// Number of elements (array/object), or 0 for null, 1 for any scalar.
226
+ std::size_t size() const noexcept;
227
+ /// True for null, an empty array, or an empty object.
228
+ bool empty() const noexcept;
229
+
230
+ // ── Object / array access ───────────────────────────────────────────────
231
+
232
+ Json& operator[](const std::string& key);
233
+ Json& operator[](const char* key) { return operator[](std::string(key)); }
234
+ const Json& operator[](const std::string& key) const;
235
+ const Json& operator[](const char* key) const { return operator[](std::string(key)); }
236
+
237
+ Json& operator[](int index) { return operator[](static_cast<std::size_t>(index)); }
238
+ Json& operator[](std::size_t index);
239
+ const Json& operator[](int index) const {
240
+ return operator[](static_cast<std::size_t>(index));
241
+ }
242
+ const Json& operator[](std::size_t index) const;
243
+
244
+ /// Bounds/existence-checked access; throws JsonError when missing.
245
+ Json& at(const std::string& key);
246
+ const Json& at(const std::string& key) const;
247
+ Json& at(std::size_t index);
248
+ const Json& at(std::size_t index) const;
249
+
250
+ bool contains(const std::string& key) const {
251
+ return is_object() && obj_->contains(key);
252
+ }
253
+ bool erase(const std::string& key);
254
+ void erase(std::size_t index);
255
+
256
+ Json& front();
257
+ const Json& front() const;
258
+ Json& back();
259
+ const Json& back() const;
260
+
261
+ void push_back(const Json& value);
262
+ void push_back(Json&& value);
263
+ template <typename... Args>
264
+ Json& emplace_back(Args&&... args) {
265
+ push_back(Json(std::forward<Args>(args)...));
266
+ return back();
267
+ }
268
+
269
+ void clear();
270
+
271
+ // ── Typed extraction ────────────────────────────────────────────────────
272
+
273
+ template <typename T>
274
+ T get() const {
275
+ if constexpr (std::is_same<T, bool>::value) {
276
+ return static_cast<T>(as_bool());
277
+ } else if constexpr (std::is_integral<T>::value) {
278
+ if constexpr (std::is_unsigned<T>::value) return static_cast<T>(as_uint64());
279
+ else return static_cast<T>(as_int64());
280
+ } else if constexpr (std::is_floating_point<T>::value) {
281
+ return static_cast<T>(as_double());
282
+ } else {
283
+ return get_impl(static_cast<T*>(nullptr));
284
+ }
285
+ }
286
+
287
+ /// Implicit conversion to arithmetic types and std::string, so call sites
288
+ /// like `int v = j["x"];` and `std::string s = j["y"];` read naturally.
289
+ template <typename T,
290
+ typename std::enable_if<(std::is_arithmetic<T>::value ||
291
+ std::is_same<T, std::string>::value) &&
292
+ !std::is_same<T, Json>::value,
293
+ int>::type = 0>
294
+ operator T() const { return get<T>(); }
295
+
296
+ /// value(key, default): typed object lookup with a fallback. Returns the
297
+ /// default when this is not an object or the key is absent.
298
+ template <typename T>
299
+ T value(const std::string& key, const T& default_value) const {
300
+ if (is_object()) {
301
+ if (const Json* v = obj_->find(key)) return v->get<T>();
302
+ }
303
+ return default_value;
304
+ }
305
+ /// const char* default resolves to a std::string result (nlohmann parity).
306
+ std::string value(const std::string& key, const char* default_value) const {
307
+ if (is_object()) {
308
+ if (const Json* v = obj_->find(key)) return v->get<std::string>();
309
+ }
310
+ return std::string(default_value);
311
+ }
312
+
313
+ // ── Iteration ───────────────────────────────────────────────────────────
314
+ //
315
+ // Range-for visits array elements, or object values in insertion order.
316
+ // The iterator exposes .key()/.value() (nlohmann-style). For key/value
317
+ // structured bindings, use items(): `for (auto e : j.items()) ...`.
318
+
319
+ template <bool Const>
320
+ class Iterator {
321
+ public:
322
+ using JsonRef = typename std::conditional<Const, const Json&, Json&>::type;
323
+ using JsonPtr = typename std::conditional<Const, const Json*, Json*>::type;
324
+
325
+ Iterator(JsonPtr owner, std::size_t idx) : owner_(owner), idx_(idx) {}
326
+
327
+ JsonRef operator*() const { return value(); }
328
+ JsonPtr operator->() const { return &value(); }
329
+ Iterator& operator++() { ++idx_; return *this; }
330
+ Iterator operator++(int) { Iterator tmp = *this; ++idx_; return tmp; }
331
+ bool operator==(const Iterator& o) const { return owner_ == o.owner_ && idx_ == o.idx_; }
332
+ bool operator!=(const Iterator& o) const { return !(*this == o); }
333
+
334
+ const std::string& key() const;
335
+ JsonRef value() const;
336
+
337
+ private:
338
+ JsonPtr owner_;
339
+ std::size_t idx_;
340
+ };
341
+
342
+ using iterator = Iterator<false>;
343
+ using const_iterator = Iterator<true>;
344
+
345
+ iterator begin() { return iterator(this, 0); }
346
+ iterator end() { return iterator(this, size()); }
347
+ const_iterator begin() const { return const_iterator(this, 0); }
348
+ const_iterator end() const { return const_iterator(this, size()); }
349
+ const_iterator cbegin() const { return const_iterator(this, 0); }
350
+ const_iterator cend() const { return const_iterator(this, size()); }
351
+
352
+ /// A key/value view supporting structured bindings:
353
+ /// for (auto&& [key, val] : obj.items()) { ... }
354
+ /// For arrays, key() is the decimal index.
355
+ template <bool Const>
356
+ class ItemsProxy {
357
+ public:
358
+ using JsonPtr = typename std::conditional<Const, const Json*, Json*>::type;
359
+ explicit ItemsProxy(JsonPtr owner) : owner_(owner) {}
360
+ Iterator<Const> begin() const { return Iterator<Const>(owner_, 0); }
361
+ Iterator<Const> end() const { return Iterator<Const>(owner_, owner_->size()); }
362
+ private:
363
+ JsonPtr owner_;
364
+ };
365
+
366
+ ItemsProxy<false> items() { return ItemsProxy<false>(this); }
367
+ ItemsProxy<true> items() const { return ItemsProxy<true>(this); }
368
+
369
+ // ── Equality ────────────────────────────────────────────────────────────
370
+
371
+ bool operator==(const Json& other) const;
372
+ bool operator!=(const Json& other) const { return !(*this == other); }
373
+
374
+ // ── Direct container access (advanced) ──────────────────────────────────
375
+
376
+ Array& as_array();
377
+ const Array& as_array() const;
378
+ Object& as_object();
379
+ const Object& as_object() const;
380
+
381
+ private:
382
+ // value storage: scalars live inline, heavy payloads behind a pointer.
383
+ Type type_ = Type::Null;
384
+ union {
385
+ bool bool_;
386
+ int64_t int_;
387
+ uint64_t uint_;
388
+ double float_;
389
+ std::string* str_;
390
+ Array* arr_;
391
+ Object* obj_;
392
+ };
393
+
394
+ void destroy() noexcept;
395
+ void copy_from(const Json& other);
396
+ void move_from(Json& other) noexcept;
397
+
398
+ bool as_bool() const;
399
+ int64_t as_int64() const;
400
+ uint64_t as_uint64() const;
401
+ double as_double() const;
402
+ const std::string& as_string() const;
403
+
404
+ // get_impl tag overloads — only std::string is supported as a class type.
405
+ std::string get_impl(std::string*) const { return as_string(); }
406
+
407
+ void dump_to(std::string& out, int indent, int depth) const;
408
+
409
+ static Json make_discarded() { Json j; j.type_ = Type::Discarded; return j; }
410
+
411
+ // The parser is implemented in json.cpp.
412
+ friend class JsonParser;
413
+ };
414
+
415
+ // Stream helpers: `is >> j` parses the whole stream; `os << j` writes dump().
416
+ std::istream& operator>>(std::istream& is, Json& j);
417
+ std::ostream& operator<<(std::ostream& os, const Json& j);
418
+
419
+ // ── Iterator member definitions (need the complete Json type) ───────────────
420
+
421
+ template <bool Const>
422
+ inline const std::string& Json::Iterator<Const>::key() const {
423
+ if (owner_->type_ == Type::Object) {
424
+ return (owner_->obj_->begin() + idx_)->first;
425
+ }
426
+ // Arrays: synthesise a decimal index string on demand (thread-local cache).
427
+ static thread_local std::string idx_str;
428
+ idx_str = std::to_string(idx_);
429
+ return idx_str;
430
+ }
431
+
432
+ template <bool Const>
433
+ inline typename Json::Iterator<Const>::JsonRef Json::Iterator<Const>::value() const {
434
+ if (owner_->type_ == Type::Object) {
435
+ return (owner_->obj_->begin() + idx_)->second;
436
+ }
437
+ if (owner_->type_ == Type::Array) {
438
+ return (*owner_->arr_)[idx_];
439
+ }
440
+ // Scalars iterate as a single element.
441
+ return *owner_;
442
+ }
443
+
444
+ } // namespace librats
@@ -1,4 +1,4 @@
1
- #include "logger.h"
1
+ #include "librats/util/logger.h"
2
2
 
3
3
  namespace librats {
4
4
 
@@ -1,5 +1,6 @@
1
1
  #pragma once
2
2
 
3
+ #include "librats/util/rats_export.h"
3
4
  #include <string>
4
5
  #include <iostream>
5
6
  #include <mutex>
@@ -8,9 +9,16 @@
8
9
  #include <iomanip>
9
10
  #include <cstdint>
10
11
  #include <fstream>
11
- #include "fs.h"
12
+ #include <atomic>
13
+ #include "librats/util/fs.h"
12
14
 
13
15
  #ifdef _WIN32
16
+ // Include winsock2.h before windows.h: winsock2 defines _WINSOCKAPI_, which
17
+ // stops windows.h from pulling in the legacy winsock.h. Without this a TU that
18
+ // includes this header before a socket header (e.g. core/socket.h) gets
19
+ // winsock.h first and then a wall of winsock.h/winsock2.h redefinition errors
20
+ // under MSVC.
21
+ #include <winsock2.h>
14
22
  #include <windows.h>
15
23
  #include <io.h>
16
24
  #define isatty _isatty
@@ -32,7 +40,7 @@ enum class LogLevel {
32
40
  ERROR = 3
33
41
  };
34
42
 
35
- class Logger {
43
+ class RATS_API Logger {
36
44
  public:
37
45
  // Singleton pattern - implementation in logger.cpp to ensure single instance across TUs
38
46
  static Logger& getInstance();
@@ -44,7 +52,19 @@ public:
44
52
  // Set the minimum log level
45
53
  void set_log_level(LogLevel level) {
46
54
  std::lock_guard<std::mutex> lock(mutex_);
47
- min_level_ = level;
55
+ min_level_.store(level, std::memory_order_relaxed);
56
+ }
57
+
58
+ // Current minimum level (lock-free).
59
+ LogLevel get_log_level() const {
60
+ return min_level_.load(std::memory_order_relaxed);
61
+ }
62
+
63
+ // True if a message at `level` would be emitted. Cheap and lock-free, so the LOG_*
64
+ // macros can gate message construction on it and skip formatting work — string
65
+ // building, id-to-hex conversions — that would otherwise be built and thrown away.
66
+ bool is_enabled(LogLevel level) const {
67
+ return level >= min_level_.load(std::memory_order_relaxed);
48
68
  }
49
69
 
50
70
  // Enable/disable colors
@@ -125,8 +145,8 @@ public:
125
145
  // Main logging function
126
146
  void log(LogLevel level, const std::string& module, const std::string& message) {
127
147
  std::lock_guard<std::mutex> lock(mutex_);
128
-
129
- if (level < min_level_) {
148
+
149
+ if (level < min_level_.load(std::memory_order_relaxed)) {
130
150
  return;
131
151
  }
132
152
 
@@ -406,7 +426,7 @@ private:
406
426
  }
407
427
 
408
428
  mutable std::mutex mutex_;
409
- LogLevel min_level_;
429
+ std::atomic<LogLevel> min_level_;
410
430
  bool colors_enabled_;
411
431
  bool timestamps_enabled_;
412
432
  bool is_terminal_;
@@ -429,33 +449,25 @@ private:
429
449
 
430
450
  } // namespace librats
431
451
 
432
- // Convenience macros for easy logging
433
- #define LOG_DEBUG(module, message) \
434
- do { \
435
- std::ostringstream oss; \
436
- oss << message; \
437
- librats::Logger::getInstance().log(librats::LogLevel::DEBUG, module, oss.str()); \
438
- } while(0)
439
-
440
- #define LOG_INFO(module, message) \
452
+ // Convenience macros for easy logging.
453
+ //
454
+ // Each macro first checks is_enabled() — a lock-free level read — and only builds the
455
+ // message string when it would actually be emitted. This keeps a filtered-out log
456
+ // (e.g. a DEBUG line while running at INFO) down to a single atomic load, so hot-path
457
+ // logging costs nothing until the level is turned up. `message` is only evaluated when
458
+ // the level is enabled; keep it side-effect free.
459
+ #define RATS_LOG_AT(level_enum, module, message) \
441
460
  do { \
442
- std::ostringstream oss; \
443
- oss << message; \
444
- librats::Logger::getInstance().log(librats::LogLevel::INFO, module, oss.str()); \
461
+ if (librats::Logger::getInstance().is_enabled(level_enum)) { \
462
+ std::ostringstream oss; \
463
+ oss << message; \
464
+ librats::Logger::getInstance().log(level_enum, module, oss.str()); \
465
+ } \
445
466
  } while(0)
446
467
 
447
- #define LOG_WARN(module, message) \
448
- do { \
449
- std::ostringstream oss; \
450
- oss << message; \
451
- librats::Logger::getInstance().log(librats::LogLevel::WARN, module, oss.str()); \
452
- } while(0)
453
-
454
- #define LOG_ERROR(module, message) \
455
- do { \
456
- std::ostringstream oss; \
457
- oss << message; \
458
- librats::Logger::getInstance().log(librats::LogLevel::ERROR, module, oss.str()); \
459
- } while(0)
468
+ #define LOG_DEBUG(module, message) RATS_LOG_AT(librats::LogLevel::DEBUG, module, message)
469
+ #define LOG_INFO(module, message) RATS_LOG_AT(librats::LogLevel::INFO, module, message)
470
+ #define LOG_WARN(module, message) RATS_LOG_AT(librats::LogLevel::WARN, module, message)
471
+ #define LOG_ERROR(module, message) RATS_LOG_AT(librats::LogLevel::ERROR, module, message)
460
472
 
461
473
 
@@ -5,10 +5,10 @@
5
5
 
6
6
  // socket.h pulls in winsock2.h/ws2tcpip.h first on Windows (must precede the
7
7
  // iphlpapi / windows headers below to avoid the classic winsock2/windows.h clash).
8
- #include "socket.h"
9
- #include "network_monitor.h"
10
- #include "network_utils.h"
11
- #include "logger.h"
8
+ #include "librats/core/socket.h"
9
+ #include "librats/util/network_monitor.h"
10
+ #include "librats/util/network_utils.h"
11
+ #include "librats/util/logger.h"
12
12
 
13
13
  #include <algorithm>
14
14
 
@@ -110,6 +110,14 @@ void NetworkMonitor::stop() {
110
110
  if (!running_.exchange(false)) {
111
111
  return;
112
112
  }
113
+ // Signal under mutex_ so this synchronizes with the worker's wait: without
114
+ // holding the lock, a notify_all() that lands between the worker's predicate
115
+ // check and its enrollment in the CV wait queue is lost, and the worker then
116
+ // sleeps the full poll_interval (30 s with an event backend) before join()
117
+ // returns. Taking the lock (as check_now() does) closes that window.
118
+ {
119
+ std::lock_guard<std::mutex> lock(mutex_);
120
+ }
113
121
  cv_.notify_all(); // wake the worker out of its wait
114
122
  backend_stop(); // stop OS notifications / join the reader thread
115
123
  if (worker_.joinable()) {
@@ -29,6 +29,7 @@
29
29
  * long; offload slow recovery work (STUN, port mapping) to another thread.
30
30
  */
31
31
 
32
+ #include "librats/util/rats_export.h"
32
33
  #include <atomic>
33
34
  #include <chrono>
34
35
  #include <condition_variable>
@@ -41,7 +42,7 @@
41
42
 
42
43
  namespace librats {
43
44
 
44
- class NetworkMonitor {
45
+ class RATS_API NetworkMonitor {
45
46
  public:
46
47
  /// Invoked (debounced) whenever the set of local interface addresses changes.
47
48
  /// @param current_addresses the new, full list of local interface addresses.