Expose real time synced event (#800)

This commit is contained in:
Daniel Granhão
2025-03-24 11:46:02 +00:00
committed by GitHub
parent 3088526bdf
commit 2952b6133e
14 changed files with 225 additions and 35 deletions

View File

@@ -614,6 +614,10 @@ typedef struct wire_cst_SdkEvent_PaymentWaitingFeeAcceptance {
struct wire_cst_payment *details; struct wire_cst_payment *details;
} wire_cst_SdkEvent_PaymentWaitingFeeAcceptance; } wire_cst_SdkEvent_PaymentWaitingFeeAcceptance;
typedef struct wire_cst_SdkEvent_DataSynced {
bool did_pull_new_records;
} wire_cst_SdkEvent_DataSynced;
typedef union SdkEventKind { typedef union SdkEventKind {
struct wire_cst_SdkEvent_PaymentFailed PaymentFailed; struct wire_cst_SdkEvent_PaymentFailed PaymentFailed;
struct wire_cst_SdkEvent_PaymentPending PaymentPending; struct wire_cst_SdkEvent_PaymentPending PaymentPending;
@@ -623,6 +627,7 @@ typedef union SdkEventKind {
struct wire_cst_SdkEvent_PaymentSucceeded PaymentSucceeded; struct wire_cst_SdkEvent_PaymentSucceeded PaymentSucceeded;
struct wire_cst_SdkEvent_PaymentWaitingConfirmation PaymentWaitingConfirmation; struct wire_cst_SdkEvent_PaymentWaitingConfirmation PaymentWaitingConfirmation;
struct wire_cst_SdkEvent_PaymentWaitingFeeAcceptance PaymentWaitingFeeAcceptance; struct wire_cst_SdkEvent_PaymentWaitingFeeAcceptance PaymentWaitingFeeAcceptance;
struct wire_cst_SdkEvent_DataSynced DataSynced;
} SdkEventKind; } SdkEventKind;
typedef struct wire_cst_sdk_event { typedef struct wire_cst_sdk_event {

View File

@@ -1,5 +1,6 @@
.swiftpm/ .swiftpm/
.build/ .build/
.index-build/
*.xcodeproj *.xcodeproj
*.podspec *.podspec
Sources/BreezSDKLiquid/BreezSDKLiquid.swift Sources/BreezSDKLiquid/BreezSDKLiquid.swift

View File

@@ -690,6 +690,7 @@ interface SdkEvent {
PaymentWaitingConfirmation(Payment details); PaymentWaitingConfirmation(Payment details);
PaymentWaitingFeeAcceptance(Payment details); PaymentWaitingFeeAcceptance(Payment details);
Synced(); Synced();
DataSynced(boolean did_pull_new_records);
}; };
callback interface EventListener { callback interface EventListener {

View File

@@ -4545,6 +4545,12 @@ impl SseDecode for crate::model::SdkEvent {
8 => { 8 => {
return crate::model::SdkEvent::Synced; return crate::model::SdkEvent::Synced;
} }
9 => {
let mut var_didPullNewRecords = <bool>::sse_decode(deserializer);
return crate::model::SdkEvent::DataSynced {
did_pull_new_records: var_didPullNewRecords,
};
}
_ => { _ => {
unimplemented!(""); unimplemented!("");
} }
@@ -6999,6 +7005,13 @@ impl flutter_rust_bridge::IntoDart for crate::model::SdkEvent {
[7.into_dart(), details.into_into_dart().into_dart()].into_dart() [7.into_dart(), details.into_into_dart().into_dart()].into_dart()
} }
crate::model::SdkEvent::Synced => [8.into_dart()].into_dart(), crate::model::SdkEvent::Synced => [8.into_dart()].into_dart(),
crate::model::SdkEvent::DataSynced {
did_pull_new_records,
} => [
9.into_dart(),
did_pull_new_records.into_into_dart().into_dart(),
]
.into_dart(),
_ => { _ => {
unimplemented!(""); unimplemented!("");
} }
@@ -9057,6 +9070,12 @@ impl SseEncode for crate::model::SdkEvent {
crate::model::SdkEvent::Synced => { crate::model::SdkEvent::Synced => {
<i32>::sse_encode(8, serializer); <i32>::sse_encode(8, serializer);
} }
crate::model::SdkEvent::DataSynced {
did_pull_new_records,
} => {
<i32>::sse_encode(9, serializer);
<bool>::sse_encode(did_pull_new_records, serializer);
}
_ => { _ => {
unimplemented!(""); unimplemented!("");
} }
@@ -11248,6 +11267,12 @@ mod io {
} }
} }
8 => crate::model::SdkEvent::Synced, 8 => crate::model::SdkEvent::Synced,
9 => {
let ans = unsafe { self.kind.DataSynced };
crate::model::SdkEvent::DataSynced {
did_pull_new_records: ans.did_pull_new_records.cst_decode(),
}
}
_ => unreachable!(), _ => unreachable!(),
} }
} }
@@ -14930,6 +14955,7 @@ mod io {
PaymentSucceeded: wire_cst_SdkEvent_PaymentSucceeded, PaymentSucceeded: wire_cst_SdkEvent_PaymentSucceeded,
PaymentWaitingConfirmation: wire_cst_SdkEvent_PaymentWaitingConfirmation, PaymentWaitingConfirmation: wire_cst_SdkEvent_PaymentWaitingConfirmation,
PaymentWaitingFeeAcceptance: wire_cst_SdkEvent_PaymentWaitingFeeAcceptance, PaymentWaitingFeeAcceptance: wire_cst_SdkEvent_PaymentWaitingFeeAcceptance,
DataSynced: wire_cst_SdkEvent_DataSynced,
nil__: (), nil__: (),
} }
#[repr(C)] #[repr(C)]
@@ -14974,6 +15000,11 @@ mod io {
} }
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct wire_cst_SdkEvent_DataSynced {
did_pull_new_records: bool,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct wire_cst_send_destination { pub struct wire_cst_send_destination {
tag: i32, tag: i32,
kind: SendDestinationKind, kind: SendDestinationKind,

View File

@@ -295,15 +295,37 @@ pub trait EventListener: MaybeSend + MaybeSync {
/// to listen for emitted events. /// to listen for emitted events.
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum SdkEvent { pub enum SdkEvent {
PaymentFailed { details: Payment }, PaymentFailed {
PaymentPending { details: Payment }, details: Payment,
PaymentRefundable { details: Payment }, },
PaymentRefunded { details: Payment }, PaymentPending {
PaymentRefundPending { details: Payment }, details: Payment,
PaymentSucceeded { details: Payment }, },
PaymentWaitingConfirmation { details: Payment }, PaymentRefundable {
PaymentWaitingFeeAcceptance { details: Payment }, details: Payment,
},
PaymentRefunded {
details: Payment,
},
PaymentRefundPending {
details: Payment,
},
PaymentSucceeded {
details: Payment,
},
PaymentWaitingConfirmation {
details: Payment,
},
PaymentWaitingFeeAcceptance {
details: Payment,
},
/// Synced with mempool and onchain data
Synced, Synced,
/// Synced with real-time data sync
DataSynced {
/// Indicates new data was pulled from other instances.
did_pull_new_records: bool,
},
} }
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]

View File

@@ -519,19 +519,21 @@ impl LiquidSdk {
loop { loop {
tokio::select! { tokio::select! {
event = sync_events_receiver.recv() => { event = sync_events_receiver.recv() => {
if let Ok(e) = event { if let Ok(e) = event {
match e { match e {
sync::Event::SyncedCompleted{data} => { sync::Event::SyncedCompleted{data} => {
info!( info!(
"Received sync event: pulled {} records, pushed {} records", "Received sync event: pulled {} records, pushed {} records",
data.pulled_records_count, data.pushed_records_count data.pulled_records_count, data.pushed_records_count
); );
if data.pulled_records_count > 0 { let did_pull_new_records = data.pulled_records_count > 0;
subscription_handler.subscribe_swaps().await; if did_pull_new_records {
subscription_handler.subscribe_swaps().await;
}
cloned.notify_event_listeners(SdkEvent::DataSynced {did_pull_new_records}).await
}
} }
}
} }
}
} }
_ = shutdown_receiver.changed() => { _ = shutdown_receiver.changed() => {
info!("Received shutdown signal, exiting real-time sync loop"); info!("Received shutdown signal, exiting real-time sync loop");
@@ -682,9 +684,8 @@ impl LiquidSdk {
}); });
} }
async fn notify_event_listeners(&self, e: SdkEvent) -> Result<()> { async fn notify_event_listeners(&self, e: SdkEvent) {
self.event_manager.notify(e).await; self.event_manager.notify(e).await;
Ok(())
} }
/// Adds an event listener to the [LiquidSdk] instance, where all [SdkEvent]'s will be emitted to. /// Adds an event listener to the [LiquidSdk] instance, where all [SdkEvent]'s will be emitted to.
@@ -717,7 +718,7 @@ impl LiquidSdk {
self.notify_event_listeners(SdkEvent::PaymentSucceeded { self.notify_event_listeners(SdkEvent::PaymentSucceeded {
details: payment, details: payment,
}) })
.await? .await
} }
Pending => { Pending => {
match &payment.details.get_swap_id() { match &payment.details.get_swap_id() {
@@ -730,13 +731,13 @@ impl LiquidSdk {
details: payment, details: payment,
}, },
) )
.await? .await
} else { } else {
// The lockup tx is in the mempool/confirmed // The lockup tx is in the mempool/confirmed
self.notify_event_listeners(SdkEvent::PaymentPending { self.notify_event_listeners(SdkEvent::PaymentPending {
details: payment, details: payment,
}) })
.await? .await
} }
} }
Swap::Receive(ReceiveSwap { Swap::Receive(ReceiveSwap {
@@ -751,13 +752,13 @@ impl LiquidSdk {
details: payment, details: payment,
}, },
) )
.await? .await
} else { } else {
// The lockup tx is in the mempool/confirmed // The lockup tx is in the mempool/confirmed
self.notify_event_listeners(SdkEvent::PaymentPending { self.notify_event_listeners(SdkEvent::PaymentPending {
details: payment, details: payment,
}) })
.await? .await
} }
} }
Swap::Send(_) => { Swap::Send(_) => {
@@ -765,7 +766,7 @@ impl LiquidSdk {
self.notify_event_listeners(SdkEvent::PaymentPending { self.notify_event_listeners(SdkEvent::PaymentPending {
details: payment, details: payment,
}) })
.await? .await
} }
}, },
// Here we probably have a liquid address payment so we emit PaymentWaitingConfirmation // Here we probably have a liquid address payment so we emit PaymentWaitingConfirmation
@@ -773,7 +774,7 @@ impl LiquidSdk {
self.notify_event_listeners( self.notify_event_listeners(
SdkEvent::PaymentWaitingConfirmation { details: payment }, SdkEvent::PaymentWaitingConfirmation { details: payment },
) )
.await? .await
} }
}; };
} }
@@ -794,34 +795,34 @@ impl LiquidSdk {
self.notify_event_listeners(SdkEvent::PaymentWaitingFeeAcceptance { self.notify_event_listeners(SdkEvent::PaymentWaitingFeeAcceptance {
details: payment, details: payment,
}) })
.await?; .await;
} }
Refundable => { Refundable => {
self.notify_event_listeners(SdkEvent::PaymentRefundable { self.notify_event_listeners(SdkEvent::PaymentRefundable {
details: payment, details: payment,
}) })
.await? .await
} }
RefundPending => { RefundPending => {
// The swap state has changed to RefundPending // The swap state has changed to RefundPending
self.notify_event_listeners(SdkEvent::PaymentRefundPending { self.notify_event_listeners(SdkEvent::PaymentRefundPending {
details: payment, details: payment,
}) })
.await? .await
} }
Failed => match payment.payment_type { Failed => match payment.payment_type {
PaymentType::Receive => { PaymentType::Receive => {
self.notify_event_listeners(SdkEvent::PaymentFailed { self.notify_event_listeners(SdkEvent::PaymentFailed {
details: payment, details: payment,
}) })
.await? .await
} }
PaymentType::Send => { PaymentType::Send => {
// The refund tx is confirmed // The refund tx is confirmed
self.notify_event_listeners(SdkEvent::PaymentRefunded { self.notify_event_listeners(SdkEvent::PaymentRefunded {
details: payment, details: payment,
}) })
.await? .await
} }
}, },
_ => (), _ => (),
@@ -3343,7 +3344,7 @@ impl LiquidSdk {
let duration_ms = Instant::now().duration_since(t0).as_millis(); let duration_ms = Instant::now().duration_since(t0).as_millis();
info!("Synchronized (partial: {partial_sync}) with mempool and onchain data ({duration_ms} ms)"); info!("Synchronized (partial: {partial_sync}) with mempool and onchain data ({duration_ms} ms)");
self.notify_event_listeners(SdkEvent::Synced).await?; self.notify_event_listeners(SdkEvent::Synced).await;
Ok(()) Ok(())
} }

View File

@@ -3169,6 +3169,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return SdkEvent_PaymentWaitingFeeAcceptance(details: dco_decode_box_autoadd_payment(raw[1])); return SdkEvent_PaymentWaitingFeeAcceptance(details: dco_decode_box_autoadd_payment(raw[1]));
case 8: case 8:
return SdkEvent_Synced(); return SdkEvent_Synced();
case 9:
return SdkEvent_DataSynced(didPullNewRecords: dco_decode_bool(raw[1]));
default: default:
throw Exception("unreachable"); throw Exception("unreachable");
} }
@@ -5540,6 +5542,9 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return SdkEvent_PaymentWaitingFeeAcceptance(details: var_details); return SdkEvent_PaymentWaitingFeeAcceptance(details: var_details);
case 8: case 8:
return SdkEvent_Synced(); return SdkEvent_Synced();
case 9:
var var_didPullNewRecords = sse_decode_bool(deserializer);
return SdkEvent_DataSynced(didPullNewRecords: var_didPullNewRecords);
default: default:
throw UnimplementedError(''); throw UnimplementedError('');
} }
@@ -7676,6 +7681,9 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
sse_encode_box_autoadd_payment(details, serializer); sse_encode_box_autoadd_payment(details, serializer);
case SdkEvent_Synced(): case SdkEvent_Synced():
sse_encode_i_32(8, serializer); sse_encode_i_32(8, serializer);
case SdkEvent_DataSynced(didPullNewRecords: final didPullNewRecords):
sse_encode_i_32(9, serializer);
sse_encode_bool(didPullNewRecords, serializer);
} }
} }

View File

@@ -3809,6 +3809,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
wireObj.tag = 8; wireObj.tag = 8;
return; return;
} }
if (apiObj is SdkEvent_DataSynced) {
var pre_did_pull_new_records = cst_encode_bool(apiObj.didPullNewRecords);
wireObj.tag = 9;
wireObj.kind.DataSynced.did_pull_new_records = pre_did_pull_new_records;
return;
}
} }
@protected @protected
@@ -7018,6 +7024,11 @@ final class wire_cst_SdkEvent_PaymentWaitingFeeAcceptance extends ffi.Struct {
external ffi.Pointer<wire_cst_payment> details; external ffi.Pointer<wire_cst_payment> details;
} }
final class wire_cst_SdkEvent_DataSynced extends ffi.Struct {
@ffi.Bool()
external bool did_pull_new_records;
}
final class SdkEventKind extends ffi.Union { final class SdkEventKind extends ffi.Union {
external wire_cst_SdkEvent_PaymentFailed PaymentFailed; external wire_cst_SdkEvent_PaymentFailed PaymentFailed;
@@ -7034,6 +7045,8 @@ final class SdkEventKind extends ffi.Union {
external wire_cst_SdkEvent_PaymentWaitingConfirmation PaymentWaitingConfirmation; external wire_cst_SdkEvent_PaymentWaitingConfirmation PaymentWaitingConfirmation;
external wire_cst_SdkEvent_PaymentWaitingFeeAcceptance PaymentWaitingFeeAcceptance; external wire_cst_SdkEvent_PaymentWaitingFeeAcceptance PaymentWaitingFeeAcceptance;
external wire_cst_SdkEvent_DataSynced DataSynced;
} }
final class wire_cst_sdk_event extends ffi.Struct { final class wire_cst_sdk_event extends ffi.Struct {

View File

@@ -1570,7 +1570,15 @@ sealed class SdkEvent with _$SdkEvent {
SdkEvent_PaymentWaitingConfirmation; SdkEvent_PaymentWaitingConfirmation;
const factory SdkEvent.paymentWaitingFeeAcceptance({required Payment details}) = const factory SdkEvent.paymentWaitingFeeAcceptance({required Payment details}) =
SdkEvent_PaymentWaitingFeeAcceptance; SdkEvent_PaymentWaitingFeeAcceptance;
/// Synced with mempool and onchain data
const factory SdkEvent.synced() = SdkEvent_Synced; const factory SdkEvent.synced() = SdkEvent_Synced;
/// Synced with real-time data sync
const factory SdkEvent.dataSynced({
/// Indicates new data was pulled from other instances.
required bool didPullNewRecords,
}) = SdkEvent_DataSynced;
} }
@freezed @freezed

View File

@@ -1857,6 +1857,73 @@ String toString() {
/// @nodoc
class SdkEvent_DataSynced extends SdkEvent {
const SdkEvent_DataSynced({required this.didPullNewRecords}): super._();
/// Indicates new data was pulled from other instances.
final bool didPullNewRecords;
/// Create a copy of SdkEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$SdkEvent_DataSyncedCopyWith<SdkEvent_DataSynced> get copyWith => _$SdkEvent_DataSyncedCopyWithImpl<SdkEvent_DataSynced>(this, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is SdkEvent_DataSynced&&(identical(other.didPullNewRecords, didPullNewRecords) || other.didPullNewRecords == didPullNewRecords));
}
@override
int get hashCode => Object.hash(runtimeType,didPullNewRecords);
@override
String toString() {
return 'SdkEvent.dataSynced(didPullNewRecords: $didPullNewRecords)';
}
}
/// @nodoc
abstract mixin class $SdkEvent_DataSyncedCopyWith<$Res> implements $SdkEventCopyWith<$Res> {
factory $SdkEvent_DataSyncedCopyWith(SdkEvent_DataSynced value, $Res Function(SdkEvent_DataSynced) _then) = _$SdkEvent_DataSyncedCopyWithImpl;
@useResult
$Res call({
bool didPullNewRecords
});
}
/// @nodoc
class _$SdkEvent_DataSyncedCopyWithImpl<$Res>
implements $SdkEvent_DataSyncedCopyWith<$Res> {
_$SdkEvent_DataSyncedCopyWithImpl(this._self, this._then);
final SdkEvent_DataSynced _self;
final $Res Function(SdkEvent_DataSynced) _then;
/// Create a copy of SdkEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') $Res call({Object? didPullNewRecords = null,}) {
return _then(SdkEvent_DataSynced(
didPullNewRecords: null == didPullNewRecords ? _self.didPullNewRecords : didPullNewRecords // ignore: cast_nullable_to_non_nullable
as bool,
));
}
}
/// @nodoc /// @nodoc
mixin _$SendDestination { mixin _$SendDestination {

View File

@@ -4953,6 +4953,11 @@ final class wire_cst_SdkEvent_PaymentWaitingFeeAcceptance extends ffi.Struct {
external ffi.Pointer<wire_cst_payment> details; external ffi.Pointer<wire_cst_payment> details;
} }
final class wire_cst_SdkEvent_DataSynced extends ffi.Struct {
@ffi.Bool()
external bool did_pull_new_records;
}
final class SdkEventKind extends ffi.Union { final class SdkEventKind extends ffi.Union {
external wire_cst_SdkEvent_PaymentFailed PaymentFailed; external wire_cst_SdkEvent_PaymentFailed PaymentFailed;
@@ -4969,6 +4974,8 @@ final class SdkEventKind extends ffi.Union {
external wire_cst_SdkEvent_PaymentWaitingConfirmation PaymentWaitingConfirmation; external wire_cst_SdkEvent_PaymentWaitingConfirmation PaymentWaitingConfirmation;
external wire_cst_SdkEvent_PaymentWaitingFeeAcceptance PaymentWaitingFeeAcceptance; external wire_cst_SdkEvent_PaymentWaitingFeeAcceptance PaymentWaitingFeeAcceptance;
external wire_cst_SdkEvent_DataSynced DataSynced;
} }
final class wire_cst_sdk_event extends ffi.Struct { final class wire_cst_sdk_event extends ffi.Struct {

View File

@@ -3715,6 +3715,10 @@ fun asSdkEvent(sdkEvent: ReadableMap): SdkEvent? {
if (type == "synced") { if (type == "synced") {
return SdkEvent.Synced return SdkEvent.Synced
} }
if (type == "dataSynced") {
val didPullNewRecords = sdkEvent.getBoolean("didPullNewRecords")
return SdkEvent.DataSynced(didPullNewRecords)
}
return null return null
} }
@@ -3756,6 +3760,10 @@ fun readableMapOf(sdkEvent: SdkEvent): ReadableMap? {
is SdkEvent.Synced -> { is SdkEvent.Synced -> {
pushToMap(map, "type", "synced") pushToMap(map, "type", "synced")
} }
is SdkEvent.DataSynced -> {
pushToMap(map, "type", "dataSynced")
pushToMap(map, "didPullNewRecords", sdkEvent.didPullNewRecords)
}
} }
return map return map
} }

View File

@@ -4623,6 +4623,12 @@ enum BreezSDKLiquidMapper {
if type == "synced" { if type == "synced" {
return SdkEvent.synced return SdkEvent.synced
} }
if type == "dataSynced" {
guard let _didPullNewRecords = sdkEvent["didPullNewRecords"] as? Bool else {
throw SdkError.Generic(message: errMissingMandatoryField(fieldName: "didPullNewRecords", typeName: "SdkEvent"))
}
return SdkEvent.dataSynced(didPullNewRecords: _didPullNewRecords)
}
throw SdkError.Generic(message: "Unexpected type \(type) for enum SdkEvent") throw SdkError.Generic(message: "Unexpected type \(type) for enum SdkEvent")
} }
@@ -4697,6 +4703,14 @@ enum BreezSDKLiquidMapper {
return [ return [
"type": "synced", "type": "synced",
] ]
case let .dataSynced(
didPullNewRecords
):
return [
"type": "dataSynced",
"didPullNewRecords": didPullNewRecords,
]
} }
} }

View File

@@ -759,7 +759,8 @@ export enum SdkEventVariant {
PAYMENT_SUCCEEDED = "paymentSucceeded", PAYMENT_SUCCEEDED = "paymentSucceeded",
PAYMENT_WAITING_CONFIRMATION = "paymentWaitingConfirmation", PAYMENT_WAITING_CONFIRMATION = "paymentWaitingConfirmation",
PAYMENT_WAITING_FEE_ACCEPTANCE = "paymentWaitingFeeAcceptance", PAYMENT_WAITING_FEE_ACCEPTANCE = "paymentWaitingFeeAcceptance",
SYNCED = "synced" SYNCED = "synced",
DATA_SYNCED = "dataSynced"
} }
export type SdkEvent = { export type SdkEvent = {
@@ -788,6 +789,9 @@ export type SdkEvent = {
details: Payment details: Payment
} | { } | {
type: SdkEventVariant.SYNCED type: SdkEventVariant.SYNCED
} | {
type: SdkEventVariant.DATA_SYNCED,
didPullNewRecords: boolean
} }
export enum SendDestinationVariant { export enum SendDestinationVariant {