unregister closed tab and dialog subscribers, fix connection error reset behaviour

This commit is contained in:
Craig Raw 2020-08-20 11:25:34 +02:00
parent d5aba35184
commit 77dd8ca5d7
22 changed files with 188 additions and 15 deletions

View file

@ -188,6 +188,18 @@ public class AppController implements Initializable {
EventManager.get().post(new OpenWalletsEvent(getOpenWallets()));
}
List<WalletTabData> closedWalletTabs = c.getRemoved().stream().map(tab -> (TabData)tab.getUserData())
.filter(tabData -> tabData.getType() == TabData.TabType.WALLET).map(tabData -> (WalletTabData)tabData).collect(Collectors.toList());
if(!closedWalletTabs.isEmpty()) {
EventManager.get().post(new WalletTabsClosedEvent(closedWalletTabs));
}
List<TransactionTabData> closedTransactionTabs = c.getRemoved().stream().map(tab -> (TabData)tab.getUserData())
.filter(tabData -> tabData.getType() == TabData.TabType.TRANSACTION).map(tabData -> (TransactionTabData)tabData).collect(Collectors.toList());
if(!closedTransactionTabs.isEmpty()) {
EventManager.get().post(new TransactionTabsClosedEvent(closedTransactionTabs));
}
if(tabs.getTabs().isEmpty()) {
Stage tabStage = (Stage)tabs.getScene().getWindow();
tabStage.setTitle("Sparrow");
@ -268,10 +280,14 @@ public class AppController implements Initializable {
}
});
connectionService.setOnFailed(failEvent -> {
//Close connection here to create a new transport next time we try
connectionService.resetConnection();
changeMode = false;
onlineProperty.setValue(false);
changeMode = true;
log.debug("Connection failed", failEvent.getSource().getException());
EventManager.get().post(new ConnectionFailedEvent(failEvent.getSource().getException()));
});

View file

@ -12,6 +12,10 @@ public class WalletTabData extends TabData {
this.walletForm = walletForm;
}
public WalletForm getWalletForm() {
return walletForm;
}
public Wallet getWallet() {
return walletForm.getWallet();
}

View file

@ -19,6 +19,9 @@ public class DeviceAddressDialog extends DeviceDialog<String> {
this.keyDerivation = keyDerivation;
EventManager.get().register(this);
setOnCloseRequest(event -> {
EventManager.get().unregister(this);
});
}
@Override
@ -28,7 +31,6 @@ public class DeviceAddressDialog extends DeviceDialog<String> {
@Subscribe
public void addressDisplayed(AddressDisplayedEvent event) {
EventManager.get().unregister(this);
setResult(event.getAddress());
this.close();
}

View file

@ -15,6 +15,9 @@ public class DeviceSignDialog extends DeviceDialog<PSBT> {
super(devices);
this.psbt = psbt;
EventManager.get().register(this);
setOnCloseRequest(event -> {
EventManager.get().unregister(this);
});
setResultConverter(dialogButton -> dialogButton.getButtonData().isCancelButton() ? null : psbt);
}
@ -26,7 +29,6 @@ public class DeviceSignDialog extends DeviceDialog<PSBT> {
@Subscribe
public void psbtSigned(PSBTSignedEvent event) {
if(psbt == event.getPsbt()) {
EventManager.get().unregister(this);
setResult(event.getSignedPsbt());
this.close();
}

View file

@ -21,6 +21,9 @@ public class WalletExportDialog extends Dialog<Wallet> {
public WalletExportDialog(Wallet wallet) {
EventManager.get().register(this);
setOnCloseRequest(event -> {
EventManager.get().unregister(this);
});
final DialogPane dialogPane = getDialogPane();
@ -64,7 +67,6 @@ public class WalletExportDialog extends Dialog<Wallet> {
@Subscribe
public void walletExported(WalletExportEvent event) {
EventManager.get().unregister(this);
wallet = event.getWallet();
setResult(wallet);
this.close();

View file

@ -16,6 +16,9 @@ public class WalletImportDialog extends Dialog<Wallet> {
public WalletImportDialog() {
EventManager.get().register(this);
setOnCloseRequest(event -> {
EventManager.get().unregister(this);
});
final DialogPane dialogPane = getDialogPane();
@ -51,7 +54,6 @@ public class WalletImportDialog extends Dialog<Wallet> {
@Subscribe
public void walletImported(WalletImportEvent event) {
EventManager.get().unregister(this);
wallet = event.getWallet();
setResult(wallet);
this.close();

View file

@ -0,0 +1,17 @@
package com.sparrowwallet.sparrow.event;
import com.sparrowwallet.sparrow.TransactionTabData;
import java.util.List;
public class TransactionTabsClosedEvent {
private final List<TransactionTabData> closedTransactionTabData;
public TransactionTabsClosedEvent(List<TransactionTabData> closedTransactionTabData) {
this.closedTransactionTabData = closedTransactionTabData;
}
public List<TransactionTabData> getClosedTransactionTabData() {
return closedTransactionTabData;
}
}

View file

@ -0,0 +1,17 @@
package com.sparrowwallet.sparrow.event;
import com.sparrowwallet.sparrow.WalletTabData;
import java.util.List;
public class WalletTabsClosedEvent {
private final List<WalletTabData> closedWalletTabData;
public WalletTabsClosedEvent(List<WalletTabData> closedWalletTabData) {
this.closedWalletTabData = closedWalletTabData;
}
public List<WalletTabData> getClosedWalletTabData() {
return closedWalletTabData;
}
}

View file

@ -27,6 +27,10 @@ public class KeystoreImportDialog extends Dialog<Keystore> {
public KeystoreImportDialog(Wallet wallet, KeystoreSource initialSource) {
EventManager.get().register(this);
setOnCloseRequest(event -> {
EventManager.get().unregister(this);
});
final DialogPane dialogPane = getDialogPane();
try {

View file

@ -579,7 +579,6 @@ public class ElectrumServer {
private final boolean subscribe;
private boolean firstCall = true;
private Thread reader;
private Throwable lastReaderException;
private long feeRatesRetrievedAt;
public ConnectionService() {
@ -598,7 +597,7 @@ public class ElectrumServer {
if(firstCall) {
electrumServer.connect();
reader = new Thread(new ReadRunnable());
reader = new Thread(new ReadRunnable(), "ElectrumServerReadThread");
reader.setDaemon(true);
reader.setUncaughtExceptionHandler(ConnectionService.this);
reader.start();
@ -639,8 +638,7 @@ public class ElectrumServer {
return new FeeRatesUpdatedEvent(blockTargetFeeRates);
}
} else {
firstCall = true;
throw new ServerException("Connection to server failed", lastReaderException);
resetConnection();
}
}
@ -649,12 +647,21 @@ public class ElectrumServer {
};
}
public void resetConnection() {
try {
closeActiveConnection();
firstCall = true;
} catch (ServerException e) {
log.error("Error closing connection during connection reset", e);
}
}
@Override
public boolean cancel() {
try {
closeActiveConnection();
} catch (ServerException e) {
log.error("Eror closing connection", e);
log.error("Error closing connection", e);
}
return super.cancel();
@ -664,12 +671,11 @@ public class ElectrumServer {
public void reset() {
super.reset();
firstCall = true;
lastReaderException = null;
}
@Override
public void uncaughtException(Thread t, Throwable e) {
this.lastReaderException = e;
log.error("Uncaught error in ConnectionService", e);
}
}
@ -680,7 +686,8 @@ public class ElectrumServer {
TcpTransport tcpTransport = (TcpTransport)getTransport();
tcpTransport.readInputLoop();
} catch(ServerException e) {
throw new RuntimeException(e.getCause() != null ? e.getCause() : e);
//Only debug logging here as the exception has been passed on to the ConnectionService thread via TcpTransport
log.debug("Read thread terminated", e);
}
}
}

View file

@ -28,6 +28,8 @@ public class TcpTransport implements Transport, Closeable {
private final JsonRpcServer jsonRpcServer = new JsonRpcServer();
private final SubscriptionService subscriptionService = new SubscriptionService();
private Exception lastException;
public TcpTransport(HostAndPort server) {
this.server = server;
this.socketFactory = SocketFactory.getDefault();
@ -50,7 +52,7 @@ public class TcpTransport implements Transport, Closeable {
out.flush();
}
private synchronized String readResponse() {
private synchronized String readResponse() throws IOException {
while(reading) {
try {
wait();
@ -60,6 +62,10 @@ public class TcpTransport implements Transport, Closeable {
}
}
if(lastException != null) {
throw new IOException("Error reading response", lastException);
}
reading = true;
notifyAll();
@ -83,8 +89,12 @@ public class TcpTransport implements Transport, Closeable {
} catch(InterruptedException e) {
//Restore interrupt status and continue
Thread.currentThread().interrupt();
} catch(IOException e) {
} catch(Exception e) {
if(running) {
lastException = e;
reading = false;
notifyAll();
//Allow this thread to terminate as we will need to reconnect with a new transport anyway
throw new ServerException(e);
}
}

View file

@ -196,6 +196,11 @@ public class HeadersController extends TransactionFormController implements Init
initializeView();
}
@Override
protected TransactionForm getTransactionForm() {
return headersForm;
}
private void initializeView() {
Transaction tx = headersForm.getTransaction();

View file

@ -461,6 +461,11 @@ public class InputController extends TransactionFormController implements Initia
initializeView();
}
@Override
protected TransactionForm getTransactionForm() {
return inputForm;
}
@Override
protected String describeScriptChunk(ScriptChunk chunk) {
String chunkString = super.describeScriptChunk(chunk);

View file

@ -49,6 +49,11 @@ public class InputsController extends TransactionFormController implements Initi
initialiseView();
}
@Override
protected TransactionForm getTransactionForm() {
return inputsForm;
}
private void initialiseView() {
Transaction tx = inputsForm.getTransaction();
count.setText(Integer.toString(tx.getInputs().size()));

View file

@ -147,6 +147,11 @@ public class OutputController extends TransactionFormController implements Initi
initializeView();
}
@Override
protected TransactionForm getTransactionForm() {
return outputForm;
}
@Subscribe
public void blockTransactionOutputsFetched(BlockTransactionOutputsFetchedEvent event) {
if(event.getTxId().equals(outputForm.getTransaction().getTxId()) && outputForm.getPsbt() == null && outputForm.getIndex() >= event.getPageStart() && outputForm.getIndex() < event.getPageEnd()) {

View file

@ -51,6 +51,11 @@ public class OutputsController extends TransactionFormController implements Init
}
}
@Override
protected TransactionForm getTransactionForm() {
return outputsForm;
}
@Subscribe
public void bitcoinUnitChanged(BitcoinUnitChangedEvent event) {
total.refresh(event.getBitcoinUnit());

View file

@ -8,6 +8,7 @@ import com.sparrowwallet.drongo.psbt.PSBTOutput;
import com.sparrowwallet.drongo.wallet.BlockTransaction;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.TransactionTabData;
import com.sparrowwallet.sparrow.control.TransactionHexArea;
import com.sparrowwallet.sparrow.event.*;
import com.sparrowwallet.sparrow.net.ElectrumServer;
@ -489,4 +490,13 @@ public class TransactionController implements Initializable {
highlightTxHex();
}
}
@Subscribe
public void transactionTabsClosed(TransactionTabsClosedEvent event) {
for(TransactionTabData tabData : event.getClosedTransactionTabData()) {
if(tabData.getTransactionData() == txdata) {
EventManager.get().unregister(this);
}
}
}
}

View file

@ -23,6 +23,10 @@ public abstract class TransactionForm {
this.txdata = txdata;
}
public TransactionData getTransactionData() {
return txdata;
}
public Transaction getTransaction() {
return txdata.getTransaction();
}

View file

@ -1,9 +1,13 @@
package com.sparrowwallet.sparrow.transaction;
import com.google.common.eventbus.Subscribe;
import com.sparrowwallet.drongo.address.Address;
import com.sparrowwallet.drongo.protocol.NonStandardScriptException;
import com.sparrowwallet.drongo.protocol.TransactionOutput;
import com.sparrowwallet.sparrow.BaseController;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.TransactionTabData;
import com.sparrowwallet.sparrow.event.TransactionTabsClosedEvent;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.chart.PieChart;
@ -18,6 +22,8 @@ import java.util.List;
public abstract class TransactionFormController extends BaseController {
private static final int MAX_PIE_SEGMENTS = 200;
protected abstract TransactionForm getTransactionForm();
protected void addPieData(PieChart pie, List<TransactionOutput> outputs) {
ObservableList<PieChart.Data> outputsPieData = FXCollections.observableArrayList();
@ -64,6 +70,15 @@ public abstract class TransactionFormController extends BaseController {
});
}
@Subscribe
public void transactionTabsClosed(TransactionTabsClosedEvent event) {
for(TransactionTabData tabData : event.getClosedTransactionTabData()) {
if(tabData.getTransactionData() == getTransactionForm().getTransactionData()) {
EventManager.get().unregister(this);
}
}
}
public static class TransactionReferenceContextMenu extends ContextMenu {
public TransactionReferenceContextMenu(String reference) {
MenuItem referenceItem = new MenuItem("Copy Reference");

View file

@ -7,8 +7,10 @@ import com.sparrowwallet.drongo.wallet.BlockTransactionHash;
import com.sparrowwallet.drongo.wallet.BlockTransactionHashIndex;
import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.WalletTabData;
import com.sparrowwallet.sparrow.event.WalletBlockHeightChangedEvent;
import com.sparrowwallet.sparrow.event.WalletEntryLabelChangedEvent;
import com.sparrowwallet.sparrow.event.WalletTabsClosedEvent;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.IntegerPropertyBase;
import javafx.beans.property.LongProperty;
@ -204,4 +206,13 @@ public class TransactionEntry extends Entry implements Comparable<TransactionEnt
}
}
}
@Subscribe
public void walletTabsClosed(WalletTabsClosedEvent event) {
for(WalletTabData tabData : event.getClosedWalletTabData()) {
if(tabData.getWalletForm().getWallet() == wallet) {
EventManager.get().unregister(this);
}
}
}
}

View file

@ -6,6 +6,7 @@ import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.drongo.wallet.WalletNode;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.WalletTabData;
import com.sparrowwallet.sparrow.event.*;
import com.sparrowwallet.sparrow.net.ElectrumServer;
import com.sparrowwallet.sparrow.io.Storage;
@ -216,4 +217,13 @@ public class WalletForm {
refreshHistory(AppController.getCurrentBlockHeight());
}
}
@Subscribe
public void walletTabsClosed(WalletTabsClosedEvent event) {
for(WalletTabData tabData : event.getClosedWalletTabData()) {
if(tabData.getWalletForm() == this) {
EventManager.get().unregister(this);
}
}
}
}

View file

@ -1,6 +1,10 @@
package com.sparrowwallet.sparrow.wallet;
import com.google.common.eventbus.Subscribe;
import com.sparrowwallet.sparrow.BaseController;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.WalletTabData;
import com.sparrowwallet.sparrow.event.WalletTabsClosedEvent;
public abstract class WalletFormController extends BaseController {
public WalletForm walletForm;
@ -15,4 +19,15 @@ public abstract class WalletFormController extends BaseController {
}
public abstract void initializeView();
@Subscribe
public void walletTabsClosed(WalletTabsClosedEvent event) {
for(WalletTabData tabData : event.getClosedWalletTabData()) {
if(tabData.getWalletForm() == walletForm) {
EventManager.get().unregister(this);
} else if(walletForm instanceof SettingsWalletForm && tabData.getStorage() == walletForm.getStorage()) {
EventManager.get().unregister(this);
}
}
}
}