fix(LNC): route register callbacks through events to avoid new-arch crash

This commit is contained in:
Evan Kaloudis
2026-07-27 10:54:33 -04:00
parent e36862e3f9
commit 4f36cad55c
11 changed files with 179 additions and 35 deletions
+25 -2
View File
@@ -2,15 +2,38 @@
#import "Callback.h"
#import <React/RCTEventEmitter.h>
#import <Foundation/Foundation.h>
#include <atomic>
@implementation Callback
@implementation Callback {
std::atomic<bool> _consumed;
}
-(instancetype)init {
if ((self = [super init])) {
_consumed.store(false, std::memory_order_relaxed);
}
return self;
}
-(void)setCallback:(RCTResponseSenderBlock)callback {
self.rnCallback = callback;
}
-(void)sendResult:(NSString *)data {
self.rnCallback(@[data]);
// Under React Native's new architecture, RCTResponseSenderBlock can only be
// invoked once. The Go LNC bridge may legitimately fire callbacks more than
// once for some routes (potentially from different threads); the atomic
// compare-exchange drops subsequent invocations safely to avoid a fatal abort.
bool expected = false;
if (!_consumed.compare_exchange_strong(expected, true)) {
return;
}
RCTResponseSenderBlock cb = self.rnCallback;
if (cb == nil) {
return;
}
// Defend against a nil data argument — @[nil] would throw NSInvalidArgumentException.
cb(@[data ?: @""]);
}
@end
+15 -9
View File
@@ -21,10 +21,11 @@ RCT_EXPORT_METHOD(initLNC:(NSString *)nameSpace)
}
RCT_EXPORT_METHOD(registerLocalPrivCreateCallback:(NSString *)nameSpace
resolver:(RCTResponseSenderBlock)onLocalPrivCreate)
eventName:(NSString *)eventName)
{
Callback *lpccb = [[Callback alloc] init];
[lpccb setCallback:onLocalPrivCreate];
StreamingCallback *lpccb = [[StreamingCallback alloc] init];
lpccb.delegate = self;
[lpccb setEventName:eventName];
NSError *error;
LndmobileRegisterLocalPrivCreateCallback(nameSpace, lpccb, &error);
if (error) {
@@ -33,10 +34,11 @@ RCT_EXPORT_METHOD(registerLocalPrivCreateCallback:(NSString *)nameSpace
}
RCT_EXPORT_METHOD(registerRemoteKeyReceiveCallback:(NSString *)nameSpace
resolver:(RCTResponseSenderBlock)onRemoteKeyReceive)
eventName:(NSString *)eventName)
{
Callback * rkrcb = [[Callback alloc] init];
[rkrcb setCallback:onRemoteKeyReceive];
StreamingCallback *rkrcb = [[StreamingCallback alloc] init];
rkrcb.delegate = self;
[rkrcb setEventName:eventName];
NSError *error;
LndmobileRegisterRemoteKeyReceiveCallback(nameSpace, rkrcb, &error);
if (error) {
@@ -45,10 +47,11 @@ RCT_EXPORT_METHOD(registerRemoteKeyReceiveCallback:(NSString *)nameSpace
}
RCT_EXPORT_METHOD(registerAuthDataCallback:(NSString *)nameSpace
resolver:(RCTResponseSenderBlock)onAuthData)
eventName:(NSString *)eventName)
{
Callback * oacb = [[Callback alloc] init];
[oacb setCallback:onAuthData];
StreamingCallback *oacb = [[StreamingCallback alloc] init];
oacb.delegate = self;
[oacb setEventName:eventName];
NSError *error;
LndmobileRegisterAuthDataCallback(nameSpace, oacb, &error);
if (error) {
@@ -187,6 +190,9 @@ RCT_EXPORT_METHOD(initListener:(NSString *)nameSpace
- (NSArray<NSString *> *)supportedEvents {
return @[
@"lnc.localPrivCreate",
@"lnc.remoteKeyReceive",
@"lnc.authData",
@"chainrpc.ChainNotifier.RegisterBlockEpochNtfn",
@"chainrpc.ChainNotifier.RegisterConfirmationsNtfn",
@"chainrpc.ChainNotifier.RegisterSpendNtfn",