librats 0.7.2 → 0.9.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 (35) hide show
  1. package/README.md +9 -4
  2. package/lib/index.d.ts +9 -22
  3. package/native-src/CMakeLists.txt +132 -50
  4. package/native-src/cmake/ratsConfig.cmake.in +8 -0
  5. package/native-src/src/bt_network.cpp +296 -183
  6. package/native-src/src/bt_network.h +25 -5
  7. package/native-src/src/crypto/sha256.c +1 -1
  8. package/native-src/src/dht.cpp +297 -47
  9. package/native-src/src/dht.h +70 -6
  10. package/native-src/src/file_transfer.cpp +1185 -1578
  11. package/native-src/src/file_transfer.h +240 -521
  12. package/native-src/src/io_poller.cpp +917 -0
  13. package/native-src/src/io_poller.h +138 -0
  14. package/native-src/src/krpc.cpp +161 -96
  15. package/native-src/src/krpc.h +18 -4
  16. package/native-src/src/librats.cpp +812 -1236
  17. package/native-src/src/librats.h +207 -208
  18. package/native-src/src/librats_bittorrent.cpp +1 -5
  19. package/native-src/src/librats_c.cpp +22 -39
  20. package/native-src/src/librats_discovery.cpp +377 -0
  21. package/native-src/src/librats_encryption.cpp +130 -283
  22. package/native-src/src/librats_file_transfer.cpp +27 -109
  23. package/native-src/src/librats_gossipsub.cpp +1 -5
  24. package/native-src/src/librats_ice.cpp +5 -1
  25. package/native-src/src/librats_log_macros.h +36 -0
  26. package/native-src/src/librats_logging.cpp +1 -7
  27. package/native-src/src/librats_mdns.cpp +1 -11
  28. package/native-src/src/librats_persistence.cpp +1 -11
  29. package/native-src/src/librats_reconnection.cpp +2 -13
  30. package/native-src/src/librats_statistic.cpp +105 -0
  31. package/native-src/src/socket.cpp +15 -3
  32. package/package.json +1 -1
  33. package/scripts/build-librats.js +3 -0
  34. package/scripts/prepare-package.js +10 -0
  35. package/src/librats_node.cpp +53 -64
@@ -1,15 +1,11 @@
1
1
  #include "librats.h"
2
- // Logging macros for RatsClient
3
- #define LOG_CLIENT_DEBUG(message) LOG_DEBUG("client", message)
4
- #define LOG_CLIENT_INFO(message) LOG_INFO("client", message)
5
- #define LOG_CLIENT_WARN(message) LOG_WARN("client", message)
6
- #define LOG_CLIENT_ERROR(message) LOG_ERROR("client", message)
2
+ #include "librats_log_macros.h"
7
3
 
8
4
  namespace librats {
9
5
 
10
- //=============================================================================
11
- // File Transfer API Implementation
12
- //=============================================================================
6
+ // =============================================================================
7
+ // File transfer API - thin forwarding layer over FileTransferManager
8
+ // =============================================================================
13
9
 
14
10
  FileTransferManager& RatsClient::get_file_transfer_manager() {
15
11
  if (!file_transfer_manager_) {
@@ -22,24 +18,22 @@ bool RatsClient::is_file_transfer_available() const {
22
18
  return file_transfer_manager_ != nullptr;
23
19
  }
24
20
 
25
- std::string RatsClient::send_file(const std::string& peer_id, const std::string& file_path,
26
- const std::string& remote_filename) {
21
+ std::string RatsClient::send_file(const std::string& peer_id, const std::string& file_path,
22
+ const std::string& remote_filename) {
27
23
  if (!is_file_transfer_available()) {
28
24
  LOG_CLIENT_ERROR("File transfer manager not available");
29
25
  return "";
30
26
  }
31
-
32
27
  return file_transfer_manager_->send_file(peer_id, file_path, remote_filename);
33
28
  }
34
29
 
35
30
  std::string RatsClient::send_directory(const std::string& peer_id, const std::string& directory_path,
36
- const std::string& remote_directory_name, bool recursive) {
31
+ const std::string& remote_name) {
37
32
  if (!is_file_transfer_available()) {
38
33
  LOG_CLIENT_ERROR("File transfer manager not available");
39
34
  return "";
40
35
  }
41
-
42
- return file_transfer_manager_->send_directory(peer_id, directory_path, remote_directory_name, recursive);
36
+ return file_transfer_manager_->send_directory(peer_id, directory_path, remote_name);
43
37
  }
44
38
 
45
39
  bool RatsClient::accept_file_transfer(const std::string& transfer_id, const std::string& local_path) {
@@ -47,8 +41,7 @@ bool RatsClient::accept_file_transfer(const std::string& transfer_id, const std:
47
41
  LOG_CLIENT_ERROR("File transfer manager not available");
48
42
  return false;
49
43
  }
50
-
51
- return file_transfer_manager_->accept_file_transfer(transfer_id, local_path);
44
+ return file_transfer_manager_->accept(transfer_id, local_path);
52
45
  }
53
46
 
54
47
  bool RatsClient::reject_file_transfer(const std::string& transfer_id, const std::string& reason) {
@@ -56,26 +49,7 @@ bool RatsClient::reject_file_transfer(const std::string& transfer_id, const std:
56
49
  LOG_CLIENT_ERROR("File transfer manager not available");
57
50
  return false;
58
51
  }
59
-
60
- return file_transfer_manager_->reject_file_transfer(transfer_id, reason);
61
- }
62
-
63
- bool RatsClient::accept_directory_transfer(const std::string& transfer_id, const std::string& local_path) {
64
- if (!is_file_transfer_available()) {
65
- LOG_CLIENT_ERROR("File transfer manager not available");
66
- return false;
67
- }
68
-
69
- return file_transfer_manager_->accept_directory_transfer(transfer_id, local_path);
70
- }
71
-
72
- bool RatsClient::reject_directory_transfer(const std::string& transfer_id, const std::string& reason) {
73
- if (!is_file_transfer_available()) {
74
- LOG_CLIENT_ERROR("File transfer manager not available");
75
- return false;
76
- }
77
-
78
- return file_transfer_manager_->reject_directory_transfer(transfer_id, reason);
52
+ return file_transfer_manager_->reject(transfer_id, reason);
79
53
  }
80
54
 
81
55
  bool RatsClient::pause_file_transfer(const std::string& transfer_id) {
@@ -83,8 +57,7 @@ bool RatsClient::pause_file_transfer(const std::string& transfer_id) {
83
57
  LOG_CLIENT_ERROR("File transfer manager not available");
84
58
  return false;
85
59
  }
86
-
87
- return file_transfer_manager_->pause_transfer(transfer_id);
60
+ return file_transfer_manager_->pause(transfer_id);
88
61
  }
89
62
 
90
63
  bool RatsClient::resume_file_transfer(const std::string& transfer_id) {
@@ -92,8 +65,7 @@ bool RatsClient::resume_file_transfer(const std::string& transfer_id) {
92
65
  LOG_CLIENT_ERROR("File transfer manager not available");
93
66
  return false;
94
67
  }
95
-
96
- return file_transfer_manager_->resume_transfer(transfer_id);
68
+ return file_transfer_manager_->resume(transfer_id);
97
69
  }
98
70
 
99
71
  bool RatsClient::cancel_file_transfer(const std::string& transfer_id) {
@@ -101,25 +73,24 @@ bool RatsClient::cancel_file_transfer(const std::string& transfer_id) {
101
73
  LOG_CLIENT_ERROR("File transfer manager not available");
102
74
  return false;
103
75
  }
104
-
105
- return file_transfer_manager_->cancel_transfer(transfer_id);
76
+ return file_transfer_manager_->cancel(transfer_id);
106
77
  }
107
78
 
108
- std::shared_ptr<FileTransferProgress> RatsClient::get_file_transfer_progress(const std::string& transfer_id) const {
79
+ std::shared_ptr<FileTransferProgress>
80
+ RatsClient::get_file_transfer_progress(const std::string& transfer_id) const {
109
81
  if (!is_file_transfer_available()) {
110
82
  LOG_CLIENT_ERROR("File transfer manager not available");
111
83
  return nullptr;
112
84
  }
113
-
114
- return file_transfer_manager_->get_transfer_progress(transfer_id);
85
+ return file_transfer_manager_->get_progress(transfer_id);
115
86
  }
116
87
 
117
- std::vector<std::shared_ptr<FileTransferProgress>> RatsClient::get_active_file_transfers() const {
88
+ std::vector<std::shared_ptr<FileTransferProgress>>
89
+ RatsClient::get_active_file_transfers() const {
118
90
  if (!is_file_transfer_available()) {
119
91
  LOG_CLIENT_ERROR("File transfer manager not available");
120
92
  return {};
121
93
  }
122
-
123
94
  return file_transfer_manager_->get_active_transfers();
124
95
  }
125
96
 
@@ -128,8 +99,7 @@ nlohmann::json RatsClient::get_file_transfer_statistics() const {
128
99
  LOG_CLIENT_ERROR("File transfer manager not available");
129
100
  return nlohmann::json::object();
130
101
  }
131
-
132
- return file_transfer_manager_->get_transfer_statistics();
102
+ return file_transfer_manager_->get_statistics();
133
103
  }
134
104
 
135
105
  void RatsClient::set_file_transfer_config(const FileTransferConfig& config) {
@@ -137,90 +107,38 @@ void RatsClient::set_file_transfer_config(const FileTransferConfig& config) {
137
107
  LOG_CLIENT_ERROR("File transfer manager not available");
138
108
  return;
139
109
  }
140
-
141
110
  file_transfer_manager_->set_config(config);
142
111
  }
143
112
 
144
- const FileTransferConfig& RatsClient::get_file_transfer_config() const {
113
+ FileTransferConfig RatsClient::get_file_transfer_config() const {
145
114
  if (!is_file_transfer_available()) {
146
115
  throw std::runtime_error("File transfer manager not available");
147
116
  }
148
-
149
117
  return file_transfer_manager_->get_config();
150
118
  }
151
119
 
152
- void RatsClient::on_file_transfer_progress(FileTransferProgressCallback callback) {
153
- if (!is_file_transfer_available()) {
154
- LOG_CLIENT_ERROR("File transfer manager not available");
155
- return;
156
- }
157
-
158
- file_transfer_manager_->set_progress_callback(callback);
159
- }
160
-
161
- void RatsClient::on_file_transfer_completed(FileTransferCompletedCallback callback) {
162
- if (!is_file_transfer_available()) {
163
- LOG_CLIENT_ERROR("File transfer manager not available");
164
- return;
165
- }
166
-
167
- file_transfer_manager_->set_completion_callback(callback);
168
- }
169
-
170
- void RatsClient::on_file_transfer_request(FileTransferRequestCallback callback) {
120
+ void RatsClient::on_file_transfer_progress(TransferProgressCallback callback) {
171
121
  if (!is_file_transfer_available()) {
172
122
  LOG_CLIENT_ERROR("File transfer manager not available");
173
123
  return;
174
124
  }
175
-
176
- file_transfer_manager_->set_request_callback(callback);
177
- }
178
-
179
- void RatsClient::on_directory_transfer_progress(DirectoryTransferProgressCallback callback) {
180
- if (!is_file_transfer_available()) {
181
- LOG_CLIENT_ERROR("File transfer manager not available");
182
- return;
183
- }
184
-
185
- file_transfer_manager_->set_directory_progress_callback(callback);
186
- }
187
-
188
- std::string RatsClient::request_file(const std::string& peer_id, const std::string& remote_file_path,
189
- const std::string& local_path) {
190
- if (!is_file_transfer_available()) {
191
- LOG_CLIENT_ERROR("File transfer manager not available");
192
- return "";
193
- }
194
-
195
- return file_transfer_manager_->request_file(peer_id, remote_file_path, local_path);
196
- }
197
-
198
- std::string RatsClient::request_directory(const std::string& peer_id, const std::string& remote_directory_path,
199
- const std::string& local_directory_path, bool recursive) {
200
- if (!is_file_transfer_available()) {
201
- LOG_CLIENT_ERROR("File transfer manager not available");
202
- return "";
203
- }
204
-
205
- return file_transfer_manager_->request_directory(peer_id, remote_directory_path, local_directory_path, recursive);
125
+ file_transfer_manager_->set_progress_callback(std::move(callback));
206
126
  }
207
127
 
208
- void RatsClient::on_file_request(FileRequestCallback callback) {
128
+ void RatsClient::on_file_transfer_completed(TransferCompletedCallback callback) {
209
129
  if (!is_file_transfer_available()) {
210
130
  LOG_CLIENT_ERROR("File transfer manager not available");
211
131
  return;
212
132
  }
213
-
214
- file_transfer_manager_->set_file_request_callback(callback);
133
+ file_transfer_manager_->set_completed_callback(std::move(callback));
215
134
  }
216
135
 
217
- void RatsClient::on_directory_request(DirectoryRequestCallback callback) {
136
+ void RatsClient::on_file_transfer_request(TransferOfferCallback callback) {
218
137
  if (!is_file_transfer_available()) {
219
138
  LOG_CLIENT_ERROR("File transfer manager not available");
220
139
  return;
221
140
  }
222
-
223
- file_transfer_manager_->set_directory_request_callback(callback);
141
+ file_transfer_manager_->set_offer_callback(std::move(callback));
224
142
  }
225
143
 
226
- }
144
+ } // namespace librats
@@ -1,9 +1,5 @@
1
1
  #include "librats.h"
2
- // Logging macros for RatsClient
3
- #define LOG_CLIENT_DEBUG(message) LOG_DEBUG("client", message)
4
- #define LOG_CLIENT_INFO(message) LOG_INFO("client", message)
5
- #define LOG_CLIENT_WARN(message) LOG_WARN("client", message)
6
- #define LOG_CLIENT_ERROR(message) LOG_ERROR("client", message)
2
+ #include "librats_log_macros.h"
7
3
 
8
4
  namespace librats {
9
5
 
@@ -91,6 +91,10 @@ std::optional<StunMappedAddress> RatsClient::discover_public_address(
91
91
 
92
92
  if (result.success && result.mapped_address) {
93
93
  LOG_INFO("ice", "Discovered public address: " << result.mapped_address->to_string());
94
+
95
+ // Add public IP to our own addresses list to prevent self-connections
96
+ add_ignored_address(result.mapped_address->address);
97
+
94
98
  return result.mapped_address;
95
99
  }
96
100
 
@@ -183,7 +187,7 @@ void RatsClient::set_ice_config(const IceConfig& config) {
183
187
  get_ice_manager().set_config(config);
184
188
  }
185
189
 
186
- const IceConfig& RatsClient::get_ice_config() const {
190
+ IceConfig RatsClient::get_ice_config() const {
187
191
  // Need to cast away const to get mutable reference for lazy initialization
188
192
  return const_cast<RatsClient*>(this)->get_ice_manager().config();
189
193
  }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * @file librats_log_macros.h
3
+ * @brief Shared logging macros for all librats_*.cpp files.
4
+ *
5
+ * In TESTING builds the macros embed the `this` pointer so that
6
+ * log lines from different RatsClient instances can be distinguished.
7
+ */
8
+
9
+ #ifndef LIBRATS_LOG_MACROS_H
10
+ #define LIBRATS_LOG_MACROS_H
11
+
12
+ #include "logger.h"
13
+
14
+ #ifdef TESTING
15
+ #define LOG_CLIENT_DEBUG(message) LOG_DEBUG("client", "[pointer: " << this << "] " << message)
16
+ #define LOG_CLIENT_INFO(message) LOG_INFO("client", "[pointer: " << this << "] " << message)
17
+ #define LOG_CLIENT_WARN(message) LOG_WARN("client", "[pointer: " << this << "] " << message)
18
+ #define LOG_CLIENT_ERROR(message) LOG_ERROR("client", "[pointer: " << this << "] " << message)
19
+
20
+ #define LOG_SERVER_DEBUG(message) LOG_DEBUG("server", "[pointer: " << this << "] " << message)
21
+ #define LOG_SERVER_INFO(message) LOG_INFO("server", "[pointer: " << this << "] " << message)
22
+ #define LOG_SERVER_WARN(message) LOG_WARN("server", "[pointer: " << this << "] " << message)
23
+ #define LOG_SERVER_ERROR(message) LOG_ERROR("server", "[pointer: " << this << "] " << message)
24
+ #else
25
+ #define LOG_CLIENT_DEBUG(message) LOG_DEBUG("client", message)
26
+ #define LOG_CLIENT_INFO(message) LOG_INFO("client", message)
27
+ #define LOG_CLIENT_WARN(message) LOG_WARN("client", message)
28
+ #define LOG_CLIENT_ERROR(message) LOG_ERROR("client", message)
29
+
30
+ #define LOG_SERVER_DEBUG(message) LOG_DEBUG("server", message)
31
+ #define LOG_SERVER_INFO(message) LOG_INFO("server", message)
32
+ #define LOG_SERVER_WARN(message) LOG_WARN("server", message)
33
+ #define LOG_SERVER_ERROR(message) LOG_ERROR("server", message)
34
+ #endif
35
+
36
+ #endif // LIBRATS_LOG_MACROS_H
@@ -1,13 +1,7 @@
1
1
  #include "librats.h"
2
- #include "logger.h"
2
+ #include "librats_log_macros.h"
3
3
  #include <algorithm>
4
4
 
5
- // Logging macros for RatsClient
6
- #define LOG_CLIENT_DEBUG(message) LOG_DEBUG("client", message)
7
- #define LOG_CLIENT_INFO(message) LOG_INFO("client", message)
8
- #define LOG_CLIENT_WARN(message) LOG_WARN("client", message)
9
- #define LOG_CLIENT_ERROR(message) LOG_ERROR("client", message)
10
-
11
5
  namespace librats {
12
6
 
13
7
  //=============================================================================
@@ -6,17 +6,7 @@
6
6
  #include <memory>
7
7
  #include <stdexcept>
8
8
 
9
- #ifdef TESTING
10
- #define LOG_CLIENT_DEBUG(message) LOG_DEBUG("client", "[pointer: " << this << "] " << message)
11
- #define LOG_CLIENT_INFO(message) LOG_INFO("client", "[pointer: " << this << "] " << message)
12
- #define LOG_CLIENT_WARN(message) LOG_WARN("client", "[pointer: " << this << "] " << message)
13
- #define LOG_CLIENT_ERROR(message) LOG_ERROR("client", "[pointer: " << this << "] " << message)
14
- #else
15
- #define LOG_CLIENT_DEBUG(message) LOG_DEBUG("client", message)
16
- #define LOG_CLIENT_INFO(message) LOG_INFO("client", message)
17
- #define LOG_CLIENT_WARN(message) LOG_WARN("client", message)
18
- #define LOG_CLIENT_ERROR(message) LOG_ERROR("client", message)
19
- #endif
9
+ #include "librats_log_macros.h"
20
10
 
21
11
  namespace librats {
22
12
 
@@ -12,17 +12,7 @@
12
12
  #include <iomanip>
13
13
  #include <stdexcept>
14
14
 
15
- #ifdef TESTING
16
- #define LOG_CLIENT_DEBUG(message) LOG_DEBUG("client", "[pointer: " << this << "] " << message)
17
- #define LOG_CLIENT_INFO(message) LOG_INFO("client", "[pointer: " << this << "] " << message)
18
- #define LOG_CLIENT_WARN(message) LOG_WARN("client", "[pointer: " << this << "] " << message)
19
- #define LOG_CLIENT_ERROR(message) LOG_ERROR("client", "[pointer: " << this << "] " << message)
20
- #else
21
- #define LOG_CLIENT_DEBUG(message) LOG_DEBUG("client", message)
22
- #define LOG_CLIENT_INFO(message) LOG_INFO("client", message)
23
- #define LOG_CLIENT_WARN(message) LOG_WARN("client", message)
24
- #define LOG_CLIENT_ERROR(message) LOG_ERROR("client", message)
25
- #endif
15
+ #include "librats_log_macros.h"
26
16
 
27
17
  namespace librats {
28
18
 
@@ -1,16 +1,5 @@
1
1
  #include "librats.h"
2
-
3
- #ifdef TESTING
4
- #define LOG_CLIENT_DEBUG(message) LOG_DEBUG("client", "[pointer: " << this << "] " << message)
5
- #define LOG_CLIENT_INFO(message) LOG_INFO("client", "[pointer: " << this << "] " << message)
6
- #define LOG_CLIENT_WARN(message) LOG_WARN("client", "[pointer: " << this << "] " << message)
7
- #define LOG_CLIENT_ERROR(message) LOG_ERROR("client", "[pointer: " << this << "] " << message)
8
- #else
9
- #define LOG_CLIENT_DEBUG(message) LOG_DEBUG("client", message)
10
- #define LOG_CLIENT_INFO(message) LOG_INFO("client", message)
11
- #define LOG_CLIENT_WARN(message) LOG_WARN("client", message)
12
- #define LOG_CLIENT_ERROR(message) LOG_ERROR("client", message)
13
- #endif
2
+ #include "librats_log_macros.h"
14
3
 
15
4
  namespace librats {
16
5
 
@@ -37,7 +26,7 @@ void RatsClient::set_reconnect_config(const ReconnectConfig& config) {
37
26
  << ", stable_threshold=" << config.stable_connection_threshold_seconds << "s");
38
27
  }
39
28
 
40
- const ReconnectConfig& RatsClient::get_reconnect_config() const {
29
+ ReconnectConfig RatsClient::get_reconnect_config() const {
41
30
  std::lock_guard<std::mutex> lock(reconnect_mutex_);
42
31
  return reconnect_config_;
43
32
  }
@@ -0,0 +1,105 @@
1
+ #include "librats.h"
2
+ #include "librats_log_macros.h"
3
+ #include "os.h"
4
+
5
+ namespace librats {
6
+
7
+
8
+ // =========================================================================
9
+ // Statistics and Information
10
+ // =========================================================================
11
+
12
+ nlohmann::json RatsClient::get_connection_statistics() const {
13
+ nlohmann::json stats;
14
+
15
+ {
16
+ std::lock_guard<std::mutex> lock(peers_mutex_);
17
+ stats["total_peers"] = peers_.size();
18
+ stats["validated_peers"] = get_peer_count_unlocked();
19
+ stats["max_peers"] = max_peers_;
20
+ }
21
+
22
+ stats["running"] = is_running();
23
+ stats["listen_port"] = listen_port_;
24
+ stats["our_peer_id"] = get_our_peer_id();
25
+ stats["encryption_enabled"] = is_encryption_enabled();
26
+
27
+ // DHT statistics (IPv4 + IPv6 combined)
28
+ if (is_dht_running()) {
29
+ stats["dht_running"] = true;
30
+ stats["dht_routing_table_size"] = get_dht_routing_table_size();
31
+ stats["dht_ipv4_running"] = (dht_client_ && dht_client_->is_running());
32
+ stats["dht_ipv6_running"] = (dht_client_v6_ && dht_client_v6_->is_running());
33
+ if (dht_client_ && dht_client_->is_running()) {
34
+ stats["dht_ipv4_routing_table_size"] = dht_client_->get_routing_table_size();
35
+ }
36
+ if (dht_client_v6_ && dht_client_v6_->is_running()) {
37
+ stats["dht_ipv6_routing_table_size"] = dht_client_v6_->get_routing_table_size();
38
+ }
39
+ } else {
40
+ stats["dht_running"] = false;
41
+ }
42
+
43
+ // mDNS statistics
44
+ stats["mdns_running"] = is_mdns_running();
45
+
46
+ // Reconnection statistics
47
+ {
48
+ std::lock_guard<std::mutex> lock(reconnect_mutex_);
49
+ stats["reconnect_enabled"] = reconnect_config_.enabled;
50
+ stats["reconnect_queue_size"] = reconnect_queue_.size();
51
+ stats["reconnect_max_attempts"] = reconnect_config_.max_attempts;
52
+ }
53
+
54
+ return stats;
55
+ }
56
+
57
+ // Cached formatting helpers - computed once on first use
58
+ static const std::string& get_box_separator() {
59
+ static const std::string separator = supports_unicode() ?
60
+ "════════════════════════════════════════════════════════════════════" :
61
+ "=====================================================================";
62
+ return separator;
63
+ }
64
+
65
+ static const std::string& get_box_vertical() {
66
+ static const std::string vertical = supports_unicode() ? "│" : "|";
67
+ return vertical;
68
+ }
69
+
70
+ static const std::string& get_checkmark() {
71
+ static const std::string checkmark = supports_unicode() ? "✓" : "[*]";
72
+ return checkmark;
73
+ }
74
+
75
+ void RatsClient::log_handshake_completion_unlocked(const RatsPeer& peer) {
76
+ // Calculate connection duration
77
+ auto now = std::chrono::steady_clock::now();
78
+ auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now - peer.connected_at);
79
+
80
+ // Get current peer count (assumes peers_mutex_ is already locked)
81
+ int current_peer_count = get_peer_count_unlocked();
82
+
83
+ // Create visually appealing log output
84
+ std::string connection_type = peer.is_outgoing ? "OUTGOING" : "INCOMING";
85
+ const std::string& separator = get_box_separator();
86
+ const std::string& vertical = get_box_vertical();
87
+ const std::string& checkmark = get_checkmark();
88
+
89
+ LOG_CLIENT_INFO("");
90
+ LOG_CLIENT_INFO(separator);
91
+ LOG_CLIENT_INFO(checkmark << " HANDSHAKE COMPLETED - NEW PEER CONNECTED");
92
+ LOG_CLIENT_INFO(separator);
93
+ LOG_CLIENT_INFO(vertical << " Peer ID : " << peer.peer_id);
94
+ LOG_CLIENT_INFO(vertical << " Address : " << peer.ip << ":" << peer.port);
95
+ LOG_CLIENT_INFO(vertical << " Connection : " << connection_type);
96
+ LOG_CLIENT_INFO(vertical << " Protocol Ver. : " << peer.version);
97
+ LOG_CLIENT_INFO(vertical << " Socket : " << peer.socket);
98
+ LOG_CLIENT_INFO(vertical << " Duration : " << duration.count() << "ms");
99
+ LOG_CLIENT_INFO(vertical << " Network Peers : " << current_peer_count << "/" << max_peers_);
100
+
101
+ LOG_CLIENT_INFO(separator);
102
+ LOG_CLIENT_INFO("");
103
+ }
104
+
105
+ }
@@ -760,13 +760,25 @@ static bool build_udp_dest_addr(const std::string& host, int port, AddressFamily
760
760
  sockaddr_storage& addr, socklen_t& addr_len) {
761
761
  memset(&addr, 0, sizeof(addr));
762
762
 
763
- // Native IPv6 address
763
+ // Native IPv6 address, or hostname that must resolve to IPv6 (pure IPv6 socket).
764
+ // A pure IPv6 socket (V6ONLY) cannot send to IPv4-mapped addresses, so hostnames
765
+ // are resolved via AAAA records here.
766
+ std::string ipv6_host;
764
767
  if (network_utils::is_valid_ipv6(host)) {
768
+ ipv6_host = host;
769
+ } else if (af == AddressFamily::IPv6) {
770
+ ipv6_host = network_utils::resolve_hostname_v6(host);
771
+ if (ipv6_host.empty()) {
772
+ LOG_SOCKET_DEBUG("Failed to resolve hostname to IPv6: " << host);
773
+ return false;
774
+ }
775
+ }
776
+ if (!ipv6_host.empty()) {
765
777
  auto* a6 = reinterpret_cast<sockaddr_in6*>(&addr);
766
778
  a6->sin6_family = AF_INET6;
767
779
  a6->sin6_port = htons(port);
768
- if (inet_pton(AF_INET6, host.c_str(), &a6->sin6_addr) <= 0) {
769
- LOG_SOCKET_ERROR("Invalid IPv6 address: " << host);
780
+ if (inet_pton(AF_INET6, ipv6_host.c_str(), &a6->sin6_addr) <= 0) {
781
+ LOG_SOCKET_ERROR("Invalid IPv6 address: " << ipv6_host);
770
782
  return false;
771
783
  }
772
784
  addr_len = sizeof(sockaddr_in6);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "librats",
3
- "version": "0.7.2",
3
+ "version": "0.9.0",
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",
@@ -136,6 +136,9 @@ try {
136
136
  '-DRATS_BUILD_EXAMPLES=OFF',
137
137
  '-DRATS_STATIC_LIBRARY=ON',
138
138
  '-DRATS_BINDINGS=ON',
139
+ // The bindings only need the static archive; install/package-config rules
140
+ // (find_package support) are unnecessary here and pull in cmake/ratsConfig.cmake.in.
141
+ '-DRATS_INSTALL=OFF',
139
142
  '-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDLL'
140
143
  ];
141
144
 
@@ -108,6 +108,16 @@ copyDir(
108
108
  srcFilter
109
109
  );
110
110
 
111
+ // Copy cmake/ directory (package-config templates referenced by CMakeLists.txt
112
+ // when RATS_INSTALL is enabled, e.g. cmake/ratsConfig.cmake.in)
113
+ if (fs.existsSync(path.join(projectRoot, 'cmake'))) {
114
+ console.log(' Copying cmake/ directory...');
115
+ copyDir(
116
+ path.join(projectRoot, 'cmake'),
117
+ path.join(nativeSrcDir, 'cmake')
118
+ );
119
+ }
120
+
111
121
  // Copy 3rdparty/ directory
112
122
  if (fs.existsSync(path.join(projectRoot, '3rdparty'))) {
113
123
  console.log(' Copying 3rdparty/ directory...');