bwt preferences and connection handling improvements

This commit is contained in:
Craig Raw 2021-01-12 13:24:11 +02:00
parent 6637ea09bf
commit d847da9d61
10 changed files with 100 additions and 40 deletions

View file

@ -1268,11 +1268,13 @@ public class AppController implements Initializable {
@Subscribe @Subscribe
public void bwtBootStatus(BwtBootStatusEvent event) { public void bwtBootStatus(BwtBootStatusEvent event) {
serverToggle.setDisable(true);
statusUpdated(new StatusEvent(event.getStatus())); statusUpdated(new StatusEvent(event.getStatus()));
} }
@Subscribe @Subscribe
public void bwtSyncStatus(BwtSyncStatusEvent event) { public void bwtSyncStatus(BwtSyncStatusEvent event) {
serverToggle.setDisable(false);
if((AppServices.isConnecting() || AppServices.isConnected()) && !event.isCompleted()) { if((AppServices.isConnecting() || AppServices.isConnected()) && !event.isCompleted()) {
statusUpdated(new StatusEvent(event.getStatus())); statusUpdated(new StatusEvent(event.getStatus()));
} }
@ -1280,11 +1282,25 @@ public class AppController implements Initializable {
@Subscribe @Subscribe
public void bwtScanStatus(BwtScanStatusEvent event) { public void bwtScanStatus(BwtScanStatusEvent event) {
serverToggle.setDisable(true);
if((AppServices.isConnecting() || AppServices.isConnected()) && !event.isCompleted()) { if((AppServices.isConnecting() || AppServices.isConnected()) && !event.isCompleted()) {
statusUpdated(new StatusEvent(event.getStatus())); 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 @Subscribe
public void newBlock(NewBlockEvent event) { public void newBlock(NewBlockEvent event) {
setServerToggleTooltip(event.getHeight()); setServerToggleTooltip(event.getHeight());

View file

@ -108,7 +108,7 @@ public class AppServices {
service.cancel(); service.cancel();
} }
if(service.getState() == Worker.State.CANCELLED) { if(service.getState() == Worker.State.CANCELLED || service.getState() == Worker.State.FAILED) {
service.reset(); service.reset();
} }
@ -171,6 +171,8 @@ public class AppServices {
}); });
connectionService.setOnSucceeded(successEvent -> { connectionService.setOnSucceeded(successEvent -> {
connectionService.setRestartOnFailure(true);
onlineProperty.removeListener(onlineServicesListener); onlineProperty.removeListener(onlineServicesListener);
onlineProperty.setValue(true); onlineProperty.setValue(true);
onlineProperty.addListener(onlineServicesListener); onlineProperty.addListener(onlineServicesListener);
@ -183,6 +185,10 @@ public class AppServices {
//Close connection here to create a new transport next time we try //Close connection here to create a new transport next time we try
connectionService.resetConnection(); connectionService.resetConnection();
if(failEvent.getSource().getException() instanceof ServerConfigException) {
connectionService.setRestartOnFailure(false);
}
onlineProperty.removeListener(onlineServicesListener); onlineProperty.removeListener(onlineServicesListener);
onlineProperty.setValue(false); onlineProperty.setValue(false);
onlineProperty.addListener(onlineServicesListener); onlineProperty.addListener(onlineServicesListener);
@ -303,7 +309,7 @@ public class AppServices {
} }
public static boolean isConnecting() { public static boolean isConnecting() {
return onlineProperty.get() && get().connectionService.isConnecting(); return get().connectionService != null && get().connectionService.isConnecting();
} }
public static boolean isConnected() { public static boolean isConnected() {

View file

@ -2,7 +2,8 @@ package com.sparrowwallet.sparrow.event;
/** /**
* Empty class used to notify the bwt has shut down. * 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 {
} }

View file

@ -0,0 +1,8 @@
package com.sparrowwallet.sparrow.event;
/**
* Empty class used to signal that the server has been disconnected from.
*/
public class DisconnectionEvent {
}

View file

@ -129,6 +129,7 @@ public class Bwt {
} }
NativeBwtDaemon.shutdown(shutdownPtr); NativeBwtDaemon.shutdown(shutdownPtr);
this.terminating = false;
this.ready = false; this.ready = false;
this.shutdownPtr = null; this.shutdownPtr = null;
Platform.runLater(() -> EventManager.get().post(new BwtShutdownEvent())); Platform.runLater(() -> EventManager.get().post(new BwtShutdownEvent()));

View file

@ -10,6 +10,7 @@ import com.sparrowwallet.drongo.Utils;
import com.sparrowwallet.drongo.protocol.*; import com.sparrowwallet.drongo.protocol.*;
import com.sparrowwallet.drongo.wallet.*; import com.sparrowwallet.drongo.wallet.*;
import com.sparrowwallet.sparrow.AppServices; import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.event.*; import com.sparrowwallet.sparrow.event.*;
import com.sparrowwallet.sparrow.io.Config; import com.sparrowwallet.sparrow.io.Config;
import com.sparrowwallet.sparrow.wallet.SendController; import com.sparrowwallet.sparrow.wallet.SendController;
@ -54,7 +55,7 @@ public class ElectrumServer {
if(Config.get().getServerType() == ServerType.BITCOIN_CORE) { if(Config.get().getServerType() == ServerType.BITCOIN_CORE) {
if(bwtElectrumServer == null) { 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; electrumServer = bwtElectrumServer;
} else if(Config.get().getServerType() == ServerType.ELECTRUM_SERVER) { } else if(Config.get().getServerType() == ServerType.ELECTRUM_SERVER) {
@ -64,16 +65,16 @@ public class ElectrumServer {
} }
if(electrumServer == null) { if(electrumServer == null) {
throw new ServerException("Electrum server URL not specified"); throw new ServerConfigException("Electrum server URL not specified");
} }
if(electrumServerCert != null && !electrumServerCert.exists()) { 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); Protocol protocol = Protocol.getProtocol(electrumServer);
if(protocol == null) { 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); HostAndPort server = protocol.getServerHostAndPort(electrumServer);
@ -93,7 +94,7 @@ public class ElectrumServer {
} }
} }
} catch (Exception e) { } catch (Exception e) {
throw new ServerException(e); throw new ServerConfigException(e);
} }
} }
@ -795,18 +796,6 @@ public class ElectrumServer {
ElectrumServer electrumServer = new ElectrumServer(); ElectrumServer electrumServer = new ElectrumServer();
if(Config.get().getServerType() == ServerType.BITCOIN_CORE) { 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()) { if(!bwt.isRunning()) {
Bwt.ConnectionService bwtConnectionService = bwt.getConnectionService(subscribe ? AppServices.get().getOpenWallets().keySet() : null); Bwt.ConnectionService bwtConnectionService = bwt.getConnectionService(subscribe ? AppServices.get().getOpenWallets().keySet() : null);
bwtConnectionService.setOnFailed(workerStateEvent -> { bwtConnectionService.setOnFailed(workerStateEvent -> {
@ -900,7 +889,7 @@ public class ElectrumServer {
public void resetConnection() { public void resetConnection() {
try { try {
closeActiveConnection(); closeActiveConnection();
shutdownBwt(); shutdown();
firstCall = true; firstCall = true;
} catch (ServerException e) { } catch (ServerException e) {
log.error("Error closing connection during connection reset", e); log.error("Error closing connection during connection reset", e);
@ -919,7 +908,7 @@ public class ElectrumServer {
public boolean cancel() { public boolean cancel() {
try { try {
closeActiveConnection(); closeActiveConnection();
shutdownBwt(); shutdown();
} catch (ServerException e) { } catch (ServerException e) {
log.error("Error closing connection", e); log.error("Error closing connection", e);
} }
@ -927,8 +916,8 @@ public class ElectrumServer {
return super.cancel(); return super.cancel();
} }
private void shutdownBwt() { private void shutdown() {
if(Config.get().getServerType() == ServerType.BITCOIN_CORE) { if(Config.get().getServerType() == ServerType.BITCOIN_CORE && bwt.isRunning()) {
Bwt.DisconnectionService disconnectionService = bwt.getDisconnectionService(); Bwt.DisconnectionService disconnectionService = bwt.getDisconnectionService();
disconnectionService.setOnSucceeded(workerStateEvent -> { disconnectionService.setOnSucceeded(workerStateEvent -> {
ElectrumServer.bwtElectrumServer = null; ElectrumServer.bwtElectrumServer = null;
@ -937,6 +926,8 @@ public class ElectrumServer {
log.error("Failed to stop BWT", workerStateEvent.getSource().getException()); log.error("Failed to stop BWT", workerStateEvent.getSource().getException());
}); });
Platform.runLater(disconnectionService::start); Platform.runLater(disconnectionService::start);
} else {
Platform.runLater(() -> EventManager.get().post(new DisconnectionEvent()));
} }
} }

View file

@ -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);
}
}

View file

@ -28,6 +28,8 @@ public class PreferencesController implements Initializable {
private final BooleanProperty closing = new SimpleBooleanProperty(false); private final BooleanProperty closing = new SimpleBooleanProperty(false);
private final BooleanProperty reconnectOnClosing = new SimpleBooleanProperty(false);
@Override @Override
public void initialize(URL location, ResourceBundle resources) { public void initialize(URL location, ResourceBundle resources) {
@ -64,6 +66,14 @@ public class PreferencesController implements Initializable {
return closing; return closing;
} }
public boolean isReconnectOnClosing() {
return reconnectOnClosing.get();
}
public BooleanProperty reconnectOnClosingProperty() {
return reconnectOnClosing;
}
FXMLLoader setPreferencePane(String fxmlName) { FXMLLoader setPreferencePane(String fxmlName) {
preferencesPane.getChildren().removeAll(preferencesPane.getChildren()); preferencesPane.getChildren().removeAll(preferencesPane.getChildren());

View file

@ -15,8 +15,6 @@ import org.controlsfx.tools.Borders;
import java.io.IOException; import java.io.IOException;
public class PreferencesDialog extends Dialog<Boolean> { public class PreferencesDialog extends Dialog<Boolean> {
private final boolean existingConnection;
public PreferencesDialog() { public PreferencesDialog() {
this(null); this(null);
} }
@ -51,10 +49,10 @@ public class PreferencesDialog extends Dialog<Boolean> {
dialogPane.setPrefWidth(650); dialogPane.setPrefWidth(650);
dialogPane.setPrefHeight(600); dialogPane.setPrefHeight(600);
existingConnection = ElectrumServer.isConnected(); preferencesController.reconnectOnClosingProperty().set(AppServices.isConnecting() || AppServices.isConnected());
setOnCloseRequest(event -> { setOnCloseRequest(event -> {
preferencesController.closingProperty().set(true); preferencesController.closingProperty().set(true);
if(existingConnection && !ElectrumServer.isConnected()) { if(preferencesController.isReconnectOnClosing() && !(AppServices.isConnecting() || AppServices.isConnected())) {
EventManager.get().post(new RequestConnectEvent()); EventManager.get().post(new RequestConnectEvent());
} }
}); });

View file

@ -3,6 +3,7 @@ package com.sparrowwallet.sparrow.preferences;
import com.google.common.eventbus.Subscribe; import com.google.common.eventbus.Subscribe;
import com.google.common.net.HostAndPort; import com.google.common.net.HostAndPort;
import com.sparrowwallet.drongo.Network; import com.sparrowwallet.drongo.Network;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.EventManager; import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.control.TextFieldValidator; import com.sparrowwallet.sparrow.control.TextFieldValidator;
import com.sparrowwallet.sparrow.control.UnlabeledToggleSwitch; 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); setFieldsEditable(!isConnected);
if(AppServices.isConnecting()) {
testResults.appendText("Connecting to server, please wait...");
}
testConnection.managedProperty().bind(testConnection.visibleProperty()); testConnection.managedProperty().bind(testConnection.visibleProperty());
testConnection.setVisible(!isConnected); testConnection.setVisible(!isConnected);
setTestResultsFont(); setTestResultsFont();
@ -265,6 +270,7 @@ public class ServerPreferencesController extends PreferencesDetailController {
editConnection.managedProperty().bind(editConnection.visibleProperty()); editConnection.managedProperty().bind(editConnection.visibleProperty());
editConnection.setVisible(isConnected); editConnection.setVisible(isConnected);
editConnection.setDisable(AppServices.isConnecting());
editConnection.setOnAction(event -> { editConnection.setOnAction(event -> {
EventManager.get().post(new RequestDisconnectEvent()); EventManager.get().post(new RequestDisconnectEvent());
setFieldsEditable(true); setFieldsEditable(true);
@ -364,6 +370,7 @@ public class ServerPreferencesController extends PreferencesDetailController {
EventManager.get().unregister(connectionService); EventManager.get().unregister(connectionService);
ConnectionEvent connectionEvent = (ConnectionEvent)connectionService.getValue(); ConnectionEvent connectionEvent = (ConnectionEvent)connectionService.getValue();
showConnectionSuccess(connectionEvent.getServerVersion(), connectionEvent.getServerBanner()); showConnectionSuccess(connectionEvent.getServerVersion(), connectionEvent.getServerBanner());
getMasterController().reconnectOnClosingProperty().set(true);
connectionService.cancel(); connectionService.cancel();
}); });
connectionService.setOnFailed(workerStateEvent -> { connectionService.setOnFailed(workerStateEvent -> {
@ -377,24 +384,24 @@ public class ServerPreferencesController extends PreferencesDetailController {
private void setFieldsEditable(boolean editable) { private void setFieldsEditable(boolean editable) {
serverTypeToggleGroup.getToggles().forEach(toggle -> ((ToggleButton)toggle).setDisable(!editable)); serverTypeToggleGroup.getToggles().forEach(toggle -> ((ToggleButton)toggle).setDisable(!editable));
coreHost.setEditable(editable); coreHost.setDisable(!editable);
corePort.setEditable(editable); corePort.setDisable(!editable);
coreAuthToggleGroup.getToggles().forEach(toggle -> ((ToggleButton)toggle).setDisable(!editable)); coreAuthToggleGroup.getToggles().forEach(toggle -> ((ToggleButton)toggle).setDisable(!editable));
coreDataDir.setEditable(editable); coreDataDir.setDisable(!editable);
coreDataDirSelect.setDisable(!editable); coreDataDirSelect.setDisable(!editable);
coreUser.setEditable(editable); coreUser.setDisable(!editable);
corePass.setEditable(editable); corePass.setDisable(!editable);
coreMultiWallet.setDisable(!editable); coreMultiWallet.setDisable(!editable);
coreWallet.setEditable(editable); coreWallet.setDisable(!editable);
electrumHost.setEditable(editable); electrumHost.setDisable(!editable);
electrumPort.setEditable(editable); electrumPort.setDisable(!editable);
electrumUseSsl.setDisable(!editable); electrumUseSsl.setDisable(!editable);
electrumCertificate.setEditable(editable); electrumCertificate.setDisable(!editable);
electrumCertificateSelect.setDisable(!editable); electrumCertificateSelect.setDisable(!editable);
useProxy.setDisable(!editable); useProxy.setDisable(!editable);
proxyHost.setEditable(editable); proxyHost.setDisable(!editable);
proxyPort.setEditable(editable); proxyPort.setDisable(!editable);
} }
private void showConnectionSuccess(List<String> serverVersion, String serverBanner) { private void showConnectionSuccess(List<String> serverVersion, String serverBanner) {
@ -624,10 +631,14 @@ public class ServerPreferencesController extends PreferencesDetailController {
if(!(event instanceof BwtSyncStatusEvent)) { if(!(event instanceof BwtSyncStatusEvent)) {
testResults.appendText("\n" + event.getStatus()); testResults.appendText("\n" + event.getStatus());
} }
if(event instanceof BwtReadyStatusEvent) {
editConnection.setDisable(false);
}
} }
@Subscribe @Subscribe
public void bwtSyncStatus(BwtSyncStatusEvent event) { public void bwtSyncStatus(BwtSyncStatusEvent event) {
editConnection.setDisable(false);
if(connectionService != null && connectionService.isRunning() && event.getProgress() < 100) { if(connectionService != null && connectionService.isRunning() && event.getProgress() < 100) {
DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm"); 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."); testResults.appendText("\nThe connection to the Bitcoin Core node was successful, but it is still syncing and cannot be used yet.");