librats 1.0.0 → 1.0.1

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.
@@ -2894,7 +2894,30 @@ bool DhtClient::load_routing_table() {
2894
2894
  LOG_DHT_WARN("Unsupported routing table version: " << version);
2895
2895
  return false;
2896
2896
  }
2897
-
2897
+
2898
+ // Restore our own node ID so it stays stable across restarts (matches libtorrent's
2899
+ // calculate_node_id). The external address is not known yet at load time, which is
2900
+ // libtorrent's "external_address.is_unspecified()" case -> reuse the saved ID as long
2901
+ // as it is valid (non-zero). If the external IP is later discovered and the restored
2902
+ // ID is no longer valid for it (BEP 42), set_external_ip() regenerates it then.
2903
+ // Restored before bucketing the loaded nodes below, since get_bucket_index() is
2904
+ // computed relative to node_id_.
2905
+ if (routing_data.contains("node_id")) {
2906
+ try {
2907
+ NodeId saved_id = hex_to_node_id(routing_data["node_id"].get<std::string>());
2908
+ bool all_zeros = std::all_of(saved_id.begin(), saved_id.end(),
2909
+ [](uint8_t b) { return b == 0; });
2910
+ if (!all_zeros) {
2911
+ node_id_ = saved_id;
2912
+ LOG_DHT_INFO("Restored DHT node ID from disk: " << node_id_to_hex(node_id_));
2913
+ } else {
2914
+ LOG_DHT_WARN("Saved node ID is invalid (zero/malformed), keeping generated one");
2915
+ }
2916
+ } catch (const std::exception& e) {
2917
+ LOG_DHT_WARN("Failed to restore saved node ID, keeping generated one: " << e.what());
2918
+ }
2919
+ }
2920
+
2898
2921
  // Load nodes
2899
2922
  const auto& nodes_array = routing_data["nodes"];
2900
2923
  size_t loaded_count = 0;
@@ -265,22 +265,19 @@ std::chrono::seconds RatsClient::calculate_discovery_interval() const {
265
265
 
266
266
  void RatsClient::automatic_discovery_loop() {
267
267
  LOG_CLIENT_INFO("Automatic peer discovery loop started");
268
-
269
- // Initial delay to let DHT bootstrap
270
- {
271
- std::unique_lock<std::mutex> lock(shutdown_mutex_);
272
- if (shutdown_cv_.wait_for(lock, std::chrono::seconds(INITIAL_DISCOVERY_DELAY_SECONDS), [this] { return !auto_discovery_running_.load() || !running_.load(); })) {
273
- LOG_CLIENT_INFO("Automatic peer discovery loop stopped during initial delay");
274
- return;
275
- }
276
- }
277
268
 
278
- // Best-effort: discover our public IP via STUN and derive a BEP 42 node ID from it before
279
- // we announce, so we announce under the correct ID. This runs on the discovery thread (not
280
- // a standalone one) on purpose: stop_dht_discovery() joins this thread via
281
- // stop_automatic_peer_discovery() BEFORE resetting the DHT clients, so set_external_ip()
282
- // can never touch a destroyed DhtClient. It complements the in-DHT "ip"-field voting, which
283
- // keeps the node ID correct if the address changes or STUN is unavailable.
269
+ // Best-effort: discover our public IP via STUN and derive a BEP 42 node ID from it BEFORE
270
+ // the initial bootstrap delay below. The DHT starts receiving KRPC responses (each carrying
271
+ // our address in the "ip" field) immediately on bootstrap, and that in-DHT vote can reach
272
+ // EXTERNAL_IP_VOTE_THRESHOLD within a few seconds. Probing STUN first lets set_external_ip()
273
+ // adopt the address and regenerate the node ID up front, so the DHT bootstraps under the
274
+ // correct ID and the ip-field voting silently confirms the already-adopted address instead
275
+ // of racing it to consensus. The voting remains the fallback when STUN is unavailable or the
276
+ // address later changes.
277
+ //
278
+ // This runs on the discovery thread (not a standalone one) on purpose: stop_dht_discovery()
279
+ // joins this thread via stop_automatic_peer_discovery() BEFORE resetting the DHT clients, so
280
+ // set_external_ip() can never touch a destroyed DhtClient.
284
281
  if (auto_discovery_running_.load() && running_.load()) {
285
282
  auto mapped = discover_public_address("stun.l.google.com", 19302, 4000);
286
283
  if (mapped) {
@@ -296,6 +293,15 @@ void RatsClient::automatic_discovery_loop() {
296
293
  }
297
294
  }
298
295
 
296
+ // Initial delay to let DHT bootstrap
297
+ {
298
+ std::unique_lock<std::mutex> lock(shutdown_mutex_);
299
+ if (shutdown_cv_.wait_for(lock, std::chrono::seconds(INITIAL_DISCOVERY_DELAY_SECONDS), [this] { return !auto_discovery_running_.load() || !running_.load(); })) {
300
+ LOG_CLIENT_INFO("Automatic peer discovery loop stopped during initial delay");
301
+ return;
302
+ }
303
+ }
304
+
299
305
  // Announce immediately - this also discovers peers during traversal
300
306
  announce_rats_peer();
301
307
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "librats",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Node.js bindings for librats - A high-performance peer-to-peer networking library",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",