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,485 @@
1
+ #include "bencode.h"
2
+ #include <stdexcept>
3
+ #include <sstream>
4
+ #include <algorithm>
5
+ #include <cstdint>
6
+
7
+ namespace librats {
8
+
9
+ // BencodeValue implementation
10
+ BencodeValue::BencodeValue() : type_(Type::String), value_(std::string()) {}
11
+
12
+ BencodeValue::BencodeValue(int64_t value) : type_(Type::Integer), value_(value) {}
13
+
14
+ BencodeValue::BencodeValue(const std::string& value) : type_(Type::String), value_(value) {}
15
+
16
+ BencodeValue::BencodeValue(const char* value) : type_(Type::String), value_(std::string(value)) {}
17
+
18
+ #if LIBRATS_USE_SHARED_PTR_VARIANT
19
+ BencodeValue::BencodeValue(const BencodeList& value) : type_(Type::List), value_(std::make_shared<BencodeList>(value)) {}
20
+ #else
21
+ BencodeValue::BencodeValue(const BencodeList& value) : type_(Type::List), value_(value) {}
22
+ #endif
23
+
24
+ #if LIBRATS_USE_SHARED_PTR_VARIANT
25
+ BencodeValue::BencodeValue(const BencodeDict& value) : type_(Type::Dictionary), value_(std::make_shared<BencodeDict>(value)) {}
26
+ #else
27
+ BencodeValue::BencodeValue(const BencodeDict& value) : type_(Type::Dictionary), value_(value) {}
28
+ #endif
29
+
30
+ BencodeValue::BencodeValue(const BencodeValue& other) : type_(other.type_), value_(other.value_) {}
31
+
32
+ BencodeValue::BencodeValue(BencodeValue&& other) noexcept : type_(other.type_), value_(std::move(other.value_)) {}
33
+
34
+ BencodeValue& BencodeValue::operator=(const BencodeValue& other) {
35
+ if (this != &other) {
36
+ type_ = other.type_;
37
+ value_ = other.value_;
38
+ }
39
+ return *this;
40
+ }
41
+
42
+ BencodeValue& BencodeValue::operator=(BencodeValue&& other) noexcept {
43
+ if (this != &other) {
44
+ type_ = other.type_;
45
+ value_ = std::move(other.value_);
46
+ }
47
+ return *this;
48
+ }
49
+
50
+ BencodeValue::~BencodeValue() = default;
51
+
52
+ int64_t BencodeValue::as_integer() const {
53
+ if (type_ != Type::Integer) {
54
+ throw std::runtime_error("BencodeValue is not an integer");
55
+ }
56
+ return std::get<int64_t>(value_);
57
+ }
58
+
59
+ const std::string& BencodeValue::as_string() const {
60
+ if (type_ != Type::String) {
61
+ throw std::runtime_error("BencodeValue is not a string");
62
+ }
63
+ return std::get<std::string>(value_);
64
+ }
65
+
66
+ const BencodeList& BencodeValue::as_list() const {
67
+ if (type_ != Type::List) {
68
+ throw std::runtime_error("BencodeValue is not a list");
69
+ }
70
+ #if LIBRATS_USE_SHARED_PTR_VARIANT
71
+ return *std::get<std::shared_ptr<BencodeList>>(value_);
72
+ #else
73
+ return std::get<BencodeList>(value_);
74
+ #endif
75
+ }
76
+
77
+ const BencodeDict& BencodeValue::as_dict() const {
78
+ if (type_ != Type::Dictionary) {
79
+ throw std::runtime_error("BencodeValue is not a dictionary");
80
+ }
81
+ #if LIBRATS_USE_SHARED_PTR_VARIANT
82
+ return *std::get<std::shared_ptr<BencodeDict>>(value_);
83
+ #else
84
+ return std::get<BencodeDict>(value_);
85
+ #endif
86
+ }
87
+
88
+ BencodeList& BencodeValue::as_list() {
89
+ if (type_ != Type::List) {
90
+ throw std::runtime_error("BencodeValue is not a list");
91
+ }
92
+ #if LIBRATS_USE_SHARED_PTR_VARIANT
93
+ return *std::get<std::shared_ptr<BencodeList>>(value_);
94
+ #else
95
+ return std::get<BencodeList>(value_);
96
+ #endif
97
+ }
98
+
99
+ BencodeDict& BencodeValue::as_dict() {
100
+ if (type_ != Type::Dictionary) {
101
+ throw std::runtime_error("BencodeValue is not a dictionary");
102
+ }
103
+ #if LIBRATS_USE_SHARED_PTR_VARIANT
104
+ return *std::get<std::shared_ptr<BencodeDict>>(value_);
105
+ #else
106
+ return std::get<BencodeDict>(value_);
107
+ #endif
108
+ }
109
+
110
+ bool BencodeValue::has_key(const std::string& key) const {
111
+ if (type_ != Type::Dictionary) {
112
+ return false;
113
+ }
114
+ #if LIBRATS_USE_SHARED_PTR_VARIANT
115
+ const auto& dict = *std::get<std::shared_ptr<BencodeDict>>(value_);
116
+ #else
117
+ const auto& dict = std::get<BencodeDict>(value_);
118
+ #endif
119
+ return dict.find(key) != dict.end();
120
+ }
121
+
122
+ const BencodeValue& BencodeValue::operator[](const std::string& key) const {
123
+ if (type_ != Type::Dictionary) {
124
+ throw std::runtime_error("BencodeValue is not a dictionary");
125
+ }
126
+ #if LIBRATS_USE_SHARED_PTR_VARIANT
127
+ const auto& dict = *std::get<std::shared_ptr<BencodeDict>>(value_);
128
+ #else
129
+ const auto& dict = std::get<BencodeDict>(value_);
130
+ #endif
131
+ auto it = dict.find(key);
132
+ if (it == dict.end()) {
133
+ throw std::runtime_error("Key not found in dictionary: " + key);
134
+ }
135
+ return it->second;
136
+ }
137
+
138
+ BencodeValue& BencodeValue::operator[](const std::string& key) {
139
+ if (type_ != Type::Dictionary) {
140
+ throw std::runtime_error("BencodeValue is not a dictionary");
141
+ }
142
+ #if LIBRATS_USE_SHARED_PTR_VARIANT
143
+ auto& dict = *std::get<std::shared_ptr<BencodeDict>>(value_);
144
+ #else
145
+ auto& dict = std::get<BencodeDict>(value_);
146
+ #endif
147
+ return dict[key];
148
+ }
149
+
150
+ const BencodeValue& BencodeValue::operator[](size_t index) const {
151
+ if (type_ != Type::List) {
152
+ throw std::runtime_error("BencodeValue is not a list");
153
+ }
154
+ #if LIBRATS_USE_SHARED_PTR_VARIANT
155
+ const auto& list = *std::get<std::shared_ptr<BencodeList>>(value_);
156
+ #else
157
+ const auto& list = std::get<BencodeList>(value_);
158
+ #endif
159
+ if (index >= list.size()) {
160
+ throw std::runtime_error("Index out of bounds");
161
+ }
162
+ return list[index];
163
+ }
164
+
165
+ BencodeValue& BencodeValue::operator[](size_t index) {
166
+ if (type_ != Type::List) {
167
+ throw std::runtime_error("BencodeValue is not a list");
168
+ }
169
+ #if LIBRATS_USE_SHARED_PTR_VARIANT
170
+ auto& list = *std::get<std::shared_ptr<BencodeList>>(value_);
171
+ #else
172
+ auto& list = std::get<BencodeList>(value_);
173
+ #endif
174
+ if (index >= list.size()) {
175
+ throw std::runtime_error("Index out of bounds");
176
+ }
177
+ return list[index];
178
+ }
179
+
180
+ void BencodeValue::push_back(const BencodeValue& value) {
181
+ if (type_ != Type::List) {
182
+ throw std::runtime_error("BencodeValue is not a list");
183
+ }
184
+ #if LIBRATS_USE_SHARED_PTR_VARIANT
185
+ auto& list = *std::get<std::shared_ptr<BencodeList>>(value_);
186
+ #else
187
+ auto& list = std::get<BencodeList>(value_);
188
+ #endif
189
+ list.push_back(value);
190
+ }
191
+
192
+ size_t BencodeValue::size() const {
193
+ switch (type_) {
194
+ case Type::String:
195
+ return std::get<std::string>(value_).size();
196
+ case Type::List:
197
+ #if LIBRATS_USE_SHARED_PTR_VARIANT
198
+ return std::get<std::shared_ptr<BencodeList>>(value_)->size();
199
+ #else
200
+ return std::get<BencodeList>(value_).size();
201
+ #endif
202
+ case Type::Dictionary:
203
+ #if LIBRATS_USE_SHARED_PTR_VARIANT
204
+ return std::get<std::shared_ptr<BencodeDict>>(value_)->size();
205
+ #else
206
+ return std::get<BencodeDict>(value_).size();
207
+ #endif
208
+ default:
209
+ throw std::runtime_error("Size not applicable to this type");
210
+ }
211
+ }
212
+
213
+ std::vector<uint8_t> BencodeValue::encode() const {
214
+ std::vector<uint8_t> buffer;
215
+ encode_to_buffer(buffer);
216
+ return buffer;
217
+ }
218
+
219
+ std::string BencodeValue::encode_string() const {
220
+ auto buffer = encode();
221
+ return std::string(buffer.begin(), buffer.end());
222
+ }
223
+
224
+ void BencodeValue::encode_to_buffer(std::vector<uint8_t>& buffer) const {
225
+ switch (type_) {
226
+ case Type::Integer: {
227
+ std::string str = "i" + std::to_string(std::get<int64_t>(value_)) + "e";
228
+ buffer.insert(buffer.end(), str.begin(), str.end());
229
+ break;
230
+ }
231
+ case Type::String: {
232
+ const auto& str = std::get<std::string>(value_);
233
+ std::string len_str = std::to_string(str.size()) + ":";
234
+ buffer.insert(buffer.end(), len_str.begin(), len_str.end());
235
+ buffer.insert(buffer.end(), str.begin(), str.end());
236
+ break;
237
+ }
238
+ case Type::List: {
239
+ buffer.push_back('l');
240
+ #if LIBRATS_USE_SHARED_PTR_VARIANT
241
+ const auto& list = *std::get<std::shared_ptr<BencodeList>>(value_);
242
+ #else
243
+ const auto& list = std::get<BencodeList>(value_);
244
+ #endif
245
+ for (const auto& item : list) {
246
+ item.encode_to_buffer(buffer);
247
+ }
248
+ buffer.push_back('e');
249
+ break;
250
+ }
251
+ case Type::Dictionary: {
252
+ buffer.push_back('d');
253
+ #if LIBRATS_USE_SHARED_PTR_VARIANT
254
+ const auto& dict = *std::get<std::shared_ptr<BencodeDict>>(value_);
255
+ #else
256
+ const auto& dict = std::get<BencodeDict>(value_);
257
+ #endif
258
+
259
+ // Sort keys for consistent encoding
260
+ std::vector<std::string> keys;
261
+ for (const auto& pair : dict) {
262
+ keys.push_back(pair.first);
263
+ }
264
+ std::sort(keys.begin(), keys.end());
265
+
266
+ for (const auto& key : keys) {
267
+ // Encode key
268
+ std::string len_str = std::to_string(key.size()) + ":";
269
+ buffer.insert(buffer.end(), len_str.begin(), len_str.end());
270
+ buffer.insert(buffer.end(), key.begin(), key.end());
271
+
272
+ // Encode value
273
+ dict.at(key).encode_to_buffer(buffer);
274
+ }
275
+ buffer.push_back('e');
276
+ break;
277
+ }
278
+ }
279
+ }
280
+
281
+ BencodeValue BencodeValue::create_integer(int64_t value) {
282
+ return BencodeValue(value);
283
+ }
284
+
285
+ BencodeValue BencodeValue::create_string(const std::string& value) {
286
+ return BencodeValue(value);
287
+ }
288
+
289
+ BencodeValue BencodeValue::create_list() {
290
+ BencodeValue result;
291
+ result.type_ = Type::List;
292
+ #if LIBRATS_USE_SHARED_PTR_VARIANT
293
+ result.value_ = std::make_shared<BencodeList>();
294
+ #else
295
+ result.value_ = BencodeList();
296
+ #endif
297
+ return result;
298
+ }
299
+
300
+ BencodeValue BencodeValue::create_dict() {
301
+ BencodeValue result;
302
+ result.type_ = Type::Dictionary;
303
+ #if LIBRATS_USE_SHARED_PTR_VARIANT
304
+ result.value_ = std::make_shared<BencodeDict>();
305
+ #else
306
+ result.value_ = BencodeDict();
307
+ #endif
308
+ return result;
309
+ }
310
+
311
+ // BencodeDecoder implementation
312
+ BencodeDecoder::BencodeDecoder(const uint8_t* data, size_t size) : data_(data), size_(size), pos_(0) {}
313
+
314
+ BencodeValue BencodeDecoder::decode(const std::vector<uint8_t>& data) {
315
+ return decode(data.data(), data.size());
316
+ }
317
+
318
+ BencodeValue BencodeDecoder::decode(const std::string& data) {
319
+ return decode(reinterpret_cast<const uint8_t*>(data.data()), data.size());
320
+ }
321
+
322
+ BencodeValue BencodeDecoder::decode(const uint8_t* data, size_t size) {
323
+ BencodeDecoder decoder(data, size);
324
+ return decoder.decode_value();
325
+ }
326
+
327
+ BencodeValue BencodeDecoder::decode_value() {
328
+ if (!has_more()) {
329
+ throw std::runtime_error("Unexpected end of data");
330
+ }
331
+
332
+ uint8_t first_byte = current_byte();
333
+
334
+ if (first_byte == 'i') {
335
+ return decode_integer();
336
+ } else if (first_byte == 'l') {
337
+ return decode_list();
338
+ } else if (first_byte == 'd') {
339
+ return decode_dict();
340
+ } else if (first_byte >= '0' && first_byte <= '9') {
341
+ return decode_string();
342
+ } else {
343
+ throw std::runtime_error("Invalid bencode data");
344
+ }
345
+ }
346
+
347
+ BencodeValue BencodeDecoder::decode_integer() {
348
+ if (consume_byte() != 'i') {
349
+ throw std::runtime_error("Expected 'i' for integer");
350
+ }
351
+
352
+ std::string num_str;
353
+ while (has_more() && current_byte() != 'e') {
354
+ num_str += consume_byte();
355
+ }
356
+
357
+ if (!has_more() || consume_byte() != 'e') {
358
+ throw std::runtime_error("Expected 'e' to end integer");
359
+ }
360
+
361
+ if (num_str.empty()) {
362
+ throw std::runtime_error("Empty integer");
363
+ }
364
+
365
+ try {
366
+ return BencodeValue(std::stoll(num_str));
367
+ } catch (const std::exception&) {
368
+ throw std::runtime_error("Invalid integer: " + num_str);
369
+ }
370
+ }
371
+
372
+ BencodeValue BencodeDecoder::decode_string() {
373
+ std::string len_str;
374
+ while (has_more() && current_byte() != ':') {
375
+ len_str += consume_byte();
376
+ }
377
+
378
+ if (!has_more() || consume_byte() != ':') {
379
+ throw std::runtime_error("Expected ':' in string");
380
+ }
381
+
382
+ if (len_str.empty()) {
383
+ throw std::runtime_error("Empty string length");
384
+ }
385
+
386
+ size_t length;
387
+ try {
388
+ length = std::stoull(len_str);
389
+ } catch (const std::exception&) {
390
+ throw std::runtime_error("Invalid string length: " + len_str);
391
+ }
392
+
393
+ if (pos_ + length > size_) {
394
+ throw std::runtime_error("String length exceeds data size");
395
+ }
396
+
397
+ std::string str = consume_string(length);
398
+ return BencodeValue(str);
399
+ }
400
+
401
+ BencodeValue BencodeDecoder::decode_list() {
402
+ if (consume_byte() != 'l') {
403
+ throw std::runtime_error("Expected 'l' for list");
404
+ }
405
+
406
+ BencodeValue list = BencodeValue::create_list();
407
+
408
+ while (has_more() && current_byte() != 'e') {
409
+ list.push_back(decode_value());
410
+ }
411
+
412
+ if (!has_more() || consume_byte() != 'e') {
413
+ throw std::runtime_error("Expected 'e' to end list");
414
+ }
415
+
416
+ return list;
417
+ }
418
+
419
+ BencodeValue BencodeDecoder::decode_dict() {
420
+ if (consume_byte() != 'd') {
421
+ throw std::runtime_error("Expected 'd' for dictionary");
422
+ }
423
+
424
+ BencodeValue dict = BencodeValue::create_dict();
425
+
426
+ while (has_more() && current_byte() != 'e') {
427
+ // Decode key (must be string)
428
+ BencodeValue key = decode_string();
429
+
430
+ // Decode value
431
+ BencodeValue value = decode_value();
432
+
433
+ dict[key.as_string()] = value;
434
+ }
435
+
436
+ if (!has_more() || consume_byte() != 'e') {
437
+ throw std::runtime_error("Expected 'e' to end dictionary");
438
+ }
439
+
440
+ return dict;
441
+ }
442
+
443
+ uint8_t BencodeDecoder::current_byte() const {
444
+ if (pos_ >= size_) {
445
+ throw std::runtime_error("Unexpected end of data");
446
+ }
447
+ return data_[pos_];
448
+ }
449
+
450
+ uint8_t BencodeDecoder::consume_byte() {
451
+ if (pos_ >= size_) {
452
+ throw std::runtime_error("Unexpected end of data");
453
+ }
454
+ return data_[pos_++];
455
+ }
456
+
457
+ std::string BencodeDecoder::consume_string(size_t length) {
458
+ if (pos_ + length > size_) {
459
+ throw std::runtime_error("String length exceeds data size");
460
+ }
461
+ std::string str(reinterpret_cast<const char*>(data_ + pos_), length);
462
+ pos_ += length;
463
+ return str;
464
+ }
465
+
466
+ // Utility functions
467
+ namespace bencode {
468
+ BencodeValue decode(const std::vector<uint8_t>& data) {
469
+ return BencodeDecoder::decode(data);
470
+ }
471
+
472
+ BencodeValue decode(const std::string& data) {
473
+ return BencodeDecoder::decode(data);
474
+ }
475
+
476
+ std::vector<uint8_t> encode(const BencodeValue& value) {
477
+ return value.encode();
478
+ }
479
+
480
+ std::string encode_string(const BencodeValue& value) {
481
+ return value.encode_string();
482
+ }
483
+ }
484
+
485
+ } // namespace librats
@@ -0,0 +1,145 @@
1
+ #pragma once
2
+
3
+ #include <vector>
4
+ #include <string>
5
+ #include <unordered_map>
6
+ #include <memory>
7
+ #include <variant>
8
+ #include <cstdint>
9
+
10
+ // Use shared_ptr variant for GCC 11 and lower compatibility
11
+ #ifndef LIBRATS_USE_SHARED_PTR_VARIANT
12
+ #if defined(__GNUC__) && (__GNUC__ <= 11)
13
+ #define LIBRATS_USE_SHARED_PTR_VARIANT 1
14
+ #else
15
+ #define LIBRATS_USE_SHARED_PTR_VARIANT 0
16
+ #endif
17
+ #endif
18
+
19
+ namespace librats {
20
+
21
+ // Forward declarations
22
+ class BencodeValue;
23
+ using BencodeDict = std::unordered_map<std::string, BencodeValue>;
24
+ using BencodeList = std::vector<BencodeValue>;
25
+
26
+ /**
27
+ * Represents a bencoded value which can be:
28
+ * - Integer (signed 64-bit)
29
+ * - String (byte string)
30
+ * - List (array of bencoded values)
31
+ * - Dictionary (map of string keys to bencoded values)
32
+ */
33
+ class BencodeValue {
34
+ public:
35
+ enum class Type {
36
+ Integer,
37
+ String,
38
+ List,
39
+ Dictionary
40
+ };
41
+
42
+ // Constructors
43
+ BencodeValue();
44
+ BencodeValue(int64_t value);
45
+ BencodeValue(const std::string& value);
46
+ BencodeValue(const char* value);
47
+ BencodeValue(const BencodeList& value);
48
+ BencodeValue(const BencodeDict& value);
49
+
50
+ // Copy and move constructors
51
+ BencodeValue(const BencodeValue& other);
52
+ BencodeValue(BencodeValue&& other) noexcept;
53
+ BencodeValue& operator=(const BencodeValue& other);
54
+ BencodeValue& operator=(BencodeValue&& other) noexcept;
55
+
56
+ ~BencodeValue();
57
+
58
+ // Type checking
59
+ Type get_type() const { return type_; }
60
+ bool is_integer() const { return type_ == Type::Integer; }
61
+ bool is_string() const { return type_ == Type::String; }
62
+ bool is_list() const { return type_ == Type::List; }
63
+ bool is_dict() const { return type_ == Type::Dictionary; }
64
+
65
+ // Value access
66
+ int64_t as_integer() const;
67
+ const std::string& as_string() const;
68
+ const BencodeList& as_list() const;
69
+ const BencodeDict& as_dict() const;
70
+
71
+ // Mutable access
72
+ BencodeList& as_list();
73
+ BencodeDict& as_dict();
74
+
75
+ // Dictionary operations
76
+ bool has_key(const std::string& key) const;
77
+ const BencodeValue& operator[](const std::string& key) const;
78
+ BencodeValue& operator[](const std::string& key);
79
+
80
+ // List operations
81
+ const BencodeValue& operator[](size_t index) const;
82
+ BencodeValue& operator[](size_t index);
83
+ void push_back(const BencodeValue& value);
84
+ size_t size() const;
85
+
86
+ // Encoding
87
+ std::vector<uint8_t> encode() const;
88
+ std::string encode_string() const;
89
+
90
+ // Static creation methods
91
+ static BencodeValue create_integer(int64_t value);
92
+ static BencodeValue create_string(const std::string& value);
93
+ static BencodeValue create_list();
94
+ static BencodeValue create_dict();
95
+
96
+ private:
97
+ Type type_;
98
+ #if LIBRATS_USE_SHARED_PTR_VARIANT
99
+ std::variant<int64_t, std::string, std::shared_ptr<BencodeList>, std::shared_ptr<BencodeDict>> value_;
100
+ #else
101
+ std::variant<int64_t, std::string, BencodeList, BencodeDict> value_;
102
+ #endif
103
+
104
+ void encode_to_buffer(std::vector<uint8_t>& buffer) const;
105
+ };
106
+
107
+ /**
108
+ * Bencode decoder
109
+ */
110
+ class BencodeDecoder {
111
+ public:
112
+ static BencodeValue decode(const std::vector<uint8_t>& data);
113
+ static BencodeValue decode(const std::string& data);
114
+ static BencodeValue decode(const uint8_t* data, size_t size);
115
+
116
+ private:
117
+ const uint8_t* data_;
118
+ size_t size_;
119
+ size_t pos_;
120
+
121
+ BencodeDecoder(const uint8_t* data, size_t size);
122
+
123
+ BencodeValue decode_value();
124
+ BencodeValue decode_integer();
125
+ BencodeValue decode_string();
126
+ BencodeValue decode_list();
127
+ BencodeValue decode_dict();
128
+
129
+ bool has_more() const { return pos_ < size_; }
130
+ uint8_t current_byte() const;
131
+ uint8_t consume_byte();
132
+ std::string consume_string(size_t length);
133
+ };
134
+
135
+ /**
136
+ * Utility functions
137
+ */
138
+ namespace bencode {
139
+ BencodeValue decode(const std::vector<uint8_t>& data);
140
+ BencodeValue decode(const std::string& data);
141
+ std::vector<uint8_t> encode(const BencodeValue& value);
142
+ std::string encode_string(const BencodeValue& value);
143
+ }
144
+
145
+ } // namespace librats