diff --git a/core/src/main/java/bisq/core/app/AppStartupState.java b/core/src/main/java/bisq/core/app/AppStartupState.java new file mode 100644 index 00000000000..16a22f8552b --- /dev/null +++ b/core/src/main/java/bisq/core/app/AppStartupState.java @@ -0,0 +1,149 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.core.app; + +import bisq.core.btc.setup.WalletsSetup; + +import bisq.network.p2p.BootstrapListener; +import bisq.network.p2p.P2PService; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.fxmisc.easybind.EasyBind; +import org.fxmisc.easybind.monadic.MonadicBinding; + +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.ReadOnlyBooleanProperty; +import javafx.beans.property.SimpleBooleanProperty; + +import lombok.extern.slf4j.Slf4j; + +/** + * We often need to wait until network and wallet is ready or other combination of startup states. + * To avoid those repeated checks for the state or setting of listeners on different domains we provide here a + * collection of useful states. + */ +@Slf4j +@Singleton +public class AppStartupState { + // Do not convert to local field as there have been issues observed that the object got GC'ed. + private final MonadicBinding p2pNetworkAndWalletInitialized; + + private final BooleanProperty walletAndNetworkReady = new SimpleBooleanProperty(); + private final BooleanProperty allDomainServicesInitialized = new SimpleBooleanProperty(); + private final BooleanProperty applicationFullyInitialized = new SimpleBooleanProperty(); + private final BooleanProperty updatedDataReceived = new SimpleBooleanProperty(); + private final BooleanProperty isBlockDownloadComplete = new SimpleBooleanProperty(); + private final BooleanProperty hasSufficientPeersForBroadcast = new SimpleBooleanProperty(); + + @Inject + public AppStartupState(WalletsSetup walletsSetup, P2PService p2PService) { + + p2PService.addP2PServiceListener(new BootstrapListener() { + @Override + public void onUpdatedDataReceived() { + updatedDataReceived.set(true); + } + }); + + walletsSetup.downloadPercentageProperty().addListener((observable, oldValue, newValue) -> { + if (walletsSetup.isDownloadComplete()) + isBlockDownloadComplete.set(true); + }); + + walletsSetup.numPeersProperty().addListener((observable, oldValue, newValue) -> { + if (walletsSetup.hasSufficientPeersForBroadcast()) + hasSufficientPeersForBroadcast.set(true); + }); + + p2pNetworkAndWalletInitialized = EasyBind.combine(updatedDataReceived, + isBlockDownloadComplete, + hasSufficientPeersForBroadcast, + allDomainServicesInitialized, + (a, b, c, d) -> { + if (a && b && c) { + walletAndNetworkReady.set(true); + } + return a && b && c && d; + }); + p2pNetworkAndWalletInitialized.subscribe((observable, oldValue, newValue) -> { + if (newValue) { + applicationFullyInitialized.set(true); + } + }); + } + + public void onDomainServicesInitialized() { + allDomainServicesInitialized.set(true); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Getters + /////////////////////////////////////////////////////////////////////////////////////////// + + public boolean isWalletAndNetworkReady() { + return walletAndNetworkReady.get(); + } + + public ReadOnlyBooleanProperty walletAndNetworkReadyProperty() { + return walletAndNetworkReady; + } + + public boolean isAllDomainServicesInitialized() { + return allDomainServicesInitialized.get(); + } + + public ReadOnlyBooleanProperty allDomainServicesInitializedProperty() { + return allDomainServicesInitialized; + } + + public boolean isApplicationFullyInitialized() { + return applicationFullyInitialized.get(); + } + + public ReadOnlyBooleanProperty applicationFullyInitializedProperty() { + return applicationFullyInitialized; + } + + public boolean isUpdatedDataReceived() { + return updatedDataReceived.get(); + } + + public ReadOnlyBooleanProperty updatedDataReceivedProperty() { + return updatedDataReceived; + } + + public boolean isIsBlockDownloadComplete() { + return isBlockDownloadComplete.get(); + } + + public ReadOnlyBooleanProperty isBlockDownloadCompleteProperty() { + return isBlockDownloadComplete; + } + + public boolean isHasSufficientPeersForBroadcast() { + return hasSufficientPeersForBroadcast.get(); + } + + public ReadOnlyBooleanProperty hasSufficientPeersForBroadcastProperty() { + return hasSufficientPeersForBroadcast; + } + +} diff --git a/core/src/main/java/bisq/core/app/BisqSetup.java b/core/src/main/java/bisq/core/app/BisqSetup.java index 57a5b00fd61..6027f7f892a 100644 --- a/core/src/main/java/bisq/core/app/BisqSetup.java +++ b/core/src/main/java/bisq/core/app/BisqSetup.java @@ -18,48 +18,24 @@ package bisq.core.app; import bisq.core.account.sign.SignedWitness; -import bisq.core.account.sign.SignedWitnessService; import bisq.core.account.witness.AccountAgeWitnessService; import bisq.core.alert.Alert; import bisq.core.alert.AlertManager; -import bisq.core.alert.PrivateNotificationManager; import bisq.core.alert.PrivateNotificationPayload; -import bisq.core.btc.Balances; import bisq.core.btc.model.AddressEntry; import bisq.core.btc.nodes.LocalBitcoinNode; import bisq.core.btc.setup.WalletsSetup; import bisq.core.btc.wallet.BtcWalletService; import bisq.core.btc.wallet.WalletsManager; -import bisq.core.dao.DaoSetup; import bisq.core.dao.governance.voteresult.VoteResultException; -import bisq.core.dao.governance.voteresult.VoteResultService; import bisq.core.dao.state.unconfirmed.UnconfirmedBsqChangeOutputListService; -import bisq.core.filter.FilterManager; import bisq.core.locale.Res; -import bisq.core.notifications.MobileNotificationService; -import bisq.core.notifications.alerts.DisputeMsgEvents; -import bisq.core.notifications.alerts.MyOfferTakenEvents; -import bisq.core.notifications.alerts.TradeEvents; -import bisq.core.notifications.alerts.market.MarketAlerts; -import bisq.core.notifications.alerts.price.PriceAlert; import bisq.core.offer.OpenOfferManager; import bisq.core.payment.PaymentAccount; import bisq.core.payment.RevolutAccount; -import bisq.core.payment.TradeLimits; import bisq.core.payment.payload.PaymentMethod; -import bisq.core.provider.fee.FeeService; -import bisq.core.provider.price.PriceFeedService; -import bisq.core.support.dispute.arbitration.ArbitrationManager; -import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager; -import bisq.core.support.dispute.mediation.MediationManager; -import bisq.core.support.dispute.mediation.mediator.MediatorManager; -import bisq.core.support.dispute.refund.RefundManager; -import bisq.core.support.dispute.refund.refundagent.RefundAgentManager; -import bisq.core.support.traderchat.TraderChatManager; import bisq.core.trade.TradeManager; import bisq.core.trade.TradeTxException; -import bisq.core.trade.statistics.TradeStatisticsManager; -import bisq.core.trade.txproof.xmr.XmrTxProofService; import bisq.core.user.Preferences; import bisq.core.user.User; import bisq.core.util.FormattingUtils; @@ -68,7 +44,6 @@ import bisq.network.p2p.P2PService; import bisq.network.p2p.storage.payload.PersistableNetworkPayload; -import bisq.common.ClockWatcher; import bisq.common.Timer; import bisq.common.UserThread; import bisq.common.app.DevEnv; @@ -92,7 +67,6 @@ import javafx.beans.property.StringProperty; import javafx.beans.value.ChangeListener; -import javafx.collections.ListChangeListener; import javafx.collections.SetChangeListener; import org.bouncycastle.crypto.params.KeyParameter; @@ -106,7 +80,6 @@ import java.util.concurrent.TimeUnit; import java.util.function.BiConsumer; import java.util.function.Consumer; -import java.util.stream.Collectors; import ch.qos.logback.classic.Level; @@ -135,48 +108,25 @@ default void onRequestWalletPassword() { private static final long STARTUP_TIMEOUT_MINUTES = 4; + private final DomainInitialisation domainInitialisation; private final P2PNetworkSetup p2PNetworkSetup; private final WalletAppSetup walletAppSetup; private final WalletsManager walletsManager; private final WalletsSetup walletsSetup; private final BtcWalletService btcWalletService; - private final Balances balances; - private final PriceFeedService priceFeedService; - private final ArbitratorManager arbitratorManager; - private final MediatorManager mediatorManager; - private final RefundAgentManager refundAgentManager; private final P2PService p2PService; private final TradeManager tradeManager; private final OpenOfferManager openOfferManager; - private final ArbitrationManager arbitrationManager; - private final MediationManager mediationManager; - private final RefundManager refundManager; - private final TraderChatManager traderChatManager; private final Preferences preferences; private final User user; private final AlertManager alertManager; - private final PrivateNotificationManager privateNotificationManager; - private final FilterManager filterManager; - private final TradeStatisticsManager tradeStatisticsManager; - private final XmrTxProofService xmrTxProofService; - private final ClockWatcher clockWatcher; - private final FeeService feeService; - private final DaoSetup daoSetup; private final UnconfirmedBsqChangeOutputListService unconfirmedBsqChangeOutputListService; private final Config config; private final AccountAgeWitnessService accountAgeWitnessService; - private final SignedWitnessService signedWitnessService; - private final MobileNotificationService mobileNotificationService; - private final MyOfferTakenEvents myOfferTakenEvents; - private final TradeEvents tradeEvents; - private final DisputeMsgEvents disputeMsgEvents; - private final PriceAlert priceAlert; - private final MarketAlerts marketAlerts; - private final VoteResultService voteResultService; private final TorSetup torSetup; - private final TradeLimits tradeLimits; private final CoinFormatter formatter; private final LocalBitcoinNode localBitcoinNode; + private final AppStartupState appStartupState; @Setter @Nullable @@ -233,133 +183,46 @@ default void onRequestWalletPassword() { private final List bisqSetupListeners = new ArrayList<>(); @Inject - public BisqSetup(P2PNetworkSetup p2PNetworkSetup, + public BisqSetup(DomainInitialisation domainInitialisation, + P2PNetworkSetup p2PNetworkSetup, WalletAppSetup walletAppSetup, WalletsManager walletsManager, WalletsSetup walletsSetup, BtcWalletService btcWalletService, - Balances balances, - PriceFeedService priceFeedService, - ArbitratorManager arbitratorManager, - MediatorManager mediatorManager, - RefundAgentManager refundAgentManager, P2PService p2PService, TradeManager tradeManager, OpenOfferManager openOfferManager, - ArbitrationManager arbitrationManager, - MediationManager mediationManager, - RefundManager refundManager, - TraderChatManager traderChatManager, Preferences preferences, User user, AlertManager alertManager, - PrivateNotificationManager privateNotificationManager, - FilterManager filterManager, - TradeStatisticsManager tradeStatisticsManager, - XmrTxProofService xmrTxProofService, - ClockWatcher clockWatcher, - FeeService feeService, - DaoSetup daoSetup, UnconfirmedBsqChangeOutputListService unconfirmedBsqChangeOutputListService, Config config, AccountAgeWitnessService accountAgeWitnessService, - SignedWitnessService signedWitnessService, - MobileNotificationService mobileNotificationService, - MyOfferTakenEvents myOfferTakenEvents, - TradeEvents tradeEvents, - DisputeMsgEvents disputeMsgEvents, - PriceAlert priceAlert, - MarketAlerts marketAlerts, - VoteResultService voteResultService, TorSetup torSetup, - TradeLimits tradeLimits, @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter, - LocalBitcoinNode localBitcoinNode) { - + LocalBitcoinNode localBitcoinNode, + AppStartupState appStartupState) { + this.domainInitialisation = domainInitialisation; this.p2PNetworkSetup = p2PNetworkSetup; this.walletAppSetup = walletAppSetup; - this.walletsManager = walletsManager; this.walletsSetup = walletsSetup; this.btcWalletService = btcWalletService; - this.balances = balances; - this.priceFeedService = priceFeedService; - this.arbitratorManager = arbitratorManager; - this.mediatorManager = mediatorManager; - this.refundAgentManager = refundAgentManager; this.p2PService = p2PService; this.tradeManager = tradeManager; this.openOfferManager = openOfferManager; - this.arbitrationManager = arbitrationManager; - this.mediationManager = mediationManager; - this.refundManager = refundManager; - this.traderChatManager = traderChatManager; this.preferences = preferences; this.user = user; this.alertManager = alertManager; - this.privateNotificationManager = privateNotificationManager; - this.filterManager = filterManager; - this.tradeStatisticsManager = tradeStatisticsManager; - this.xmrTxProofService = xmrTxProofService; - this.clockWatcher = clockWatcher; - this.feeService = feeService; - this.daoSetup = daoSetup; this.unconfirmedBsqChangeOutputListService = unconfirmedBsqChangeOutputListService; this.config = config; this.accountAgeWitnessService = accountAgeWitnessService; - this.signedWitnessService = signedWitnessService; - this.mobileNotificationService = mobileNotificationService; - this.myOfferTakenEvents = myOfferTakenEvents; - this.tradeEvents = tradeEvents; - this.disputeMsgEvents = disputeMsgEvents; - this.priceAlert = priceAlert; - this.marketAlerts = marketAlerts; - this.voteResultService = voteResultService; this.torSetup = torSetup; - this.tradeLimits = tradeLimits; this.formatter = formatter; this.localBitcoinNode = localBitcoinNode; + this.appStartupState = appStartupState; } - - /////////////////////////////////////////////////////////////////////////////////////////// - // Setup - /////////////////////////////////////////////////////////////////////////////////////////// - - public void addBisqSetupListener(BisqSetupListener listener) { - bisqSetupListeners.add(listener); - } - - public void start() { - maybeReSyncSPVChain(); - maybeShowTac(this::step2); - } - - private void step2() { - torSetup.cleanupTorFiles(); - readMapsFromResources(this::step3); - checkForCorrectOSArchitecture(); - checkOSXVersion(); - checkIfRunningOnQubesOS(); - } - - private void step3() { - startP2pNetworkAndWallet(this::step4); - } - - private void step4() { - initDomainServices(); - - bisqSetupListeners.forEach(BisqSetupListener::onSetupComplete); - - // We set that after calling the setupCompleteHandler to not trigger a popup from the dev dummy accounts - // in MainViewModel - maybeShowSecurityRecommendation(); - maybeShowLocalhostRunningInfo(); - maybeShowAccountSigningStateInfo(); - } - - /////////////////////////////////////////////////////////////////////////////////////////// // API /////////////////////////////////////////////////////////////////////////////////////////// @@ -384,58 +247,45 @@ public void displayAlertIfPresent(Alert alert, boolean openNewVersionPopup) { /////////////////////////////////////////////////////////////////////////////////////////// - // Getters + // Main startup tasks /////////////////////////////////////////////////////////////////////////////////////////// - // Wallet - public StringProperty getBtcInfo() { - return walletAppSetup.getBtcInfo(); - } - - public DoubleProperty getBtcSyncProgress() { - return walletAppSetup.getBtcSyncProgress(); - } - - public StringProperty getWalletServiceErrorMsg() { - return walletAppSetup.getWalletServiceErrorMsg(); - } - - public StringProperty getBtcSplashSyncIconId() { - return walletAppSetup.getBtcSplashSyncIconId(); - } - - public BooleanProperty getUseTorForBTC() { - return walletAppSetup.getUseTorForBTC(); + public void addBisqSetupListener(BisqSetupListener listener) { + bisqSetupListeners.add(listener); } - // P2P - public StringProperty getP2PNetworkInfo() { - return p2PNetworkSetup.getP2PNetworkInfo(); + public void start() { + maybeReSyncSPVChain(); + maybeShowTac(this::step2); } - public BooleanProperty getSplashP2PNetworkAnimationVisible() { - return p2PNetworkSetup.getSplashP2PNetworkAnimationVisible(); + private void step2() { + torSetup.cleanupTorFiles(); + readMapsFromResources(this::step3); + checkForCorrectOSArchitecture(); + checkOSXVersion(); + checkIfRunningOnQubesOS(); } - public StringProperty getP2pNetworkWarnMsg() { - return p2PNetworkSetup.getP2pNetworkWarnMsg(); + private void step3() { + startP2pNetworkAndWallet(this::step4); } - public StringProperty getP2PNetworkIconId() { - return p2PNetworkSetup.getP2PNetworkIconId(); - } + private void step4() { + initDomainServices(); - public BooleanProperty getUpdatedDataReceived() { - return p2PNetworkSetup.getUpdatedDataReceived(); - } + bisqSetupListeners.forEach(BisqSetupListener::onSetupComplete); - public StringProperty getP2pNetworkLabelId() { - return p2PNetworkSetup.getP2pNetworkLabelId(); + // We set that after calling the setupCompleteHandler to not trigger a popup from the dev dummy accounts + // in MainViewModel + maybeShowSecurityRecommendation(); + maybeShowLocalhostRunningInfo(); + maybeShowAccountSigningStateInfo(); } /////////////////////////////////////////////////////////////////////////////////////////// - // Private + // Sub tasks /////////////////////////////////////////////////////////////////////////////////////////// private void maybeReSyncSPVChain() { @@ -565,6 +415,35 @@ private void initWallet() { () -> walletInitialized.set(true)); } + private void initDomainServices() { + log.info("initDomainServices"); + + domainInitialisation.initDomainServices(rejectedTxErrorMessageHandler, + displayPrivateNotificationHandler, + daoErrorMessageHandler, + daoWarnMessageHandler, + filterWarningHandler, + voteResultExceptionHandler, + revolutAccountsUpdateHandler); + + if (walletsSetup.downloadPercentageProperty().get() == 1) { + checkForLockedUpFunds(); + checkForInvalidMakerFeeTxs(); + } + + alertManager.alertMessageProperty().addListener((observable, oldValue, newValue) -> + displayAlertIfPresent(newValue, false)); + displayAlertIfPresent(alertManager.alertMessageProperty().get(), false); + + allBasicServicesInitialized = true; + + appStartupState.onDomainServicesInitialized(); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Utils + /////////////////////////////////////////////////////////////////////////////////////////// private void checkForLockedUpFunds() { // We check if there are locked up funds in failed or closed trades @@ -645,94 +524,6 @@ private void checkIfRunningOnQubesOS() { } } - private void initDomainServices() { - log.info("initDomainServices"); - - clockWatcher.start(); - - tradeLimits.onAllServicesInitialized(); - - arbitrationManager.onAllServicesInitialized(); - mediationManager.onAllServicesInitialized(); - refundManager.onAllServicesInitialized(); - traderChatManager.onAllServicesInitialized(); - - tradeManager.onAllServicesInitialized(); - xmrTxProofService.onAllServicesInitialized(); - - if (walletsSetup.downloadPercentageProperty().get() == 1) { - checkForLockedUpFunds(); - checkForInvalidMakerFeeTxs(); - } - - openOfferManager.onAllServicesInitialized(); - - balances.onAllServicesInitialized(); - - walletAppSetup.setRejectedTxErrorMessageHandler(rejectedTxErrorMessageHandler, openOfferManager, tradeManager); - - arbitratorManager.onAllServicesInitialized(); - mediatorManager.onAllServicesInitialized(); - refundAgentManager.onAllServicesInitialized(); - - alertManager.alertMessageProperty().addListener((observable, oldValue, newValue) -> - displayAlertIfPresent(newValue, false)); - displayAlertIfPresent(alertManager.alertMessageProperty().get(), false); - - privateNotificationManager.privateNotificationProperty().addListener((observable, oldValue, newValue) -> { - if (displayPrivateNotificationHandler != null) - displayPrivateNotificationHandler.accept(newValue); - }); - - p2PService.onAllServicesInitialized(); - - feeService.onAllServicesInitialized(); - - if (DevEnv.isDaoActivated()) { - daoSetup.onAllServicesInitialized(errorMessage -> { - if (daoErrorMessageHandler != null) - daoErrorMessageHandler.accept(errorMessage); - }, warningMessage -> { - if (daoWarnMessageHandler != null) - daoWarnMessageHandler.accept(warningMessage); - }); - } - - tradeStatisticsManager.onAllServicesInitialized(); - - accountAgeWitnessService.onAllServicesInitialized(); - signedWitnessService.onAllServicesInitialized(); - - priceFeedService.setCurrencyCodeOnInit(); - - filterManager.onAllServicesInitialized(); - filterManager.setFilterWarningHandler(filterWarningHandler); - - voteResultService.getVoteResultExceptions().addListener((ListChangeListener) c -> { - c.next(); - if (c.wasAdded() && voteResultExceptionHandler != null) { - c.getAddedSubList().forEach(e -> voteResultExceptionHandler.accept(e)); - } - }); - - mobileNotificationService.onAllServicesInitialized(); - myOfferTakenEvents.onAllServicesInitialized(); - tradeEvents.onAllServicesInitialized(); - disputeMsgEvents.onAllServicesInitialized(); - priceAlert.onAllServicesInitialized(); - marketAlerts.onAllServicesInitialized(); - - if (revolutAccountsUpdateHandler != null) { - revolutAccountsUpdateHandler.accept(user.getPaymentAccountsAsObservable().stream() - .filter(paymentAccount -> paymentAccount instanceof RevolutAccount) - .map(paymentAccount -> (RevolutAccount) paymentAccount) - .filter(RevolutAccount::userNameNotSet) - .collect(Collectors.toList())); - } - - allBasicServicesInitialized = true; - } - private void maybeShowSecurityRecommendation() { String key = "remindPasswordAndBackup"; user.getPaymentAccountsAsObservable().addListener((SetChangeListener) change -> { @@ -801,4 +592,57 @@ private void maybeTriggerDisplayHandler(String key, Consumer displayHand displayHandler.accept(key); } } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Getters + /////////////////////////////////////////////////////////////////////////////////////////// + + // Wallet + public StringProperty getBtcInfo() { + return walletAppSetup.getBtcInfo(); + } + + public DoubleProperty getBtcSyncProgress() { + return walletAppSetup.getBtcSyncProgress(); + } + + public StringProperty getWalletServiceErrorMsg() { + return walletAppSetup.getWalletServiceErrorMsg(); + } + + public StringProperty getBtcSplashSyncIconId() { + return walletAppSetup.getBtcSplashSyncIconId(); + } + + public BooleanProperty getUseTorForBTC() { + return walletAppSetup.getUseTorForBTC(); + } + + // P2P + public StringProperty getP2PNetworkInfo() { + return p2PNetworkSetup.getP2PNetworkInfo(); + } + + public BooleanProperty getSplashP2PNetworkAnimationVisible() { + return p2PNetworkSetup.getSplashP2PNetworkAnimationVisible(); + } + + public StringProperty getP2pNetworkWarnMsg() { + return p2PNetworkSetup.getP2pNetworkWarnMsg(); + } + + public StringProperty getP2PNetworkIconId() { + return p2PNetworkSetup.getP2PNetworkIconId(); + } + + public BooleanProperty getUpdatedDataReceived() { + return p2PNetworkSetup.getUpdatedDataReceived(); + } + + public StringProperty getP2pNetworkLabelId() { + return p2PNetworkSetup.getP2pNetworkLabelId(); + } + + } diff --git a/core/src/main/java/bisq/core/app/DomainInitialisation.java b/core/src/main/java/bisq/core/app/DomainInitialisation.java new file mode 100644 index 00000000000..614ba083c76 --- /dev/null +++ b/core/src/main/java/bisq/core/app/DomainInitialisation.java @@ -0,0 +1,249 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.core.app; + +import bisq.core.account.sign.SignedWitnessService; +import bisq.core.account.witness.AccountAgeWitnessService; +import bisq.core.alert.PrivateNotificationManager; +import bisq.core.alert.PrivateNotificationPayload; +import bisq.core.btc.Balances; +import bisq.core.dao.DaoSetup; +import bisq.core.dao.governance.voteresult.VoteResultException; +import bisq.core.dao.governance.voteresult.VoteResultService; +import bisq.core.filter.FilterManager; +import bisq.core.notifications.MobileNotificationService; +import bisq.core.notifications.alerts.DisputeMsgEvents; +import bisq.core.notifications.alerts.MyOfferTakenEvents; +import bisq.core.notifications.alerts.TradeEvents; +import bisq.core.notifications.alerts.market.MarketAlerts; +import bisq.core.notifications.alerts.price.PriceAlert; +import bisq.core.offer.OpenOfferManager; +import bisq.core.payment.RevolutAccount; +import bisq.core.payment.TradeLimits; +import bisq.core.provider.fee.FeeService; +import bisq.core.provider.price.PriceFeedService; +import bisq.core.support.dispute.arbitration.ArbitrationManager; +import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager; +import bisq.core.support.dispute.mediation.MediationManager; +import bisq.core.support.dispute.mediation.mediator.MediatorManager; +import bisq.core.support.dispute.refund.RefundManager; +import bisq.core.support.dispute.refund.refundagent.RefundAgentManager; +import bisq.core.support.traderchat.TraderChatManager; +import bisq.core.trade.TradeManager; +import bisq.core.trade.statistics.TradeStatisticsManager; +import bisq.core.trade.txproof.xmr.XmrTxProofService; +import bisq.core.user.User; + +import bisq.network.p2p.P2PService; + +import bisq.common.ClockWatcher; +import bisq.common.app.DevEnv; + +import javax.inject.Inject; + +import javafx.collections.ListChangeListener; + +import java.util.List; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +/** + * Handles the initialisation of domain classes. We should refactor to the model that the domain classes listen on the + * relevant start up state from AppStartupState instead to get called. Only for initialisation which has a required + * order we will still need this class. For now it helps to keep BisqSetup more focussed on the process and not getting + * overloaded with domain initialisation code. + */ +public class DomainInitialisation { + private final ClockWatcher clockWatcher; + private final TradeLimits tradeLimits; + private final ArbitrationManager arbitrationManager; + private final MediationManager mediationManager; + private final RefundManager refundManager; + private final TraderChatManager traderChatManager; + private final TradeManager tradeManager; + private final XmrTxProofService xmrTxProofService; + private final OpenOfferManager openOfferManager; + private final Balances balances; + private final WalletAppSetup walletAppSetup; + private final ArbitratorManager arbitratorManager; + private final MediatorManager mediatorManager; + private final RefundAgentManager refundAgentManager; + private final PrivateNotificationManager privateNotificationManager; + private final P2PService p2PService; + private final FeeService feeService; + private final DaoSetup daoSetup; + private final TradeStatisticsManager tradeStatisticsManager; + private final AccountAgeWitnessService accountAgeWitnessService; + private final SignedWitnessService signedWitnessService; + private final PriceFeedService priceFeedService; + private final FilterManager filterManager; + private final VoteResultService voteResultService; + private final MobileNotificationService mobileNotificationService; + private final MyOfferTakenEvents myOfferTakenEvents; + private final TradeEvents tradeEvents; + private final DisputeMsgEvents disputeMsgEvents; + private final PriceAlert priceAlert; + private final MarketAlerts marketAlerts; + private final User user; + + @Inject + public DomainInitialisation(ClockWatcher clockWatcher, + TradeLimits tradeLimits, + ArbitrationManager arbitrationManager, + MediationManager mediationManager, + RefundManager refundManager, + TraderChatManager traderChatManager, + TradeManager tradeManager, + XmrTxProofService xmrTxProofService, + OpenOfferManager openOfferManager, + Balances balances, + WalletAppSetup walletAppSetup, + ArbitratorManager arbitratorManager, + MediatorManager mediatorManager, + RefundAgentManager refundAgentManager, + PrivateNotificationManager privateNotificationManager, + P2PService p2PService, + FeeService feeService, + DaoSetup daoSetup, + TradeStatisticsManager tradeStatisticsManager, + AccountAgeWitnessService accountAgeWitnessService, + SignedWitnessService signedWitnessService, + PriceFeedService priceFeedService, + FilterManager filterManager, + VoteResultService voteResultService, + MobileNotificationService mobileNotificationService, + MyOfferTakenEvents myOfferTakenEvents, + TradeEvents tradeEvents, + DisputeMsgEvents disputeMsgEvents, + PriceAlert priceAlert, + MarketAlerts marketAlerts, + User user) { + this.clockWatcher = clockWatcher; + this.tradeLimits = tradeLimits; + this.arbitrationManager = arbitrationManager; + this.mediationManager = mediationManager; + this.refundManager = refundManager; + this.traderChatManager = traderChatManager; + this.tradeManager = tradeManager; + this.xmrTxProofService = xmrTxProofService; + this.openOfferManager = openOfferManager; + this.balances = balances; + this.walletAppSetup = walletAppSetup; + this.arbitratorManager = arbitratorManager; + this.mediatorManager = mediatorManager; + this.refundAgentManager = refundAgentManager; + this.privateNotificationManager = privateNotificationManager; + this.p2PService = p2PService; + this.feeService = feeService; + this.daoSetup = daoSetup; + this.tradeStatisticsManager = tradeStatisticsManager; + this.accountAgeWitnessService = accountAgeWitnessService; + this.signedWitnessService = signedWitnessService; + this.priceFeedService = priceFeedService; + this.filterManager = filterManager; + this.voteResultService = voteResultService; + this.mobileNotificationService = mobileNotificationService; + this.myOfferTakenEvents = myOfferTakenEvents; + this.tradeEvents = tradeEvents; + this.disputeMsgEvents = disputeMsgEvents; + this.priceAlert = priceAlert; + this.marketAlerts = marketAlerts; + this.user = user; + } + + public void initDomainServices(Consumer rejectedTxErrorMessageHandler, + Consumer displayPrivateNotificationHandler, + Consumer daoErrorMessageHandler, + Consumer daoWarnMessageHandler, + Consumer filterWarningHandler, + Consumer voteResultExceptionHandler, + Consumer> revolutAccountsUpdateHandler) { + clockWatcher.start(); + + tradeLimits.onAllServicesInitialized(); + + arbitrationManager.onAllServicesInitialized(); + mediationManager.onAllServicesInitialized(); + refundManager.onAllServicesInitialized(); + traderChatManager.onAllServicesInitialized(); + + tradeManager.onAllServicesInitialized(); + xmrTxProofService.onAllServicesInitialized(); + + openOfferManager.onAllServicesInitialized(); + + balances.onAllServicesInitialized(); + + walletAppSetup.setRejectedTxErrorMessageHandler(rejectedTxErrorMessageHandler, openOfferManager, tradeManager); + + arbitratorManager.onAllServicesInitialized(); + mediatorManager.onAllServicesInitialized(); + refundAgentManager.onAllServicesInitialized(); + + privateNotificationManager.privateNotificationProperty().addListener((observable, oldValue, newValue) -> { + if (displayPrivateNotificationHandler != null) + displayPrivateNotificationHandler.accept(newValue); + }); + + p2PService.onAllServicesInitialized(); + + feeService.onAllServicesInitialized(); + + if (DevEnv.isDaoActivated()) { + daoSetup.onAllServicesInitialized(errorMessage -> { + if (daoErrorMessageHandler != null) + daoErrorMessageHandler.accept(errorMessage); + }, warningMessage -> { + if (daoWarnMessageHandler != null) + daoWarnMessageHandler.accept(warningMessage); + }); + } + + tradeStatisticsManager.onAllServicesInitialized(); + + accountAgeWitnessService.onAllServicesInitialized(); + signedWitnessService.onAllServicesInitialized(); + + priceFeedService.setCurrencyCodeOnInit(); + + filterManager.onAllServicesInitialized(); + filterManager.setFilterWarningHandler(filterWarningHandler); + + voteResultService.getVoteResultExceptions().addListener((ListChangeListener) c -> { + c.next(); + if (c.wasAdded() && voteResultExceptionHandler != null) { + c.getAddedSubList().forEach(voteResultExceptionHandler); + } + }); + + mobileNotificationService.onAllServicesInitialized(); + myOfferTakenEvents.onAllServicesInitialized(); + tradeEvents.onAllServicesInitialized(); + disputeMsgEvents.onAllServicesInitialized(); + priceAlert.onAllServicesInitialized(); + marketAlerts.onAllServicesInitialized(); + + if (revolutAccountsUpdateHandler != null) { + revolutAccountsUpdateHandler.accept(user.getPaymentAccountsAsObservable().stream() + .filter(paymentAccount -> paymentAccount instanceof RevolutAccount) + .map(paymentAccount -> (RevolutAccount) paymentAccount) + .filter(RevolutAccount::userNameNotSet) + .collect(Collectors.toList())); + } + } +}