1use std::future::Future;
14use std::sync::Arc;
15
16use anyhow::{anyhow, Result};
17use flutter_rust_bridge::StreamSink;
18use log::{Level, LevelFilter, Metadata, Record};
19use once_cell::sync::{Lazy, OnceCell};
20use sdk_common::invoice;
21pub use sdk_common::prelude::{
22 parse, AesSuccessActionDataDecrypted, AesSuccessActionDataResult, BitcoinAddressData,
23 CurrencyInfo, FiatCurrency, InputType, LNInvoice, LnUrlAuthRequestData, LnUrlCallbackStatus,
24 LnUrlError, LnUrlErrorData, LnUrlPayErrorData, LnUrlPayRequest, LnUrlPayRequestData,
25 LnUrlWithdrawRequest, LnUrlWithdrawRequestData, LnUrlWithdrawResult, LnUrlWithdrawSuccessData,
26 LocaleOverrides, LocalizedName, MessageSuccessActionData, Network, Rate, RouteHint,
27 RouteHintHop, SuccessActionProcessed, Symbol, UrlSuccessActionData,
28};
29use tokio::sync::Mutex;
30
31use crate::breez_services::{self, BreezEvent, BreezServices, EventListener};
32use crate::chain::RecommendedFees;
33use crate::error::{
34 ConnectError, ReceiveOnchainError, ReceivePaymentError, RedeemOnchainError, SdkError,
35 SendOnchainError, SendPaymentError,
36};
37use crate::lsp::LspInformation;
38use crate::models::{Config, LogEntry, NodeState, Payment, SwapInfo};
39use crate::{
40 BackupStatus, BuyBitcoinRequest, BuyBitcoinResponse, CheckMessageRequest, CheckMessageResponse,
41 ConfigureNodeRequest, ConnectRequest, EnvironmentType, ListPaymentsRequest, ListSwapsRequest,
42 LnUrlAuthError, NodeConfig, NodeCredentials, OnchainPaymentLimitsResponse,
43 OpenChannelFeeRequest, OpenChannelFeeResponse, PayOnchainRequest, PayOnchainResponse,
44 PrepareOnchainPaymentRequest, PrepareOnchainPaymentResponse, PrepareRedeemOnchainFundsRequest,
45 PrepareRedeemOnchainFundsResponse, PrepareRefundRequest, PrepareRefundResponse,
46 ReceiveOnchainRequest, ReceivePaymentRequest, ReceivePaymentResponse,
47 RedeemOnchainFundsRequest, RedeemOnchainFundsResponse, RefundRequest, RefundResponse,
48 ReportIssueRequest, ReverseSwapFeesRequest, ReverseSwapInfo, ReverseSwapPairInfo,
49 SendPaymentRequest, SendPaymentResponse, SendSpontaneousPaymentRequest,
50 ServiceHealthCheckResponse, SignMessageRequest, SignMessageResponse, StaticBackupRequest,
51 StaticBackupResponse,
52};
53
54use flutter_rust_bridge::frb;
62
63#[frb(mirror(LnUrlAuthRequestData))]
64pub struct _LnUrlAuthRequestData {
65 pub k1: String,
66 pub action: Option<String>,
67 pub domain: String,
68 pub url: String,
69}
70
71#[frb(mirror(LnUrlErrorData))]
72pub struct _LnUrlErrorData {
73 pub reason: String,
74}
75
76#[frb(mirror(LnUrlCallbackStatus))]
77pub enum _LnUrlCallbackStatus {
78 Ok,
79 ErrorStatus { data: LnUrlErrorData },
80}
81
82#[frb(mirror(Network))]
83pub enum _Network {
84 Bitcoin,
85 Testnet,
86 Signet,
87 Regtest,
88}
89
90#[frb(mirror(LNInvoice))]
91pub struct _LNInvoice {
92 pub bolt11: String,
93 pub network: Network,
94 pub payee_pubkey: String,
95 pub payment_hash: String,
96 pub description: Option<String>,
97 pub description_hash: Option<String>,
98 pub amount_msat: Option<u64>,
99 pub timestamp: u64,
100 pub expiry: u64,
101 pub routing_hints: Vec<RouteHint>,
102 pub payment_secret: Vec<u8>,
103 pub min_final_cltv_expiry_delta: u64,
104}
105
106#[frb(mirror(RouteHint))]
107pub struct _RouteHint {
108 pub hops: Vec<RouteHintHop>,
109}
110
111#[frb(mirror(RouteHintHop))]
112pub struct _RouteHintHop {
113 pub src_node_id: String,
114 pub short_channel_id: String,
115 pub fees_base_msat: u32,
116 pub fees_proportional_millionths: u32,
117 pub cltv_expiry_delta: u64,
118 pub htlc_minimum_msat: Option<u64>,
119 pub htlc_maximum_msat: Option<u64>,
120}
121
122#[frb(mirror(LnUrlPayRequest))]
123pub struct _LnUrlPayRequest {
124 pub data: LnUrlPayRequestData,
125 pub amount_msat: u64,
126 pub use_trampoline: bool,
127 pub comment: Option<String>,
128 pub payment_label: Option<String>,
129 pub validate_success_action_url: Option<bool>,
130}
131
132#[frb(mirror(LnUrlPayRequestData))]
133pub struct _LnUrlPayRequestData {
134 pub callback: String,
135 pub min_sendable: u64,
136 pub max_sendable: u64,
137 pub metadata_str: String,
138 pub comment_allowed: u16,
139 pub domain: String,
140 pub allows_nostr: bool,
141 pub nostr_pubkey: Option<String>,
142 pub ln_address: Option<String>,
143}
144
145#[frb(mirror(LnUrlWithdrawRequest))]
146pub struct _LnUrlWithdrawRequest {
147 pub data: LnUrlWithdrawRequestData,
148 pub amount_msat: u64,
149 pub description: Option<String>,
150}
151
152#[frb(mirror(LnUrlWithdrawRequestData))]
153pub struct _LnUrlWithdrawRequestData {
154 pub callback: String,
155 pub k1: String,
156 pub default_description: String,
157 pub min_withdrawable: u64,
158 pub max_withdrawable: u64,
159}
160
161#[frb(mirror(InputType))]
162pub enum _InputType {
163 BitcoinAddress {
164 address: BitcoinAddressData,
165 },
166 Bolt11 {
167 invoice: LNInvoice,
168 },
169 NodeId {
170 node_id: String,
171 },
172 Url {
173 url: String,
174 },
175 LnUrlPay {
176 data: LnUrlPayRequestData,
177 bip353_address: Option<String>,
178 },
179 LnUrlWithdraw {
180 data: LnUrlWithdrawRequestData,
181 },
182 LnUrlAuth {
183 data: LnUrlAuthRequestData,
184 },
185 LnUrlError {
186 data: LnUrlErrorData,
187 },
188}
189
190#[frb(mirror(BitcoinAddressData))]
191pub struct _BitcoinAddressData {
192 pub address: String,
193 pub network: Network,
194 pub amount_sat: Option<u64>,
195 pub label: Option<String>,
196 pub message: Option<String>,
197}
198
199#[frb(mirror(SuccessActionProcessed))]
200pub enum _SuccessActionProcessed {
201 Aes { result: AesSuccessActionDataResult },
202 Message { data: MessageSuccessActionData },
203 Url { data: UrlSuccessActionData },
204}
205
206#[frb(mirror(AesSuccessActionDataResult))]
207pub enum _AesSuccessActionDataResult {
208 Decrypted { data: AesSuccessActionDataDecrypted },
209 ErrorStatus { reason: String },
210}
211
212#[frb(mirror(AesSuccessActionDataDecrypted))]
213pub struct _AesSuccessActionDataDecrypted {
214 pub description: String,
215 pub plaintext: String,
216}
217
218#[frb(mirror(MessageSuccessActionData))]
219pub struct _MessageSuccessActionData {
220 pub message: String,
221}
222
223#[frb(mirror(UrlSuccessActionData))]
224pub struct _UrlSuccessActionData {
225 pub description: String,
226 pub url: String,
227}
228
229#[frb(mirror(LnUrlPayErrorData))]
230pub struct _LnUrlPayErrorData {
231 pub payment_hash: String,
232 pub reason: String,
233}
234
235#[frb(mirror(LnUrlPayError))]
236pub enum _LnUrlPayError {
237 AlreadyPaid,
238 Generic { err: String },
239 InvalidAmount { err: String },
240 InvalidInvoice { err: String },
241 InvalidNetwork { err: String },
242 InvalidUri { err: String },
243 InvoiceExpired { err: String },
244 PaymentFailed { err: String },
245 PaymentTimeout { err: String },
246 RouteNotFound { err: String },
247 RouteTooExpensive { err: String },
248 ServiceConnectivity { err: String },
249}
250
251#[frb(mirror(LnUrlWithdrawResult))]
252pub enum _LnUrlWithdrawResult {
253 Ok { data: LnUrlWithdrawSuccessData },
254 Timeout { data: LnUrlWithdrawSuccessData },
255 ErrorStatus { data: LnUrlErrorData },
256}
257
258#[frb(mirror(LnUrlWithdrawSuccessData))]
259pub struct _LnUrlWithdrawSuccessData {
260 pub invoice: LNInvoice,
261}
262
263#[frb(mirror(Rate))]
264pub struct _Rate {
265 pub coin: String,
266 pub value: f64,
267}
268
269#[frb(mirror(FiatCurrency))]
270pub struct _FiatCurrency {
271 pub id: String,
272 pub info: CurrencyInfo,
273}
274
275#[frb(mirror(CurrencyInfo))]
276pub struct _CurrencyInfo {
277 pub name: String,
278 pub fraction_size: u32,
279 pub spacing: Option<u32>,
280 pub symbol: Option<Symbol>,
281 pub uniq_symbol: Option<Symbol>,
282 pub localized_name: Vec<LocalizedName>,
283 pub locale_overrides: Vec<LocaleOverrides>,
284}
285
286#[frb(mirror(LocaleOverrides))]
287pub struct _LocaleOverrides {
288 pub locale: String,
289 pub spacing: Option<u32>,
290 pub symbol: Symbol,
291}
292
293#[frb(mirror(LocalizedName))]
294pub struct _LocalizedName {
295 pub locale: String,
296 pub name: String,
297}
298
299#[frb(mirror(Symbol))]
300pub struct _Symbol {
301 pub grapheme: Option<String>,
302 pub template: Option<String>,
303 pub rtl: Option<bool>,
304 pub position: Option<u32>,
305}
306
307static BREEZ_SERVICES_INSTANCE: Lazy<Mutex<Option<Arc<BreezServices>>>> =
312 Lazy::new(|| Mutex::new(None));
313static NOTIFICATION_STREAM: OnceCell<StreamSink<BreezEvent>> = OnceCell::new();
314static RT: Lazy<tokio::runtime::Runtime> = Lazy::new(|| tokio::runtime::Runtime::new().unwrap());
315static LOG_INIT: OnceCell<bool> = OnceCell::new();
316
317pub fn connect(req: ConnectRequest) -> Result<()> {
321 block_on(async move {
322 let mut locked = BREEZ_SERVICES_INSTANCE.lock().await;
323 match *locked {
324 None => {
325 let breez_services =
326 BreezServices::connect(req, Box::new(BindingEventListener {})).await?;
327
328 *locked = Some(breez_services);
329 Ok(())
330 }
331 Some(_) => Err(ConnectError::Generic {
332 err: "Static node services already set, please call disconnect() first".into(),
333 }),
334 }
335 })
336 .map_err(anyhow::Error::new::<ConnectError>)
337}
338
339pub fn is_initialized() -> bool {
341 block_on(async { get_breez_services().await.is_ok() })
342}
343
344pub fn sync() -> Result<()> {
346 block_on(async { get_breez_services().await?.sync().await })
347 .map_err(anyhow::Error::new::<SdkError>)
348}
349
350pub fn node_credentials() -> Result<Option<NodeCredentials>> {
352 block_on(async { get_breez_services().await?.node_credentials().await })
353 .map_err(anyhow::Error::new::<SdkError>)
354}
355
356pub fn node_info() -> Result<NodeState> {
358 block_on(async {
359 get_breez_services()
360 .await?
361 .node_info()
362 .map_err(anyhow::Error::new::<SdkError>)
363 })
364}
365
366pub fn configure_node(req: ConfigureNodeRequest) -> Result<()> {
368 block_on(async { get_breez_services().await?.configure_node(req).await })
369 .map_err(anyhow::Error::new::<SdkError>)
370}
371
372pub fn disconnect() -> Result<()> {
374 block_on(async {
375 get_breez_services().await?.disconnect().await?;
377 let mut locked_sdk_instance = BREEZ_SERVICES_INSTANCE.lock().await;
378 *locked_sdk_instance = None;
379
380 Ok(())
381 })
382 .map_err(anyhow::Error::new::<SdkError>)
383}
384
385pub fn sign_message(req: SignMessageRequest) -> Result<SignMessageResponse> {
387 block_on(async { get_breez_services().await?.sign_message(req).await })
388 .map_err(anyhow::Error::new::<SdkError>)
389}
390
391pub fn check_message(req: CheckMessageRequest) -> Result<CheckMessageResponse> {
393 block_on(async { get_breez_services().await?.check_message(req).await })
394 .map_err(anyhow::Error::new::<SdkError>)
395}
396
397pub fn mnemonic_to_seed(phrase: String) -> Result<Vec<u8>> {
401 breez_services::mnemonic_to_seed(phrase)
402}
403
404pub fn default_config(
406 env_type: EnvironmentType,
407 api_key: String,
408 node_config: NodeConfig,
409) -> Config {
410 BreezServices::default_config(env_type, api_key, node_config)
411}
412
413pub fn static_backup(req: StaticBackupRequest) -> Result<StaticBackupResponse> {
415 BreezServices::static_backup(req).map_err(anyhow::Error::new::<SdkError>)
416}
417
418pub fn service_health_check(api_key: String) -> Result<ServiceHealthCheckResponse> {
420 block_on(async { BreezServices::service_health_check(api_key).await })
421 .map_err(anyhow::Error::new::<SdkError>)
422}
423
424pub fn breez_events_stream(s: StreamSink<BreezEvent>) -> Result<()> {
428 NOTIFICATION_STREAM
429 .set(s)
430 .map_err(|_| anyhow!("Events stream already created"))?;
431 Ok(())
432}
433
434pub fn breez_log_stream(s: StreamSink<LogEntry>) -> Result<()> {
436 LOG_INIT
437 .set(true)
438 .map_err(|_| anyhow!("Log stream already created"))?;
439 BindingLogger::init(s);
440 Ok(())
441}
442
443pub fn list_lsps() -> Result<Vec<LspInformation>> {
447 block_on(async { get_breez_services().await?.list_lsps().await })
448 .map_err(anyhow::Error::new::<SdkError>)
449}
450
451pub fn connect_lsp(lsp_id: String) -> Result<()> {
453 block_on(async { get_breez_services().await?.connect_lsp(lsp_id).await })
454 .map_err(anyhow::Error::new::<SdkError>)
455}
456
457pub fn lsp_id() -> Result<Option<String>> {
459 block_on(async { get_breez_services().await?.lsp_id().await })
460 .map_err(anyhow::Error::new::<SdkError>)
461}
462
463pub fn fetch_lsp_info(id: String) -> Result<Option<LspInformation>> {
465 block_on(async { get_breez_services().await?.fetch_lsp_info(id).await })
466 .map_err(anyhow::Error::new::<SdkError>)
467}
468
469pub fn lsp_info() -> Result<LspInformation> {
471 block_on(async { get_breez_services().await?.lsp_info().await })
472 .map_err(anyhow::Error::new::<SdkError>)
473}
474
475pub fn close_lsp_channels() -> Result<()> {
477 block_on(async {
478 _ = get_breez_services().await?.close_lsp_channels().await?;
479 Ok(())
480 })
481}
482
483pub fn register_webhook(webhook_url: String) -> Result<()> {
484 block_on(async {
485 get_breez_services()
486 .await?
487 .register_webhook(webhook_url)
488 .await
489 })
490 .map_err(anyhow::Error::new::<SdkError>)
491}
492
493pub fn unregister_webhook(webhook_url: String) -> Result<()> {
494 block_on(async {
495 get_breez_services()
496 .await?
497 .unregister_webhook(webhook_url)
498 .await
499 })
500 .map_err(anyhow::Error::new::<SdkError>)
501}
502
503pub fn backup() -> Result<()> {
507 block_on(async { get_breez_services().await?.backup().await })
508 .map_err(anyhow::Error::new::<SdkError>)
509}
510
511pub fn backup_status() -> Result<BackupStatus> {
513 block_on(async { get_breez_services().await?.backup_status() })
514 .map_err(anyhow::Error::new::<SdkError>)
515}
516
517pub fn parse_invoice(invoice: String) -> Result<LNInvoice> {
520 invoice::parse_invoice(&invoice).map_err(|e| anyhow::Error::new::<SdkError>(e.into()))
521}
522
523pub fn parse_input(input: String) -> Result<InputType> {
524 block_on(async { parse(&input, None).await })
525}
526
527pub fn list_payments(req: ListPaymentsRequest) -> Result<Vec<Payment>> {
531 block_on(async { get_breez_services().await?.list_payments(req).await })
532 .map_err(anyhow::Error::new::<SdkError>)
533}
534
535pub fn payment_by_hash(hash: String) -> Result<Option<Payment>> {
537 block_on(async { get_breez_services().await?.payment_by_hash(hash).await })
538 .map_err(anyhow::Error::new::<SdkError>)
539}
540
541pub fn set_payment_metadata(hash: String, metadata: String) -> Result<()> {
543 block_on(async {
544 get_breez_services()
545 .await?
546 .set_payment_metadata(hash, metadata)
547 .await
548 })
549 .map_err(anyhow::Error::new::<SdkError>)
550}
551
552pub fn send_payment(req: SendPaymentRequest) -> Result<SendPaymentResponse> {
556 block_on(async { get_breez_services().await?.send_payment(req).await })
557 .map_err(anyhow::Error::new::<SendPaymentError>)
558}
559
560pub fn send_spontaneous_payment(req: SendSpontaneousPaymentRequest) -> Result<SendPaymentResponse> {
562 block_on(async {
563 get_breez_services()
564 .await?
565 .send_spontaneous_payment(req)
566 .await
567 })
568 .map_err(anyhow::Error::new::<SendPaymentError>)
569}
570
571pub fn receive_payment(req: ReceivePaymentRequest) -> Result<ReceivePaymentResponse> {
573 block_on(async { get_breez_services().await?.receive_payment(req).await })
574 .map_err(anyhow::Error::new::<ReceivePaymentError>)
575}
576
577pub fn lnurl_pay(req: LnUrlPayRequest) -> Result<crate::lnurl::pay::LnUrlPayResult> {
581 block_on(async { get_breez_services().await?.lnurl_pay(req).await })
582 .map_err(anyhow::Error::new::<crate::LnUrlPayError>)
583}
584
585pub fn lnurl_withdraw(req: LnUrlWithdrawRequest) -> Result<LnUrlWithdrawResult> {
587 block_on(async { get_breez_services().await?.lnurl_withdraw(req).await })
588 .map_err(anyhow::Error::new::<crate::LnUrlWithdrawError>)
589}
590
591pub fn lnurl_auth(req_data: crate::LnUrlAuthRequestData) -> Result<LnUrlCallbackStatus> {
593 block_on(async { get_breez_services().await?.lnurl_auth(req_data).await })
594 .map_err(anyhow::Error::new::<LnUrlAuthError>)
595}
596
597pub fn report_issue(req: ReportIssueRequest) -> Result<()> {
601 block_on(async { get_breez_services().await?.report_issue(req).await })
602 .map_err(anyhow::Error::new::<SdkError>)
603}
604
605pub fn fetch_fiat_rates() -> Result<Vec<Rate>> {
609 block_on(async { get_breez_services().await?.fetch_fiat_rates().await })
610 .map_err(anyhow::Error::new::<SdkError>)
611}
612
613pub fn list_fiat_currencies() -> Result<Vec<FiatCurrency>> {
615 block_on(async { get_breez_services().await?.list_fiat_currencies().await })
616 .map_err(anyhow::Error::new::<SdkError>)
617}
618
619pub fn pay_onchain(req: PayOnchainRequest) -> Result<PayOnchainResponse> {
623 block_on(async { get_breez_services().await?.pay_onchain(req).await })
624 .map_err(anyhow::Error::new::<SendOnchainError>)
625}
626
627pub fn receive_onchain(req: ReceiveOnchainRequest) -> Result<SwapInfo> {
629 block_on(async { get_breez_services().await?.receive_onchain(req).await })
630 .map_err(anyhow::Error::new::<ReceiveOnchainError>)
631}
632
633pub fn buy_bitcoin(req: BuyBitcoinRequest) -> Result<BuyBitcoinResponse> {
635 block_on(async { get_breez_services().await?.buy_bitcoin(req).await })
636 .map_err(anyhow::Error::new::<ReceiveOnchainError>)
637}
638
639pub fn redeem_onchain_funds(req: RedeemOnchainFundsRequest) -> Result<RedeemOnchainFundsResponse> {
641 block_on(async { get_breez_services().await?.redeem_onchain_funds(req).await })
642 .map_err(anyhow::Error::new::<RedeemOnchainError>)
643}
644
645pub fn prepare_redeem_onchain_funds(
647 req: PrepareRedeemOnchainFundsRequest,
648) -> Result<PrepareRedeemOnchainFundsResponse> {
649 block_on(async {
650 get_breez_services()
651 .await?
652 .prepare_redeem_onchain_funds(req)
653 .await
654 })
655 .map_err(anyhow::Error::new::<RedeemOnchainError>)
656}
657
658pub fn list_refundables() -> Result<Vec<SwapInfo>> {
662 block_on(async { get_breez_services().await?.list_refundables().await })
663 .map_err(anyhow::Error::new::<SdkError>)
664}
665
666pub fn prepare_refund(req: PrepareRefundRequest) -> Result<PrepareRefundResponse> {
668 block_on(async { get_breez_services().await?.prepare_refund(req).await })
669 .map_err(anyhow::Error::new::<SdkError>)
670}
671
672pub fn refund(req: RefundRequest) -> Result<RefundResponse> {
674 block_on(async { get_breez_services().await?.refund(req).await })
675 .map_err(anyhow::Error::new::<SdkError>)
676}
677
678pub fn rescan_swaps() -> Result<()> {
680 block_on(async { get_breez_services().await?.rescan_swaps().await })
681 .map_err(anyhow::Error::new::<SdkError>)
682}
683
684pub fn redeem_swap(swap_address: String) -> Result<()> {
686 block_on(async { get_breez_services().await?.redeem_swap(swap_address).await })
687 .map_err(anyhow::Error::new::<SdkError>)
688}
689
690pub fn in_progress_swap() -> Result<Option<SwapInfo>> {
694 block_on(async { get_breez_services().await?.in_progress_swap().await })
695 .map_err(anyhow::Error::new::<SdkError>)
696}
697
698pub fn list_swaps(req: ListSwapsRequest) -> Result<Vec<SwapInfo>> {
700 block_on(async { get_breez_services().await?.list_swaps(req).await })
701 .map_err(anyhow::Error::new::<SdkError>)
702}
703
704pub fn claim_reverse_swap(lockup_address: String) -> Result<()> {
706 block_on(async {
707 get_breez_services()
708 .await?
709 .claim_reverse_swap(lockup_address)
710 .await
711 })
712 .map_err(anyhow::Error::new::<SdkError>)
713}
714
715pub fn open_channel_fee(req: OpenChannelFeeRequest) -> Result<OpenChannelFeeResponse> {
719 block_on(async { get_breez_services().await?.open_channel_fee(req).await })
720 .map_err(anyhow::Error::new::<SdkError>)
721}
722
723pub fn fetch_reverse_swap_fees(req: ReverseSwapFeesRequest) -> Result<ReverseSwapPairInfo> {
725 block_on(async {
726 get_breez_services()
727 .await?
728 .fetch_reverse_swap_fees(req)
729 .await
730 })
731 .map_err(anyhow::Error::new::<SdkError>)
732}
733
734pub fn onchain_payment_limits() -> Result<OnchainPaymentLimitsResponse> {
736 block_on(async { get_breez_services().await?.onchain_payment_limits().await })
737 .map_err(anyhow::Error::new::<SdkError>)
738}
739
740pub fn prepare_onchain_payment(
742 req: PrepareOnchainPaymentRequest,
743) -> Result<PrepareOnchainPaymentResponse> {
744 block_on(async {
745 get_breez_services()
746 .await?
747 .prepare_onchain_payment(req)
748 .await
749 .map_err(anyhow::Error::new::<SendOnchainError>)
750 })
751}
752
753pub fn in_progress_onchain_payments() -> Result<Vec<ReverseSwapInfo>> {
755 block_on(async {
756 get_breez_services()
757 .await?
758 .in_progress_onchain_payments()
759 .await
760 })
761 .map_err(anyhow::Error::new::<SdkError>)
762}
763
764pub fn recommended_fees() -> Result<RecommendedFees> {
766 block_on(async { get_breez_services().await?.recommended_fees().await })
767 .map_err(anyhow::Error::new::<SdkError>)
768}
769
770pub fn execute_command(command: String) -> Result<String> {
774 block_on(async {
775 get_breez_services()
776 .await?
777 .execute_dev_command(command)
778 .await
779 })
780 .map_err(anyhow::Error::new::<SdkError>)
781}
782
783pub fn generate_diagnostic_data() -> Result<String> {
785 block_on(async { get_breez_services().await?.generate_diagnostic_data().await })
786 .map_err(anyhow::Error::new::<SdkError>)
787}
788
789struct BindingEventListener;
792
793impl EventListener for BindingEventListener {
794 fn on_event(&self, e: BreezEvent) {
795 if let Some(stream) = NOTIFICATION_STREAM.get() {
796 stream.add(e);
797 }
798 }
799}
800
801struct BindingLogger {
802 log_stream: StreamSink<LogEntry>,
803}
804
805impl BindingLogger {
806 fn init(log_stream: StreamSink<LogEntry>) {
807 let binding_logger = BindingLogger { log_stream };
808 log::set_boxed_logger(Box::new(binding_logger)).unwrap();
809 log::set_max_level(LevelFilter::Trace);
810 }
811}
812
813impl log::Log for BindingLogger {
814 fn enabled(&self, m: &Metadata) -> bool {
815 m.level() <= Level::Trace
816 }
817
818 fn log(&self, record: &Record) {
819 if self.enabled(record.metadata()) {
820 self.log_stream.add(LogEntry {
821 line: record.args().to_string(),
822 level: record.level().as_str().to_string(),
823 });
824 }
825 }
826 fn flush(&self) {}
827}
828
829async fn get_breez_services() -> Result<Arc<BreezServices>, SdkError> {
830 match BREEZ_SERVICES_INSTANCE.lock().await.as_ref() {
831 None => Err(SdkError::Generic {
832 err: "Node service was not initialized".into(),
833 }),
834 Some(sdk) => Ok(sdk.clone()),
835 }
836}
837
838fn block_on<F: Future>(future: F) -> F::Output {
839 rt().block_on(future)
840}
841
842pub(crate) fn rt() -> &'static tokio::runtime::Runtime {
843 &RT
844}