librats 0.5.0 → 0.5.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.
Files changed (63) hide show
  1. package/binding.gyp +1 -0
  2. package/native-src/3rdparty/android/ifaddrs-android.c +600 -0
  3. package/native-src/3rdparty/android/ifaddrs-android.h +54 -0
  4. package/native-src/CMakeLists.txt +360 -0
  5. package/native-src/LICENSE +21 -0
  6. package/native-src/src/bencode.cpp +485 -0
  7. package/native-src/src/bencode.h +145 -0
  8. package/native-src/src/bittorrent.cpp +3682 -0
  9. package/native-src/src/bittorrent.h +731 -0
  10. package/native-src/src/dht.cpp +2342 -0
  11. package/native-src/src/dht.h +501 -0
  12. package/native-src/src/encrypted_socket.cpp +817 -0
  13. package/native-src/src/encrypted_socket.h +239 -0
  14. package/native-src/src/file_transfer.cpp +1808 -0
  15. package/native-src/src/file_transfer.h +567 -0
  16. package/native-src/src/fs.cpp +639 -0
  17. package/native-src/src/fs.h +108 -0
  18. package/native-src/src/gossipsub.cpp +1137 -0
  19. package/native-src/src/gossipsub.h +403 -0
  20. package/native-src/src/ice.cpp +1386 -0
  21. package/native-src/src/ice.h +328 -0
  22. package/native-src/src/json.hpp +25526 -0
  23. package/native-src/src/krpc.cpp +558 -0
  24. package/native-src/src/krpc.h +145 -0
  25. package/native-src/src/librats.cpp +2715 -0
  26. package/native-src/src/librats.h +1729 -0
  27. package/native-src/src/librats_bittorrent.cpp +167 -0
  28. package/native-src/src/librats_c.cpp +1317 -0
  29. package/native-src/src/librats_c.h +237 -0
  30. package/native-src/src/librats_encryption.cpp +123 -0
  31. package/native-src/src/librats_file_transfer.cpp +226 -0
  32. package/native-src/src/librats_gossipsub.cpp +293 -0
  33. package/native-src/src/librats_ice.cpp +515 -0
  34. package/native-src/src/librats_logging.cpp +158 -0
  35. package/native-src/src/librats_mdns.cpp +171 -0
  36. package/native-src/src/librats_nat.cpp +571 -0
  37. package/native-src/src/librats_persistence.cpp +815 -0
  38. package/native-src/src/logger.h +412 -0
  39. package/native-src/src/mdns.cpp +1178 -0
  40. package/native-src/src/mdns.h +253 -0
  41. package/native-src/src/network_utils.cpp +598 -0
  42. package/native-src/src/network_utils.h +162 -0
  43. package/native-src/src/noise.cpp +981 -0
  44. package/native-src/src/noise.h +227 -0
  45. package/native-src/src/os.cpp +371 -0
  46. package/native-src/src/os.h +40 -0
  47. package/native-src/src/rats_export.h +17 -0
  48. package/native-src/src/sha1.cpp +163 -0
  49. package/native-src/src/sha1.h +42 -0
  50. package/native-src/src/socket.cpp +1376 -0
  51. package/native-src/src/socket.h +309 -0
  52. package/native-src/src/stun.cpp +484 -0
  53. package/native-src/src/stun.h +349 -0
  54. package/native-src/src/threadmanager.cpp +105 -0
  55. package/native-src/src/threadmanager.h +53 -0
  56. package/native-src/src/tracker.cpp +1110 -0
  57. package/native-src/src/tracker.h +268 -0
  58. package/native-src/src/version.cpp +24 -0
  59. package/native-src/src/version.h.in +45 -0
  60. package/native-src/version.rc.in +31 -0
  61. package/package.json +2 -8
  62. package/scripts/build-librats.js +59 -12
  63. package/scripts/prepare-package.js +133 -37
@@ -0,0 +1,639 @@
1
+ #include "fs.h"
2
+ #include "logger.h"
3
+ #include <cstring>
4
+ #include <cstdlib>
5
+ #include <sys/stat.h>
6
+
7
+ #ifdef _WIN32
8
+ #include <windows.h>
9
+ #include <direct.h>
10
+ #include <io.h>
11
+ #define stat _stat
12
+ #define mkdir(path, mode) _mkdir(path)
13
+ #define access _access
14
+ #define F_OK 0
15
+ #define getcwd _getcwd
16
+ #define chdir _chdir
17
+ #else
18
+ #include <unistd.h>
19
+ #include <dirent.h>
20
+ #include <errno.h>
21
+ #include <libgen.h>
22
+ #endif
23
+
24
+ namespace librats {
25
+
26
+ bool file_or_directory_exists(const char* path) {
27
+ if (!path) return false;
28
+ return access(path, F_OK) == 0;
29
+ }
30
+
31
+ bool file_exists(const char* path) {
32
+ if (!path) return false;
33
+
34
+ struct stat st;
35
+ if (stat(path, &st) == 0) {
36
+ return (st.st_mode & S_IFREG) != 0;
37
+ }
38
+ return false;
39
+ }
40
+
41
+ bool directory_exists(const char* path) {
42
+ if (!path) return false;
43
+
44
+ struct stat st;
45
+ if (stat(path, &st) == 0) {
46
+ return (st.st_mode & S_IFDIR) != 0;
47
+ }
48
+ return false;
49
+ }
50
+
51
+ bool create_file(const char* path, const char* content) {
52
+ if (!path) return false;
53
+
54
+ FILE* file = fopen(path, "wb");
55
+ if (!file) {
56
+ LOG_ERROR("FS", "Failed to create file: " << path);
57
+ return false;
58
+ }
59
+
60
+ if (content) {
61
+ size_t len = strlen(content);
62
+ size_t written = fwrite(content, 1, len, file);
63
+ fclose(file);
64
+
65
+ if (written != len) {
66
+ LOG_ERROR("FS", "Failed to write complete content to file: " << path);
67
+ return false;
68
+ }
69
+ } else {
70
+ fclose(file);
71
+ }
72
+
73
+ return true;
74
+ }
75
+
76
+ bool create_file_binary(const char* path, const void* data, size_t size) {
77
+ if (!path) return false;
78
+
79
+ FILE* file = fopen(path, "wb");
80
+ if (!file) {
81
+ LOG_ERROR("FS", "Failed to create binary file: " << path);
82
+ return false;
83
+ }
84
+
85
+ if (data && size > 0) {
86
+ size_t written = fwrite(data, 1, size, file);
87
+ fclose(file);
88
+
89
+ if (written != size) {
90
+ LOG_ERROR("FS", "Failed to write complete binary data to file: " << path);
91
+ return false;
92
+ }
93
+ } else {
94
+ fclose(file);
95
+ }
96
+
97
+ return true;
98
+ }
99
+
100
+ bool append_to_file(const char* path, const char* content) {
101
+ if (!path || !content) return false;
102
+
103
+ FILE* file = fopen(path, "ab");
104
+ if (!file) {
105
+ LOG_ERROR("FS", "Failed to open file for appending: " << path);
106
+ return false;
107
+ }
108
+
109
+ size_t len = strlen(content);
110
+ size_t written = fwrite(content, 1, len, file);
111
+ fclose(file);
112
+
113
+ if (written != len) {
114
+ LOG_ERROR("FS", "Failed to append complete content to file: " << path);
115
+ return false;
116
+ }
117
+
118
+ return true;
119
+ }
120
+
121
+ char* read_file_text(const char* path, size_t* size_out) {
122
+ if (!path) return nullptr;
123
+
124
+ struct stat st;
125
+ if (stat(path, &st) != 0) {
126
+ LOG_ERROR("FS", "Failed to stat file: " << path);
127
+ return nullptr;
128
+ }
129
+
130
+ size_t file_size = st.st_size;
131
+
132
+ FILE* file = fopen(path, "rb");
133
+ if (!file) {
134
+ LOG_ERROR("FS", "Failed to open file for reading: " << path);
135
+ return nullptr;
136
+ }
137
+
138
+ // Allocate buffer (+1 for null terminator)
139
+ char* buffer = static_cast<char*>(malloc(file_size + 1));
140
+ if (!buffer) {
141
+ LOG_ERROR("FS", "Failed to allocate memory for file: " << path);
142
+ fclose(file);
143
+ return nullptr;
144
+ }
145
+
146
+ // Read file
147
+ size_t bytes_read = fread(buffer, 1, file_size, file);
148
+ fclose(file);
149
+
150
+ // Null terminate
151
+ buffer[bytes_read] = '\0';
152
+
153
+ if (size_out) {
154
+ *size_out = bytes_read;
155
+ }
156
+
157
+ return buffer;
158
+ }
159
+
160
+ void* read_file_binary(const char* path, size_t* size_out) {
161
+ if (!path || !size_out) return nullptr;
162
+
163
+ FILE* file = fopen(path, "rb");
164
+ if (!file) {
165
+ LOG_ERROR("FS", "Failed to open binary file for reading: " << path);
166
+ return nullptr;
167
+ }
168
+
169
+ // Get file size
170
+ fseek(file, 0, SEEK_END);
171
+ long file_size = ftell(file);
172
+ fseek(file, 0, SEEK_SET);
173
+
174
+ if (file_size < 0) {
175
+ LOG_ERROR("FS", "Failed to get binary file size: " << path);
176
+ fclose(file);
177
+ return nullptr;
178
+ }
179
+
180
+ // Allocate buffer
181
+ void* buffer = malloc(file_size);
182
+ if (!buffer) {
183
+ LOG_ERROR("FS", "Failed to allocate memory for binary file: " << path);
184
+ fclose(file);
185
+ return nullptr;
186
+ }
187
+
188
+ // Read file
189
+ size_t bytes_read = fread(buffer, 1, file_size, file);
190
+ fclose(file);
191
+
192
+ *size_out = bytes_read;
193
+ return buffer;
194
+ }
195
+
196
+ bool create_directory(const char* path) {
197
+ if (!path) return false;
198
+
199
+ if (directory_exists(path)) {
200
+ return true; // Already exists
201
+ }
202
+
203
+ #ifdef _WIN32
204
+ return _mkdir(path) == 0;
205
+ #else
206
+ return mkdir(path, 0755) == 0;
207
+ #endif
208
+ }
209
+
210
+ bool create_directories(const char* path) {
211
+ if (!path) return false;
212
+
213
+ if (directory_exists(path)) {
214
+ return true; // Already exists
215
+ }
216
+
217
+ // Create a copy of the path to modify
218
+ size_t len = strlen(path);
219
+ char* path_copy = static_cast<char*>(malloc(len + 1));
220
+ if (!path_copy) {
221
+ LOG_ERROR("FS", "Failed to allocate memory for path copy in create_directories");
222
+ return false;
223
+ }
224
+
225
+ memcpy(path_copy, path, len + 1);
226
+
227
+ // Create parent directories recursively
228
+ for (size_t i = 1; i < len; i++) {
229
+ if (path_copy[i] == '/' || path_copy[i] == '\\') {
230
+ path_copy[i] = '\0';
231
+
232
+ if (!directory_exists(path_copy)) {
233
+ if (!create_directory(path_copy)) {
234
+ free(path_copy);
235
+ return false;
236
+ }
237
+ }
238
+
239
+ path_copy[i] = '/'; // Normalize to forward slash
240
+ }
241
+ }
242
+
243
+ // Create the final directory
244
+ bool result = create_directory(path_copy);
245
+ free(path_copy);
246
+ return result;
247
+ }
248
+
249
+ int64_t get_file_size(const char* path) {
250
+ if (!path) return -1;
251
+
252
+ struct stat st;
253
+ if (stat(path, &st) == 0) {
254
+ return st.st_size;
255
+ }
256
+ return -1;
257
+ }
258
+
259
+ bool is_file(const char* path) {
260
+ return file_exists(path);
261
+ }
262
+
263
+ bool is_directory(const char* path) {
264
+ return directory_exists(path);
265
+ }
266
+
267
+ bool delete_file(const char* path) {
268
+ if (!path) return false;
269
+
270
+ return remove(path) == 0;
271
+ }
272
+
273
+ bool delete_directory(const char* path) {
274
+ if (!path) return false;
275
+
276
+ #ifdef _WIN32
277
+ return RemoveDirectoryA(path) != 0;
278
+ #else
279
+ return rmdir(path) == 0;
280
+ #endif
281
+ }
282
+
283
+ bool copy_file(const char* src_path, const char* dest_path) {
284
+ if (!src_path || !dest_path) return false;
285
+
286
+ FILE* src_file = fopen(src_path, "rb");
287
+ if (!src_file) {
288
+ LOG_ERROR("FS", "Failed to open source file for copying: " << src_path);
289
+ return false;
290
+ }
291
+
292
+ FILE* dest_file = fopen(dest_path, "wb");
293
+ if (!dest_file) {
294
+ LOG_ERROR("FS", "Failed to open destination file for copying: " << dest_path);
295
+ fclose(src_file);
296
+ return false;
297
+ }
298
+
299
+ char buffer[4096];
300
+ size_t bytes_read;
301
+ bool success = true;
302
+
303
+ while ((bytes_read = fread(buffer, 1, sizeof(buffer), src_file)) > 0) {
304
+ if (fwrite(buffer, 1, bytes_read, dest_file) != bytes_read) {
305
+ LOG_ERROR("FS", "Failed to write to destination file: " << dest_path);
306
+ success = false;
307
+ break;
308
+ }
309
+ }
310
+
311
+ if (ferror(src_file)) {
312
+ LOG_ERROR("FS", "Error reading from source file: " << src_path);
313
+ success = false;
314
+ }
315
+
316
+ fclose(src_file);
317
+ fclose(dest_file);
318
+
319
+ if (!success) {
320
+ delete_file(dest_path);
321
+ }
322
+
323
+ return success;
324
+ }
325
+
326
+ bool move_file(const char* src_path, const char* dest_path) {
327
+ if (!src_path || !dest_path) return false;
328
+
329
+ if (rename(src_path, dest_path) == 0) {
330
+ return true;
331
+ }
332
+
333
+ // If rename fails, try copy and delete
334
+ if (copy_file(src_path, dest_path)) {
335
+ return delete_file(src_path);
336
+ }
337
+
338
+ return false;
339
+ }
340
+
341
+ void free_file_buffer(void* buffer) {
342
+ if (buffer) {
343
+ free(buffer);
344
+ }
345
+ }
346
+
347
+ bool get_current_directory(char* buffer, size_t buffer_size) {
348
+ if (!buffer || buffer_size == 0) return false;
349
+
350
+ return getcwd(buffer, buffer_size) != nullptr;
351
+ }
352
+
353
+ bool set_current_directory(const char* path) {
354
+ if (!path) return false;
355
+
356
+ return chdir(path) == 0;
357
+ }
358
+
359
+ // File metadata operations
360
+ uint64_t get_file_modified_time(const char* path) {
361
+ if (!path) return 0;
362
+
363
+ struct stat st;
364
+ if (stat(path, &st) == 0) {
365
+ return static_cast<uint64_t>(st.st_mtime);
366
+ }
367
+ return 0;
368
+ }
369
+
370
+ std::string get_file_extension(const char* path) {
371
+ if (!path) return "";
372
+
373
+ const char* dot = strrchr(path, '.');
374
+ if (dot && dot != path) {
375
+ return std::string(dot);
376
+ }
377
+ return "";
378
+ }
379
+
380
+ std::string get_filename_from_path(const char* path) {
381
+ if (!path) return "";
382
+
383
+ const char* filename = strrchr(path, '/');
384
+ if (!filename) {
385
+ filename = strrchr(path, '\\');
386
+ }
387
+
388
+ if (filename) {
389
+ return std::string(filename + 1);
390
+ } else {
391
+ return std::string(path);
392
+ }
393
+ }
394
+
395
+ std::string get_parent_directory(const char* path) {
396
+ if (!path) return "";
397
+
398
+ std::string str_path(path);
399
+ size_t pos = str_path.find_last_of("/\\");
400
+ if (pos != std::string::npos) {
401
+ return str_path.substr(0, pos);
402
+ }
403
+ return "";
404
+ }
405
+
406
+ // File chunk operations
407
+ bool write_file_chunk(const char* path, uint64_t offset, const void* data, size_t size) {
408
+ if (!path || !data) return false;
409
+
410
+ FILE* file = fopen(path, "r+b");
411
+ if (!file) {
412
+ // Try to create the file if it doesn't exist
413
+ file = fopen(path, "w+b");
414
+ if (!file) {
415
+ LOG_ERROR("FS", "Failed to open file for chunk writing: " << path);
416
+ return false;
417
+ }
418
+ }
419
+
420
+ // Use platform-specific 64-bit seek
421
+ #ifdef _WIN32
422
+ if (_fseeki64(file, static_cast<__int64>(offset), SEEK_SET) != 0) {
423
+ #else
424
+ if (fseeko(file, static_cast<off_t>(offset), SEEK_SET) != 0) {
425
+ #endif
426
+ LOG_ERROR("FS", "Failed to seek to offset " << offset << " in file: " << path);
427
+ fclose(file);
428
+ return false;
429
+ }
430
+
431
+ size_t written = fwrite(data, 1, size, file);
432
+ fclose(file);
433
+
434
+ if (written != size) {
435
+ LOG_ERROR("FS", "Failed to write complete chunk to file: " << path);
436
+ return false;
437
+ }
438
+
439
+ return true;
440
+ }
441
+
442
+ bool read_file_chunk(const char* path, uint64_t offset, void* buffer, size_t size) {
443
+ if (!path || !buffer) return false;
444
+
445
+ FILE* file = fopen(path, "rb");
446
+ if (!file) {
447
+ LOG_ERROR("FS", "Failed to open file for chunk reading: " << path);
448
+ return false;
449
+ }
450
+
451
+ // Use platform-specific 64-bit seek
452
+ #ifdef _WIN32
453
+ if (_fseeki64(file, static_cast<__int64>(offset), SEEK_SET) != 0) {
454
+ #else
455
+ if (fseeko(file, static_cast<off_t>(offset), SEEK_SET) != 0) {
456
+ #endif
457
+ LOG_ERROR("FS", "Failed to seek to offset " << offset << " in file: " << path);
458
+ fclose(file);
459
+ return false;
460
+ }
461
+
462
+ size_t bytes_read = fread(buffer, 1, size, file);
463
+ fclose(file);
464
+
465
+ if (bytes_read != size) {
466
+ LOG_ERROR("FS", "Failed to read complete chunk from file: " << path);
467
+ return false;
468
+ }
469
+
470
+ return true;
471
+ }
472
+
473
+ // Advanced file operations
474
+ bool create_file_with_size(const char* path, uint64_t size) {
475
+ if (!path) return false;
476
+
477
+ FILE* file = fopen(path, "wb");
478
+ if (!file) {
479
+ LOG_ERROR("FS", "Failed to create file with size: " << path);
480
+ return false;
481
+ }
482
+
483
+ if (size > 0) {
484
+ // Pre-allocate file space by seeking to size-1 and writing a byte
485
+ // Use platform-specific 64-bit seek
486
+ #ifdef _WIN32
487
+ if (_fseeki64(file, static_cast<__int64>(size - 1), SEEK_SET) == 0) {
488
+ #else
489
+ if (fseeko(file, static_cast<off_t>(size - 1), SEEK_SET) == 0) {
490
+ #endif
491
+ fputc(0, file);
492
+ }
493
+ }
494
+
495
+ fclose(file);
496
+ return true;
497
+ }
498
+
499
+ bool rename_file(const char* old_path, const char* new_path) {
500
+ if (!old_path || !new_path) return false;
501
+
502
+ return rename(old_path, new_path) == 0;
503
+ }
504
+
505
+ // Path utilities
506
+ std::string combine_paths(const std::string& base, const std::string& relative) {
507
+ if (base.empty()) return relative;
508
+ if (relative.empty()) return base;
509
+
510
+ std::string result = base;
511
+
512
+ // Normalize all backslashes to forward slashes in result
513
+ for (char& c : result) {
514
+ if (c == '\\') c = '/';
515
+ }
516
+
517
+ // Ensure base path ends with separator
518
+ if (result.back() != '/') {
519
+ result += '/';
520
+ }
521
+
522
+ // Remove leading separator from relative path and normalize
523
+ std::string rel = relative;
524
+ if (!rel.empty() && (rel.front() == '/' || rel.front() == '\\')) {
525
+ rel = rel.substr(1);
526
+ }
527
+
528
+ // Normalize backslashes to forward slashes in relative path
529
+ for (char& c : rel) {
530
+ if (c == '\\') c = '/';
531
+ }
532
+
533
+ return result + rel;
534
+ }
535
+
536
+ bool validate_path(const char* path, bool check_write_access) {
537
+ if (!path) return false;
538
+
539
+ if (check_write_access) {
540
+ // Check if we can write to the parent directory
541
+ std::string parent = get_parent_directory(path);
542
+ if (!parent.empty() && !directory_exists(parent.c_str())) {
543
+ return false;
544
+ }
545
+ // Additional write permission checks could be added here
546
+ } else {
547
+ // Check if path exists and is a regular file (not a directory)
548
+ if (!is_file(path)) {
549
+ return false;
550
+ }
551
+ }
552
+
553
+ return true;
554
+ }
555
+
556
+ // Directory listing
557
+ bool list_directory(const char* path, std::vector<DirectoryEntry>& entries) {
558
+ if (!path || !directory_exists(path)) return false;
559
+
560
+ entries.clear();
561
+
562
+ #ifdef _WIN32
563
+ WIN32_FIND_DATAA find_data;
564
+ std::string search_path = std::string(path) + "\\*";
565
+ HANDLE find_handle = FindFirstFileA(search_path.c_str(), &find_data);
566
+
567
+ if (find_handle == INVALID_HANDLE_VALUE) {
568
+ return false;
569
+ }
570
+
571
+ do {
572
+ // Skip "." and ".." entries
573
+ if (strcmp(find_data.cFileName, ".") == 0 || strcmp(find_data.cFileName, "..") == 0) {
574
+ continue;
575
+ }
576
+
577
+ DirectoryEntry entry;
578
+ entry.name = find_data.cFileName;
579
+ entry.path = combine_paths(path, entry.name);
580
+ entry.is_directory = (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
581
+
582
+ if (!entry.is_directory) {
583
+ entry.size = (static_cast<uint64_t>(find_data.nFileSizeHigh) << 32) | find_data.nFileSizeLow;
584
+ } else {
585
+ entry.size = 0;
586
+ }
587
+
588
+ // Convert Windows FILETIME to Unix timestamp
589
+ FILETIME ft = find_data.ftLastWriteTime;
590
+ LARGE_INTEGER li;
591
+ li.LowPart = ft.dwLowDateTime;
592
+ li.HighPart = ft.dwHighDateTime;
593
+ // Convert from 100ns intervals since 1601 to seconds since 1970
594
+ entry.modified_time = (li.QuadPart - 116444736000000000LL) / 10000000LL;
595
+
596
+ entries.push_back(entry);
597
+
598
+ } while (FindNextFileA(find_handle, &find_data));
599
+
600
+ FindClose(find_handle);
601
+
602
+ #else
603
+ DIR* dir = opendir(path);
604
+ if (!dir) {
605
+ return false;
606
+ }
607
+
608
+ struct dirent* entry_ptr;
609
+ while ((entry_ptr = readdir(dir)) != nullptr) {
610
+ // Skip "." and ".." entries
611
+ if (strcmp(entry_ptr->d_name, ".") == 0 || strcmp(entry_ptr->d_name, "..") == 0) {
612
+ continue;
613
+ }
614
+
615
+ DirectoryEntry entry;
616
+ entry.name = entry_ptr->d_name;
617
+ entry.path = combine_paths(path, entry.name);
618
+
619
+ struct stat st;
620
+ if (stat(entry.path.c_str(), &st) == 0) {
621
+ entry.is_directory = S_ISDIR(st.st_mode);
622
+ entry.size = entry.is_directory ? 0 : static_cast<uint64_t>(st.st_size);
623
+ entry.modified_time = static_cast<uint64_t>(st.st_mtime);
624
+ } else {
625
+ entry.is_directory = false;
626
+ entry.size = 0;
627
+ entry.modified_time = 0;
628
+ }
629
+
630
+ entries.push_back(entry);
631
+ }
632
+
633
+ closedir(dir);
634
+ #endif
635
+
636
+ return true;
637
+ }
638
+
639
+ } // namespace librats