From 7f4232ecb5f92a8d9a0b558a6491257beed3d07f Mon Sep 17 00:00:00 2001 From: benthecarman Date: Fri, 17 May 2024 14:39:03 -0500 Subject: [PATCH 1/2] Add unique message id to requests/responses --- src/bridge.rs | 91 ++++++++++++++++++++++-------- src/core.rs | 109 +++++++++++++++++++++++------------- src/fedimint_client.rs | 124 ++++++++++++++++++++++++++++------------- src/main.rs | 96 ++++++++++++++++++++----------- 4 files changed, 287 insertions(+), 133 deletions(-) diff --git a/src/bridge.rs b/src/bridge.rs index a73aaa3..febb155 100644 --- a/src/bridge.rs +++ b/src/bridge.rs @@ -5,6 +5,13 @@ use fedimint_core::config::ClientConfig; use fedimint_core::Amount; use fedimint_ln_common::lightning_invoice::Bolt11Invoice; use tokio::sync::mpsc; +use uuid::Uuid; + +#[derive(Debug, Clone)] +pub struct UICoreMsgPacket { + pub id: Uuid, + pub msg: UICoreMsg, +} #[derive(Debug, Clone)] pub enum UICoreMsg { @@ -33,6 +40,12 @@ pub enum ReceiveSuccessMsg { Onchain { txid: Txid }, } +#[derive(Debug, Clone)] +pub struct CoreUIMsgPacket { + pub id: Option, + pub msg: CoreUIMsg, +} + #[derive(Debug, Clone)] pub enum CoreUIMsg { Sending, @@ -58,7 +71,7 @@ pub enum CoreUIMsg { #[derive(Debug)] pub struct UIHandle { - ui_to_core_tx: mpsc::Sender, + ui_to_core_tx: mpsc::Sender, } #[derive(Debug, Clone)] @@ -68,61 +81,91 @@ pub enum BridgeError { } impl UIHandle { - pub async fn msg_send(&self, msg: UICoreMsg) { + pub async fn msg_send(&self, msg: UICoreMsgPacket) { self.ui_to_core_tx.send(msg).await.unwrap(); } - pub async fn send_lightning(&self, invoice: Bolt11Invoice) { - self.msg_send(UICoreMsg::SendLightning(invoice)).await; + pub async fn send_lightning(&self, id: Uuid, invoice: Bolt11Invoice) { + self.msg_send(UICoreMsgPacket { + msg: UICoreMsg::SendLightning(invoice), + id, + }) + .await; } - pub async fn send_onchain(&self, address: Address, amount_sats: Option) { - self.msg_send(UICoreMsg::SendOnChain { - address, - amount_sats, + pub async fn send_onchain(&self, id: Uuid, address: Address, amount_sats: Option) { + self.msg_send(UICoreMsgPacket { + msg: UICoreMsg::SendOnChain { + address, + amount_sats, + }, + id, }) .await; } - pub async fn receive(&self, amount: u64) { - self.msg_send(UICoreMsg::ReceiveLightning(Amount::from_sats(amount))) - .await; + pub async fn receive(&self, id: Uuid, amount: u64) { + self.msg_send(UICoreMsgPacket { + msg: UICoreMsg::ReceiveLightning(Amount::from_sats(amount)), + id, + }) + .await; } - pub async fn receive_onchain(&self) { - self.msg_send(UICoreMsg::ReceiveOnChain).await; + pub async fn receive_onchain(&self, id: Uuid) { + self.msg_send(UICoreMsgPacket { + msg: UICoreMsg::ReceiveOnChain, + id, + }) + .await; } - pub async fn unlock(&self, password: String) { - self.msg_send(UICoreMsg::Unlock(password)).await; + pub async fn unlock(&self, id: Uuid, password: String) { + self.msg_send(UICoreMsgPacket { + msg: UICoreMsg::Unlock(password), + id, + }) + .await; } - pub async fn add_federation(&self, invite: InviteCode) { - self.msg_send(UICoreMsg::AddFederation(invite)).await; + pub async fn add_federation(&self, id: Uuid, invite: InviteCode) { + self.msg_send(UICoreMsgPacket { + msg: UICoreMsg::AddFederation(invite), + id, + }) + .await; } - pub async fn peek_federation(&self, invite: InviteCode) { - self.msg_send(UICoreMsg::GetFederationInfo(invite)).await; + pub async fn peek_federation(&self, id: Uuid, invite: InviteCode) { + self.msg_send(UICoreMsgPacket { + msg: UICoreMsg::GetFederationInfo(invite), + id, + }) + .await; } - pub async fn get_seed_words(&self) { - self.msg_send(UICoreMsg::GetSeedWords).await; + pub async fn get_seed_words(&self, id: Uuid) { + self.msg_send(UICoreMsgPacket { + msg: UICoreMsg::GetSeedWords, + id, + }) + .await; } } impl CoreHandle { - pub async fn recv(&mut self) -> Option { + pub async fn recv(&mut self) -> Option { self.core_from_ui_rx.recv().await } } #[derive(Debug)] pub struct CoreHandle { - core_from_ui_rx: mpsc::Receiver, + core_from_ui_rx: mpsc::Receiver, } pub fn create_handles() -> (UIHandle, CoreHandle) { - let (ui_to_core_tx, core_from_ui_rx) = mpsc::channel::(50); + let (ui_to_core_tx, core_from_ui_rx) = mpsc::channel::(50); let ui_handle = UIHandle { ui_to_core_tx }; diff --git a/src/core.rs b/src/core.rs index ba88fb0..2e6b872 100644 --- a/src/core.rs +++ b/src/core.rs @@ -22,6 +22,7 @@ use iced::{ use log::{error, trace, warn}; use tokio::sync::RwLock; use tokio::task::spawn_blocking; +use uuid::Uuid; use crate::components::FederationItem; use crate::fedimint_client::{ @@ -54,10 +55,10 @@ struct HarborCore { } impl HarborCore { - async fn msg(&self, msg: CoreUIMsg) { + async fn msg(&self, id: Option, msg: CoreUIMsg) { self.tx .clone() - .send(Message::CoreMessage(msg)) + .send(Message::core_msg(id, msg)) .await .unwrap(); } @@ -69,14 +70,14 @@ impl HarborCore { balance += client.fedimint_client.get_balance().await; } - self.msg(CoreUIMsg::BalanceUpdated(balance)).await; + self.msg(None, CoreUIMsg::BalanceUpdated(balance)).await; let history = self.storage.get_transaction_history().unwrap(); - self.msg(CoreUIMsg::TransactionHistoryUpdated(history)) + self.msg(None, CoreUIMsg::TransactionHistoryUpdated(history)) .await; let federation_items = self.get_federation_items().await; - self.msg(CoreUIMsg::FederationListUpdated(federation_items)) + self.msg(None, CoreUIMsg::FederationListUpdated(federation_items)) .await; } @@ -85,7 +86,7 @@ impl HarborCore { self.clients.read().await.values().next().unwrap().clone() } - async fn send_lightning(&self, invoice: Bolt11Invoice) -> anyhow::Result<()> { + async fn send_lightning(&self, msg_id: Uuid, invoice: Bolt11Invoice) -> anyhow::Result<()> { if invoice.amount_milli_satoshis().is_none() { return Err(anyhow!("Invoice must have an amount")); } @@ -123,6 +124,7 @@ impl HarborCore { client.clone(), self.storage.clone(), op_id, + msg_id, sub, ) .await; @@ -134,6 +136,7 @@ impl HarborCore { client.clone(), self.storage.clone(), op_id, + msg_id, sub, ) .await; @@ -145,7 +148,11 @@ impl HarborCore { Ok(()) } - async fn receive_lightning(&self, amount: Amount) -> anyhow::Result { + async fn receive_lightning( + &self, + msg_id: Uuid, + amount: Amount, + ) -> anyhow::Result { let client = self.get_client().await.fedimint_client; let lightning_module = client.get_first_module::(); @@ -182,6 +189,7 @@ impl HarborCore { client.clone(), self.storage.clone(), op_id, + msg_id, subscription, ) .await; @@ -193,7 +201,12 @@ impl HarborCore { } /// Sends a given amount of sats to a given address, if the amount is None, send all funds - async fn send_onchain(&self, address: Address, sats: Option) -> anyhow::Result<()> { + async fn send_onchain( + &self, + msg_id: Uuid, + address: Address, + sats: Option, + ) -> anyhow::Result<()> { // todo go through all clients and select the first one that has enough balance let client = self.get_client().await.fedimint_client; let onchain = client.get_first_module::(); @@ -248,6 +261,7 @@ impl HarborCore { client.clone(), self.storage.clone(), op_id, + msg_id, sub, ) .await; @@ -255,7 +269,7 @@ impl HarborCore { Ok(()) } - async fn receive_onchain(&self) -> anyhow::Result
{ + async fn receive_onchain(&self, msg_id: Uuid) -> anyhow::Result
{ // todo add federation id selection let client = self.get_client().await.fedimint_client; let onchain = client.get_first_module::(); @@ -275,6 +289,7 @@ impl HarborCore { client.clone(), self.storage.clone(), op_id, + msg_id, sub, ) .await; @@ -364,10 +379,12 @@ pub fn run_core() -> Subscription { loop { let msg = core_handle.recv().await; - match msg { + let id = msg.as_ref().map(|m| m.id); + + match msg.map(|m| m.msg) { Some(UICoreMsg::Unlock(password)) => { log::info!("Sending unlock message"); - tx.send(Message::CoreMessage(CoreUIMsg::Unlocking)) + tx.send(Message::core_msg(id, CoreUIMsg::Unlocking)) .await .expect("should send"); @@ -382,9 +399,10 @@ pub fn run_core() -> Subscription { // probably invalid password error!("error using password: {e}"); - tx.send(Message::CoreMessage(CoreUIMsg::UnlockFailed( - "Invalid Password".to_string(), - ))) + tx.send(Message::core_msg( + id, + CoreUIMsg::UnlockFailed(e.to_string()), + )) .await .expect("should send"); continue; @@ -425,7 +443,7 @@ pub fn run_core() -> Subscription { stop, }; - tx.send(Message::CoreMessage(CoreUIMsg::UnlockSuccess)) + tx.send(Message::core_msg(id, CoreUIMsg::UnlockSuccess)) .await .expect("should send"); @@ -450,23 +468,26 @@ async fn process_core(core_handle: &mut bridge::CoreHandle, core: &HarborCore) { let core = core.clone(); tokio::spawn(async move { if let Some(msg) = msg { - match msg { + match msg.msg { UICoreMsg::SendLightning(invoice) => { log::info!("Got UICoreMsg::Send"); - core.msg(CoreUIMsg::Sending).await; - if let Err(e) = core.send_lightning(invoice).await { + core.msg(Some(msg.id), CoreUIMsg::Sending).await; + if let Err(e) = core.send_lightning(msg.id, invoice).await { error!("Error sending: {e}"); - core.msg(CoreUIMsg::SendFailure(e.to_string())).await; + core.msg(Some(msg.id), CoreUIMsg::SendFailure(e.to_string())) + .await; } } UICoreMsg::ReceiveLightning(amount) => { - core.msg(CoreUIMsg::ReceiveGenerating).await; - match core.receive_lightning(amount).await { + core.msg(Some(msg.id), CoreUIMsg::ReceiveGenerating).await; + match core.receive_lightning(msg.id, amount).await { Err(e) => { - core.msg(CoreUIMsg::ReceiveFailed(e.to_string())).await; + core.msg(Some(msg.id), CoreUIMsg::ReceiveFailed(e.to_string())) + .await; } Ok(invoice) => { - core.msg(CoreUIMsg::ReceiveInvoiceGenerated(invoice)).await; + core.msg(Some(msg.id), CoreUIMsg::ReceiveInvoiceGenerated(invoice)) + .await; } } } @@ -475,20 +496,23 @@ async fn process_core(core_handle: &mut bridge::CoreHandle, core: &HarborCore) { amount_sats, } => { log::info!("Got UICoreMsg::SendOnChain"); - core.msg(CoreUIMsg::Sending).await; - if let Err(e) = core.send_onchain(address, amount_sats).await { + core.msg(Some(msg.id), CoreUIMsg::Sending).await; + if let Err(e) = core.send_onchain(msg.id, address, amount_sats).await { error!("Error sending: {e}"); - core.msg(CoreUIMsg::SendFailure(e.to_string())).await; + core.msg(Some(msg.id), CoreUIMsg::SendFailure(e.to_string())) + .await; } } UICoreMsg::ReceiveOnChain => { - core.msg(CoreUIMsg::ReceiveGenerating).await; - match core.receive_onchain().await { + core.msg(Some(msg.id), CoreUIMsg::ReceiveGenerating).await; + match core.receive_onchain(msg.id).await { Err(e) => { - core.msg(CoreUIMsg::ReceiveFailed(e.to_string())).await; + core.msg(Some(msg.id), CoreUIMsg::ReceiveFailed(e.to_string())) + .await; } Ok(address) => { - core.msg(CoreUIMsg::ReceiveAddressGenerated(address)).await; + core.msg(Some(msg.id), CoreUIMsg::ReceiveAddressGenerated(address)) + .await; } } } @@ -496,24 +520,32 @@ async fn process_core(core_handle: &mut bridge::CoreHandle, core: &HarborCore) { match core.get_federation_info(invite_code).await { Err(e) => { error!("Error getting federation info: {e}"); - core.msg(CoreUIMsg::AddFederationFailed(e.to_string())) - .await; + core.msg( + Some(msg.id), + CoreUIMsg::AddFederationFailed(e.to_string()), + ) + .await; } Ok(config) => { - core.msg(CoreUIMsg::FederationInfo(config)).await; + core.msg(Some(msg.id), CoreUIMsg::FederationInfo(config)) + .await; } } } UICoreMsg::AddFederation(invite_code) => { if let Err(e) = core.add_federation(invite_code).await { error!("Error adding federation: {e}"); - core.msg(CoreUIMsg::AddFederationFailed(e.to_string())) + core.msg(Some(msg.id), CoreUIMsg::AddFederationFailed(e.to_string())) .await; } else { - core.msg(CoreUIMsg::AddFederationSuccess).await; - let new_federation_list = core.get_federation_items().await; - core.msg(CoreUIMsg::FederationListUpdated(new_federation_list)) + core.msg(Some(msg.id), CoreUIMsg::AddFederationSuccess) .await; + let new_federation_list = core.get_federation_items().await; + core.msg( + Some(msg.id), + CoreUIMsg::FederationListUpdated(new_federation_list), + ) + .await; } } UICoreMsg::Unlock(_password) => { @@ -521,7 +553,8 @@ async fn process_core(core_handle: &mut bridge::CoreHandle, core: &HarborCore) { } UICoreMsg::GetSeedWords => { let seed_words = core.get_seed_words().await; - core.msg(CoreUIMsg::SeedWords(seed_words)).await; + core.msg(Some(msg.id), CoreUIMsg::SeedWords(seed_words)) + .await; } } } diff --git a/src/fedimint_client.rs b/src/fedimint_client.rs index 550dc13..fc90a90 100644 --- a/src/fedimint_client.rs +++ b/src/fedimint_client.rs @@ -35,6 +35,7 @@ use std::{ sync::atomic::{AtomicBool, Ordering}, }; use tokio::spawn; +use uuid::Uuid; #[allow(dead_code)] #[derive(Debug, Clone)] @@ -227,13 +228,15 @@ pub(crate) async fn select_gateway(client: &ClientHandleArc) -> Option, + msg_id: Uuid, sender: &mut Sender, ) { if let Ok(history) = storage.get_transaction_history() { sender - .send(Message::CoreMessage(CoreUIMsg::TransactionHistoryUpdated( - history, - ))) + .send(Message::core_msg( + Some(msg_id), + CoreUIMsg::TransactionHistoryUpdated(history), + )) .await .unwrap(); } @@ -244,6 +247,7 @@ pub(crate) async fn spawn_invoice_receive_subscription( client: ClientHandleArc, storage: Arc, operation_id: OperationId, + msg_id: Uuid, subscription: UpdateStreamOrOutcome, ) { spawn(async move { @@ -253,22 +257,25 @@ pub(crate) async fn spawn_invoice_receive_subscription( LnReceiveState::Canceled { reason } => { error!("Payment canceled, reason: {:?}", reason); sender - .send(Message::CoreMessage(CoreUIMsg::ReceiveFailed( - reason.to_string(), - ))) + .send(Message::core_msg( + Some(msg_id), + CoreUIMsg::ReceiveFailed(reason.to_string()), + )) .await .unwrap(); if let Err(e) = storage.mark_ln_receive_as_failed(operation_id) { error!("Could not mark lightning receive as failed: {e}"); } + break; } LnReceiveState::Claimed => { info!("Payment claimed"); sender - .send(Message::CoreMessage(CoreUIMsg::ReceiveSuccess( - ReceiveSuccessMsg::Lightning, - ))) + .send(Message::core_msg( + Some(msg_id), + CoreUIMsg::ReceiveSuccess(ReceiveSuccessMsg::Lightning), + )) .await .unwrap(); @@ -278,11 +285,14 @@ pub(crate) async fn spawn_invoice_receive_subscription( let new_balance = client.get_balance().await; sender - .send(Message::CoreMessage(CoreUIMsg::BalanceUpdated(new_balance))) + .send(Message::core_msg( + Some(msg_id), + CoreUIMsg::BalanceUpdated(new_balance), + )) .await .unwrap(); - update_history(storage.clone(), &mut sender).await; + update_history(storage.clone(), msg_id, &mut sender).await; break; } @@ -297,6 +307,7 @@ pub(crate) async fn spawn_invoice_payment_subscription( client: ClientHandleArc, storage: Arc, operation_id: OperationId, + msg_id: Uuid, subscription: UpdateStreamOrOutcome, ) { spawn(async move { @@ -306,9 +317,10 @@ pub(crate) async fn spawn_invoice_payment_subscription( LnPayState::Canceled => { error!("Payment canceled"); sender - .send(Message::CoreMessage(CoreUIMsg::SendFailure( - "Canceled".to_string(), - ))) + .send(Message::core_msg( + Some(msg_id), + CoreUIMsg::SendFailure("Canceled".to_string()), + )) .await .unwrap(); @@ -320,7 +332,10 @@ pub(crate) async fn spawn_invoice_payment_subscription( LnPayState::UnexpectedError { error_message } => { error!("Unexpected payment error: {:?}", error_message); sender - .send(Message::CoreMessage(CoreUIMsg::SendFailure(error_message))) + .send(Message::core_msg( + Some(msg_id), + CoreUIMsg::SendFailure(error_message), + )) .await .unwrap(); @@ -335,7 +350,10 @@ pub(crate) async fn spawn_invoice_payment_subscription( FromHex::from_hex(&preimage).expect("Invalid preimage"); let params = SendSuccessMsg::Lightning { preimage }; sender - .send(Message::CoreMessage(CoreUIMsg::SendSuccess(params))) + .send(Message::core_msg( + Some(msg_id), + CoreUIMsg::SendSuccess(params), + )) .await .unwrap(); @@ -345,11 +363,14 @@ pub(crate) async fn spawn_invoice_payment_subscription( let new_balance = client.get_balance().await; sender - .send(Message::CoreMessage(CoreUIMsg::BalanceUpdated(new_balance))) + .send(Message::core_msg( + Some(msg_id), + CoreUIMsg::BalanceUpdated(new_balance), + )) .await .unwrap(); - update_history(storage.clone(), &mut sender).await; + update_history(storage.clone(), msg_id, &mut sender).await; break; } @@ -364,6 +385,7 @@ pub(crate) async fn spawn_internal_payment_subscription( client: ClientHandleArc, storage: Arc, operation_id: OperationId, + msg_id: Uuid, subscription: UpdateStreamOrOutcome, ) { spawn(async move { @@ -373,9 +395,10 @@ pub(crate) async fn spawn_internal_payment_subscription( InternalPayState::FundingFailed { error } => { error!("Funding failed: {error:?}"); sender - .send(Message::CoreMessage(CoreUIMsg::ReceiveFailed( - error.to_string(), - ))) + .send(Message::core_msg( + Some(msg_id), + CoreUIMsg::ReceiveFailed(error.to_string()), + )) .await .unwrap(); if let Err(e) = storage.mark_lightning_payment_as_failed(operation_id) { @@ -386,7 +409,10 @@ pub(crate) async fn spawn_internal_payment_subscription( InternalPayState::UnexpectedError(error_message) => { error!("Unexpected payment error: {error_message:?}"); sender - .send(Message::CoreMessage(CoreUIMsg::SendFailure(error_message))) + .send(Message::core_msg( + Some(msg_id), + CoreUIMsg::SendFailure(error_message), + )) .await .unwrap(); if let Err(e) = storage.mark_lightning_payment_as_failed(operation_id) { @@ -400,7 +426,10 @@ pub(crate) async fn spawn_internal_payment_subscription( preimage: preimage.0, }; sender - .send(Message::CoreMessage(CoreUIMsg::SendSuccess(params))) + .send(Message::core_msg( + Some(msg_id), + CoreUIMsg::SendSuccess(params), + )) .await .unwrap(); @@ -411,11 +440,14 @@ pub(crate) async fn spawn_internal_payment_subscription( let new_balance = client.get_balance().await; sender - .send(Message::CoreMessage(CoreUIMsg::BalanceUpdated(new_balance))) + .send(Message::core_msg( + Some(msg_id), + CoreUIMsg::BalanceUpdated(new_balance), + )) .await .unwrap(); - update_history(storage, &mut sender).await; + update_history(storage, msg_id, &mut sender).await; break; } @@ -430,6 +462,7 @@ pub(crate) async fn spawn_onchain_payment_subscription( client: ClientHandleArc, storage: Arc, operation_id: OperationId, + msg_id: Uuid, subscription: UpdateStreamOrOutcome, ) { spawn(async move { @@ -440,9 +473,10 @@ pub(crate) async fn spawn_onchain_payment_subscription( WithdrawState::Failed(error) => { error!("Onchain payment failed: {error:?}"); sender - .send(Message::CoreMessage(CoreUIMsg::SendFailure( - error.to_string(), - ))) + .send(Message::core_msg( + Some(msg_id), + CoreUIMsg::SendFailure(error), + )) .await .unwrap(); if let Err(e) = storage.mark_onchain_payment_as_failed(operation_id) { @@ -455,7 +489,10 @@ pub(crate) async fn spawn_onchain_payment_subscription( info!("Onchain payment success: {txid}"); let params = SendSuccessMsg::Onchain { txid }; sender - .send(Message::CoreMessage(CoreUIMsg::SendSuccess(params))) + .send(Message::core_msg( + Some(msg_id), + CoreUIMsg::SendSuccess(params), + )) .await .unwrap(); @@ -465,11 +502,14 @@ pub(crate) async fn spawn_onchain_payment_subscription( let new_balance = client.get_balance().await; sender - .send(Message::CoreMessage(CoreUIMsg::BalanceUpdated(new_balance))) + .send(Message::core_msg( + Some(msg_id), + CoreUIMsg::BalanceUpdated(new_balance), + )) .await .unwrap(); - update_history(storage.clone(), &mut sender).await; + update_history(storage.clone(), msg_id, &mut sender).await; break; } @@ -483,6 +523,7 @@ pub(crate) async fn spawn_onchain_receive_subscription( client: ClientHandleArc, storage: Arc, operation_id: OperationId, + msg_id: Uuid, subscription: UpdateStreamOrOutcome, ) { spawn(async move { @@ -493,9 +534,10 @@ pub(crate) async fn spawn_onchain_receive_subscription( DepositState::Failed(error) => { error!("Onchain receive failed: {error:?}"); sender - .send(Message::CoreMessage(CoreUIMsg::ReceiveFailed( - error.to_string(), - ))) + .send(Message::core_msg( + Some(msg_id), + CoreUIMsg::ReceiveFailed(error), + )) .await .unwrap(); @@ -512,7 +554,10 @@ pub(crate) async fn spawn_onchain_receive_subscription( let amount = data.btc_transaction.output[index].value; let params = ReceiveSuccessMsg::Onchain { txid }; sender - .send(Message::CoreMessage(CoreUIMsg::ReceiveSuccess(params))) + .send(Message::core_msg( + Some(msg_id), + CoreUIMsg::ReceiveSuccess(params), + )) .await .unwrap(); @@ -523,7 +568,7 @@ pub(crate) async fn spawn_onchain_receive_subscription( error!("Could not mark onchain payment txid: {e}"); } - update_history(storage.clone(), &mut sender).await; + update_history(storage.clone(), msg_id, &mut sender).await; } DepositState::Confirmed(data) => { info!("Onchain receive confirmed: {data:?}"); @@ -532,7 +577,10 @@ pub(crate) async fn spawn_onchain_receive_subscription( info!("Onchain receive claimed: {data:?}"); let new_balance = client.get_balance().await; sender - .send(Message::CoreMessage(CoreUIMsg::BalanceUpdated(new_balance))) + .send(Message::core_msg( + Some(msg_id), + CoreUIMsg::BalanceUpdated(new_balance), + )) .await .unwrap(); @@ -540,7 +588,7 @@ pub(crate) async fn spawn_onchain_receive_subscription( error!("Could not mark onchain payment txid: {e}"); } - update_history(storage.clone(), &mut sender).await; + update_history(storage.clone(), msg_id, &mut sender).await; break; } diff --git a/src/main.rs b/src/main.rs index 67ca76d..d6c515c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,13 +8,14 @@ use routes::Route; use std::str::FromStr; use std::sync::Arc; -use bridge::{CoreUIMsg, ReceiveSuccessMsg, SendSuccessMsg}; +use bridge::{CoreUIMsg, CoreUIMsgPacket, ReceiveSuccessMsg, SendSuccessMsg}; use iced::subscription::Subscription; use iced::widget::row; use iced::Element; use iced::{clipboard, program, Color}; use iced::{Command, Font}; use log::{error, info}; +use uuid::Uuid; use crate::components::focus_input_id; @@ -104,7 +105,13 @@ pub enum Message { PeekFederation(String), Donate, // Core messages we get from core - CoreMessage(CoreUIMsg), + CoreMessage(CoreUIMsgPacket), +} + +impl Message { + pub fn core_msg(id: Option, msg: CoreUIMsg) -> Self { + Self::CoreMessage(CoreUIMsgPacket { id, msg }) + } } // This is the UI state. It should only contain data that is directly rendered by the UI @@ -156,10 +163,11 @@ impl HarborWallet { async fn async_send_lightning( ui_handle: Option>, + id: Uuid, invoice: Bolt11Invoice, ) { if let Some(ui_handle) = ui_handle { - ui_handle.clone().send_lightning(invoice).await; + ui_handle.clone().send_lightning(id, invoice).await; } else { panic!("UI handle is None"); } @@ -167,61 +175,72 @@ impl HarborWallet { async fn async_send_onchain( ui_handle: Option>, + id: Uuid, address: Address, amount_sats: Option, ) { println!("Got to async_send"); if let Some(ui_handle) = ui_handle { - println!("Have a ui_handle, sending the invoice over"); - ui_handle.clone().send_onchain(address, amount_sats).await; + ui_handle + .clone() + .send_onchain(id, address, amount_sats) + .await; } else { panic!("UI handle is None"); } } - async fn async_receive(ui_handle: Option>, amount: u64) { + async fn async_receive(ui_handle: Option>, id: Uuid, amount: u64) { if let Some(ui_handle) = ui_handle { - ui_handle.clone().receive(amount).await; + ui_handle.clone().receive(id, amount).await; } else { panic!("UI handle is None"); } } - async fn async_receive_onchain(ui_handle: Option>) { + async fn async_receive_onchain(ui_handle: Option>, id: Uuid) { if let Some(ui_handle) = ui_handle { - ui_handle.clone().receive_onchain().await; + ui_handle.clone().receive_onchain(id).await; } else { panic!("UI handle is None"); } } - async fn async_unlock(ui_handle: Option>, password: String) { + async fn async_unlock(ui_handle: Option>, id: Uuid, password: String) { if let Some(ui_handle) = ui_handle { - ui_handle.clone().unlock(password).await; + ui_handle.clone().unlock(id, password).await; } else { panic!("UI handle is None"); } } - async fn async_add_federation(ui_handle: Option>, invite: InviteCode) { + async fn async_add_federation( + ui_handle: Option>, + id: Uuid, + invite: InviteCode, + ) { if let Some(ui_handle) = ui_handle { - ui_handle.clone().add_federation(invite).await; + ui_handle.clone().add_federation(id, invite).await; } else { panic!("UI handle is None"); } } - async fn async_peek_federation(ui_handle: Option>, invite: InviteCode) { + async fn async_peek_federation( + ui_handle: Option>, + id: Uuid, + invite: InviteCode, + ) { if let Some(ui_handle) = ui_handle { - ui_handle.clone().peek_federation(invite).await; + ui_handle.clone().peek_federation(id, invite).await; } else { panic!("UI handle is None"); } } - async fn async_get_seed_words(ui_handle: Option>) { + async fn async_get_seed_words(ui_handle: Option>, id: Uuid) { if let Some(ui_handle) = ui_handle { - ui_handle.clone().get_seed_words().await; + ui_handle.clone().get_seed_words(id).await; } else { panic!("UI handle is None"); } @@ -308,9 +327,10 @@ impl HarborWallet { SendStatus::Sending => Command::none(), _ => { self.send_failure_reason = None; + let id = Uuid::new_v4(); // todo use this id somewhere if let Ok(invoice) = Bolt11Invoice::from_str(&invoice_str) { Command::perform( - Self::async_send_lightning(self.ui_handle.clone(), invoice), + Self::async_send_lightning(self.ui_handle.clone(), id, invoice), |_| Message::Noop, ) } else if let Ok(address) = Address::from_str(&invoice_str) { @@ -321,7 +341,7 @@ impl HarborWallet { Some(self.send_amount_input_str.parse::().unwrap()) }; Command::perform( - Self::async_send_onchain(self.ui_handle.clone(), address, amount), + Self::async_send_onchain(self.ui_handle.clone(), id, address, amount), |_| Message::Noop, ) } else { @@ -334,9 +354,10 @@ impl HarborWallet { ReceiveStatus::Generating => Command::none(), _ => { self.receive_failure_reason = None; + let id = Uuid::new_v4(); // todo use this id somewhere match self.receive_amount_str.parse::() { Ok(amount) => Command::perform( - Self::async_receive(self.ui_handle.clone(), amount), + Self::async_receive(self.ui_handle.clone(), id, amount), |_| Message::Noop, ), Err(e) => { @@ -350,10 +371,12 @@ impl HarborWallet { Message::GenerateAddress => match self.receive_status { ReceiveStatus::Generating => Command::none(), _ => { + let id = Uuid::new_v4(); // todo use this id somewhere self.receive_failure_reason = None; - Command::perform(Self::async_receive_onchain(self.ui_handle.clone()), |_| { - Message::Noop - }) + Command::perform( + Self::async_receive_onchain(self.ui_handle.clone(), id), + |_| Message::Noop, + ) } }, Message::Donate => match self.donate_amount_str.parse::() { @@ -361,9 +384,10 @@ impl HarborWallet { // TODO: don't hardcode this! let hardcoded_donation_address = "tb1qd28npep0s8frcm3y7dxqajkcy2m40eysplyr9v"; let address = Address::from_str(hardcoded_donation_address).unwrap(); + let id = Uuid::new_v4(); // todo use this id somewhere Command::perform( - Self::async_send_onchain(self.ui_handle.clone(), address, Some(amount)), + Self::async_send_onchain(self.ui_handle.clone(), id, address, Some(amount)), |_| Message::Noop, ) } @@ -377,16 +401,19 @@ impl HarborWallet { UnlockStatus::Unlocking => Command::none(), _ => { self.unlock_failure_reason = None; - Command::perform(Self::async_unlock(self.ui_handle.clone(), password), |_| { - Message::Noop - }) + let id = Uuid::new_v4(); // todo use this id somewhere + Command::perform( + Self::async_unlock(self.ui_handle.clone(), id, password), + |_| Message::Noop, + ) } }, Message::AddFederation(invite_code) => { let invite = InviteCode::from_str(&invite_code); if let Ok(invite) = invite { + let id = Uuid::new_v4(); // todo use this id somewhere Command::perform( - Self::async_add_federation(self.ui_handle.clone(), invite), + Self::async_add_federation(self.ui_handle.clone(), id, invite), |_| Message::Noop, ) } else { @@ -397,8 +424,9 @@ impl HarborWallet { Message::PeekFederation(invite_code) => { let invite = InviteCode::from_str(&invite_code); if let Ok(invite) = invite { + let id = Uuid::new_v4(); // todo use this id somewhere Command::perform( - Self::async_peek_federation(self.ui_handle.clone(), invite), + Self::async_peek_federation(self.ui_handle.clone(), id, invite), |_| Message::Noop, ) } else { @@ -412,16 +440,18 @@ impl HarborWallet { } Message::ShowSeedWords(show) => { if show { - Command::perform(Self::async_get_seed_words(self.ui_handle.clone()), |_| { - Message::Noop - }) + let id = Uuid::new_v4(); // todo use this id somewhere + Command::perform( + Self::async_get_seed_words(self.ui_handle.clone(), id), + |_| Message::Noop, + ) } else { self.settings_show_seed_words = false; Command::none() } } // Handle any messages we get from core - Message::CoreMessage(msg) => match msg { + Message::CoreMessage(msg) => match msg.msg { CoreUIMsg::Sending => { self.send_status = SendStatus::Sending; Command::none() From 0b3d6adaa9eba8ebbb37535feffb8a55f406838b Mon Sep 17 00:00:00 2001 From: benthecarman Date: Fri, 17 May 2024 15:22:41 -0500 Subject: [PATCH 2/2] Hookup message id for send and receive --- src/main.rs | 43 ++++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/src/main.rs b/src/main.rs index d6c515c..f70ecfc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -154,6 +154,8 @@ pub struct HarborWallet { // Settings settings_show_seed_words: bool, seed_words: Option, + current_send_id: Option, + current_receive_id: Option, } impl HarborWallet { @@ -327,7 +329,8 @@ impl HarborWallet { SendStatus::Sending => Command::none(), _ => { self.send_failure_reason = None; - let id = Uuid::new_v4(); // todo use this id somewhere + let id = Uuid::new_v4(); + self.current_send_id = Some(id); if let Ok(invoice) = Bolt11Invoice::from_str(&invoice_str) { Command::perform( Self::async_send_lightning(self.ui_handle.clone(), id, invoice), @@ -346,6 +349,7 @@ impl HarborWallet { ) } else { error!("Invalid invoice or address"); + self.current_send_id = None; Command::none() } } @@ -353,8 +357,9 @@ impl HarborWallet { Message::GenerateInvoice => match self.receive_status { ReceiveStatus::Generating => Command::none(), _ => { + let id = Uuid::new_v4(); + self.current_receive_id = Some(id); self.receive_failure_reason = None; - let id = Uuid::new_v4(); // todo use this id somewhere match self.receive_amount_str.parse::() { Ok(amount) => Command::perform( Self::async_receive(self.ui_handle.clone(), id, amount), @@ -371,7 +376,8 @@ impl HarborWallet { Message::GenerateAddress => match self.receive_status { ReceiveStatus::Generating => Command::none(), _ => { - let id = Uuid::new_v4(); // todo use this id somewhere + let id = Uuid::new_v4(); + self.current_receive_id = Some(id); self.receive_failure_reason = None; Command::perform( Self::async_receive_onchain(self.ui_handle.clone(), id), @@ -384,7 +390,8 @@ impl HarborWallet { // TODO: don't hardcode this! let hardcoded_donation_address = "tb1qd28npep0s8frcm3y7dxqajkcy2m40eysplyr9v"; let address = Address::from_str(hardcoded_donation_address).unwrap(); - let id = Uuid::new_v4(); // todo use this id somewhere + let id = Uuid::new_v4(); + self.current_send_id = Some(id); Command::perform( Self::async_send_onchain(self.ui_handle.clone(), id, address, Some(amount)), @@ -453,27 +460,41 @@ impl HarborWallet { // Handle any messages we get from core Message::CoreMessage(msg) => match msg.msg { CoreUIMsg::Sending => { - self.send_status = SendStatus::Sending; + if self.current_send_id == msg.id { + self.send_status = SendStatus::Sending; + } Command::none() } CoreUIMsg::SendSuccess(params) => { info!("Send success: {params:?}"); - self.send_success_msg = Some(params); + if self.current_send_id == msg.id { + self.send_success_msg = Some(params); + self.current_send_id = None; + } Command::none() } CoreUIMsg::SendFailure(reason) => { - self.send_status = SendStatus::Idle; - self.send_failure_reason = Some(reason); + if self.current_send_id == msg.id { + self.send_status = SendStatus::Idle; + self.send_failure_reason = Some(reason); + self.current_send_id = None; + } Command::none() } CoreUIMsg::ReceiveSuccess(params) => { info!("Receive success: {params:?}"); - self.receive_success_msg = Some(params); + if self.current_receive_id == msg.id { + self.receive_success_msg = Some(params); + self.current_receive_id = None; + } Command::none() } CoreUIMsg::ReceiveFailed(reason) => { - self.receive_status = ReceiveStatus::Idle; - self.receive_failure_reason = Some(reason); + if self.current_receive_id == msg.id { + self.receive_status = ReceiveStatus::Idle; + self.receive_failure_reason = Some(reason); + self.current_receive_id = None; + } Command::none() } CoreUIMsg::BalanceUpdated(balance) => {