mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-04-19 15:26:03 -04:00
fix startup error with localhost, support fallback from provided nodes
This commit is contained in:
parent
8f778be4d9
commit
9d58d223d5
@ -75,9 +75,10 @@ public final class XmrConnectionService {
|
||||
private static final long KEY_IMAGE_REFRESH_PERIOD_MS_LOCAL = 20000; // 20 seconds
|
||||
private static final long KEY_IMAGE_REFRESH_PERIOD_MS_REMOTE = 300000; // 5 minutes
|
||||
|
||||
public enum XmrConnectionError {
|
||||
public enum XmrConnectionFallbackType {
|
||||
LOCAL,
|
||||
CUSTOM
|
||||
CUSTOM,
|
||||
PROVIDED
|
||||
}
|
||||
|
||||
private final Object lock = new Object();
|
||||
@ -97,7 +98,7 @@ public final class XmrConnectionService {
|
||||
private final LongProperty chainHeight = new SimpleLongProperty(0);
|
||||
private final DownloadListener downloadListener = new DownloadListener();
|
||||
@Getter
|
||||
private final ObjectProperty<XmrConnectionError> connectionServiceError = new SimpleObjectProperty<>();
|
||||
private final ObjectProperty<XmrConnectionFallbackType> connectionServiceFallbackType = new SimpleObjectProperty<>();
|
||||
@Getter
|
||||
private final StringProperty connectionServiceErrorMsg = new SimpleStringProperty();
|
||||
private final LongProperty numUpdates = new SimpleLongProperty(0);
|
||||
@ -129,6 +130,7 @@ public final class XmrConnectionService {
|
||||
private Set<MoneroRpcConnection> excludedConnections = new HashSet<>();
|
||||
private static final long FALLBACK_INVOCATION_PERIOD_MS = 1000 * 30 * 1; // offer to fallback up to once every 30s
|
||||
private boolean fallbackApplied;
|
||||
private boolean usedSyncingLocalNodeBeforeStartup;
|
||||
|
||||
@Inject
|
||||
public XmrConnectionService(P2PService p2PService,
|
||||
@ -156,7 +158,13 @@ public final class XmrConnectionService {
|
||||
p2PService.addP2PServiceListener(new P2PServiceListener() {
|
||||
@Override
|
||||
public void onTorNodeReady() {
|
||||
ThreadUtils.submitToPool(() -> initialize());
|
||||
ThreadUtils.submitToPool(() -> {
|
||||
try {
|
||||
initialize();
|
||||
} catch (Exception e) {
|
||||
log.warn("Error initializing connection service, error={}\n", e.getMessage(), e);
|
||||
}
|
||||
});
|
||||
}
|
||||
@Override
|
||||
public void onHiddenServicePublished() {}
|
||||
@ -270,7 +278,7 @@ public final class XmrConnectionService {
|
||||
accountService.checkAccountOpen();
|
||||
|
||||
// user needs to authorize fallback on startup after using locally synced node
|
||||
if (lastInfo == null && !fallbackApplied && lastUsedLocalSyncingNode() && !xmrLocalNode.isDetected()) {
|
||||
if (fallbackRequiredBeforeConnectionSwitch()) {
|
||||
log.warn("Cannot get best connection on startup because we last synced local node and user has not opted to fallback");
|
||||
return null;
|
||||
}
|
||||
@ -283,6 +291,10 @@ public final class XmrConnectionService {
|
||||
return bestConnection;
|
||||
}
|
||||
|
||||
private boolean fallbackRequiredBeforeConnectionSwitch() {
|
||||
return lastInfo == null && !fallbackApplied && usedSyncingLocalNodeBeforeStartup && (!xmrLocalNode.isDetected() || xmrLocalNode.shouldBeIgnored());
|
||||
}
|
||||
|
||||
private void addLocalNodeIfIgnored(Collection<MoneroRpcConnection> ignoredConnections) {
|
||||
if (xmrLocalNode.shouldBeIgnored() && connectionManager.hasConnection(xmrLocalNode.getUri())) ignoredConnections.add(connectionManager.getConnectionByUri(xmrLocalNode.getUri()));
|
||||
}
|
||||
@ -458,15 +470,20 @@ public final class XmrConnectionService {
|
||||
|
||||
public void fallbackToBestConnection() {
|
||||
if (isShutDownStarted) return;
|
||||
if (xmrNodes.getProvidedXmrNodes().isEmpty()) {
|
||||
fallbackApplied = true;
|
||||
if (isProvidedConnections() || xmrNodes.getProvidedXmrNodes().isEmpty()) {
|
||||
log.warn("Falling back to public nodes");
|
||||
preferences.setMoneroNodesOptionOrdinal(XmrNodes.MoneroNodesOption.PUBLIC.ordinal());
|
||||
initializeConnections();
|
||||
} else {
|
||||
log.warn("Falling back to provided nodes");
|
||||
preferences.setMoneroNodesOptionOrdinal(XmrNodes.MoneroNodesOption.PROVIDED.ordinal());
|
||||
initializeConnections();
|
||||
if (getConnection() == null) {
|
||||
log.warn("No provided nodes available, falling back to public nodes");
|
||||
fallbackToBestConnection();
|
||||
}
|
||||
}
|
||||
fallbackApplied = true;
|
||||
initializeConnections();
|
||||
}
|
||||
|
||||
// ------------------------------- HELPERS --------------------------------
|
||||
@ -578,8 +595,8 @@ public final class XmrConnectionService {
|
||||
setConnection(connection.getUri());
|
||||
|
||||
// reset error connecting to local node
|
||||
if (connectionServiceError.get() == XmrConnectionError.LOCAL && isConnectionLocalHost()) {
|
||||
connectionServiceError.set(null);
|
||||
if (connectionServiceFallbackType.get() == XmrConnectionFallbackType.LOCAL && isConnectionLocalHost()) {
|
||||
connectionServiceFallbackType.set(null);
|
||||
}
|
||||
} else if (getConnection() != null && getConnection().getUri().equals(connection.getUri())) {
|
||||
MoneroRpcConnection bestConnection = getBestConnection();
|
||||
@ -602,8 +619,10 @@ public final class XmrConnectionService {
|
||||
// add default connections
|
||||
for (XmrNode node : xmrNodes.getAllXmrNodes()) {
|
||||
if (node.hasClearNetAddress()) {
|
||||
MoneroRpcConnection connection = new MoneroRpcConnection(node.getAddress() + ":" + node.getPort()).setPriority(node.getPriority());
|
||||
if (!connectionList.hasConnection(connection.getUri())) addConnection(connection);
|
||||
if (!xmrLocalNode.shouldBeIgnored() || !xmrLocalNode.equalsUri(node.getClearNetUri())) {
|
||||
MoneroRpcConnection connection = new MoneroRpcConnection(node.getHostNameOrAddress() + ":" + node.getPort()).setPriority(node.getPriority());
|
||||
if (!connectionList.hasConnection(connection.getUri())) addConnection(connection);
|
||||
}
|
||||
}
|
||||
if (node.hasOnionAddress()) {
|
||||
MoneroRpcConnection connection = new MoneroRpcConnection(node.getOnionAddress() + ":" + node.getPort()).setPriority(node.getPriority());
|
||||
@ -615,8 +634,10 @@ public final class XmrConnectionService {
|
||||
// add default connections
|
||||
for (XmrNode node : xmrNodes.selectPreferredNodes(new XmrNodesSetupPreferences(preferences))) {
|
||||
if (node.hasClearNetAddress()) {
|
||||
MoneroRpcConnection connection = new MoneroRpcConnection(node.getAddress() + ":" + node.getPort()).setPriority(node.getPriority());
|
||||
addConnection(connection);
|
||||
if (!xmrLocalNode.shouldBeIgnored() || !xmrLocalNode.equalsUri(node.getClearNetUri())) {
|
||||
MoneroRpcConnection connection = new MoneroRpcConnection(node.getHostNameOrAddress() + ":" + node.getPort()).setPriority(node.getPriority());
|
||||
addConnection(connection);
|
||||
}
|
||||
}
|
||||
if (node.hasOnionAddress()) {
|
||||
MoneroRpcConnection connection = new MoneroRpcConnection(node.getOnionAddress() + ":" + node.getPort()).setPriority(node.getPriority());
|
||||
@ -632,6 +653,11 @@ public final class XmrConnectionService {
|
||||
}
|
||||
}
|
||||
|
||||
// set if last node was locally syncing
|
||||
if (!isInitialized) {
|
||||
usedSyncingLocalNodeBeforeStartup = connectionList.getCurrentConnectionUri().isPresent() && xmrLocalNode.equalsUri(connectionList.getCurrentConnectionUri().get()) && preferences.getXmrNodeSettings().getSyncBlockchain();
|
||||
}
|
||||
|
||||
// set connection proxies
|
||||
log.info("TOR proxy URI: " + getProxyUri());
|
||||
for (MoneroRpcConnection connection : connectionManager.getConnections()) {
|
||||
@ -666,29 +692,16 @@ public final class XmrConnectionService {
|
||||
onConnectionChanged(connectionManager.getConnection());
|
||||
}
|
||||
|
||||
private boolean lastUsedLocalSyncingNode() {
|
||||
return connectionManager.getConnection() != null && xmrLocalNode.equalsUri(connectionManager.getConnection().getUri()) && !xmrLocalNode.isDetected() && !xmrLocalNode.shouldBeIgnored();
|
||||
}
|
||||
|
||||
public void startLocalNode() {
|
||||
public void startLocalNode() throws Exception {
|
||||
|
||||
// cannot start local node as seed node
|
||||
if (HavenoUtils.isSeedNode()) {
|
||||
throw new RuntimeException("Cannot start local node on seed node");
|
||||
}
|
||||
|
||||
// start local node if offline and used as last connection
|
||||
if (connectionManager.getConnection() != null && xmrLocalNode.equalsUri(connectionManager.getConnection().getUri()) && !xmrLocalNode.isDetected() && !xmrLocalNode.shouldBeIgnored()) {
|
||||
try {
|
||||
log.info("Starting local node");
|
||||
xmrLocalNode.start();
|
||||
} catch (Exception e) {
|
||||
log.error("Unable to start local monero node, error={}\n", e.getMessage(), e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException("Local node is not offline and used as last connection");
|
||||
}
|
||||
// start local node
|
||||
log.info("Starting local node");
|
||||
xmrLocalNode.start();
|
||||
}
|
||||
|
||||
private void onConnectionChanged(MoneroRpcConnection currentConnection) {
|
||||
@ -768,7 +781,7 @@ public final class XmrConnectionService {
|
||||
try {
|
||||
|
||||
// poll daemon
|
||||
if (daemon == null) switchToBestConnection();
|
||||
if (daemon == null && !fallbackRequiredBeforeConnectionSwitch()) switchToBestConnection();
|
||||
try {
|
||||
if (daemon == null) throw new RuntimeException("No connection to Monero daemon");
|
||||
lastInfo = daemon.getInfo();
|
||||
@ -778,16 +791,19 @@ public final class XmrConnectionService {
|
||||
if (isShutDownStarted) return;
|
||||
|
||||
// invoke fallback handling on startup error
|
||||
boolean canFallback = isFixedConnection() || isCustomConnections() || lastUsedLocalSyncingNode();
|
||||
boolean canFallback = isFixedConnection() || isProvidedConnections() || isCustomConnections() || usedSyncingLocalNodeBeforeStartup;
|
||||
if (lastInfo == null && canFallback) {
|
||||
if (connectionServiceError.get() == null && (lastFallbackInvocation == null || System.currentTimeMillis() - lastFallbackInvocation > FALLBACK_INVOCATION_PERIOD_MS)) {
|
||||
if (connectionServiceFallbackType.get() == null && (lastFallbackInvocation == null || System.currentTimeMillis() - lastFallbackInvocation > FALLBACK_INVOCATION_PERIOD_MS)) {
|
||||
lastFallbackInvocation = System.currentTimeMillis();
|
||||
if (lastUsedLocalSyncingNode()) {
|
||||
if (usedSyncingLocalNodeBeforeStartup) {
|
||||
log.warn("Failed to fetch daemon info from local connection on startup: " + e.getMessage());
|
||||
connectionServiceError.set(XmrConnectionError.LOCAL);
|
||||
connectionServiceFallbackType.set(XmrConnectionFallbackType.LOCAL);
|
||||
} else if (isProvidedConnections()) {
|
||||
log.warn("Failed to fetch daemon info from provided connections on startup: " + e.getMessage());
|
||||
connectionServiceFallbackType.set(XmrConnectionFallbackType.PROVIDED);
|
||||
} else {
|
||||
log.warn("Failed to fetch daemon info from custom connection on startup: " + e.getMessage());
|
||||
connectionServiceError.set(XmrConnectionError.CUSTOM);
|
||||
connectionServiceFallbackType.set(XmrConnectionFallbackType.CUSTOM);
|
||||
}
|
||||
}
|
||||
return;
|
||||
@ -808,7 +824,7 @@ public final class XmrConnectionService {
|
||||
|
||||
// connected to daemon
|
||||
isConnected = true;
|
||||
connectionServiceError.set(null);
|
||||
connectionServiceFallbackType.set(null);
|
||||
|
||||
// determine if blockchain is syncing locally
|
||||
boolean blockchainSyncing = lastInfo.getHeight().equals(lastInfo.getHeightWithoutBootstrap()) || (lastInfo.getTargetHeight().equals(0l) && lastInfo.getHeightWithoutBootstrap().equals(0l)); // blockchain is syncing if height equals height without bootstrap, or target height and height without bootstrap both equal 0
|
||||
@ -885,10 +901,14 @@ public final class XmrConnectionService {
|
||||
}
|
||||
|
||||
private boolean isFixedConnection() {
|
||||
return !"".equals(config.xmrNode) && (!HavenoUtils.isLocalHost(config.xmrNode) || !xmrLocalNode.shouldBeIgnored()) && !fallbackApplied;
|
||||
return !"".equals(config.xmrNode) && !(HavenoUtils.isLocalHost(config.xmrNode) && xmrLocalNode.shouldBeIgnored()) && !fallbackApplied;
|
||||
}
|
||||
|
||||
private boolean isCustomConnections() {
|
||||
return preferences.getMoneroNodesOption() == XmrNodes.MoneroNodesOption.CUSTOM;
|
||||
}
|
||||
|
||||
private boolean isProvidedConnections() {
|
||||
return preferences.getMoneroNodesOption() == XmrNodes.MoneroNodesOption.PROVIDED;
|
||||
}
|
||||
}
|
||||
|
@ -109,17 +109,18 @@ public class XmrLocalNode {
|
||||
public boolean shouldBeIgnored() {
|
||||
if (config.ignoreLocalXmrNode) return true;
|
||||
|
||||
// determine if local node is configured
|
||||
// ignore if fixed connection is not local
|
||||
if (!"".equals(config.xmrNode)) return !HavenoUtils.isLocalHost(config.xmrNode);
|
||||
|
||||
// check if local node is within configuration
|
||||
boolean hasConfiguredLocalNode = false;
|
||||
for (XmrNode node : xmrNodes.selectPreferredNodes(new XmrNodesSetupPreferences(preferences))) {
|
||||
if (node.getAddress() != null && equalsUri("http://" + node.getAddress() + ":" + node.getPort())) {
|
||||
if (node.hasClearNetAddress() && equalsUri(node.getClearNetUri())) {
|
||||
hasConfiguredLocalNode = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasConfiguredLocalNode) return true;
|
||||
|
||||
return false;
|
||||
return !hasConfiguredLocalNode;
|
||||
}
|
||||
|
||||
public void addListener(XmrLocalNodeListener listener) {
|
||||
|
@ -75,7 +75,7 @@ public class HavenoHeadlessApp implements HeadlessApp {
|
||||
log.info("onDisplayTacHandler: We accept the tacs automatically in headless mode");
|
||||
acceptedHandler.run();
|
||||
});
|
||||
havenoSetup.setDisplayMoneroConnectionErrorHandler(show -> log.warn("onDisplayMoneroConnectionErrorHandler: show={}", show));
|
||||
havenoSetup.setDisplayMoneroConnectionFallbackHandler(show -> log.warn("onDisplayMoneroConnectionFallbackHandler: show={}", show));
|
||||
havenoSetup.setDisplayTorNetworkSettingsHandler(show -> log.info("onDisplayTorNetworkSettingsHandler: show={}", show));
|
||||
havenoSetup.setChainFileLockedExceptionHandler(msg -> log.error("onChainFileLockedExceptionHandler: msg={}", msg));
|
||||
tradeManager.setLockedUpFundsHandler(msg -> log.info("onLockedUpFundsHandler: msg={}", msg));
|
||||
|
@ -55,7 +55,7 @@ import haveno.core.alert.PrivateNotificationManager;
|
||||
import haveno.core.alert.PrivateNotificationPayload;
|
||||
import haveno.core.api.CoreContext;
|
||||
import haveno.core.api.XmrConnectionService;
|
||||
import haveno.core.api.XmrConnectionService.XmrConnectionError;
|
||||
import haveno.core.api.XmrConnectionService.XmrConnectionFallbackType;
|
||||
import haveno.core.api.XmrLocalNode;
|
||||
import haveno.core.locale.Res;
|
||||
import haveno.core.offer.OpenOfferManager;
|
||||
@ -159,7 +159,7 @@ public class HavenoSetup {
|
||||
rejectedTxErrorMessageHandler;
|
||||
@Setter
|
||||
@Nullable
|
||||
private Consumer<XmrConnectionError> displayMoneroConnectionErrorHandler;
|
||||
private Consumer<XmrConnectionFallbackType> displayMoneroConnectionFallbackHandler;
|
||||
@Setter
|
||||
@Nullable
|
||||
private Consumer<Boolean> displayTorNetworkSettingsHandler;
|
||||
@ -431,9 +431,9 @@ public class HavenoSetup {
|
||||
getXmrWalletSyncProgress().addListener((observable, oldValue, newValue) -> resetStartupTimeout());
|
||||
|
||||
// listen for fallback handling
|
||||
getConnectionServiceError().addListener((observable, oldValue, newValue) -> {
|
||||
if (displayMoneroConnectionErrorHandler == null) return;
|
||||
displayMoneroConnectionErrorHandler.accept(newValue);
|
||||
getConnectionServiceFallbackType().addListener((observable, oldValue, newValue) -> {
|
||||
if (displayMoneroConnectionFallbackHandler == null) return;
|
||||
displayMoneroConnectionFallbackHandler.accept(newValue);
|
||||
});
|
||||
|
||||
log.info("Init P2P network");
|
||||
@ -735,8 +735,8 @@ public class HavenoSetup {
|
||||
return xmrConnectionService.getConnectionServiceErrorMsg();
|
||||
}
|
||||
|
||||
public ObjectProperty<XmrConnectionError> getConnectionServiceError() {
|
||||
return xmrConnectionService.getConnectionServiceError();
|
||||
public ObjectProperty<XmrConnectionFallbackType> getConnectionServiceFallbackType() {
|
||||
return xmrConnectionService.getConnectionServiceFallbackType();
|
||||
}
|
||||
|
||||
public StringProperty getTopErrorMsg() {
|
||||
|
@ -184,10 +184,6 @@ public class XmrNodes {
|
||||
this.operator = operator;
|
||||
}
|
||||
|
||||
public boolean hasOnionAddress() {
|
||||
return onionAddress != null;
|
||||
}
|
||||
|
||||
public String getHostNameOrAddress() {
|
||||
if (hostName != null)
|
||||
return hostName;
|
||||
@ -195,10 +191,19 @@ public class XmrNodes {
|
||||
return address;
|
||||
}
|
||||
|
||||
public boolean hasOnionAddress() {
|
||||
return onionAddress != null;
|
||||
}
|
||||
|
||||
public boolean hasClearNetAddress() {
|
||||
return hostName != null || address != null;
|
||||
}
|
||||
|
||||
public String getClearNetUri() {
|
||||
if (!hasClearNetAddress()) throw new IllegalStateException("XmrNode does not have clearnet address");
|
||||
return "http://" + getHostNameOrAddress() + ":" + port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "onionAddress='" + onionAddress + '\'' +
|
||||
|
@ -2090,7 +2090,8 @@ closedTradesSummaryWindow.totalTradeFeeInXmr.value={0} ({1} of total trade amoun
|
||||
walletPasswordWindow.headline=Enter password to unlock
|
||||
|
||||
xmrConnectionError.headline=Monero connection error
|
||||
xmrConnectionError.customNode=Error connecting to your custom Monero node(s).\n\nDo you want to use the next best available Monero node?
|
||||
xmrConnectionError.providedNodes=Error connecting to provided Monero node(s).\n\nDo you want to use the next best available Monero node?
|
||||
xmrConnectionError.customNodes=Error connecting to your custom Monero node(s).\n\nDo you want to use the next best available Monero node?
|
||||
xmrConnectionError.localNode=We previously synced using a local Monero node, but it appears to be unreachable.\n\nPlease check that it's running and synced.
|
||||
xmrConnectionError.localNode.start=Start local node
|
||||
xmrConnectionError.localNode.start.error=Error starting local node
|
||||
|
@ -337,7 +337,7 @@ public class MainViewModel implements ViewModel, HavenoSetup.HavenoSetupListener
|
||||
tacWindow.onAction(acceptedHandler::run).show();
|
||||
}, 1));
|
||||
|
||||
havenoSetup.setDisplayMoneroConnectionErrorHandler(connectionError -> {
|
||||
havenoSetup.setDisplayMoneroConnectionFallbackHandler(connectionError -> {
|
||||
if (connectionError == null) {
|
||||
if (moneroConnectionErrorPopup != null) moneroConnectionErrorPopup.hide();
|
||||
} else {
|
||||
@ -349,7 +349,6 @@ public class MainViewModel implements ViewModel, HavenoSetup.HavenoSetupListener
|
||||
.actionButtonText(Res.get("xmrConnectionError.localNode.start"))
|
||||
.onAction(() -> {
|
||||
log.warn("User has chosen to start local node.");
|
||||
havenoSetup.getConnectionServiceError().set(null);
|
||||
new Thread(() -> {
|
||||
try {
|
||||
HavenoUtils.xmrConnectionService.startLocalNode();
|
||||
@ -359,16 +358,20 @@ public class MainViewModel implements ViewModel, HavenoSetup.HavenoSetupListener
|
||||
.headLine(Res.get("xmrConnectionError.localNode.start.error"))
|
||||
.warning(e.getMessage())
|
||||
.closeButtonText(Res.get("shared.close"))
|
||||
.onClose(() -> havenoSetup.getConnectionServiceError().set(null))
|
||||
.onClose(() -> havenoSetup.getConnectionServiceFallbackType().set(null))
|
||||
.show();
|
||||
} finally {
|
||||
havenoSetup.getConnectionServiceFallbackType().set(null);
|
||||
}
|
||||
}).start();
|
||||
})
|
||||
.secondaryActionButtonText(Res.get("xmrConnectionError.localNode.fallback"))
|
||||
.onSecondaryAction(() -> {
|
||||
log.warn("User has chosen to fallback to the next best available Monero node.");
|
||||
havenoSetup.getConnectionServiceError().set(null);
|
||||
new Thread(() -> HavenoUtils.xmrConnectionService.fallbackToBestConnection()).start();
|
||||
new Thread(() -> {
|
||||
HavenoUtils.xmrConnectionService.fallbackToBestConnection();
|
||||
havenoSetup.getConnectionServiceFallbackType().set(null);
|
||||
}).start();
|
||||
})
|
||||
.closeButtonText(Res.get("shared.shutDown"))
|
||||
.onClose(HavenoApp.getShutDownHandler());
|
||||
@ -376,16 +379,35 @@ public class MainViewModel implements ViewModel, HavenoSetup.HavenoSetupListener
|
||||
case CUSTOM:
|
||||
moneroConnectionErrorPopup = new Popup()
|
||||
.headLine(Res.get("xmrConnectionError.headline"))
|
||||
.warning(Res.get("xmrConnectionError.customNode"))
|
||||
.warning(Res.get("xmrConnectionError.customNodes"))
|
||||
.actionButtonText(Res.get("shared.yes"))
|
||||
.onAction(() -> {
|
||||
havenoSetup.getConnectionServiceError().set(null);
|
||||
new Thread(() -> HavenoUtils.xmrConnectionService.fallbackToBestConnection()).start();
|
||||
new Thread(() -> {
|
||||
HavenoUtils.xmrConnectionService.fallbackToBestConnection();
|
||||
havenoSetup.getConnectionServiceFallbackType().set(null);
|
||||
}).start();
|
||||
})
|
||||
.closeButtonText(Res.get("shared.no"))
|
||||
.onClose(() -> {
|
||||
log.warn("User has declined to fallback to the next best available Monero node.");
|
||||
havenoSetup.getConnectionServiceError().set(null);
|
||||
havenoSetup.getConnectionServiceFallbackType().set(null);
|
||||
});
|
||||
break;
|
||||
case PROVIDED:
|
||||
moneroConnectionErrorPopup = new Popup()
|
||||
.headLine(Res.get("xmrConnectionError.headline"))
|
||||
.warning(Res.get("xmrConnectionError.providedNodes"))
|
||||
.actionButtonText(Res.get("shared.yes"))
|
||||
.onAction(() -> {
|
||||
new Thread(() -> {
|
||||
HavenoUtils.xmrConnectionService.fallbackToBestConnection();
|
||||
havenoSetup.getConnectionServiceFallbackType().set(null);
|
||||
}).start();
|
||||
})
|
||||
.closeButtonText(Res.get("shared.no"))
|
||||
.onClose(() -> {
|
||||
log.warn("User has declined to fallback to the next best available Monero node.");
|
||||
havenoSetup.getConnectionServiceFallbackType().set(null);
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user