librats 0.5.0 → 0.5.2

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 (66) hide show
  1. package/README.md +1 -1
  2. package/binding.gyp +1 -0
  3. package/lib/index.d.ts +2 -1
  4. package/native-src/3rdparty/android/ifaddrs-android.c +600 -0
  5. package/native-src/3rdparty/android/ifaddrs-android.h +54 -0
  6. package/native-src/CMakeLists.txt +360 -0
  7. package/native-src/LICENSE +21 -0
  8. package/native-src/src/bencode.cpp +485 -0
  9. package/native-src/src/bencode.h +145 -0
  10. package/native-src/src/bittorrent.cpp +3682 -0
  11. package/native-src/src/bittorrent.h +731 -0
  12. package/native-src/src/dht.cpp +2460 -0
  13. package/native-src/src/dht.h +508 -0
  14. package/native-src/src/encrypted_socket.cpp +817 -0
  15. package/native-src/src/encrypted_socket.h +239 -0
  16. package/native-src/src/file_transfer.cpp +1808 -0
  17. package/native-src/src/file_transfer.h +567 -0
  18. package/native-src/src/fs.cpp +639 -0
  19. package/native-src/src/fs.h +108 -0
  20. package/native-src/src/gossipsub.cpp +1137 -0
  21. package/native-src/src/gossipsub.h +403 -0
  22. package/native-src/src/ice.cpp +1386 -0
  23. package/native-src/src/ice.h +328 -0
  24. package/native-src/src/json.hpp +25526 -0
  25. package/native-src/src/krpc.cpp +558 -0
  26. package/native-src/src/krpc.h +145 -0
  27. package/native-src/src/librats.cpp +2735 -0
  28. package/native-src/src/librats.h +1732 -0
  29. package/native-src/src/librats_bittorrent.cpp +167 -0
  30. package/native-src/src/librats_c.cpp +1333 -0
  31. package/native-src/src/librats_c.h +239 -0
  32. package/native-src/src/librats_encryption.cpp +123 -0
  33. package/native-src/src/librats_file_transfer.cpp +226 -0
  34. package/native-src/src/librats_gossipsub.cpp +293 -0
  35. package/native-src/src/librats_ice.cpp +515 -0
  36. package/native-src/src/librats_logging.cpp +158 -0
  37. package/native-src/src/librats_mdns.cpp +171 -0
  38. package/native-src/src/librats_nat.cpp +571 -0
  39. package/native-src/src/librats_persistence.cpp +815 -0
  40. package/native-src/src/logger.h +412 -0
  41. package/native-src/src/mdns.cpp +1178 -0
  42. package/native-src/src/mdns.h +253 -0
  43. package/native-src/src/network_utils.cpp +598 -0
  44. package/native-src/src/network_utils.h +162 -0
  45. package/native-src/src/noise.cpp +981 -0
  46. package/native-src/src/noise.h +227 -0
  47. package/native-src/src/os.cpp +371 -0
  48. package/native-src/src/os.h +40 -0
  49. package/native-src/src/rats_export.h +17 -0
  50. package/native-src/src/sha1.cpp +163 -0
  51. package/native-src/src/sha1.h +42 -0
  52. package/native-src/src/socket.cpp +1376 -0
  53. package/native-src/src/socket.h +309 -0
  54. package/native-src/src/stun.cpp +484 -0
  55. package/native-src/src/stun.h +349 -0
  56. package/native-src/src/threadmanager.cpp +105 -0
  57. package/native-src/src/threadmanager.h +53 -0
  58. package/native-src/src/tracker.cpp +1110 -0
  59. package/native-src/src/tracker.h +268 -0
  60. package/native-src/src/version.cpp +24 -0
  61. package/native-src/src/version.h.in +45 -0
  62. package/native-src/version.rc.in +31 -0
  63. package/package.json +2 -8
  64. package/scripts/build-librats.js +59 -12
  65. package/scripts/prepare-package.js +133 -37
  66. package/src/librats_node.cpp +46 -1
@@ -0,0 +1,227 @@
1
+ #pragma once
2
+
3
+ #include <array>
4
+ #include <vector>
5
+ #include <string>
6
+ #include <memory>
7
+ #include <cstdint>
8
+
9
+ namespace librats {
10
+
11
+ // Noise Protocol constants
12
+ constexpr size_t NOISE_KEY_SIZE = 32; // 32 bytes for Curve25519 keys
13
+ constexpr size_t NOISE_HASH_SIZE = 32; // 32 bytes for SHA256
14
+ constexpr size_t NOISE_TAG_SIZE = 16; // 16 bytes for ChaCha20-Poly1305 tag
15
+ constexpr size_t NOISE_MAX_MESSAGE_SIZE = 65535; // Maximum noise message size
16
+
17
+ // Noise key types
18
+ using NoiseKey = std::array<uint8_t, NOISE_KEY_SIZE>;
19
+ using NoiseHash = std::array<uint8_t, NOISE_HASH_SIZE>;
20
+
21
+ /**
22
+ * Noise Protocol handshake state enumeration
23
+ */
24
+ enum class NoiseHandshakeState {
25
+ UNINITIALIZED,
26
+ WRITE_MESSAGE_1, // Initiator sends first message
27
+ READ_MESSAGE_1, // Responder receives first message
28
+ WRITE_MESSAGE_2, // Responder sends second message
29
+ READ_MESSAGE_2, // Initiator receives second message
30
+ WRITE_MESSAGE_3, // Initiator sends third message
31
+ READ_MESSAGE_3, // Responder receives third message
32
+ COMPLETED, // Handshake completed successfully
33
+ FAILED // Handshake failed
34
+ };
35
+
36
+ /**
37
+ * Noise Protocol role enumeration
38
+ */
39
+ enum class NoiseRole {
40
+ INITIATOR, // The peer that initiates the handshake
41
+ RESPONDER // The peer that responds to the handshake
42
+ };
43
+
44
+ /**
45
+ * Cryptographic functions interface for Noise Protocol
46
+ */
47
+ class NoiseCrypto {
48
+ public:
49
+ // ECDH operations using Curve25519
50
+ static NoiseKey generate_keypair(NoiseKey& private_key);
51
+ static NoiseKey dh(const NoiseKey& private_key, const NoiseKey& public_key);
52
+
53
+ // AEAD encryption/decryption using ChaCha20-Poly1305
54
+ static std::vector<uint8_t> encrypt(const NoiseKey& key, uint64_t nonce,
55
+ const std::vector<uint8_t>& plaintext,
56
+ const std::vector<uint8_t>& ad = {});
57
+ static std::vector<uint8_t> decrypt(const NoiseKey& key, uint64_t nonce,
58
+ const std::vector<uint8_t>& ciphertext,
59
+ const std::vector<uint8_t>& ad = {});
60
+
61
+ // Hash functions using SHA256
62
+ static NoiseHash hash(const std::vector<uint8_t>& data);
63
+ static void hkdf(const std::vector<uint8_t>& salt, const std::vector<uint8_t>& ikm,
64
+ const std::vector<uint8_t>& info, uint8_t* okm, size_t okm_len);
65
+
66
+ // Utility functions
67
+ static void secure_memzero(void* ptr, size_t size);
68
+ static void random_bytes(uint8_t* buffer, size_t size);
69
+ };
70
+
71
+ /**
72
+ * Noise Protocol cipher state for managing encryption/decryption
73
+ */
74
+ class NoiseCipherState {
75
+ public:
76
+ NoiseCipherState();
77
+ ~NoiseCipherState();
78
+
79
+ void initialize_key(const NoiseKey& key);
80
+ bool has_key() const { return has_key_; }
81
+
82
+ std::vector<uint8_t> encrypt_with_ad(const std::vector<uint8_t>& plaintext,
83
+ const std::vector<uint8_t>& ad = {});
84
+ std::vector<uint8_t> decrypt_with_ad(const std::vector<uint8_t>& ciphertext,
85
+ const std::vector<uint8_t>& ad = {});
86
+
87
+ void set_nonce(uint64_t nonce) { nonce_ = nonce; }
88
+ uint64_t get_nonce() const { return nonce_; }
89
+
90
+ private:
91
+ NoiseKey key_;
92
+ uint64_t nonce_;
93
+ bool has_key_;
94
+ };
95
+
96
+ /**
97
+ * Noise Protocol symmetric state for managing handshake state
98
+ */
99
+ class NoiseSymmetricState {
100
+ public:
101
+ NoiseSymmetricState();
102
+ ~NoiseSymmetricState();
103
+
104
+ void initialize(const std::string& protocol_name);
105
+ void mix_key(const std::vector<uint8_t>& input_key_material);
106
+ void mix_hash(const std::vector<uint8_t>& data);
107
+ void mix_key_and_hash(const std::vector<uint8_t>& input_key_material);
108
+
109
+ std::vector<uint8_t> encrypt_and_hash(const std::vector<uint8_t>& plaintext);
110
+ std::vector<uint8_t> decrypt_and_hash(const std::vector<uint8_t>& ciphertext);
111
+
112
+ std::pair<NoiseCipherState, NoiseCipherState> split();
113
+
114
+ const NoiseHash& get_handshake_hash() const { return h_; }
115
+
116
+ private:
117
+ NoiseCipherState cipher_state_;
118
+ NoiseKey ck_; // Chaining key
119
+ NoiseHash h_; // Handshake hash
120
+ };
121
+
122
+ /**
123
+ * Noise Protocol handshake state for Noise_XX pattern
124
+ */
125
+ class NoiseHandshake {
126
+ public:
127
+ NoiseHandshake();
128
+ ~NoiseHandshake();
129
+
130
+ // Initialize for either initiator or responder role
131
+ bool initialize(NoiseRole role, const NoiseKey& static_private_key);
132
+
133
+ // Handshake message processing
134
+ std::vector<uint8_t> write_message(const std::vector<uint8_t>& payload = {});
135
+ std::vector<uint8_t> read_message(const std::vector<uint8_t>& message);
136
+
137
+ // State queries
138
+ NoiseHandshakeState get_state() const { return state_; }
139
+ NoiseRole get_role() const { return role_; }
140
+ bool is_completed() const { return state_ == NoiseHandshakeState::COMPLETED; }
141
+ bool has_failed() const { return state_ == NoiseHandshakeState::FAILED; }
142
+
143
+ // Get cipher states after handshake completion
144
+ std::pair<NoiseCipherState, NoiseCipherState> get_cipher_states();
145
+
146
+ // Get remote static public key (available after handshake)
147
+ const NoiseKey& get_remote_static_public_key() const { return rs_; }
148
+
149
+ private:
150
+ NoiseRole role_;
151
+ NoiseHandshakeState state_;
152
+ NoiseSymmetricState symmetric_state_;
153
+
154
+ // Local keys
155
+ NoiseKey s_; // Local static private key
156
+ NoiseKey e_; // Local ephemeral private key
157
+
158
+ // Remote keys
159
+ NoiseKey rs_; // Remote static public key
160
+ NoiseKey re_; // Remote ephemeral public key
161
+
162
+ void advance_state();
163
+ void fail_handshake();
164
+ };
165
+
166
+ /**
167
+ * High-level Noise Protocol session manager
168
+ */
169
+ class NoiseSession {
170
+ public:
171
+ NoiseSession();
172
+ ~NoiseSession();
173
+
174
+ // Initialize session for client (initiator) or server (responder)
175
+ bool initialize_as_initiator(const NoiseKey& static_private_key);
176
+ bool initialize_as_responder(const NoiseKey& static_private_key);
177
+
178
+ // Handshake operations
179
+ bool is_handshake_completed() const;
180
+ bool has_handshake_failed() const;
181
+
182
+ std::vector<uint8_t> create_handshake_message(const std::vector<uint8_t>& payload = {});
183
+ std::vector<uint8_t> process_handshake_message(const std::vector<uint8_t>& message);
184
+
185
+ // Transport operations (available after handshake completion)
186
+ std::vector<uint8_t> encrypt_transport_message(const std::vector<uint8_t>& plaintext);
187
+ std::vector<uint8_t> decrypt_transport_message(const std::vector<uint8_t>& ciphertext);
188
+
189
+ // Utility functions
190
+ NoiseRole get_role() const;
191
+ NoiseHandshakeState get_handshake_state() const;
192
+ const NoiseKey& get_remote_static_public_key() const;
193
+
194
+ private:
195
+ std::unique_ptr<NoiseHandshake> handshake_state_;
196
+ std::unique_ptr<NoiseCipherState> send_cipher_;
197
+ std::unique_ptr<NoiseCipherState> receive_cipher_;
198
+ bool handshake_completed_;
199
+ };
200
+
201
+ /**
202
+ * Utility functions for Noise Protocol
203
+ */
204
+ namespace noise_utils {
205
+ // Key management
206
+ NoiseKey generate_static_keypair();
207
+ std::string key_to_hex(const NoiseKey& key);
208
+ NoiseKey hex_to_key(const std::string& hex);
209
+
210
+ // Protocol utilities
211
+ std::string get_protocol_name();
212
+ bool validate_message_size(size_t size);
213
+
214
+ // Error handling
215
+ enum class NoiseError {
216
+ SUCCESS,
217
+ INVALID_STATE,
218
+ HANDSHAKE_FAILED,
219
+ DECRYPTION_FAILED,
220
+ INVALID_MESSAGE_SIZE,
221
+ CRYPTO_ERROR
222
+ };
223
+
224
+ std::string noise_error_to_string(NoiseError error);
225
+ }
226
+
227
+ } // namespace librats
@@ -0,0 +1,371 @@
1
+ #include "os.h"
2
+ #include "logger.h"
3
+ #include <iostream>
4
+ #include <sstream>
5
+ #include <fstream>
6
+ #include <thread>
7
+ #include <cstdlib>
8
+
9
+ #ifdef _WIN32
10
+ #include <windows.h>
11
+ #include <sysinfoapi.h>
12
+ #include <versionhelpers.h>
13
+ #include <intrin.h>
14
+ #pragma comment(lib, "version.lib")
15
+ #elif __APPLE__
16
+ #include <sys/utsname.h>
17
+ #include <sys/sysctl.h>
18
+ #include <unistd.h>
19
+ #include <mach/mach.h>
20
+ #include <mach/vm_statistics.h>
21
+ #include <mach/mach_types.h>
22
+ #include <mach/mach_init.h>
23
+ #include <mach/mach_host.h>
24
+ #else
25
+ #include <sys/utsname.h>
26
+ #include <sys/sysinfo.h>
27
+ #include <unistd.h>
28
+ #include <fstream>
29
+ #include <regex>
30
+ #endif
31
+
32
+ namespace librats {
33
+
34
+ #ifdef _WIN32
35
+
36
+ std::string get_os_name() {
37
+ return "Windows";
38
+ }
39
+
40
+ std::string get_os_version() {
41
+ std::string version = "Unknown";
42
+
43
+ OSVERSIONINFOEX osvi;
44
+ ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
45
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
46
+
47
+ if (GetVersionEx((OSVERSIONINFO*)&osvi)) {
48
+ std::ostringstream oss;
49
+ oss << osvi.dwMajorVersion << "." << osvi.dwMinorVersion;
50
+ if (osvi.dwBuildNumber > 0) {
51
+ oss << "." << osvi.dwBuildNumber;
52
+ }
53
+ version = oss.str();
54
+ }
55
+
56
+ return version;
57
+ }
58
+
59
+ std::string get_architecture() {
60
+ SYSTEM_INFO si;
61
+ GetSystemInfo(&si);
62
+
63
+ switch (si.wProcessorArchitecture) {
64
+ case PROCESSOR_ARCHITECTURE_AMD64:
65
+ return "x64";
66
+ case PROCESSOR_ARCHITECTURE_INTEL:
67
+ return "x86";
68
+ case PROCESSOR_ARCHITECTURE_ARM:
69
+ return "ARM";
70
+ case PROCESSOR_ARCHITECTURE_ARM64:
71
+ return "ARM64";
72
+ default:
73
+ return "Unknown";
74
+ }
75
+ }
76
+
77
+ std::string get_hostname() {
78
+ char hostname[256];
79
+ DWORD hostname_len = sizeof(hostname);
80
+ if (GetComputerNameA(hostname, &hostname_len)) {
81
+ return std::string(hostname);
82
+ }
83
+ return "Unknown";
84
+ }
85
+
86
+ std::string get_cpu_model() {
87
+ int CPUInfo[4] = {-1};
88
+ unsigned nExIds, i = 0;
89
+ char CPUBrandString[0x40];
90
+
91
+ __cpuid(CPUInfo, 0x80000000);
92
+ nExIds = CPUInfo[0];
93
+
94
+ for (i = 0x80000000; i <= nExIds; ++i) {
95
+ __cpuid(CPUInfo, i);
96
+
97
+ if (i == 0x80000002)
98
+ memcpy(CPUBrandString, CPUInfo, sizeof(CPUInfo));
99
+ else if (i == 0x80000003)
100
+ memcpy(CPUBrandString + 16, CPUInfo, sizeof(CPUInfo));
101
+ else if (i == 0x80000004)
102
+ memcpy(CPUBrandString + 32, CPUInfo, sizeof(CPUInfo));
103
+ }
104
+
105
+ return std::string(CPUBrandString);
106
+ }
107
+
108
+ int get_cpu_cores() {
109
+ SYSTEM_INFO si;
110
+ GetSystemInfo(&si);
111
+ return static_cast<int>(si.dwNumberOfProcessors);
112
+ }
113
+
114
+ int get_cpu_logical_cores() {
115
+ return get_cpu_cores(); // Same as cores on Windows with this method
116
+ }
117
+
118
+ uint64_t get_total_memory_mb() {
119
+ MEMORYSTATUSEX memInfo;
120
+ memInfo.dwLength = sizeof(MEMORYSTATUSEX);
121
+ GlobalMemoryStatusEx(&memInfo);
122
+ return memInfo.ullTotalPhys / (1024 * 1024);
123
+ }
124
+
125
+ uint64_t get_available_memory_mb() {
126
+ MEMORYSTATUSEX memInfo;
127
+ memInfo.dwLength = sizeof(MEMORYSTATUSEX);
128
+ GlobalMemoryStatusEx(&memInfo);
129
+ return memInfo.ullAvailPhys / (1024 * 1024);
130
+ }
131
+
132
+ #elif __APPLE__
133
+
134
+ std::string get_os_name() {
135
+ return "macOS";
136
+ }
137
+
138
+ std::string get_os_version() {
139
+ struct utsname unameData;
140
+ uname(&unameData);
141
+ return std::string(unameData.release);
142
+ }
143
+
144
+ std::string get_architecture() {
145
+ struct utsname unameData;
146
+ uname(&unameData);
147
+ return std::string(unameData.machine);
148
+ }
149
+
150
+ std::string get_hostname() {
151
+ struct utsname unameData;
152
+ uname(&unameData);
153
+ return std::string(unameData.nodename);
154
+ }
155
+
156
+ std::string get_cpu_model() {
157
+ char buffer[256];
158
+ size_t size = sizeof(buffer);
159
+ if (sysctlbyname("machdep.cpu.brand_string", buffer, &size, NULL, 0) == 0) {
160
+ return std::string(buffer);
161
+ }
162
+ return "Unknown";
163
+ }
164
+
165
+ int get_cpu_cores() {
166
+ int cores = 0;
167
+ size_t size = sizeof(cores);
168
+ if (sysctlbyname("hw.physicalcpu", &cores, &size, NULL, 0) == 0) {
169
+ return cores;
170
+ }
171
+ return std::thread::hardware_concurrency();
172
+ }
173
+
174
+ int get_cpu_logical_cores() {
175
+ int cores = 0;
176
+ size_t size = sizeof(cores);
177
+ if (sysctlbyname("hw.logicalcpu", &cores, &size, NULL, 0) == 0) {
178
+ return cores;
179
+ }
180
+ return std::thread::hardware_concurrency();
181
+ }
182
+
183
+ uint64_t get_total_memory_mb() {
184
+ uint64_t memsize = 0;
185
+ size_t size = sizeof(memsize);
186
+ if (sysctlbyname("hw.memsize", &memsize, &size, NULL, 0) == 0) {
187
+ return memsize / (1024 * 1024);
188
+ }
189
+ return 0;
190
+ }
191
+
192
+ uint64_t get_available_memory_mb() {
193
+ vm_size_t page_size;
194
+ mach_port_t mach_port = mach_host_self();
195
+ vm_statistics64_data_t vm_stat;
196
+ mach_msg_type_number_t host_size = sizeof(vm_statistics64_data_t) / sizeof(natural_t);
197
+
198
+ host_page_size(mach_port, &page_size);
199
+ host_statistics64(mach_port, HOST_VM_INFO, (host_info64_t)&vm_stat, &host_size);
200
+
201
+ uint64_t free_memory = (uint64_t)vm_stat.free_count * (uint64_t)page_size;
202
+ return free_memory / (1024 * 1024);
203
+ }
204
+
205
+ #else // Linux
206
+
207
+ std::string get_os_name() {
208
+ std::ifstream file("/etc/os-release");
209
+ std::string line;
210
+ while (std::getline(file, line)) {
211
+ if (line.find("PRETTY_NAME=") == 0) {
212
+ std::string name = line.substr(12);
213
+ // Remove quotes if present
214
+ if (name.front() == '"' && name.back() == '"') {
215
+ name = name.substr(1, name.length() - 2);
216
+ }
217
+ return name;
218
+ }
219
+ }
220
+
221
+ struct utsname unameData;
222
+ uname(&unameData);
223
+ return std::string(unameData.sysname);
224
+ }
225
+
226
+ std::string get_os_version() {
227
+ struct utsname unameData;
228
+ uname(&unameData);
229
+ return std::string(unameData.release);
230
+ }
231
+
232
+ std::string get_architecture() {
233
+ struct utsname unameData;
234
+ uname(&unameData);
235
+ return std::string(unameData.machine);
236
+ }
237
+
238
+ std::string get_hostname() {
239
+ struct utsname unameData;
240
+ uname(&unameData);
241
+ return std::string(unameData.nodename);
242
+ }
243
+
244
+ std::string get_cpu_model() {
245
+ std::ifstream file("/proc/cpuinfo");
246
+ std::string line;
247
+ while (std::getline(file, line)) {
248
+ if (line.find("model name") != std::string::npos) {
249
+ size_t pos = line.find(':');
250
+ if (pos != std::string::npos) {
251
+ std::string model = line.substr(pos + 1);
252
+ // Trim whitespace
253
+ model.erase(0, model.find_first_not_of(" \t"));
254
+ model.erase(model.find_last_not_of(" \t") + 1);
255
+ return model;
256
+ }
257
+ }
258
+ }
259
+ return "Unknown";
260
+ }
261
+
262
+ int get_cpu_cores() {
263
+ std::ifstream file("/proc/cpuinfo");
264
+ std::string line;
265
+ int cores = 0;
266
+
267
+ while (std::getline(file, line)) {
268
+ if (line.find("cpu cores") != std::string::npos) {
269
+ size_t pos = line.find(':');
270
+ if (pos != std::string::npos) {
271
+ cores = std::stoi(line.substr(pos + 1));
272
+ break;
273
+ }
274
+ }
275
+ }
276
+
277
+ if (cores == 0) {
278
+ cores = std::thread::hardware_concurrency();
279
+ }
280
+
281
+ return cores;
282
+ }
283
+
284
+ int get_cpu_logical_cores() {
285
+ return std::thread::hardware_concurrency();
286
+ }
287
+
288
+ uint64_t get_total_memory_mb() {
289
+ std::ifstream file("/proc/meminfo");
290
+ std::string line;
291
+ while (std::getline(file, line)) {
292
+ if (line.find("MemTotal:") == 0) {
293
+ std::regex regex(R"(MemTotal:\s+(\d+)\s+kB)");
294
+ std::smatch match;
295
+ if (std::regex_search(line, match, regex)) {
296
+ return std::stoull(match[1]) / 1024; // Convert kB to MB
297
+ }
298
+ }
299
+ }
300
+ return 0;
301
+ }
302
+
303
+ uint64_t get_available_memory_mb() {
304
+ std::ifstream file("/proc/meminfo");
305
+ std::string line;
306
+ while (std::getline(file, line)) {
307
+ if (line.find("MemAvailable:") == 0) {
308
+ std::regex regex(R"(MemAvailable:\s+(\d+)\s+kB)");
309
+ std::smatch match;
310
+ if (std::regex_search(line, match, regex)) {
311
+ return std::stoull(match[1]) / 1024; // Convert kB to MB
312
+ }
313
+ }
314
+ }
315
+ return 0;
316
+ }
317
+
318
+ #endif
319
+
320
+ SystemInfo get_system_info() {
321
+ SystemInfo info;
322
+ info.os_name = get_os_name();
323
+ info.os_version = get_os_version();
324
+ info.architecture = get_architecture();
325
+ info.hostname = get_hostname();
326
+ info.cpu_model = get_cpu_model();
327
+ info.cpu_cores = get_cpu_cores();
328
+ info.cpu_logical_cores = get_cpu_logical_cores();
329
+ info.total_memory_mb = get_total_memory_mb();
330
+ info.available_memory_mb = get_available_memory_mb();
331
+ return info;
332
+ }
333
+
334
+ void print_system_info() {
335
+ SystemInfo info = get_system_info();
336
+
337
+ std::cout << "=== System Information ===" << std::endl;
338
+ std::cout << "OS: " << info.os_name << " " << info.os_version << std::endl;
339
+ std::cout << "Architecture: " << info.architecture << std::endl;
340
+ std::cout << "Hostname: " << info.hostname << std::endl;
341
+ std::cout << "CPU: " << info.cpu_model << std::endl;
342
+ std::cout << "CPU Cores: " << info.cpu_cores << " physical, " << info.cpu_logical_cores << " logical" << std::endl;
343
+ std::cout << "Memory: " << info.total_memory_mb << " MB total, " << info.available_memory_mb << " MB available" << std::endl;
344
+ std::cout << "=========================" << std::endl;
345
+ }
346
+
347
+ bool supports_unicode() {
348
+ static bool checked = false;
349
+ static bool unicode_supported = false;
350
+
351
+ if (!checked) {
352
+ std::string os = get_os_name();
353
+ // Check if we're on Windows, which often has console encoding issues
354
+ if (os.find("Windows") != std::string::npos) {
355
+ // Try to detect if we're in a proper Unicode-enabled terminal
356
+ // For simplicity, we'll assume Windows console doesn't support Unicode well
357
+ // unless specific environment variables are set
358
+ const char* term = std::getenv("TERM");
359
+ const char* wt = std::getenv("WT_SESSION"); // Windows Terminal
360
+ unicode_supported = (term && std::string(term) != "dumb") || wt;
361
+ } else {
362
+ // On Unix-like systems, assume Unicode is supported
363
+ unicode_supported = true;
364
+ }
365
+ checked = true;
366
+ }
367
+
368
+ return unicode_supported;
369
+ }
370
+
371
+ } // namespace librats
@@ -0,0 +1,40 @@
1
+ #pragma once
2
+
3
+ #include <string>
4
+ #include <cstdint>
5
+
6
+ namespace librats {
7
+
8
+ struct SystemInfo {
9
+ std::string os_name;
10
+ std::string os_version;
11
+ std::string architecture;
12
+ std::string hostname;
13
+ std::string cpu_model;
14
+ int cpu_cores;
15
+ int cpu_logical_cores;
16
+ uint64_t total_memory_mb;
17
+ uint64_t available_memory_mb;
18
+ };
19
+
20
+ // Get comprehensive system information
21
+ SystemInfo get_system_info();
22
+
23
+ // Individual functions for specific info
24
+ std::string get_os_name();
25
+ std::string get_os_version();
26
+ std::string get_architecture();
27
+ std::string get_hostname();
28
+ std::string get_cpu_model();
29
+ int get_cpu_cores();
30
+ int get_cpu_logical_cores();
31
+ uint64_t get_total_memory_mb();
32
+ uint64_t get_available_memory_mb();
33
+
34
+ // Unicode support detection
35
+ bool supports_unicode();
36
+
37
+ // Utility function to print system info
38
+ void print_system_info();
39
+
40
+ } // namespace librats
@@ -0,0 +1,17 @@
1
+ #pragma once
2
+
3
+ #ifdef _WIN32
4
+ #if defined(RATS_EXPORT_DLL)
5
+ #define RATS_API __declspec(dllexport)
6
+ #elif defined(RATS_IMPORT_DLL)
7
+ #define RATS_API __declspec(dllimport)
8
+ #else
9
+ #define RATS_API
10
+ #endif
11
+ #else
12
+ #if __GNUC__ >= 4
13
+ #define RATS_API __attribute__((visibility("default")))
14
+ #else
15
+ #define RATS_API
16
+ #endif
17
+ #endif