diff --git a/Cargo.lock b/Cargo.lock index 4c1d4d60..afd7a52f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2313,9 +2313,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.9" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", diff --git a/src/event.rs b/src/event.rs index 0ea04785..ed09622a 100644 --- a/src/event.rs +++ b/src/event.rs @@ -22,11 +22,10 @@ impl LipaEventListener { impl EventListener for LipaEventListener { fn on_event(&self, e: BreezEvent) { + report_event_for_analytics(&e, &self.analytics_interceptor); match e { BreezEvent::NewBlock { .. } => {} BreezEvent::InvoicePaid { details } => { - self.analytics_interceptor - .request_succeeded(details.clone()); self.events_callback.payment_received(details.payment_hash) } BreezEvent::Synced => { @@ -34,14 +33,12 @@ impl EventListener for LipaEventListener { } BreezEvent::PaymentSucceed { details } => { if let PaymentDetails::Ln { data } = details.details.clone() { - self.analytics_interceptor.pay_succeeded(details); self.events_callback .payment_sent(data.payment_hash, data.payment_preimage) } } BreezEvent::PaymentFailed { details } => { if let Some(invoice) = details.invoice.clone() { - self.analytics_interceptor.pay_failed(details); self.events_callback.payment_failed(invoice.payment_hash) } } @@ -51,3 +48,29 @@ impl EventListener for LipaEventListener { } } } + +pub(crate) fn report_event_for_analytics( + e: &BreezEvent, + analytics_interceptor: &AnalyticsInterceptor, +) { + match e { + BreezEvent::NewBlock { .. } => {} + BreezEvent::InvoicePaid { details } => { + analytics_interceptor.request_succeeded(details.clone()); + } + BreezEvent::Synced => {} + BreezEvent::PaymentSucceed { details } => { + if let PaymentDetails::Ln { .. } = details.details.clone() { + analytics_interceptor.pay_succeeded(details.clone()); + } + } + BreezEvent::PaymentFailed { details } => { + if details.invoice.is_some() { + analytics_interceptor.pay_failed(details.clone()); + } + } + BreezEvent::BackupStarted => {} + BreezEvent::BackupSucceeded => {} + BreezEvent::BackupFailed { .. } => {} + } +} diff --git a/src/notification_handling.rs b/src/notification_handling.rs index 538edd92..404f6b75 100644 --- a/src/notification_handling.rs +++ b/src/notification_handling.rs @@ -1,15 +1,23 @@ +use crate::analytics::{derive_analytics_keys, AnalyticsInterceptor}; use crate::async_runtime::AsyncRuntime; +use crate::auth::build_async_auth; +use crate::data_store::DataStore; use crate::environment::Environment; use crate::errors::Result; +use crate::event::report_event_for_analytics; use crate::logger::init_logger_once; -use crate::{enable_backtrace, start_sdk, Config, RuntimeErrorCode, LOGS_DIR, LOG_LEVEL}; +use crate::{ + enable_backtrace, sanitize_input, start_sdk, Config, RuntimeErrorCode, UserPreferences, + DB_FILENAME, LOGS_DIR, LOG_LEVEL, +}; use breez_sdk_core::{BreezEvent, BreezServices, EventListener, PaymentStatus}; use log::{debug, error}; +use parrot::AnalyticsClient; use perro::{permanent_failure, MapToError}; use serde::Deserialize; use std::path::Path; use std::sync::mpsc::{Receiver, RecvTimeoutError, Sender}; -use std::sync::{mpsc, Arc}; +use std::sync::{mpsc, Arc, Mutex}; use std::time::{Duration, Instant}; const TIMEOUT: Duration = Duration::from_secs(60); @@ -62,7 +70,11 @@ pub fn handle_notification( let rt = AsyncRuntime::new()?; let (tx, rx) = mpsc::channel(); - let event_listener = Box::new(NotificationHandlerEventListener { event_sender: tx }); + let analytics_interceptor = build_analytics_interceptor(&config, &rt)?; + let event_listener = Box::new(NotificationHandlerEventListener::new( + tx, + analytics_interceptor, + )); let environment = Environment::load(config.environment)?; let sdk = rt .handle() @@ -75,6 +87,36 @@ pub fn handle_notification( } } +fn build_analytics_interceptor(config: &Config, rt: &AsyncRuntime) -> Result { + let user_preferences = Arc::new(Mutex::new(UserPreferences { + fiat_currency: config.fiat_currency.clone(), + timezone_config: config.timezone_config.clone(), + })); + + let environment = Environment::load(config.environment)?; + let strong_typed_seed = sanitize_input::strong_type_seed(&config.seed)?; + let async_auth = Arc::new(build_async_auth( + &strong_typed_seed, + environment.backend_url.clone(), + )?); + + let analytics_client = AnalyticsClient::new( + environment.backend_url.clone(), + derive_analytics_keys(&strong_typed_seed)?, + Arc::clone(&async_auth), + ); + + let db_path = format!("{}/{DB_FILENAME}", config.local_persistence_path); + let data_store = DataStore::new(&db_path)?; + let analytics_config = data_store.retrieve_analytics_config()?; + Ok(AnalyticsInterceptor::new( + analytics_client, + Arc::clone(&user_preferences), + rt.handle(), + analytics_config, + )) +} + fn handle_payment_received_notification( rt: AsyncRuntime, sdk: Arc, @@ -135,10 +177,21 @@ enum Payload { struct NotificationHandlerEventListener { event_sender: Sender, + analytics_interceptor: AnalyticsInterceptor, +} + +impl NotificationHandlerEventListener { + fn new(event_sender: Sender, analytics_interceptor: AnalyticsInterceptor) -> Self { + NotificationHandlerEventListener { + event_sender, + analytics_interceptor, + } + } } impl EventListener for NotificationHandlerEventListener { fn on_event(&self, e: BreezEvent) { + report_event_for_analytics(&e, &self.analytics_interceptor); let _ = self.event_sender.send(e); } }