react-native-nitro-ark 0.0.94 → 0.0.96

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.
@@ -324,10 +324,10 @@ JNIEXPORT void JNICALL Java_com_margelo_nitro_nitroark_NitroArkNative_tryClaimLi
324
324
  }
325
325
  }
326
326
 
327
- JNIEXPORT jobject JNICALL Java_com_margelo_nitro_nitroark_NitroArkNative_peakKeyPair(JNIEnv* env, jobject /*thiz*/,
327
+ JNIEXPORT jobject JNICALL Java_com_margelo_nitro_nitroark_NitroArkNative_peekKeyPair(JNIEnv* env, jobject /*thiz*/,
328
328
  jint jIndex) {
329
329
  try {
330
- bark_cxx::KeyPairResult keypair = bark_cxx::peak_keypair(static_cast<uint32_t>(jIndex));
330
+ bark_cxx::KeyPairResult keypair = bark_cxx::peek_keypair(static_cast<uint32_t>(jIndex));
331
331
  return MakeKeyPairResult(env, keypair);
332
332
  } catch (const std::exception& e) {
333
333
  HandleException(env, e);
@@ -92,7 +92,7 @@ object NitroArkNative {
92
92
  token: String?
93
93
  )
94
94
  external fun offboardAll(destinationAddress: String): RoundStatusResult
95
- external fun peakKeyPair(index: Int): KeyPairResultAndroid
95
+ external fun peekKeyPair(index: Int): KeyPairResultAndroid
96
96
  external fun verifyMessage(message: String, signature: String, publicKey: String): Boolean
97
97
  external fun bolt11Invoice(amountMsat: Long): Bolt11InvoiceResult
98
98
  external fun signMessage(message: String, index: Int): String
@@ -0,0 +1,179 @@
1
+ #pragma once
2
+
3
+ #include "BarkNotificationEvent.hpp"
4
+ #include "HybridBarkNotificationSubscriptionSpec.hpp"
5
+ #include "generated/ark_cxx.h"
6
+ #include <atomic>
7
+ #include <functional>
8
+ #include <memory>
9
+ #include <mutex>
10
+ #include <stdexcept>
11
+ #include <thread>
12
+ #include <utility>
13
+
14
+ namespace margelo::nitro::nitroark {
15
+
16
+ class BarkNotificationSubscription final : public HybridBarkNotificationSubscriptionSpec {
17
+ public:
18
+ BarkNotificationSubscription(rust::Box<bark_cxx::NotificationSubscription> subscription,
19
+ std::function<void(const BarkNotificationEvent&)>&& onEvent)
20
+ : HybridObject(TAG), subscription_(std::move(subscription)), onEvent_(std::move(onEvent)),
21
+ worker_([this]() { pumpEvents(); }) {}
22
+
23
+ ~BarkNotificationSubscription() override {
24
+ stopInternal(false);
25
+ }
26
+
27
+ void stop() override {
28
+ stopInternal(true);
29
+ }
30
+
31
+ bool isActive() override {
32
+ if (!isActive_.load()) {
33
+ return false;
34
+ }
35
+
36
+ std::lock_guard<std::mutex> lock(subscriptionMutex_);
37
+ return subscription_->is_active();
38
+ }
39
+
40
+ private:
41
+ void stopInternal(bool rethrowErrors) {
42
+ const bool wasActive = isActive_.exchange(false);
43
+
44
+ if (wasActive) {
45
+ try {
46
+ std::lock_guard<std::mutex> lock(subscriptionMutex_);
47
+ subscription_->stop();
48
+ } catch (const std::exception& error) {
49
+ if (rethrowErrors) {
50
+ throw std::runtime_error(error.what());
51
+ }
52
+ }
53
+ }
54
+
55
+ joinWorker();
56
+ }
57
+
58
+ void joinWorker() {
59
+ if (!worker_.joinable()) {
60
+ return;
61
+ }
62
+
63
+ if (worker_.get_id() == std::this_thread::get_id()) {
64
+ worker_.detach();
65
+ return;
66
+ }
67
+
68
+ worker_.join();
69
+ }
70
+
71
+ void pumpEvents() {
72
+ try {
73
+ while (isActive_.load()) {
74
+ bark_cxx::NotificationPollResult result;
75
+ {
76
+ std::lock_guard<std::mutex> lock(subscriptionMutex_);
77
+ result = subscription_->wait_next(250);
78
+ }
79
+
80
+ if (!isActive_.load()) {
81
+ break;
82
+ }
83
+
84
+ if (result.has_event) {
85
+ onEvent_(convertEvent(result.event));
86
+ }
87
+
88
+ if (!result.is_active) {
89
+ isActive_.store(false);
90
+ break;
91
+ }
92
+ }
93
+ } catch (...) {
94
+ isActive_.store(false);
95
+ }
96
+ }
97
+
98
+ static BarkMovementDestination convertDestination(const bark_cxx::BarkMovementDestination& destinationRs) {
99
+ BarkMovementDestination destination;
100
+ destination.destination =
101
+ std::string(destinationRs.destination.data(), destinationRs.destination.length());
102
+ destination.payment_method =
103
+ std::string(destinationRs.payment_method.data(), destinationRs.payment_method.length());
104
+ destination.amount_sat = static_cast<double>(destinationRs.amount_sat);
105
+ return destination;
106
+ }
107
+
108
+ static BarkMovement convertMovement(const bark_cxx::BarkMovement& movementRs) {
109
+ BarkMovement movement;
110
+ movement.id = static_cast<double>(movementRs.id);
111
+ movement.status = std::string(movementRs.status.data(), movementRs.status.length());
112
+ movement.metadata_json = std::string(movementRs.metadata_json.data(), movementRs.metadata_json.length());
113
+ movement.intended_balance_sat = static_cast<double>(movementRs.intended_balance_sat);
114
+ movement.effective_balance_sat = static_cast<double>(movementRs.effective_balance_sat);
115
+ movement.offchain_fee_sat = static_cast<double>(movementRs.offchain_fee_sat);
116
+ movement.created_at = std::string(movementRs.created_at.data(), movementRs.created_at.length());
117
+ movement.updated_at = std::string(movementRs.updated_at.data(), movementRs.updated_at.length());
118
+
119
+ if (movementRs.completed_at.length() == 0) {
120
+ movement.completed_at = std::nullopt;
121
+ } else {
122
+ movement.completed_at = std::string(movementRs.completed_at.data(), movementRs.completed_at.length());
123
+ }
124
+
125
+ movement.subsystem.name =
126
+ std::string(movementRs.subsystem_name.data(), movementRs.subsystem_name.length());
127
+ movement.subsystem.kind =
128
+ std::string(movementRs.subsystem_kind.data(), movementRs.subsystem_kind.length());
129
+
130
+ movement.sent_to.reserve(movementRs.sent_to.size());
131
+ for (const auto& destinationRs : movementRs.sent_to) {
132
+ movement.sent_to.push_back(convertDestination(destinationRs));
133
+ }
134
+
135
+ movement.received_on.reserve(movementRs.received_on.size());
136
+ for (const auto& destinationRs : movementRs.received_on) {
137
+ movement.received_on.push_back(convertDestination(destinationRs));
138
+ }
139
+
140
+ movement.input_vtxos.reserve(movementRs.input_vtxos.size());
141
+ for (const auto& vtxoId : movementRs.input_vtxos) {
142
+ movement.input_vtxos.emplace_back(std::string(vtxoId.data(), vtxoId.length()));
143
+ }
144
+
145
+ movement.output_vtxos.reserve(movementRs.output_vtxos.size());
146
+ for (const auto& vtxoId : movementRs.output_vtxos) {
147
+ movement.output_vtxos.emplace_back(std::string(vtxoId.data(), vtxoId.length()));
148
+ }
149
+
150
+ movement.exited_vtxos.reserve(movementRs.exited_vtxos.size());
151
+ for (const auto& vtxoId : movementRs.exited_vtxos) {
152
+ movement.exited_vtxos.emplace_back(std::string(vtxoId.data(), vtxoId.length()));
153
+ }
154
+
155
+ return movement;
156
+ }
157
+
158
+ static BarkNotificationEvent convertEvent(const bark_cxx::NotificationEvent& eventRs) {
159
+ BarkNotificationEvent event;
160
+ event.kind = std::string(eventRs.kind.data(), eventRs.kind.length());
161
+
162
+ if (eventRs.has_movement) {
163
+ event.movement = convertMovement(eventRs.movement);
164
+ } else {
165
+ event.movement = std::nullopt;
166
+ }
167
+
168
+ return event;
169
+ }
170
+
171
+ private:
172
+ rust::Box<bark_cxx::NotificationSubscription> subscription_;
173
+ std::function<void(const BarkNotificationEvent&)> onEvent_;
174
+ std::thread worker_;
175
+ std::atomic<bool> isActive_{true};
176
+ std::mutex subscriptionMutex_;
177
+ };
178
+
179
+ } // namespace margelo::nitro::nitroark
package/cpp/NitroArk.hpp CHANGED
@@ -1,9 +1,11 @@
1
1
  #pragma once
2
2
 
3
+ #include "BarkNotificationSubscription.hpp"
3
4
  #include "HybridNitroArkSpec.hpp"
4
5
  #include "generated/ark_cxx.h"
5
6
  #include "generated/cxx.h"
6
7
  #include <memory>
8
+ #include <mutex>
7
9
  #include <stdexcept>
8
10
  #include <string>
9
11
  #include <sys/wait.h>
@@ -32,9 +34,92 @@ inline std::vector<BarkVtxo> convertRustVtxosToVector(const rust::Vec<bark_cxx::
32
34
  return vtxos;
33
35
  }
34
36
 
37
+ inline BarkMovementDestination convertRustMovementDestination(const bark_cxx::BarkMovementDestination& destination_rs) {
38
+ BarkMovementDestination destination;
39
+ destination.destination = std::string(destination_rs.destination.data(), destination_rs.destination.length());
40
+ destination.payment_method = std::string(destination_rs.payment_method.data(), destination_rs.payment_method.length());
41
+ destination.amount_sat = static_cast<double>(destination_rs.amount_sat);
42
+ return destination;
43
+ }
44
+
45
+ inline BarkMovement convertRustMovement(const bark_cxx::BarkMovement& movement_rs) {
46
+ BarkMovement movement;
47
+ movement.id = static_cast<double>(movement_rs.id);
48
+ movement.status = std::string(movement_rs.status.data(), movement_rs.status.length());
49
+ movement.metadata_json = std::string(movement_rs.metadata_json.data(), movement_rs.metadata_json.length());
50
+ movement.intended_balance_sat = static_cast<double>(movement_rs.intended_balance_sat);
51
+ movement.effective_balance_sat = static_cast<double>(movement_rs.effective_balance_sat);
52
+ movement.offchain_fee_sat = static_cast<double>(movement_rs.offchain_fee_sat);
53
+ movement.created_at = std::string(movement_rs.created_at.data(), movement_rs.created_at.length());
54
+ movement.updated_at = std::string(movement_rs.updated_at.data(), movement_rs.updated_at.length());
55
+ if (movement_rs.completed_at.length() == 0) {
56
+ movement.completed_at = std::nullopt;
57
+ } else {
58
+ movement.completed_at = std::string(movement_rs.completed_at.data(), movement_rs.completed_at.length());
59
+ }
60
+
61
+ movement.subsystem.name = std::string(movement_rs.subsystem_name.data(), movement_rs.subsystem_name.length());
62
+ movement.subsystem.kind = std::string(movement_rs.subsystem_kind.data(), movement_rs.subsystem_kind.length());
63
+
64
+ movement.sent_to.reserve(movement_rs.sent_to.size());
65
+ for (const auto& destination_rs : movement_rs.sent_to) {
66
+ movement.sent_to.push_back(convertRustMovementDestination(destination_rs));
67
+ }
68
+
69
+ movement.received_on.reserve(movement_rs.received_on.size());
70
+ for (const auto& destination_rs : movement_rs.received_on) {
71
+ movement.received_on.push_back(convertRustMovementDestination(destination_rs));
72
+ }
73
+
74
+ movement.input_vtxos.reserve(movement_rs.input_vtxos.size());
75
+ for (const auto& vtxo_id : movement_rs.input_vtxos) {
76
+ movement.input_vtxos.emplace_back(std::string(vtxo_id.data(), vtxo_id.length()));
77
+ }
78
+
79
+ movement.output_vtxos.reserve(movement_rs.output_vtxos.size());
80
+ for (const auto& vtxo_id : movement_rs.output_vtxos) {
81
+ movement.output_vtxos.emplace_back(std::string(vtxo_id.data(), vtxo_id.length()));
82
+ }
83
+
84
+ movement.exited_vtxos.reserve(movement_rs.exited_vtxos.size());
85
+ for (const auto& vtxo_id : movement_rs.exited_vtxos) {
86
+ movement.exited_vtxos.emplace_back(std::string(vtxo_id.data(), vtxo_id.length()));
87
+ }
88
+
89
+ return movement;
90
+ }
91
+
35
92
  class NitroArk : public HybridNitroArkSpec {
36
93
 
37
94
  private:
95
+ void trackSubscription(const std::shared_ptr<HybridBarkNotificationSubscriptionSpec>& subscription) {
96
+ std::lock_guard<std::mutex> lock(subscriptions_mutex_);
97
+ subscriptions_.push_back(subscription);
98
+ }
99
+
100
+ void stopAllSubscriptions() {
101
+ std::vector<std::shared_ptr<HybridBarkNotificationSubscriptionSpec>> active_subscriptions;
102
+ {
103
+ std::lock_guard<std::mutex> lock(subscriptions_mutex_);
104
+ auto it = subscriptions_.begin();
105
+ while (it != subscriptions_.end()) {
106
+ if (auto subscription = it->lock()) {
107
+ active_subscriptions.push_back(std::move(subscription));
108
+ ++it;
109
+ } else {
110
+ it = subscriptions_.erase(it);
111
+ }
112
+ }
113
+ }
114
+
115
+ for (const auto& subscription : active_subscriptions) {
116
+ try {
117
+ subscription->stop();
118
+ } catch (...) {
119
+ }
120
+ }
121
+ }
122
+
38
123
  // Helper function to create ConfigOpts from BarkConfigOpts
39
124
  static bark_cxx::ConfigOpts createConfigOpts(const std::optional<BarkConfigOpts>& config) {
40
125
  bark_cxx::ConfigOpts config_opts;
@@ -61,6 +146,10 @@ public:
61
146
  bark_cxx::init_logger();
62
147
  }
63
148
 
149
+ ~NitroArk() override {
150
+ stopAllSubscriptions();
151
+ }
152
+
64
153
  // --- Management ---
65
154
 
66
155
  std::shared_ptr<Promise<std::string>> createMnemonic() override {
@@ -127,6 +216,8 @@ public:
127
216
  }
128
217
 
129
218
  std::shared_ptr<Promise<void>> closeWallet() override {
219
+ stopAllSubscriptions();
220
+
130
221
  return Promise<void>::async([]() {
131
222
  try {
132
223
  bark_cxx::close_wallet();
@@ -300,11 +391,11 @@ public:
300
391
  });
301
392
  }
302
393
 
303
- std::shared_ptr<Promise<KeyPairResult>> peakKeyPair(double index) override {
394
+ std::shared_ptr<Promise<KeyPairResult>> peekKeyPair(double index) override {
304
395
  return Promise<KeyPairResult>::async([index]() {
305
396
  try {
306
397
  uint32_t index_val = static_cast<uint32_t>(index);
307
- bark_cxx::KeyPairResult keypair_rs = bark_cxx::peak_keypair(index_val);
398
+ bark_cxx::KeyPairResult keypair_rs = bark_cxx::peek_keypair(index_val);
308
399
  KeyPairResult keypair;
309
400
  keypair.public_key = std::string(keypair_rs.public_key.data(), keypair_rs.public_key.length());
310
401
  keypair.secret_key = std::string(keypair_rs.secret_key.data(), keypair_rs.secret_key.length());
@@ -331,10 +422,10 @@ public:
331
422
  });
332
423
  }
333
424
 
334
- std::shared_ptr<Promise<NewAddressResult>> peakAddress(double index) override {
425
+ std::shared_ptr<Promise<NewAddressResult>> peekAddress(double index) override {
335
426
  return Promise<NewAddressResult>::async([index]() {
336
427
  try {
337
- bark_cxx::NewAddressResult address_rs = bark_cxx::peak_address(static_cast<uint32_t>(index));
428
+ bark_cxx::NewAddressResult address_rs = bark_cxx::peek_address(static_cast<uint32_t>(index));
338
429
  NewAddressResult address;
339
430
  address.user_pubkey = std::string(address_rs.user_pubkey.data(), address_rs.user_pubkey.length());
340
431
  address.ark_id = std::string(address_rs.ark_id.data(), address_rs.ark_id.length());
@@ -429,6 +520,46 @@ public:
429
520
  });
430
521
  }
431
522
 
523
+ std::shared_ptr<HybridBarkNotificationSubscriptionSpec>
524
+ subscribeNotifications(const std::function<void(const BarkNotificationEvent&)>& onEvent) override {
525
+ try {
526
+ auto subscription = std::make_shared<BarkNotificationSubscription>(
527
+ bark_cxx::subscribe_notifications(), std::function<void(const BarkNotificationEvent&)>(onEvent));
528
+ trackSubscription(subscription);
529
+ return subscription;
530
+ } catch (const rust::Error& e) {
531
+ throw std::runtime_error(e.what());
532
+ }
533
+ }
534
+
535
+ std::shared_ptr<HybridBarkNotificationSubscriptionSpec>
536
+ subscribeArkoorAddressMovements(const std::string& address,
537
+ const std::function<void(const BarkNotificationEvent&)>& onEvent) override {
538
+ try {
539
+ auto subscription = std::make_shared<BarkNotificationSubscription>(
540
+ bark_cxx::subscribe_arkoor_address_movements(address),
541
+ std::function<void(const BarkNotificationEvent&)>(onEvent));
542
+ trackSubscription(subscription);
543
+ return subscription;
544
+ } catch (const rust::Error& e) {
545
+ throw std::runtime_error(e.what());
546
+ }
547
+ }
548
+
549
+ std::shared_ptr<HybridBarkNotificationSubscriptionSpec>
550
+ subscribeLightningPaymentMovements(const std::string& paymentHash,
551
+ const std::function<void(const BarkNotificationEvent&)>& onEvent) override {
552
+ try {
553
+ auto subscription = std::make_shared<BarkNotificationSubscription>(
554
+ bark_cxx::subscribe_lightning_payment_movements(paymentHash),
555
+ std::function<void(const BarkNotificationEvent&)>(onEvent));
556
+ trackSubscription(subscription);
557
+ return subscription;
558
+ } catch (const rust::Error& e) {
559
+ throw std::runtime_error(e.what());
560
+ }
561
+ }
562
+
432
563
  std::shared_ptr<Promise<std::vector<BarkMovement>>> history() override {
433
564
  return Promise<std::vector<BarkMovement>>::async([]() {
434
565
  try {
@@ -438,58 +569,7 @@ public:
438
569
  movements.reserve(movements_rs.size());
439
570
 
440
571
  for (const auto& movement_rs : movements_rs) {
441
- BarkMovement movement;
442
- movement.id = static_cast<double>(movement_rs.id);
443
- movement.status = std::string(movement_rs.status.data(), movement_rs.status.length());
444
- movement.metadata_json = std::string(movement_rs.metadata_json.data(), movement_rs.metadata_json.length());
445
- movement.intended_balance_sat = static_cast<double>(movement_rs.intended_balance_sat);
446
- movement.effective_balance_sat = static_cast<double>(movement_rs.effective_balance_sat);
447
- movement.offchain_fee_sat = static_cast<double>(movement_rs.offchain_fee_sat);
448
- movement.created_at = std::string(movement_rs.created_at.data(), movement_rs.created_at.length());
449
- movement.updated_at = std::string(movement_rs.updated_at.data(), movement_rs.updated_at.length());
450
- if (movement_rs.completed_at.length() == 0) {
451
- movement.completed_at = std::nullopt;
452
- } else {
453
- movement.completed_at = std::string(movement_rs.completed_at.data(), movement_rs.completed_at.length());
454
- }
455
-
456
- movement.subsystem.name = std::string(movement_rs.subsystem_name.data(), movement_rs.subsystem_name.length());
457
- movement.subsystem.kind = std::string(movement_rs.subsystem_kind.data(), movement_rs.subsystem_kind.length());
458
-
459
- movement.sent_to.reserve(movement_rs.sent_to.size());
460
- for (const auto& dest_rs : movement_rs.sent_to) {
461
- BarkMovementDestination destination;
462
- destination.destination = std::string(dest_rs.destination.data(), dest_rs.destination.length());
463
- destination.payment_method = std::string(dest_rs.payment_method.data(), dest_rs.payment_method.length());
464
- destination.amount_sat = static_cast<double>(dest_rs.amount_sat);
465
- movement.sent_to.push_back(std::move(destination));
466
- }
467
-
468
- movement.received_on.reserve(movement_rs.received_on.size());
469
- for (const auto& dest_rs : movement_rs.received_on) {
470
- BarkMovementDestination destination;
471
- destination.destination = std::string(dest_rs.destination.data(), dest_rs.destination.length());
472
- destination.payment_method = std::string(dest_rs.payment_method.data(), dest_rs.payment_method.length());
473
- destination.amount_sat = static_cast<double>(dest_rs.amount_sat);
474
- movement.received_on.push_back(std::move(destination));
475
- }
476
-
477
- movement.input_vtxos.reserve(movement_rs.input_vtxos.size());
478
- for (const auto& vtxo_id : movement_rs.input_vtxos) {
479
- movement.input_vtxos.emplace_back(std::string(vtxo_id.data(), vtxo_id.length()));
480
- }
481
-
482
- movement.output_vtxos.reserve(movement_rs.output_vtxos.size());
483
- for (const auto& vtxo_id : movement_rs.output_vtxos) {
484
- movement.output_vtxos.emplace_back(std::string(vtxo_id.data(), vtxo_id.length()));
485
- }
486
-
487
- movement.exited_vtxos.reserve(movement_rs.exited_vtxos.size());
488
- for (const auto& vtxo_id : movement_rs.exited_vtxos) {
489
- movement.exited_vtxos.emplace_back(std::string(vtxo_id.data(), vtxo_id.length()));
490
- }
491
-
492
- movements.push_back(std::move(movement));
572
+ movements.push_back(convertRustMovement(movement_rs));
493
573
  }
494
574
 
495
575
  return movements;
@@ -991,6 +1071,8 @@ public:
991
1071
 
992
1072
  private:
993
1073
  // Tag for logging/debugging within Nitro
1074
+ std::mutex subscriptions_mutex_;
1075
+ std::vector<std::weak_ptr<HybridBarkNotificationSubscriptionSpec>> subscriptions_;
994
1076
  static constexpr auto TAG = "NitroArk";
995
1077
  };
996
1078