From 0726bdff7edaace99ebab921f74c822deeba01dc Mon Sep 17 00:00:00 2001 From: jmacxx <47253594+jmacxx@users.noreply.github.com> Date: Tue, 17 May 2022 12:10:23 -0500 Subject: [PATCH] Prevent shutdown if trade is in process of being taken. --- .../resources/i18n/displayStrings.properties | 4 ++ .../main/java/bisq/desktop/app/BisqApp.java | 63 ++++++++++++++++++- 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/core/src/main/resources/i18n/displayStrings.properties b/core/src/main/resources/i18n/displayStrings.properties index f74edf1dccb..dee7944a17f 100644 --- a/core/src/main/resources/i18n/displayStrings.properties +++ b/core/src/main/resources/i18n/displayStrings.properties @@ -3080,6 +3080,10 @@ popup.info.shutDownWithOpenOffers=Bisq is being shut down, but there are open of they will be re-published to the P2P network the next time you start Bisq.\n\n\ To keep your offers online, keep Bisq running and make sure this computer remains online too \ (i.e., make sure it doesn't go into standby mode...monitor standby is not a problem). +popup.info.shutDownWithTradeInit=Bisq is being shut down, but there are trades still being initialized. \n\n\ + Specific trade affected: {0}\n\n\ + If a trade is still in process of being initialized, shutting down can result in the trade missing some important state.\n\n\ + Do not close Bisq if this trade has not had enough time to initialize correctly. One minute should be sufficient time. popup.info.qubesOSSetupInfo=It appears you are running Bisq on Qubes OS. \n\n\ Please make sure your Bisq qube is setup according to our Setup Guide at [HYPERLINK:https://bisq.wiki/Running_Bisq_on_Qubes]. popup.info.firewallSetupInfo=It appears this machine blocks incoming Tor connections. \ diff --git a/desktop/src/main/java/bisq/desktop/app/BisqApp.java b/desktop/src/main/java/bisq/desktop/app/BisqApp.java index 3452cffa2c5..a86c4ec6d0f 100644 --- a/desktop/src/main/java/bisq/desktop/app/BisqApp.java +++ b/desktop/src/main/java/bisq/desktop/app/BisqApp.java @@ -31,6 +31,7 @@ import bisq.desktop.main.overlays.windows.ShowWalletDataWindow; import bisq.desktop.main.overlays.windows.WalletPasswordWindow; import bisq.desktop.util.CssTheme; +import bisq.desktop.util.DisplayUtils; import bisq.desktop.util.ImageUtil; import bisq.core.btc.wallet.BtcWalletService; @@ -39,6 +40,8 @@ import bisq.core.locale.Res; import bisq.core.offer.OpenOffer; import bisq.core.offer.OpenOfferManager; +import bisq.core.trade.TradeManager; +import bisq.core.trade.model.bisq_v1.Trade; import bisq.core.user.Cookie; import bisq.core.user.CookieKey; import bisq.core.user.Preferences; @@ -73,9 +76,14 @@ import javafx.geometry.Rectangle2D; import javafx.geometry.BoundingBox; +import java.time.Instant; + import java.util.ArrayList; +import java.util.Date; import java.util.List; import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import org.slf4j.LoggerFactory; @@ -356,6 +364,52 @@ private void addSceneKeyEventHandler(Scene scene, Injector injector) { } private void shutDownByUser() { + // two potential popup prompts to user before shutting down, each step can possibly abort the shutdown + shutDownByUserCheckTrades().thenAccept(shutdownStage1 -> { + if (shutdownStage1) { + shutDownByUserCheckOffers().thenAccept(shutdownStage2 -> { + if (shutdownStage2) { + stop(); + } + }); + } + }); + } + + private CompletableFuture shutDownByUserCheckTrades() { + final CompletableFuture asyncStatus = new CompletableFuture<>(); + Instant fiveMinutesAgo = Instant.ofEpochSecond(Instant.now().getEpochSecond() - TimeUnit.MINUTES.toSeconds(5)); + String tradeIdsWithOperationsPending = ""; + for (Trade trade : injector.getInstance(TradeManager.class).getObservableList()) { + if (trade.getTradePhase().equals(Trade.Phase.TAKER_FEE_PUBLISHED) && + new Date(trade.getTakeOfferDate()).toInstant().isAfter(fiveMinutesAgo)) { + String tradeDateString = DisplayUtils.formatDateTime(new Date(trade.getTakeOfferDate())); + tradeIdsWithOperationsPending += System.lineSeparator() + + Res.get("shared.tradeId") + ": " + trade.getShortId() + " " + + Res.get("shared.dateTime") + ": " + tradeDateString; + break; + } + } + if (tradeIdsWithOperationsPending.length() > 0) { + // We show a popup to inform user that some trades are still being initialised. + String key = "showInitTradeWarnPopupAtShutDown"; + if (injector.getInstance(Preferences.class).showAgain(key) && !DevEnv.isDevMode()) { + new Popup().information(Res.get("popup.info.shutDownWithTradeInit", tradeIdsWithOperationsPending)) + .dontShowAgainId(key) + .useShutDownButton() + .onAction(() -> asyncStatus.complete(true)) + .closeButtonText(Res.get("shared.cancel")) + .onClose(() -> asyncStatus.complete(false)) + .show(); + } + } else { + asyncStatus.complete(true); + } + return asyncStatus; + } + + private CompletableFuture shutDownByUserCheckOffers() { + final CompletableFuture asyncStatus = new CompletableFuture<>(); boolean hasOpenOffers = false; for (OpenOffer openOffer : injector.getInstance(OpenOfferManager.class).getObservableList()) { if (openOffer.getState().equals(OpenOffer.State.AVAILABLE)) { @@ -365,8 +419,8 @@ private void shutDownByUser() { } if (!hasOpenOffers) { // No open offers, so no need to show the popup. - stop(); - return; + asyncStatus.complete(true); + return asyncStatus; } // We show a popup to inform user that open offers will be removed if Bisq is not running. @@ -375,11 +429,14 @@ private void shutDownByUser() { new Popup().information(Res.get("popup.info.shutDownWithOpenOffers")) .dontShowAgainId(key) .useShutDownButton() + .onAction(() -> asyncStatus.complete(true)) .closeButtonText(Res.get("shared.cancel")) + .onClose(() -> asyncStatus.complete(false)) .show(); } else { - stop(); + asyncStatus.complete(true); } + return asyncStatus; } // Used for debugging trade process