librats 0.8.0 → 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.
- package/README.md +9 -4
- package/lib/index.d.ts +9 -22
- package/native-src/CMakeLists.txt +122 -48
- package/native-src/cmake/ratsConfig.cmake.in +8 -0
- package/native-src/src/crypto/sha256.c +1 -1
- package/native-src/src/dht.cpp +297 -47
- package/native-src/src/dht.h +70 -6
- package/native-src/src/file_transfer.cpp +1185 -1578
- package/native-src/src/file_transfer.h +240 -521
- package/native-src/src/io_poller.cpp +7 -0
- package/native-src/src/krpc.cpp +161 -96
- package/native-src/src/krpc.h +18 -4
- package/native-src/src/librats.cpp +3 -0
- package/native-src/src/librats.h +61 -154
- package/native-src/src/librats_c.cpp +21 -38
- package/native-src/src/librats_discovery.cpp +107 -39
- package/native-src/src/librats_file_transfer.cpp +25 -103
- package/native-src/src/librats_ice.cpp +4 -0
- package/native-src/src/librats_statistic.cpp +10 -2
- package/native-src/src/socket.cpp +15 -3
- package/package.json +1 -1
- package/scripts/build-librats.js +3 -0
- package/scripts/prepare-package.js +10 -0
- package/src/librats_node.cpp +53 -64
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
|
|
4
4
|
namespace librats {
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
// File
|
|
8
|
-
|
|
6
|
+
// =============================================================================
|
|
7
|
+
// File transfer API - thin forwarding layer over FileTransferManager
|
|
8
|
+
// =============================================================================
|
|
9
9
|
|
|
10
10
|
FileTransferManager& RatsClient::get_file_transfer_manager() {
|
|
11
11
|
if (!file_transfer_manager_) {
|
|
@@ -18,24 +18,22 @@ bool RatsClient::is_file_transfer_available() const {
|
|
|
18
18
|
return file_transfer_manager_ != nullptr;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
std::string RatsClient::send_file(const std::string& peer_id, const std::string& file_path,
|
|
22
|
-
|
|
21
|
+
std::string RatsClient::send_file(const std::string& peer_id, const std::string& file_path,
|
|
22
|
+
const std::string& remote_filename) {
|
|
23
23
|
if (!is_file_transfer_available()) {
|
|
24
24
|
LOG_CLIENT_ERROR("File transfer manager not available");
|
|
25
25
|
return "";
|
|
26
26
|
}
|
|
27
|
-
|
|
28
27
|
return file_transfer_manager_->send_file(peer_id, file_path, remote_filename);
|
|
29
28
|
}
|
|
30
29
|
|
|
31
30
|
std::string RatsClient::send_directory(const std::string& peer_id, const std::string& directory_path,
|
|
32
|
-
|
|
31
|
+
const std::string& remote_name) {
|
|
33
32
|
if (!is_file_transfer_available()) {
|
|
34
33
|
LOG_CLIENT_ERROR("File transfer manager not available");
|
|
35
34
|
return "";
|
|
36
35
|
}
|
|
37
|
-
|
|
38
|
-
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);
|
|
39
37
|
}
|
|
40
38
|
|
|
41
39
|
bool RatsClient::accept_file_transfer(const std::string& transfer_id, const std::string& local_path) {
|
|
@@ -43,8 +41,7 @@ bool RatsClient::accept_file_transfer(const std::string& transfer_id, const std:
|
|
|
43
41
|
LOG_CLIENT_ERROR("File transfer manager not available");
|
|
44
42
|
return false;
|
|
45
43
|
}
|
|
46
|
-
|
|
47
|
-
return file_transfer_manager_->accept_file_transfer(transfer_id, local_path);
|
|
44
|
+
return file_transfer_manager_->accept(transfer_id, local_path);
|
|
48
45
|
}
|
|
49
46
|
|
|
50
47
|
bool RatsClient::reject_file_transfer(const std::string& transfer_id, const std::string& reason) {
|
|
@@ -52,26 +49,7 @@ bool RatsClient::reject_file_transfer(const std::string& transfer_id, const std:
|
|
|
52
49
|
LOG_CLIENT_ERROR("File transfer manager not available");
|
|
53
50
|
return false;
|
|
54
51
|
}
|
|
55
|
-
|
|
56
|
-
return file_transfer_manager_->reject_file_transfer(transfer_id, reason);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
bool RatsClient::accept_directory_transfer(const std::string& transfer_id, const std::string& local_path) {
|
|
60
|
-
if (!is_file_transfer_available()) {
|
|
61
|
-
LOG_CLIENT_ERROR("File transfer manager not available");
|
|
62
|
-
return false;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return file_transfer_manager_->accept_directory_transfer(transfer_id, local_path);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
bool RatsClient::reject_directory_transfer(const std::string& transfer_id, const std::string& reason) {
|
|
69
|
-
if (!is_file_transfer_available()) {
|
|
70
|
-
LOG_CLIENT_ERROR("File transfer manager not available");
|
|
71
|
-
return false;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return file_transfer_manager_->reject_directory_transfer(transfer_id, reason);
|
|
52
|
+
return file_transfer_manager_->reject(transfer_id, reason);
|
|
75
53
|
}
|
|
76
54
|
|
|
77
55
|
bool RatsClient::pause_file_transfer(const std::string& transfer_id) {
|
|
@@ -79,8 +57,7 @@ bool RatsClient::pause_file_transfer(const std::string& transfer_id) {
|
|
|
79
57
|
LOG_CLIENT_ERROR("File transfer manager not available");
|
|
80
58
|
return false;
|
|
81
59
|
}
|
|
82
|
-
|
|
83
|
-
return file_transfer_manager_->pause_transfer(transfer_id);
|
|
60
|
+
return file_transfer_manager_->pause(transfer_id);
|
|
84
61
|
}
|
|
85
62
|
|
|
86
63
|
bool RatsClient::resume_file_transfer(const std::string& transfer_id) {
|
|
@@ -88,8 +65,7 @@ bool RatsClient::resume_file_transfer(const std::string& transfer_id) {
|
|
|
88
65
|
LOG_CLIENT_ERROR("File transfer manager not available");
|
|
89
66
|
return false;
|
|
90
67
|
}
|
|
91
|
-
|
|
92
|
-
return file_transfer_manager_->resume_transfer(transfer_id);
|
|
68
|
+
return file_transfer_manager_->resume(transfer_id);
|
|
93
69
|
}
|
|
94
70
|
|
|
95
71
|
bool RatsClient::cancel_file_transfer(const std::string& transfer_id) {
|
|
@@ -97,25 +73,24 @@ bool RatsClient::cancel_file_transfer(const std::string& transfer_id) {
|
|
|
97
73
|
LOG_CLIENT_ERROR("File transfer manager not available");
|
|
98
74
|
return false;
|
|
99
75
|
}
|
|
100
|
-
|
|
101
|
-
return file_transfer_manager_->cancel_transfer(transfer_id);
|
|
76
|
+
return file_transfer_manager_->cancel(transfer_id);
|
|
102
77
|
}
|
|
103
78
|
|
|
104
|
-
std::shared_ptr<FileTransferProgress>
|
|
79
|
+
std::shared_ptr<FileTransferProgress>
|
|
80
|
+
RatsClient::get_file_transfer_progress(const std::string& transfer_id) const {
|
|
105
81
|
if (!is_file_transfer_available()) {
|
|
106
82
|
LOG_CLIENT_ERROR("File transfer manager not available");
|
|
107
83
|
return nullptr;
|
|
108
84
|
}
|
|
109
|
-
|
|
110
|
-
return file_transfer_manager_->get_transfer_progress(transfer_id);
|
|
85
|
+
return file_transfer_manager_->get_progress(transfer_id);
|
|
111
86
|
}
|
|
112
87
|
|
|
113
|
-
std::vector<std::shared_ptr<FileTransferProgress>>
|
|
88
|
+
std::vector<std::shared_ptr<FileTransferProgress>>
|
|
89
|
+
RatsClient::get_active_file_transfers() const {
|
|
114
90
|
if (!is_file_transfer_available()) {
|
|
115
91
|
LOG_CLIENT_ERROR("File transfer manager not available");
|
|
116
92
|
return {};
|
|
117
93
|
}
|
|
118
|
-
|
|
119
94
|
return file_transfer_manager_->get_active_transfers();
|
|
120
95
|
}
|
|
121
96
|
|
|
@@ -124,8 +99,7 @@ nlohmann::json RatsClient::get_file_transfer_statistics() const {
|
|
|
124
99
|
LOG_CLIENT_ERROR("File transfer manager not available");
|
|
125
100
|
return nlohmann::json::object();
|
|
126
101
|
}
|
|
127
|
-
|
|
128
|
-
return file_transfer_manager_->get_transfer_statistics();
|
|
102
|
+
return file_transfer_manager_->get_statistics();
|
|
129
103
|
}
|
|
130
104
|
|
|
131
105
|
void RatsClient::set_file_transfer_config(const FileTransferConfig& config) {
|
|
@@ -133,7 +107,6 @@ void RatsClient::set_file_transfer_config(const FileTransferConfig& config) {
|
|
|
133
107
|
LOG_CLIENT_ERROR("File transfer manager not available");
|
|
134
108
|
return;
|
|
135
109
|
}
|
|
136
|
-
|
|
137
110
|
file_transfer_manager_->set_config(config);
|
|
138
111
|
}
|
|
139
112
|
|
|
@@ -141,82 +114,31 @@ FileTransferConfig RatsClient::get_file_transfer_config() const {
|
|
|
141
114
|
if (!is_file_transfer_available()) {
|
|
142
115
|
throw std::runtime_error("File transfer manager not available");
|
|
143
116
|
}
|
|
144
|
-
|
|
145
117
|
return file_transfer_manager_->get_config();
|
|
146
118
|
}
|
|
147
119
|
|
|
148
|
-
void RatsClient::on_file_transfer_progress(
|
|
149
|
-
if (!is_file_transfer_available()) {
|
|
150
|
-
LOG_CLIENT_ERROR("File transfer manager not available");
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
file_transfer_manager_->set_progress_callback(callback);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
void RatsClient::on_file_transfer_completed(FileTransferCompletedCallback callback) {
|
|
158
|
-
if (!is_file_transfer_available()) {
|
|
159
|
-
LOG_CLIENT_ERROR("File transfer manager not available");
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
file_transfer_manager_->set_completion_callback(callback);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
void RatsClient::on_file_transfer_request(FileTransferRequestCallback callback) {
|
|
120
|
+
void RatsClient::on_file_transfer_progress(TransferProgressCallback callback) {
|
|
167
121
|
if (!is_file_transfer_available()) {
|
|
168
122
|
LOG_CLIENT_ERROR("File transfer manager not available");
|
|
169
123
|
return;
|
|
170
124
|
}
|
|
171
|
-
|
|
172
|
-
file_transfer_manager_->set_request_callback(callback);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
void RatsClient::on_directory_transfer_progress(DirectoryTransferProgressCallback callback) {
|
|
176
|
-
if (!is_file_transfer_available()) {
|
|
177
|
-
LOG_CLIENT_ERROR("File transfer manager not available");
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
file_transfer_manager_->set_directory_progress_callback(callback);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
std::string RatsClient::request_file(const std::string& peer_id, const std::string& remote_file_path,
|
|
185
|
-
const std::string& local_path) {
|
|
186
|
-
if (!is_file_transfer_available()) {
|
|
187
|
-
LOG_CLIENT_ERROR("File transfer manager not available");
|
|
188
|
-
return "";
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
return file_transfer_manager_->request_file(peer_id, remote_file_path, local_path);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
std::string RatsClient::request_directory(const std::string& peer_id, const std::string& remote_directory_path,
|
|
195
|
-
const std::string& local_directory_path, bool recursive) {
|
|
196
|
-
if (!is_file_transfer_available()) {
|
|
197
|
-
LOG_CLIENT_ERROR("File transfer manager not available");
|
|
198
|
-
return "";
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
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));
|
|
202
126
|
}
|
|
203
127
|
|
|
204
|
-
void RatsClient::
|
|
128
|
+
void RatsClient::on_file_transfer_completed(TransferCompletedCallback callback) {
|
|
205
129
|
if (!is_file_transfer_available()) {
|
|
206
130
|
LOG_CLIENT_ERROR("File transfer manager not available");
|
|
207
131
|
return;
|
|
208
132
|
}
|
|
209
|
-
|
|
210
|
-
file_transfer_manager_->set_file_request_callback(callback);
|
|
133
|
+
file_transfer_manager_->set_completed_callback(std::move(callback));
|
|
211
134
|
}
|
|
212
135
|
|
|
213
|
-
void RatsClient::
|
|
136
|
+
void RatsClient::on_file_transfer_request(TransferOfferCallback callback) {
|
|
214
137
|
if (!is_file_transfer_available()) {
|
|
215
138
|
LOG_CLIENT_ERROR("File transfer manager not available");
|
|
216
139
|
return;
|
|
217
140
|
}
|
|
218
|
-
|
|
219
|
-
file_transfer_manager_->set_directory_request_callback(callback);
|
|
141
|
+
file_transfer_manager_->set_offer_callback(std::move(callback));
|
|
220
142
|
}
|
|
221
143
|
|
|
222
|
-
}
|
|
144
|
+
} // namespace librats
|
|
@@ -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
|
|
|
@@ -24,10 +24,18 @@ nlohmann::json RatsClient::get_connection_statistics() const {
|
|
|
24
24
|
stats["our_peer_id"] = get_our_peer_id();
|
|
25
25
|
stats["encryption_enabled"] = is_encryption_enabled();
|
|
26
26
|
|
|
27
|
-
// DHT statistics
|
|
28
|
-
if (
|
|
27
|
+
// DHT statistics (IPv4 + IPv6 combined)
|
|
28
|
+
if (is_dht_running()) {
|
|
29
29
|
stats["dht_running"] = true;
|
|
30
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
|
+
}
|
|
31
39
|
} else {
|
|
32
40
|
stats["dht_running"] = false;
|
|
33
41
|
}
|
|
@@ -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,
|
|
769
|
-
LOG_SOCKET_ERROR("Invalid IPv6 address: " <<
|
|
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
package/scripts/build-librats.js
CHANGED
|
@@ -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...');
|
package/src/librats_node.cpp
CHANGED
|
@@ -24,6 +24,7 @@ std::unordered_map<rats_client_t, std::shared_ptr<CallbackData>> binary_callback
|
|
|
24
24
|
std::unordered_map<rats_client_t, std::shared_ptr<CallbackData>> json_callbacks;
|
|
25
25
|
std::unordered_map<rats_client_t, std::shared_ptr<CallbackData>> disconnect_callbacks;
|
|
26
26
|
std::unordered_map<rats_client_t, std::shared_ptr<CallbackData>> file_progress_callbacks;
|
|
27
|
+
std::unordered_map<rats_client_t, std::shared_ptr<CallbackData>> file_request_callbacks;
|
|
27
28
|
|
|
28
29
|
// C callback wrappers
|
|
29
30
|
void connection_callback_wrapper(void* user_data, const char* peer_id) {
|
|
@@ -95,6 +96,23 @@ void file_progress_callback_wrapper(void* user_data, const char* transfer_id, in
|
|
|
95
96
|
}
|
|
96
97
|
}
|
|
97
98
|
|
|
99
|
+
// Fires for every incoming transfer offer (file or directory). The app should
|
|
100
|
+
// respond by calling acceptFileTransfer()/rejectFileTransfer(). remote_path is
|
|
101
|
+
// always empty in the push-only model, so only filename is forwarded.
|
|
102
|
+
void file_request_callback_wrapper(void* user_data, const char* peer_id, const char* transfer_id, const char* remote_path, const char* filename) {
|
|
103
|
+
(void)remote_path;
|
|
104
|
+
rats_client_t client = static_cast<rats_client_t>(user_data);
|
|
105
|
+
auto it = file_request_callbacks.find(client);
|
|
106
|
+
if (it != file_request_callbacks.end() && it->second) {
|
|
107
|
+
auto callback_data = it->second;
|
|
108
|
+
callback_data->callback.Call({
|
|
109
|
+
Napi::String::New(callback_data->env, peer_id),
|
|
110
|
+
Napi::String::New(callback_data->env, transfer_id),
|
|
111
|
+
Napi::String::New(callback_data->env, filename)
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
98
116
|
class RatsClient : public Napi::ObjectWrap<RatsClient> {
|
|
99
117
|
public:
|
|
100
118
|
static Napi::Object Init(Napi::Env env, Napi::Object exports) {
|
|
@@ -178,8 +196,6 @@ public:
|
|
|
178
196
|
// File Transfer methods
|
|
179
197
|
InstanceMethod("sendFile", &RatsClient::SendFile),
|
|
180
198
|
InstanceMethod("sendDirectory", &RatsClient::SendDirectory),
|
|
181
|
-
InstanceMethod("requestFile", &RatsClient::RequestFile),
|
|
182
|
-
InstanceMethod("requestDirectory", &RatsClient::RequestDirectory),
|
|
183
199
|
InstanceMethod("acceptFileTransfer", &RatsClient::AcceptFileTransfer),
|
|
184
200
|
InstanceMethod("rejectFileTransfer", &RatsClient::RejectFileTransfer),
|
|
185
201
|
InstanceMethod("cancelFileTransfer", &RatsClient::CancelFileTransfer),
|
|
@@ -198,6 +214,7 @@ public:
|
|
|
198
214
|
InstanceMethod("onJson", &RatsClient::OnJson),
|
|
199
215
|
InstanceMethod("onDisconnect", &RatsClient::OnDisconnect),
|
|
200
216
|
InstanceMethod("onFileProgress", &RatsClient::OnFileProgress),
|
|
217
|
+
InstanceMethod("onFileRequest", &RatsClient::OnFileRequest),
|
|
201
218
|
|
|
202
219
|
// Configuration persistence
|
|
203
220
|
InstanceMethod("loadConfiguration", &RatsClient::LoadConfiguration),
|
|
@@ -240,7 +257,8 @@ public:
|
|
|
240
257
|
json_callbacks.erase(client_);
|
|
241
258
|
disconnect_callbacks.erase(client_);
|
|
242
259
|
file_progress_callbacks.erase(client_);
|
|
243
|
-
|
|
260
|
+
file_request_callbacks.erase(client_);
|
|
261
|
+
|
|
244
262
|
rats_destroy(client_);
|
|
245
263
|
}
|
|
246
264
|
}
|
|
@@ -542,9 +560,10 @@ private:
|
|
|
542
560
|
Napi::Value StartMdnsDiscovery(const Napi::CallbackInfo& info) {
|
|
543
561
|
Napi::Env env = info.Env();
|
|
544
562
|
|
|
563
|
+
std::string service;
|
|
545
564
|
const char* service_name = nullptr;
|
|
546
565
|
if (info.Length() > 0 && info[0].IsString()) {
|
|
547
|
-
|
|
566
|
+
service = info[0].As<Napi::String>().Utf8Value();
|
|
548
567
|
service_name = service.c_str();
|
|
549
568
|
}
|
|
550
569
|
|
|
@@ -750,12 +769,13 @@ private:
|
|
|
750
769
|
Napi::Value DiscoverPublicAddress(const Napi::CallbackInfo& info) {
|
|
751
770
|
Napi::Env env = info.Env();
|
|
752
771
|
|
|
772
|
+
std::string server_str;
|
|
753
773
|
const char* server = nullptr;
|
|
754
774
|
uint16_t port = 0;
|
|
755
775
|
int timeout_ms = 5000;
|
|
756
|
-
|
|
776
|
+
|
|
757
777
|
if (info.Length() > 0 && info[0].IsString()) {
|
|
758
|
-
|
|
778
|
+
server_str = info[0].As<Napi::String>().Utf8Value();
|
|
759
779
|
server = server_str.c_str();
|
|
760
780
|
}
|
|
761
781
|
if (info.Length() > 1 && info[1].IsNumber()) {
|
|
@@ -976,12 +996,13 @@ private:
|
|
|
976
996
|
std::string peer_id = info[0].As<Napi::String>().Utf8Value();
|
|
977
997
|
std::string file_path = info[1].As<Napi::String>().Utf8Value();
|
|
978
998
|
|
|
999
|
+
std::string remote_name;
|
|
979
1000
|
const char* remote_filename = nullptr;
|
|
980
1001
|
if (info.Length() > 2 && info[2].IsString()) {
|
|
981
|
-
|
|
1002
|
+
remote_name = info[2].As<Napi::String>().Utf8Value();
|
|
982
1003
|
remote_filename = remote_name.c_str();
|
|
983
1004
|
}
|
|
984
|
-
|
|
1005
|
+
|
|
985
1006
|
char* transfer_id = rats_send_file(client_, peer_id.c_str(), file_path.c_str(), remote_filename);
|
|
986
1007
|
if (!transfer_id) return env.Null();
|
|
987
1008
|
|
|
@@ -1001,63 +1022,15 @@ private:
|
|
|
1001
1022
|
std::string peer_id = info[0].As<Napi::String>().Utf8Value();
|
|
1002
1023
|
std::string directory_path = info[1].As<Napi::String>().Utf8Value();
|
|
1003
1024
|
|
|
1025
|
+
std::string remote_name;
|
|
1004
1026
|
const char* remote_directory_name = nullptr;
|
|
1005
1027
|
if (info.Length() > 2 && info[2].IsString()) {
|
|
1006
|
-
|
|
1028
|
+
remote_name = info[2].As<Napi::String>().Utf8Value();
|
|
1007
1029
|
remote_directory_name = remote_name.c_str();
|
|
1008
1030
|
}
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
recursive = info[3].As<Napi::Boolean>().Value() ? 1 : 0;
|
|
1013
|
-
}
|
|
1014
|
-
|
|
1015
|
-
char* transfer_id = rats_send_directory(client_, peer_id.c_str(), directory_path.c_str(), remote_directory_name, recursive);
|
|
1016
|
-
if (!transfer_id) return env.Null();
|
|
1017
|
-
|
|
1018
|
-
Napi::String result = Napi::String::New(env, transfer_id);
|
|
1019
|
-
rats_string_free(transfer_id);
|
|
1020
|
-
return result;
|
|
1021
|
-
}
|
|
1022
|
-
|
|
1023
|
-
Napi::Value RequestFile(const Napi::CallbackInfo& info) {
|
|
1024
|
-
Napi::Env env = info.Env();
|
|
1025
|
-
|
|
1026
|
-
if (info.Length() < 3 || !info[0].IsString() || !info[1].IsString() || !info[2].IsString()) {
|
|
1027
|
-
Napi::TypeError::New(env, "Expected peer_id (string), remote_file_path (string), and local_path (string)").ThrowAsJavaScriptException();
|
|
1028
|
-
return env.Null();
|
|
1029
|
-
}
|
|
1030
|
-
|
|
1031
|
-
std::string peer_id = info[0].As<Napi::String>().Utf8Value();
|
|
1032
|
-
std::string remote_file_path = info[1].As<Napi::String>().Utf8Value();
|
|
1033
|
-
std::string local_path = info[2].As<Napi::String>().Utf8Value();
|
|
1034
|
-
|
|
1035
|
-
char* transfer_id = rats_request_file(client_, peer_id.c_str(), remote_file_path.c_str(), local_path.c_str());
|
|
1036
|
-
if (!transfer_id) return env.Null();
|
|
1037
|
-
|
|
1038
|
-
Napi::String result = Napi::String::New(env, transfer_id);
|
|
1039
|
-
rats_string_free(transfer_id);
|
|
1040
|
-
return result;
|
|
1041
|
-
}
|
|
1042
|
-
|
|
1043
|
-
Napi::Value RequestDirectory(const Napi::CallbackInfo& info) {
|
|
1044
|
-
Napi::Env env = info.Env();
|
|
1045
|
-
|
|
1046
|
-
if (info.Length() < 3 || !info[0].IsString() || !info[1].IsString() || !info[2].IsString()) {
|
|
1047
|
-
Napi::TypeError::New(env, "Expected peer_id (string), remote_directory_path (string), and local_directory_path (string)").ThrowAsJavaScriptException();
|
|
1048
|
-
return env.Null();
|
|
1049
|
-
}
|
|
1050
|
-
|
|
1051
|
-
std::string peer_id = info[0].As<Napi::String>().Utf8Value();
|
|
1052
|
-
std::string remote_directory_path = info[1].As<Napi::String>().Utf8Value();
|
|
1053
|
-
std::string local_directory_path = info[2].As<Napi::String>().Utf8Value();
|
|
1054
|
-
|
|
1055
|
-
int recursive = 1;
|
|
1056
|
-
if (info.Length() > 3 && info[3].IsBoolean()) {
|
|
1057
|
-
recursive = info[3].As<Napi::Boolean>().Value() ? 1 : 0;
|
|
1058
|
-
}
|
|
1059
|
-
|
|
1060
|
-
char* transfer_id = rats_request_directory(client_, peer_id.c_str(), remote_directory_path.c_str(), local_directory_path.c_str(), recursive);
|
|
1031
|
+
|
|
1032
|
+
// Directory transfers are always recursive; the trailing flag is ignored.
|
|
1033
|
+
char* transfer_id = rats_send_directory(client_, peer_id.c_str(), directory_path.c_str(), remote_directory_name, 1);
|
|
1061
1034
|
if (!transfer_id) return env.Null();
|
|
1062
1035
|
|
|
1063
1036
|
Napi::String result = Napi::String::New(env, transfer_id);
|
|
@@ -1090,12 +1063,13 @@ private:
|
|
|
1090
1063
|
|
|
1091
1064
|
std::string transfer_id = info[0].As<Napi::String>().Utf8Value();
|
|
1092
1065
|
|
|
1066
|
+
std::string reason_str;
|
|
1093
1067
|
const char* reason = nullptr;
|
|
1094
1068
|
if (info.Length() > 1 && info[1].IsString()) {
|
|
1095
|
-
|
|
1069
|
+
reason_str = info[1].As<Napi::String>().Utf8Value();
|
|
1096
1070
|
reason = reason_str.c_str();
|
|
1097
1071
|
}
|
|
1098
|
-
|
|
1072
|
+
|
|
1099
1073
|
rats_error_t result = rats_reject_file_transfer(client_, transfer_id.c_str(), reason);
|
|
1100
1074
|
return Napi::Boolean::New(env, result == RATS_SUCCESS);
|
|
1101
1075
|
}
|
|
@@ -1271,7 +1245,22 @@ private:
|
|
|
1271
1245
|
file_progress_callbacks[client_] = callback_data;
|
|
1272
1246
|
rats_set_file_progress_callback(client_, file_progress_callback_wrapper, client_);
|
|
1273
1247
|
}
|
|
1274
|
-
|
|
1248
|
+
|
|
1249
|
+
void OnFileRequest(const Napi::CallbackInfo& info) {
|
|
1250
|
+
Napi::Env env = info.Env();
|
|
1251
|
+
|
|
1252
|
+
if (info.Length() < 1 || !info[0].IsFunction()) {
|
|
1253
|
+
Napi::TypeError::New(env, "Expected callback function").ThrowAsJavaScriptException();
|
|
1254
|
+
return;
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
auto callback_data = std::make_shared<CallbackData>(env);
|
|
1258
|
+
callback_data->callback = Napi::Persistent(info[0].As<Napi::Function>());
|
|
1259
|
+
|
|
1260
|
+
file_request_callbacks[client_] = callback_data;
|
|
1261
|
+
rats_set_file_request_callback(client_, file_request_callback_wrapper, client_);
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1275
1264
|
// Configuration persistence
|
|
1276
1265
|
Napi::Value LoadConfiguration(const Napi::CallbackInfo& info) {
|
|
1277
1266
|
Napi::Env env = info.Env();
|