diff --git a/cli/src/commands.rs b/cli/src/commands.rs index 0218490..20ae2b7 100644 --- a/cli/src/commands.rs +++ b/cli/src/commands.rs @@ -43,7 +43,10 @@ pub(crate) enum Command { /// Empties the encrypted transaction cache EmptyCache, /// Backs up the current pending swaps - Backup, + Backup { + #[arg(short, long)] + backup_path: Option, + }, /// Retrieve a list of backups Restore { #[arg(short, long)] @@ -159,8 +162,8 @@ pub(crate) async fn handle_command( sdk.empty_wallet_cache()?; command_result!("Cache emptied successfully") } - Command::Backup => { - sdk.backup()?; + Command::Backup { backup_path } => { + sdk.backup(BackupRequest { backup_path })?; command_result!("Backup created successfully!") } Command::Restore { backup_path } => { diff --git a/lib/bindings/langs/flutter/breez_liquid_sdk/include/breez_liquid_sdk.h b/lib/bindings/langs/flutter/breez_liquid_sdk/include/breez_liquid_sdk.h index c60bbd6..c0e8dfb 100644 --- a/lib/bindings/langs/flutter/breez_liquid_sdk/include/breez_liquid_sdk.h +++ b/lib/bindings/langs/flutter/breez_liquid_sdk/include/breez_liquid_sdk.h @@ -25,6 +25,10 @@ typedef struct wire_cst_list_prim_u_8_strict { int32_t len; } wire_cst_list_prim_u_8_strict; +typedef struct wire_cst_backup_request { + struct wire_cst_list_prim_u_8_strict *backup_path; +} wire_cst_backup_request; + typedef struct wire_cst_get_info_request { bool with_scan; } wire_cst_get_info_request; @@ -179,7 +183,8 @@ void frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_add_event_liste struct wire_cst_list_prim_u_8_strict *listener); void frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_backup(int64_t port_, - uintptr_t that); + uintptr_t that, + struct wire_cst_backup_request *req); void frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_empty_wallet_cache(int64_t port_, uintptr_t that); @@ -221,6 +226,8 @@ void frbgen_breez_liquid_rust_arc_increment_strong_count_RustOpaque_flutter_rust void frbgen_breez_liquid_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerBindingLiquidSdk(const void *ptr); +struct wire_cst_backup_request *frbgen_breez_liquid_cst_new_box_autoadd_backup_request(void); + struct wire_cst_connect_request *frbgen_breez_liquid_cst_new_box_autoadd_connect_request(void); struct wire_cst_get_info_request *frbgen_breez_liquid_cst_new_box_autoadd_get_info_request(void); @@ -244,6 +251,7 @@ struct wire_cst_list_payment *frbgen_breez_liquid_cst_new_list_payment(int32_t l struct wire_cst_list_prim_u_8_strict *frbgen_breez_liquid_cst_new_list_prim_u_8_strict(int32_t len); static int64_t dummy_method_to_enforce_bundling(void) { int64_t dummy_var = 0; + dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_box_autoadd_backup_request); dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_box_autoadd_connect_request); dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_box_autoadd_get_info_request); dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_box_autoadd_payment); diff --git a/lib/bindings/src/breez_liquid_sdk.udl b/lib/bindings/src/breez_liquid_sdk.udl index 9176c06..29f6784 100644 --- a/lib/bindings/src/breez_liquid_sdk.udl +++ b/lib/bindings/src/breez_liquid_sdk.udl @@ -69,6 +69,10 @@ dictionary ReceivePaymentResponse { string invoice; }; +dictionary BackupRequest { + string? backup_path = null; +}; + dictionary RestoreRequest { string? backup_path = null; }; @@ -145,7 +149,7 @@ interface BindingLiquidSdk { void sync(); [Throws=LiquidSdkError] - void backup(); + void backup(BackupRequest req); [Throws=LiquidSdkError] void restore(RestoreRequest req); diff --git a/lib/bindings/src/lib.rs b/lib/bindings/src/lib.rs index 2ce87c9..3926d6d 100644 --- a/lib/bindings/src/lib.rs +++ b/lib/bindings/src/lib.rs @@ -75,8 +75,8 @@ impl BindingLiquidSdk { self.sdk.empty_wallet_cache().map_err(Into::into) } - pub fn backup(&self) -> LiquidSdkResult<()> { - self.sdk.backup().map_err(Into::into) + pub fn backup(&self, req: BackupRequest) -> LiquidSdkResult<()> { + self.sdk.backup(req).map_err(Into::into) } pub fn restore(&self, req: RestoreRequest) -> LiquidSdkResult<()> { diff --git a/lib/core/src/bindings.rs b/lib/core/src/bindings.rs index 781ae30..5e5991a 100644 --- a/lib/core/src/bindings.rs +++ b/lib/core/src/bindings.rs @@ -86,8 +86,8 @@ impl BindingLiquidSdk { self.sdk.empty_wallet_cache().map_err(Into::into) } - pub fn backup(&self) -> Result<(), LiquidSdkError> { - self.sdk.backup().map_err(Into::into) + pub fn backup(&self, req: BackupRequest) -> Result<(), LiquidSdkError> { + self.sdk.backup(req).map_err(Into::into) } pub fn restore(&self, req: RestoreRequest) -> Result<(), LiquidSdkError> { diff --git a/lib/core/src/frb/bridge.io.rs b/lib/core/src/frb/bridge.io.rs index 21141de..7127214 100644 --- a/lib/core/src/frb/bridge.io.rs +++ b/lib/core/src/frb/bridge.io.rs @@ -60,6 +60,21 @@ impl CstDecode for *mut wire_cst_list_prim_u_8_strict { String::from_utf8(vec).unwrap() } } +impl CstDecode for wire_cst_backup_request { + // Codec=Cst (C-struct based), see doc to use other codecs + fn cst_decode(self) -> crate::model::BackupRequest { + crate::model::BackupRequest { + backup_path: self.backup_path.cst_decode(), + } + } +} +impl CstDecode for *mut wire_cst_backup_request { + // Codec=Cst (C-struct based), see doc to use other codecs + fn cst_decode(self) -> crate::model::BackupRequest { + let wrap = unsafe { flutter_rust_bridge::for_generated::box_from_leak_ptr(self) }; + CstDecode::::cst_decode(*wrap).into() + } +} impl CstDecode for *mut wire_cst_connect_request { // Codec=Cst (C-struct based), see doc to use other codecs fn cst_decode(self) -> crate::model::ConnectRequest { @@ -350,6 +365,18 @@ impl CstDecode for wire_cst_send_payment_resp } } } +impl NewWithNullPtr for wire_cst_backup_request { + fn new_with_null_ptr() -> Self { + Self { + backup_path: core::ptr::null_mut(), + } + } +} +impl Default for wire_cst_backup_request { + fn default() -> Self { + Self::new_with_null_ptr() + } +} impl NewWithNullPtr for wire_cst_connect_request { fn new_with_null_ptr() -> Self { Self { @@ -550,8 +577,9 @@ pub extern "C" fn frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_ad pub extern "C" fn frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_backup( port_: i64, that: usize, + req: *mut wire_cst_backup_request, ) { - wire__crate__bindings__BindingLiquidSdk_backup_impl(port_, that) + wire__crate__bindings__BindingLiquidSdk_backup_impl(port_, that, req) } #[no_mangle] @@ -658,6 +686,14 @@ pub extern "C" fn frbgen_breez_liquid_rust_arc_decrement_strong_count_RustOpaque } } +#[no_mangle] +pub extern "C" fn frbgen_breez_liquid_cst_new_box_autoadd_backup_request( +) -> *mut wire_cst_backup_request { + flutter_rust_bridge::for_generated::new_leak_box_ptr( + wire_cst_backup_request::new_with_null_ptr(), + ) +} + #[no_mangle] pub extern "C" fn frbgen_breez_liquid_cst_new_box_autoadd_connect_request( ) -> *mut wire_cst_connect_request { @@ -747,6 +783,11 @@ pub extern "C" fn frbgen_breez_liquid_cst_new_list_prim_u_8_strict( flutter_rust_bridge::for_generated::new_leak_box_ptr(ans) } +#[repr(C)] +#[derive(Clone, Copy)] +pub struct wire_cst_backup_request { + backup_path: *mut wire_cst_list_prim_u_8_strict, +} #[repr(C)] #[derive(Clone, Copy)] pub struct wire_cst_connect_request { diff --git a/lib/core/src/frb/bridge.rs b/lib/core/src/frb/bridge.rs index b1cbe5d..5fab990 100644 --- a/lib/core/src/frb/bridge.rs +++ b/lib/core/src/frb/bridge.rs @@ -86,6 +86,7 @@ fn wire__crate__bindings__BindingLiquidSdk_backup_impl( that: impl CstDecode< RustOpaqueNom>, >, + req: impl CstDecode, ) { FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( flutter_rust_bridge::for_generated::TaskInfo { @@ -95,6 +96,7 @@ fn wire__crate__bindings__BindingLiquidSdk_backup_impl( }, move || { let api_that = that.cst_decode(); + let api_req = req.cst_decode(); move |context| { transform_result_dco((move || { let mut api_that_decoded = None; @@ -111,7 +113,7 @@ fn wire__crate__bindings__BindingLiquidSdk_backup_impl( } } let api_that = api_that_decoded.unwrap(); - crate::bindings::BindingLiquidSdk::backup(&api_that) + crate::bindings::BindingLiquidSdk::backup(&api_that, api_req) })()) } }, @@ -578,6 +580,16 @@ impl SseDecode for String { } } +impl SseDecode for crate::model::BackupRequest { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut var_backupPath = >::sse_decode(deserializer); + return crate::model::BackupRequest { + backup_path: var_backupPath, + }; + } +} + impl SseDecode for bool { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { @@ -1016,6 +1028,20 @@ impl flutter_rust_bridge::IntoIntoDart> for Binding } } +// Codec=Dco (DartCObject based), see doc to use other codecs +impl flutter_rust_bridge::IntoDart for crate::model::BackupRequest { + fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi { + [self.backup_path.into_into_dart().into_dart()].into_dart() + } +} +impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive for crate::model::BackupRequest {} +impl flutter_rust_bridge::IntoIntoDart + for crate::model::BackupRequest +{ + fn into_into_dart(self) -> crate::model::BackupRequest { + self + } +} // Codec=Dco (DartCObject based), see doc to use other codecs impl flutter_rust_bridge::IntoDart for crate::model::ConnectRequest { fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi { @@ -1392,6 +1418,13 @@ impl SseEncode for String { } } +impl SseEncode for crate::model::BackupRequest { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + >::sse_encode(self.backup_path, serializer); + } +} + impl SseEncode for bool { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { diff --git a/lib/core/src/model.rs b/lib/core/src/model.rs index e86030a..5f6c8a9 100644 --- a/lib/core/src/model.rs +++ b/lib/core/src/model.rs @@ -152,6 +152,15 @@ pub struct GetInfoResponse { pub pubkey: String, } +#[derive(Debug, Serialize)] +pub struct BackupRequest { + /// Path to the backup. + /// + /// If not set, it defaults to `backup.sql` for mainnet and `backup-testnet.sql` for testnet. + /// The file will be saved in [ConnectRequest]'s `data_dir`. + pub backup_path: Option, +} + #[derive(Debug, Serialize)] pub struct RestoreRequest { pub backup_path: Option, diff --git a/lib/core/src/persist/backup.rs b/lib/core/src/persist/backup.rs index 7a1230f..1fb8182 100644 --- a/lib/core/src/persist/backup.rs +++ b/lib/core/src/persist/backup.rs @@ -6,27 +6,16 @@ use super::Persister; use crate::model::Network; impl Persister { - pub(crate) fn get_backup_path(&self) -> PathBuf { + pub(crate) fn get_default_backup_path(&self) -> PathBuf { self.main_db_dir.join(match self.network { Network::Liquid => "backup.sql", Network::LiquidTestnet => "backup-testnet.sql", }) } - pub(crate) fn backup(&self) -> Result<()> { + pub(crate) fn backup(&self, backup_path: PathBuf) -> Result<()> { let con = self.get_connection()?; - - let backup_file = match self.network { - Network::Liquid => "backup.sql", - Network::LiquidTestnet => "backup-testnet.sql", - }; - - con.backup( - rusqlite::DatabaseName::Main, - self.main_db_dir.join(backup_file), - None, - )?; - + con.backup(rusqlite::DatabaseName::Main, backup_path, None)?; Ok(()) } diff --git a/lib/core/src/sdk.rs b/lib/core/src/sdk.rs index 98848af..2d9ff35 100644 --- a/lib/core/src/sdk.rs +++ b/lib/core/src/sdk.rs @@ -1234,14 +1234,6 @@ impl LiquidSdk { Ok(()) } - pub fn restore(&self, req: RestoreRequest) -> Result<()> { - let backup_path = match req.backup_path { - Some(p) => PathBuf::from_str(&p)?, - None => self.persister.get_backup_path(), - }; - self.persister.restore_from_backup(backup_path) - } - /// Synchronize the DB with mempool and onchain data pub async fn sync(&self) -> Result<()> { let t0 = Instant::now(); @@ -1253,8 +1245,20 @@ impl LiquidSdk { Ok(()) } - pub fn backup(&self) -> Result<()> { - self.persister.backup() + pub fn backup(&self, req: BackupRequest) -> Result<()> { + let backup_path = req + .backup_path + .map(PathBuf::from) + .unwrap_or(self.persister.get_default_backup_path()); + self.persister.backup(backup_path) + } + + pub fn restore(&self, req: RestoreRequest) -> Result<()> { + let backup_path = req + .backup_path + .map(PathBuf::from) + .unwrap_or(self.persister.get_default_backup_path()); + self.persister.restore_from_backup(backup_path) } fn get_liquid_swap_key(&self) -> Result { diff --git a/packages/dart/lib/src/bindings.dart b/packages/dart/lib/src/bindings.dart index 7bce9b0..8c12bec 100644 --- a/packages/dart/lib/src/bindings.dart +++ b/packages/dart/lib/src/bindings.dart @@ -30,8 +30,8 @@ class BindingLiquidSdk extends RustOpaque { Stream addEventListener({dynamic hint}) => RustLib.instance.api.crateBindingsBindingLiquidSdkAddEventListener(that: this, hint: hint); - Future backup({dynamic hint}) => - RustLib.instance.api.crateBindingsBindingLiquidSdkBackup(that: this, hint: hint); + Future backup({required BackupRequest req, dynamic hint}) => + RustLib.instance.api.crateBindingsBindingLiquidSdkBackup(that: this, req: req, hint: hint); Future emptyWalletCache({dynamic hint}) => RustLib.instance.api.crateBindingsBindingLiquidSdkEmptyWalletCache(that: this, hint: hint); diff --git a/packages/dart/lib/src/frb_generated.dart b/packages/dart/lib/src/frb_generated.dart index e8eff31..7a7a922 100644 --- a/packages/dart/lib/src/frb_generated.dart +++ b/packages/dart/lib/src/frb_generated.dart @@ -66,7 +66,8 @@ abstract class RustLibApi extends BaseApi { Stream crateBindingsBindingLiquidSdkAddEventListener( {required BindingLiquidSdk that, dynamic hint}); - Future crateBindingsBindingLiquidSdkBackup({required BindingLiquidSdk that, dynamic hint}); + Future crateBindingsBindingLiquidSdkBackup( + {required BindingLiquidSdk that, required BackupRequest req, dynamic hint}); Future crateBindingsBindingLiquidSdkEmptyWalletCache({required BindingLiquidSdk that, dynamic hint}); @@ -140,20 +141,22 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { ); @override - Future crateBindingsBindingLiquidSdkBackup({required BindingLiquidSdk that, dynamic hint}) { + Future crateBindingsBindingLiquidSdkBackup( + {required BindingLiquidSdk that, required BackupRequest req, dynamic hint}) { return handler.executeNormal(NormalTask( callFfi: (port_) { var arg0 = cst_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerBindingLiquidSdk( that); - return wire.wire__crate__bindings__BindingLiquidSdk_backup(port_, arg0); + var arg1 = cst_encode_box_autoadd_backup_request(req); + return wire.wire__crate__bindings__BindingLiquidSdk_backup(port_, arg0, arg1); }, codec: DcoCodec( decodeSuccessData: dco_decode_unit, decodeErrorData: dco_decode_liquid_sdk_error, ), constMeta: kCrateBindingsBindingLiquidSdkBackupConstMeta, - argValues: [that], + argValues: [that, req], apiImpl: this, hint: hint, )); @@ -161,7 +164,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { TaskConstMeta get kCrateBindingsBindingLiquidSdkBackupConstMeta => const TaskConstMeta( debugName: "BindingLiquidSdk_backup", - argNames: ["that"], + argNames: ["that", "req"], ); @override @@ -467,12 +470,28 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return raw as String; } + @protected + BackupRequest dco_decode_backup_request(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + final arr = raw as List; + if (arr.length != 1) throw Exception('unexpected arr length: expect 1 but see ${arr.length}'); + return BackupRequest( + backupPath: dco_decode_opt_String(arr[0]), + ); + } + @protected bool dco_decode_bool(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs return raw as bool; } + @protected + BackupRequest dco_decode_box_autoadd_backup_request(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return dco_decode_backup_request(raw); + } + @protected ConnectRequest dco_decode_box_autoadd_connect_request(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs @@ -860,12 +879,25 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return utf8.decoder.convert(inner); } + @protected + BackupRequest sse_decode_backup_request(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + var var_backupPath = sse_decode_opt_String(deserializer); + return BackupRequest(backupPath: var_backupPath); + } + @protected bool sse_decode_bool(SseDeserializer deserializer) { // Codec=Sse (Serialization based), see doc to use other codecs return deserializer.buffer.getUint8() != 0; } + @protected + BackupRequest sse_decode_box_autoadd_backup_request(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + return (sse_decode_backup_request(deserializer)); + } + @protected ConnectRequest sse_decode_box_autoadd_connect_request(SseDeserializer deserializer) { // Codec=Sse (Serialization based), see doc to use other codecs @@ -1324,12 +1356,24 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { sse_encode_list_prim_u_8_strict(utf8.encoder.convert(self), serializer); } + @protected + void sse_encode_backup_request(BackupRequest self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_opt_String(self.backupPath, serializer); + } + @protected void sse_encode_bool(bool self, SseSerializer serializer) { // Codec=Sse (Serialization based), see doc to use other codecs serializer.buffer.putUint8(self ? 1 : 0); } + @protected + void sse_encode_box_autoadd_backup_request(BackupRequest self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_backup_request(self, serializer); + } + @protected void sse_encode_box_autoadd_connect_request(ConnectRequest self, SseSerializer serializer) { // Codec=Sse (Serialization based), see doc to use other codecs diff --git a/packages/dart/lib/src/frb_generated.io.dart b/packages/dart/lib/src/frb_generated.io.dart index 172f695..4c8bbca 100644 --- a/packages/dart/lib/src/frb_generated.io.dart +++ b/packages/dart/lib/src/frb_generated.io.dart @@ -43,9 +43,15 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected String dco_decode_String(dynamic raw); + @protected + BackupRequest dco_decode_backup_request(dynamic raw); + @protected bool dco_decode_bool(dynamic raw); + @protected + BackupRequest dco_decode_box_autoadd_backup_request(dynamic raw); + @protected ConnectRequest dco_decode_box_autoadd_connect_request(dynamic raw); @@ -174,9 +180,15 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected String sse_decode_String(SseDeserializer deserializer); + @protected + BackupRequest sse_decode_backup_request(SseDeserializer deserializer); + @protected bool sse_decode_bool(SseDeserializer deserializer); + @protected + BackupRequest sse_decode_box_autoadd_backup_request(SseDeserializer deserializer); + @protected ConnectRequest sse_decode_box_autoadd_connect_request(SseDeserializer deserializer); @@ -299,6 +311,14 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { return cst_encode_list_prim_u_8_strict(utf8.encoder.convert(raw)); } + @protected + ffi.Pointer cst_encode_box_autoadd_backup_request(BackupRequest raw) { + // Codec=Cst (C-struct based), see doc to use other codecs + final ptr = wire.cst_new_box_autoadd_backup_request(); + cst_api_fill_to_wire_backup_request(raw, ptr.ref); + return ptr; + } + @protected ffi.Pointer cst_encode_box_autoadd_connect_request(ConnectRequest raw) { // Codec=Cst (C-struct based), see doc to use other codecs @@ -409,6 +429,17 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { return raw.toInt(); } + @protected + void cst_api_fill_to_wire_backup_request(BackupRequest apiObj, wire_cst_backup_request wireObj) { + wireObj.backup_path = cst_encode_opt_String(apiObj.backupPath); + } + + @protected + void cst_api_fill_to_wire_box_autoadd_backup_request( + BackupRequest apiObj, ffi.Pointer wireObj) { + cst_api_fill_to_wire_backup_request(apiObj, wireObj.ref); + } + @protected void cst_api_fill_to_wire_box_autoadd_connect_request( ConnectRequest apiObj, ffi.Pointer wireObj) { @@ -712,9 +743,15 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected void sse_encode_String(String self, SseSerializer serializer); + @protected + void sse_encode_backup_request(BackupRequest self, SseSerializer serializer); + @protected void sse_encode_bool(bool self, SseSerializer serializer); + @protected + void sse_encode_box_autoadd_backup_request(BackupRequest self, SseSerializer serializer); + @protected void sse_encode_box_autoadd_connect_request(ConnectRequest self, SseSerializer serializer); @@ -882,18 +919,22 @@ class RustLibWire implements BaseWire { void wire__crate__bindings__BindingLiquidSdk_backup( int port_, int that, + ffi.Pointer req, ) { return _wire__crate__bindings__BindingLiquidSdk_backup( port_, that, + req, ); } - late final _wire__crate__bindings__BindingLiquidSdk_backupPtr = - _lookup>( - 'frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_backup'); + late final _wire__crate__bindings__BindingLiquidSdk_backupPtr = _lookup< + ffi + .NativeFunction)>>( + 'frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_backup'); late final _wire__crate__bindings__BindingLiquidSdk_backup = - _wire__crate__bindings__BindingLiquidSdk_backupPtr.asFunction(); + _wire__crate__bindings__BindingLiquidSdk_backupPtr + .asFunction)>(); void wire__crate__bindings__BindingLiquidSdk_empty_wallet_cache( int port_, @@ -1111,6 +1152,16 @@ class RustLibWire implements BaseWire { _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerBindingLiquidSdkPtr .asFunction)>(); + ffi.Pointer cst_new_box_autoadd_backup_request() { + return _cst_new_box_autoadd_backup_request(); + } + + late final _cst_new_box_autoadd_backup_requestPtr = + _lookup Function()>>( + 'frbgen_breez_liquid_cst_new_box_autoadd_backup_request'); + late final _cst_new_box_autoadd_backup_request = + _cst_new_box_autoadd_backup_requestPtr.asFunction Function()>(); + ffi.Pointer cst_new_box_autoadd_connect_request() { return _cst_new_box_autoadd_connect_request(); } @@ -1257,6 +1308,10 @@ final class wire_cst_list_prim_u_8_strict extends ffi.Struct { external int len; } +final class wire_cst_backup_request extends ffi.Struct { + external ffi.Pointer backup_path; +} + final class wire_cst_get_info_request extends ffi.Struct { @ffi.Bool() external bool with_scan; diff --git a/packages/dart/lib/src/model.dart b/packages/dart/lib/src/model.dart index a148c68..86e311f 100644 --- a/packages/dart/lib/src/model.dart +++ b/packages/dart/lib/src/model.dart @@ -8,6 +8,26 @@ import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; import 'package:freezed_annotation/freezed_annotation.dart' hide protected; part 'model.freezed.dart'; +class BackupRequest { + /// Path to the backup. + /// + /// If not set, it defaults to `backup.sql` for mainnet and `backup-testnet.sql` for testnet. + /// The file will be saved in [ConnectRequest]'s `data_dir`. + final String? backupPath; + + const BackupRequest({ + this.backupPath, + }); + + @override + int get hashCode => backupPath.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is BackupRequest && runtimeType == other.runtimeType && backupPath == other.backupPath; +} + class ConnectRequest { final String mnemonic; final String? dataDir; diff --git a/packages/flutter/lib/flutter_breez_liquid_bindings_generated.dart b/packages/flutter/lib/flutter_breez_liquid_bindings_generated.dart index 801fd22..d20fac5 100644 --- a/packages/flutter/lib/flutter_breez_liquid_bindings_generated.dart +++ b/packages/flutter/lib/flutter_breez_liquid_bindings_generated.dart @@ -60,19 +60,22 @@ class FlutterBreezLiquidBindings { void frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_backup( int port_, int that, + ffi.Pointer req, ) { return _frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_backup( port_, that, + req, ); } - late final _frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_backupPtr = - _lookup>( - 'frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_backup'); + late final _frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_backupPtr = _lookup< + ffi + .NativeFunction)>>( + 'frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_backup'); late final _frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_backup = _frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_backupPtr - .asFunction(); + .asFunction)>(); void frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_empty_wallet_cache( int port_, @@ -295,6 +298,17 @@ class FlutterBreezLiquidBindings { _frbgen_breez_liquid_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerBindingLiquidSdkPtr .asFunction)>(); + ffi.Pointer frbgen_breez_liquid_cst_new_box_autoadd_backup_request() { + return _frbgen_breez_liquid_cst_new_box_autoadd_backup_request(); + } + + late final _frbgen_breez_liquid_cst_new_box_autoadd_backup_requestPtr = + _lookup Function()>>( + 'frbgen_breez_liquid_cst_new_box_autoadd_backup_request'); + late final _frbgen_breez_liquid_cst_new_box_autoadd_backup_request = + _frbgen_breez_liquid_cst_new_box_autoadd_backup_requestPtr + .asFunction Function()>(); + ffi.Pointer frbgen_breez_liquid_cst_new_box_autoadd_connect_request() { return _frbgen_breez_liquid_cst_new_box_autoadd_connect_request(); } @@ -464,6 +478,10 @@ final class wire_cst_list_prim_u_8_strict extends ffi.Struct { external int len; } +final class wire_cst_backup_request extends ffi.Struct { + external ffi.Pointer backup_path; +} + final class wire_cst_get_info_request extends ffi.Struct { @ffi.Bool() external bool with_scan; diff --git a/packages/react-native/android/src/main/java/com/breezliquidsdk/BreezLiquidSDKMapper.kt b/packages/react-native/android/src/main/java/com/breezliquidsdk/BreezLiquidSDKMapper.kt index 8258cb7..ac50800 100644 --- a/packages/react-native/android/src/main/java/com/breezliquidsdk/BreezLiquidSDKMapper.kt +++ b/packages/react-native/android/src/main/java/com/breezliquidsdk/BreezLiquidSDKMapper.kt @@ -3,6 +3,37 @@ import breez_liquid_sdk.* import com.facebook.react.bridge.* import java.util.* +fun asBackupRequest(backupRequest: ReadableMap): BackupRequest? { + if (!validateMandatoryFields( + backupRequest, + arrayOf(), + ) + ) { + return null + } + val backupPath = if (hasNonNullKey(backupRequest, "backupPath")) backupRequest.getString("backupPath") else null + return BackupRequest( + backupPath, + ) +} + +fun readableMapOf(backupRequest: BackupRequest): ReadableMap { + return readableMapOf( + "backupPath" to backupRequest.backupPath, + ) +} + +fun asBackupRequestList(arr: ReadableArray): List { + val list = ArrayList() + for (value in arr.toArrayList()) { + when (value) { + is ReadableMap -> list.add(asBackupRequest(value)!!) + else -> throw LiquidSdkException.Generic(errUnexpectedType("${value::class.java.name}")) + } + } + return list +} + fun asConnectRequest(connectRequest: ReadableMap): ConnectRequest? { if (!validateMandatoryFields( connectRequest, diff --git a/packages/react-native/android/src/main/java/com/breezliquidsdk/BreezLiquidSDKModule.kt b/packages/react-native/android/src/main/java/com/breezliquidsdk/BreezLiquidSDKModule.kt index 70af62f..78f30e1 100644 --- a/packages/react-native/android/src/main/java/com/breezliquidsdk/BreezLiquidSDKModule.kt +++ b/packages/react-native/android/src/main/java/com/breezliquidsdk/BreezLiquidSDKModule.kt @@ -218,10 +218,17 @@ class BreezLiquidSDKModule(reactContext: ReactApplicationContext) : ReactContext } @ReactMethod - fun backup(promise: Promise) { + fun backup( + req: ReadableMap, + promise: Promise, + ) { executor.execute { try { - getBindingLiquidSdk().backup() + val backupRequest = + asBackupRequest( + req, + ) ?: run { throw LiquidSdkException.Generic(errMissingMandatoryField("req", "BackupRequest")) } + getBindingLiquidSdk().backup(backupRequest) promise.resolve(readableMapOf("status" to "ok")) } catch (e: Exception) { promise.reject(e.javaClass.simpleName.replace("Exception", "Error"), e.message, e) diff --git a/packages/react-native/ios/BreezLiquidSDKMapper.swift b/packages/react-native/ios/BreezLiquidSDKMapper.swift index 59d8700..206f4fa 100644 --- a/packages/react-native/ios/BreezLiquidSDKMapper.swift +++ b/packages/react-native/ios/BreezLiquidSDKMapper.swift @@ -2,6 +2,42 @@ import BreezLiquidSDK import Foundation enum BreezLiquidSDKMapper { + static func asBackupRequest(backupRequest: [String: Any?]) throws -> BackupRequest { + var backupPath: String? + if hasNonNilKey(data: backupRequest, key: "backupPath") { + guard let backupPathTmp = backupRequest["backupPath"] as? String else { + throw LiquidSdkError.Generic(message: errUnexpectedValue(fieldName: "backupPath")) + } + backupPath = backupPathTmp + } + + return BackupRequest( + backupPath: backupPath) + } + + static func dictionaryOf(backupRequest: BackupRequest) -> [String: Any?] { + return [ + "backupPath": backupRequest.backupPath == nil ? nil : backupRequest.backupPath, + ] + } + + static func asBackupRequestList(arr: [Any]) throws -> [BackupRequest] { + var list = [BackupRequest]() + for value in arr { + if let val = value as? [String: Any?] { + var backupRequest = try asBackupRequest(backupRequest: val) + list.append(backupRequest) + } else { + throw LiquidSdkError.Generic(message: errUnexpectedType(typeName: "BackupRequest")) + } + } + return list + } + + static func arrayOf(backupRequestList: [BackupRequest]) -> [Any] { + return backupRequestList.map { v -> [String: Any?] in dictionaryOf(backupRequest: v) } + } + static func asConnectRequest(connectRequest: [String: Any?]) throws -> ConnectRequest { guard let mnemonic = connectRequest["mnemonic"] as? String else { throw LiquidSdkError.Generic(message: errMissingMandatoryField(fieldName: "mnemonic", typeName: "ConnectRequest")) diff --git a/packages/react-native/ios/RNBreezLiquidSDK.m b/packages/react-native/ios/RNBreezLiquidSDK.m index 085444f..a3294a1 100644 --- a/packages/react-native/ios/RNBreezLiquidSDK.m +++ b/packages/react-native/ios/RNBreezLiquidSDK.m @@ -61,7 +61,8 @@ RCT_EXTERN_METHOD( ) RCT_EXTERN_METHOD( - backup: (RCTPromiseResolveBlock)resolve + backup: (NSDictionary*)req + resolve: (RCTPromiseResolveBlock)resolve reject: (RCTPromiseRejectBlock)reject ) diff --git a/packages/react-native/ios/RNBreezLiquidSDK.swift b/packages/react-native/ios/RNBreezLiquidSDK.swift index 9d4fa6d..dff37dd 100644 --- a/packages/react-native/ios/RNBreezLiquidSDK.swift +++ b/packages/react-native/ios/RNBreezLiquidSDK.swift @@ -171,10 +171,11 @@ class RNBreezLiquidSDK: RCTEventEmitter { } } - @objc(backup:reject:) - func backup(_ resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) { + @objc(backup:resolve:reject:) + func backup(_ req: [String: Any], resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) { do { - try getBindingLiquidSdk().backup() + let backupRequest = try BreezLiquidSDKMapper.asBackupRequest(backupRequest: req) + try getBindingLiquidSdk().backup(req: backupRequest) resolve(["status": "ok"]) } catch let err { rejectErr(err: err, reject: reject) diff --git a/packages/react-native/src/index.ts b/packages/react-native/src/index.ts index 01afb62..bf2bc89 100644 --- a/packages/react-native/src/index.ts +++ b/packages/react-native/src/index.ts @@ -19,6 +19,10 @@ const BreezLiquidSDK = NativeModules.RNBreezLiquidSDK const BreezLiquidSDKEmitter = new NativeEventEmitter(BreezLiquidSDK) +export interface BackupRequest { + backupPath?: string +} + export interface ConnectRequest { mnemonic: string network: Network @@ -179,8 +183,8 @@ export const sync = async (): Promise => { await BreezLiquidSDK.sync() } -export const backup = async (): Promise => { - await BreezLiquidSDK.backup() +export const backup = async (req: BackupRequest): Promise => { + await BreezLiquidSDK.backup(req) } export const restore = async (req: RestoreRequest): Promise => {