From d847da9d610fc8176c63da7c2e8c356b38645216 Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Tue, 12 Jan 2021 13:24:11 +0200 Subject: [PATCH] bwt preferences and connection handling improvements --- .../sparrowwallet/sparrow/AppController.java | 16 +++++++++ .../sparrowwallet/sparrow/AppServices.java | 10 ++++-- .../sparrow/event/BwtShutdownEvent.java | 3 +- .../sparrow/event/DisconnectionEvent.java | 8 +++++ .../com/sparrowwallet/sparrow/net/Bwt.java | 1 + .../sparrow/net/ElectrumServer.java | 33 +++++++---------- .../sparrow/net/ServerConfigException.java | 18 ++++++++++ .../preferences/PreferencesController.java | 10 ++++++ .../preferences/PreferencesDialog.java | 6 ++-- .../ServerPreferencesController.java | 35 ++++++++++++------- 10 files changed, 100 insertions(+), 40 deletions(-) create mode 100644 src/main/java/com/sparrowwallet/sparrow/event/DisconnectionEvent.java create mode 100644 src/main/java/com/sparrowwallet/sparrow/net/ServerConfigException.java diff --git a/src/main/java/com/sparrowwallet/sparrow/AppController.java b/src/main/java/com/sparrowwallet/sparrow/AppController.java index fe3aebbc..382adc02 100644 --- a/src/main/java/com/sparrowwallet/sparrow/AppController.java +++ b/src/main/java/com/sparrowwallet/sparrow/AppController.java @@ -1268,11 +1268,13 @@ public class AppController implements Initializable { @Subscribe public void bwtBootStatus(BwtBootStatusEvent event) { + serverToggle.setDisable(true); statusUpdated(new StatusEvent(event.getStatus())); } @Subscribe public void bwtSyncStatus(BwtSyncStatusEvent event) { + serverToggle.setDisable(false); if((AppServices.isConnecting() || AppServices.isConnected()) && !event.isCompleted()) { statusUpdated(new StatusEvent(event.getStatus())); } @@ -1280,11 +1282,25 @@ public class AppController implements Initializable { @Subscribe public void bwtScanStatus(BwtScanStatusEvent event) { + serverToggle.setDisable(true); if((AppServices.isConnecting() || AppServices.isConnected()) && !event.isCompleted()) { statusUpdated(new StatusEvent(event.getStatus())); } } + @Subscribe + public void bwtReadyStatus(BwtReadyStatusEvent event) { + serverToggle.setDisable(false); + } + + @Subscribe + public void disconnection(DisconnectionEvent event) { + serverToggle.setDisable(false); + if(!AppServices.isConnecting() && !AppServices.isConnected() && !statusBar.getText().startsWith("Connection error")) { + statusUpdated(new StatusEvent("Disconnected")); + } + } + @Subscribe public void newBlock(NewBlockEvent event) { setServerToggleTooltip(event.getHeight()); diff --git a/src/main/java/com/sparrowwallet/sparrow/AppServices.java b/src/main/java/com/sparrowwallet/sparrow/AppServices.java index ba7cf781..812523d5 100644 --- a/src/main/java/com/sparrowwallet/sparrow/AppServices.java +++ b/src/main/java/com/sparrowwallet/sparrow/AppServices.java @@ -108,7 +108,7 @@ public class AppServices { service.cancel(); } - if(service.getState() == Worker.State.CANCELLED) { + if(service.getState() == Worker.State.CANCELLED || service.getState() == Worker.State.FAILED) { service.reset(); } @@ -171,6 +171,8 @@ public class AppServices { }); connectionService.setOnSucceeded(successEvent -> { + connectionService.setRestartOnFailure(true); + onlineProperty.removeListener(onlineServicesListener); onlineProperty.setValue(true); onlineProperty.addListener(onlineServicesListener); @@ -183,6 +185,10 @@ public class AppServices { //Close connection here to create a new transport next time we try connectionService.resetConnection(); + if(failEvent.getSource().getException() instanceof ServerConfigException) { + connectionService.setRestartOnFailure(false); + } + onlineProperty.removeListener(onlineServicesListener); onlineProperty.setValue(false); onlineProperty.addListener(onlineServicesListener); @@ -303,7 +309,7 @@ public class AppServices { } public static boolean isConnecting() { - return onlineProperty.get() && get().connectionService.isConnecting(); + return get().connectionService != null && get().connectionService.isConnecting(); } public static boolean isConnected() { diff --git a/src/main/java/com/sparrowwallet/sparrow/event/BwtShutdownEvent.java b/src/main/java/com/sparrowwallet/sparrow/event/BwtShutdownEvent.java index 57f0351f..d171613f 100644 --- a/src/main/java/com/sparrowwallet/sparrow/event/BwtShutdownEvent.java +++ b/src/main/java/com/sparrowwallet/sparrow/event/BwtShutdownEvent.java @@ -2,7 +2,8 @@ package com.sparrowwallet.sparrow.event; /** * Empty class used to notify the bwt has shut down. + * Note this extends from DisconnectionEvent, which is the more general event fired on any type of disconnection. */ -public class BwtShutdownEvent { +public class BwtShutdownEvent extends DisconnectionEvent { } diff --git a/src/main/java/com/sparrowwallet/sparrow/event/DisconnectionEvent.java b/src/main/java/com/sparrowwallet/sparrow/event/DisconnectionEvent.java new file mode 100644 index 00000000..ecf21f3d --- /dev/null +++ b/src/main/java/com/sparrowwallet/sparrow/event/DisconnectionEvent.java @@ -0,0 +1,8 @@ +package com.sparrowwallet.sparrow.event; + +/** + * Empty class used to signal that the server has been disconnected from. + */ +public class DisconnectionEvent { + +} diff --git a/src/main/java/com/sparrowwallet/sparrow/net/Bwt.java b/src/main/java/com/sparrowwallet/sparrow/net/Bwt.java index 35399a2e..ebd7ce5c 100644 --- a/src/main/java/com/sparrowwallet/sparrow/net/Bwt.java +++ b/src/main/java/com/sparrowwallet/sparrow/net/Bwt.java @@ -129,6 +129,7 @@ public class Bwt { } NativeBwtDaemon.shutdown(shutdownPtr); + this.terminating = false; this.ready = false; this.shutdownPtr = null; Platform.runLater(() -> EventManager.get().post(new BwtShutdownEvent())); diff --git a/src/main/java/com/sparrowwallet/sparrow/net/ElectrumServer.java b/src/main/java/com/sparrowwallet/sparrow/net/ElectrumServer.java index 11037722..fd944c30 100644 --- a/src/main/java/com/sparrowwallet/sparrow/net/ElectrumServer.java +++ b/src/main/java/com/sparrowwallet/sparrow/net/ElectrumServer.java @@ -10,6 +10,7 @@ import com.sparrowwallet.drongo.Utils; import com.sparrowwallet.drongo.protocol.*; import com.sparrowwallet.drongo.wallet.*; import com.sparrowwallet.sparrow.AppServices; +import com.sparrowwallet.sparrow.EventManager; import com.sparrowwallet.sparrow.event.*; import com.sparrowwallet.sparrow.io.Config; import com.sparrowwallet.sparrow.wallet.SendController; @@ -54,7 +55,7 @@ public class ElectrumServer { if(Config.get().getServerType() == ServerType.BITCOIN_CORE) { if(bwtElectrumServer == null) { - throw new ServerException("Could not connect to Bitcoin Core RPC"); + throw new ServerConfigException("Could not connect to Bitcoin Core RPC"); } electrumServer = bwtElectrumServer; } else if(Config.get().getServerType() == ServerType.ELECTRUM_SERVER) { @@ -64,16 +65,16 @@ public class ElectrumServer { } if(electrumServer == null) { - throw new ServerException("Electrum server URL not specified"); + throw new ServerConfigException("Electrum server URL not specified"); } if(electrumServerCert != null && !electrumServerCert.exists()) { - throw new ServerException("Electrum server certificate file not found"); + throw new ServerConfigException("Electrum server certificate file not found"); } Protocol protocol = Protocol.getProtocol(electrumServer); if(protocol == null) { - throw new ServerException("Electrum server URL must start with " + Protocol.TCP.toUrlString() + " or " + Protocol.SSL.toUrlString()); + throw new ServerConfigException("Electrum server URL must start with " + Protocol.TCP.toUrlString() + " or " + Protocol.SSL.toUrlString()); } HostAndPort server = protocol.getServerHostAndPort(electrumServer); @@ -93,7 +94,7 @@ public class ElectrumServer { } } } catch (Exception e) { - throw new ServerException(e); + throw new ServerConfigException(e); } } @@ -795,18 +796,6 @@ public class ElectrumServer { ElectrumServer electrumServer = new ElectrumServer(); if(Config.get().getServerType() == ServerType.BITCOIN_CORE) { - if(bwt.isTerminating()) { - try { - bwtStartLock.lock(); - bwtStartCondition.await(); - } catch(InterruptedException e) { - Thread.currentThread().interrupt(); - return null; - } finally { - bwtStartLock.unlock(); - } - } - if(!bwt.isRunning()) { Bwt.ConnectionService bwtConnectionService = bwt.getConnectionService(subscribe ? AppServices.get().getOpenWallets().keySet() : null); bwtConnectionService.setOnFailed(workerStateEvent -> { @@ -900,7 +889,7 @@ public class ElectrumServer { public void resetConnection() { try { closeActiveConnection(); - shutdownBwt(); + shutdown(); firstCall = true; } catch (ServerException e) { log.error("Error closing connection during connection reset", e); @@ -919,7 +908,7 @@ public class ElectrumServer { public boolean cancel() { try { closeActiveConnection(); - shutdownBwt(); + shutdown(); } catch (ServerException e) { log.error("Error closing connection", e); } @@ -927,8 +916,8 @@ public class ElectrumServer { return super.cancel(); } - private void shutdownBwt() { - if(Config.get().getServerType() == ServerType.BITCOIN_CORE) { + private void shutdown() { + if(Config.get().getServerType() == ServerType.BITCOIN_CORE && bwt.isRunning()) { Bwt.DisconnectionService disconnectionService = bwt.getDisconnectionService(); disconnectionService.setOnSucceeded(workerStateEvent -> { ElectrumServer.bwtElectrumServer = null; @@ -937,6 +926,8 @@ public class ElectrumServer { log.error("Failed to stop BWT", workerStateEvent.getSource().getException()); }); Platform.runLater(disconnectionService::start); + } else { + Platform.runLater(() -> EventManager.get().post(new DisconnectionEvent())); } } diff --git a/src/main/java/com/sparrowwallet/sparrow/net/ServerConfigException.java b/src/main/java/com/sparrowwallet/sparrow/net/ServerConfigException.java new file mode 100644 index 00000000..cf5d93d0 --- /dev/null +++ b/src/main/java/com/sparrowwallet/sparrow/net/ServerConfigException.java @@ -0,0 +1,18 @@ +package com.sparrowwallet.sparrow.net; + +public class ServerConfigException extends ServerException { + public ServerConfigException() { + } + + public ServerConfigException(String message) { + super(message); + } + + public ServerConfigException(Throwable cause) { + super(cause); + } + + public ServerConfigException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/com/sparrowwallet/sparrow/preferences/PreferencesController.java b/src/main/java/com/sparrowwallet/sparrow/preferences/PreferencesController.java index 83f513f3..2fe79206 100644 --- a/src/main/java/com/sparrowwallet/sparrow/preferences/PreferencesController.java +++ b/src/main/java/com/sparrowwallet/sparrow/preferences/PreferencesController.java @@ -28,6 +28,8 @@ public class PreferencesController implements Initializable { private final BooleanProperty closing = new SimpleBooleanProperty(false); + private final BooleanProperty reconnectOnClosing = new SimpleBooleanProperty(false); + @Override public void initialize(URL location, ResourceBundle resources) { @@ -64,6 +66,14 @@ public class PreferencesController implements Initializable { return closing; } + public boolean isReconnectOnClosing() { + return reconnectOnClosing.get(); + } + + public BooleanProperty reconnectOnClosingProperty() { + return reconnectOnClosing; + } + FXMLLoader setPreferencePane(String fxmlName) { preferencesPane.getChildren().removeAll(preferencesPane.getChildren()); diff --git a/src/main/java/com/sparrowwallet/sparrow/preferences/PreferencesDialog.java b/src/main/java/com/sparrowwallet/sparrow/preferences/PreferencesDialog.java index c59d6c7a..9af84ec5 100644 --- a/src/main/java/com/sparrowwallet/sparrow/preferences/PreferencesDialog.java +++ b/src/main/java/com/sparrowwallet/sparrow/preferences/PreferencesDialog.java @@ -15,8 +15,6 @@ import org.controlsfx.tools.Borders; import java.io.IOException; public class PreferencesDialog extends Dialog { - private final boolean existingConnection; - public PreferencesDialog() { this(null); } @@ -51,10 +49,10 @@ public class PreferencesDialog extends Dialog { dialogPane.setPrefWidth(650); dialogPane.setPrefHeight(600); - existingConnection = ElectrumServer.isConnected(); + preferencesController.reconnectOnClosingProperty().set(AppServices.isConnecting() || AppServices.isConnected()); setOnCloseRequest(event -> { preferencesController.closingProperty().set(true); - if(existingConnection && !ElectrumServer.isConnected()) { + if(preferencesController.isReconnectOnClosing() && !(AppServices.isConnecting() || AppServices.isConnected())) { EventManager.get().post(new RequestConnectEvent()); } }); diff --git a/src/main/java/com/sparrowwallet/sparrow/preferences/ServerPreferencesController.java b/src/main/java/com/sparrowwallet/sparrow/preferences/ServerPreferencesController.java index fa13661f..fad6995f 100644 --- a/src/main/java/com/sparrowwallet/sparrow/preferences/ServerPreferencesController.java +++ b/src/main/java/com/sparrowwallet/sparrow/preferences/ServerPreferencesController.java @@ -3,6 +3,7 @@ package com.sparrowwallet.sparrow.preferences; import com.google.common.eventbus.Subscribe; import com.google.common.net.HostAndPort; import com.sparrowwallet.drongo.Network; +import com.sparrowwallet.sparrow.AppServices; import com.sparrowwallet.sparrow.EventManager; import com.sparrowwallet.sparrow.control.TextFieldValidator; import com.sparrowwallet.sparrow.control.UnlabeledToggleSwitch; @@ -251,9 +252,13 @@ public class ServerPreferencesController extends PreferencesDetailController { } }); - boolean isConnected = ElectrumServer.isConnected(); + boolean isConnected = AppServices.isConnecting() || AppServices.isConnected(); setFieldsEditable(!isConnected); + if(AppServices.isConnecting()) { + testResults.appendText("Connecting to server, please wait..."); + } + testConnection.managedProperty().bind(testConnection.visibleProperty()); testConnection.setVisible(!isConnected); setTestResultsFont(); @@ -265,6 +270,7 @@ public class ServerPreferencesController extends PreferencesDetailController { editConnection.managedProperty().bind(editConnection.visibleProperty()); editConnection.setVisible(isConnected); + editConnection.setDisable(AppServices.isConnecting()); editConnection.setOnAction(event -> { EventManager.get().post(new RequestDisconnectEvent()); setFieldsEditable(true); @@ -364,6 +370,7 @@ public class ServerPreferencesController extends PreferencesDetailController { EventManager.get().unregister(connectionService); ConnectionEvent connectionEvent = (ConnectionEvent)connectionService.getValue(); showConnectionSuccess(connectionEvent.getServerVersion(), connectionEvent.getServerBanner()); + getMasterController().reconnectOnClosingProperty().set(true); connectionService.cancel(); }); connectionService.setOnFailed(workerStateEvent -> { @@ -377,24 +384,24 @@ public class ServerPreferencesController extends PreferencesDetailController { private void setFieldsEditable(boolean editable) { serverTypeToggleGroup.getToggles().forEach(toggle -> ((ToggleButton)toggle).setDisable(!editable)); - coreHost.setEditable(editable); - corePort.setEditable(editable); + coreHost.setDisable(!editable); + corePort.setDisable(!editable); coreAuthToggleGroup.getToggles().forEach(toggle -> ((ToggleButton)toggle).setDisable(!editable)); - coreDataDir.setEditable(editable); + coreDataDir.setDisable(!editable); coreDataDirSelect.setDisable(!editable); - coreUser.setEditable(editable); - corePass.setEditable(editable); + coreUser.setDisable(!editable); + corePass.setDisable(!editable); coreMultiWallet.setDisable(!editable); - coreWallet.setEditable(editable); + coreWallet.setDisable(!editable); - electrumHost.setEditable(editable); - electrumPort.setEditable(editable); + electrumHost.setDisable(!editable); + electrumPort.setDisable(!editable); electrumUseSsl.setDisable(!editable); - electrumCertificate.setEditable(editable); + electrumCertificate.setDisable(!editable); electrumCertificateSelect.setDisable(!editable); useProxy.setDisable(!editable); - proxyHost.setEditable(editable); - proxyPort.setEditable(editable); + proxyHost.setDisable(!editable); + proxyPort.setDisable(!editable); } private void showConnectionSuccess(List serverVersion, String serverBanner) { @@ -624,10 +631,14 @@ public class ServerPreferencesController extends PreferencesDetailController { if(!(event instanceof BwtSyncStatusEvent)) { testResults.appendText("\n" + event.getStatus()); } + if(event instanceof BwtReadyStatusEvent) { + editConnection.setDisable(false); + } } @Subscribe public void bwtSyncStatus(BwtSyncStatusEvent event) { + editConnection.setDisable(false); if(connectionService != null && connectionService.isRunning() && event.getProgress() < 100) { DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm"); testResults.appendText("\nThe connection to the Bitcoin Core node was successful, but it is still syncing and cannot be used yet.");