From 55181165c8151ac83cda00523a5464ab15cd60e3 Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Thu, 29 Apr 2021 08:02:56 +0200 Subject: [PATCH] use read timeout to improve disconnection behaviour, especially while refreshing a wallet --- .../sparrowwallet/sparrow/AppController.java | 4 +++- .../sparrow/net/ElectrumServer.java | 14 +++++++++----- .../sparrow/net/TcpTransport.java | 18 ++++++++++++++++-- .../sparrow/wallet/WalletForm.java | 13 ++++++++++--- 4 files changed, 38 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/sparrowwallet/sparrow/AppController.java b/src/main/java/com/sparrowwallet/sparrow/AppController.java index 57720a6f..81bfea33 100644 --- a/src/main/java/com/sparrowwallet/sparrow/AppController.java +++ b/src/main/java/com/sparrowwallet/sparrow/AppController.java @@ -1627,7 +1627,9 @@ public class AppController implements Initializable { walletHistoryFinished(new WalletHistoryFinishedEvent(event.getWallet())); tabs.getTabs().stream().filter(tab -> tab.getUserData() instanceof WalletTabData && ((WalletTabData) tab.getUserData()).getWallet() == event.getWallet()).forEach(this::tabLabelAddFailure); if(getOpenWallets().containsKey(event.getWallet())) { - statusUpdated(new StatusEvent("Error retrieving wallet history" + (Config.get().getServerType() == ServerType.PUBLIC_ELECTRUM_SERVER ? ", " + TRYING_ANOTHER_SERVER_MESSAGE : ""))); + if(AppServices.isConnected()) { + statusUpdated(new StatusEvent("Error retrieving wallet history" + (Config.get().getServerType() == ServerType.PUBLIC_ELECTRUM_SERVER ? ", " + TRYING_ANOTHER_SERVER_MESSAGE : ""))); + } } } diff --git a/src/main/java/com/sparrowwallet/sparrow/net/ElectrumServer.java b/src/main/java/com/sparrowwallet/sparrow/net/ElectrumServer.java index 30744aa2..343ed3e1 100644 --- a/src/main/java/com/sparrowwallet/sparrow/net/ElectrumServer.java +++ b/src/main/java/com/sparrowwallet/sparrow/net/ElectrumServer.java @@ -1032,11 +1032,15 @@ public class ElectrumServer { protected Boolean call() throws ServerException { walletSynchronizeLocks.putIfAbsent(wallet, new Object()); synchronized(walletSynchronizeLocks.get(wallet)) { - ElectrumServer electrumServer = new ElectrumServer(); - Map> nodeTransactionMap = (nodes == null ? electrumServer.getHistory(wallet) : electrumServer.getHistory(wallet, nodes)); - electrumServer.getReferencedTransactions(wallet, nodeTransactionMap); - electrumServer.calculateNodeHistory(wallet, nodeTransactionMap); - return true; + if(isConnected()) { + ElectrumServer electrumServer = new ElectrumServer(); + Map> nodeTransactionMap = (nodes == null ? electrumServer.getHistory(wallet) : electrumServer.getHistory(wallet, nodes)); + electrumServer.getReferencedTransactions(wallet, nodeTransactionMap); + electrumServer.calculateNodeHistory(wallet, nodeTransactionMap); + return true; + } + + return false; } } }; diff --git a/src/main/java/com/sparrowwallet/sparrow/net/TcpTransport.java b/src/main/java/com/sparrowwallet/sparrow/net/TcpTransport.java index aed87b0e..973d7229 100644 --- a/src/main/java/com/sparrowwallet/sparrow/net/TcpTransport.java +++ b/src/main/java/com/sparrowwallet/sparrow/net/TcpTransport.java @@ -13,6 +13,7 @@ import javax.net.SocketFactory; import javax.net.ssl.SSLHandshakeException; import java.io.*; import java.net.Socket; +import java.net.SocketTimeoutException; import java.nio.charset.StandardCharsets; import java.util.Objects; import java.util.concurrent.TimeUnit; @@ -24,6 +25,7 @@ public class TcpTransport implements Transport, Closeable { public static final int DEFAULT_PORT = 50001; private static final int[] READ_TIMEOUT_SECS = {3, 8, 16, 34}; + public static final int SOCKET_READ_TIMEOUT_MILLIS = 5000; protected final HostAndPort server; protected final SocketFactory socketFactory; @@ -181,7 +183,7 @@ public class TcpTransport implements Transport, Closeable { } protected String readInputStream(BufferedReader in) throws IOException { - String response = in.readLine(); + String response = readLine(in); if(response == null) { throw new IOException("Could not connect to server at " + Config.get().getServerAddress()); @@ -190,9 +192,22 @@ public class TcpTransport implements Transport, Closeable { return response; } + private String readLine(BufferedReader in) throws IOException { + while(!socket.isClosed()) { + try { + return in.readLine(); + } catch(SocketTimeoutException e) { + //ignore and continue + } + } + + return null; + } + public void connect() throws ServerException { try { socket = createSocket(); + socket.setSoTimeout(SOCKET_READ_TIMEOUT_MILLIS); running = true; } catch(SSLHandshakeException e) { throw new TlsServerException(server, e); @@ -216,7 +231,6 @@ public class TcpTransport implements Transport, Closeable { @Override public void close() throws IOException { if(socket != null) { - running = false; socket.close(); } } diff --git a/src/main/java/com/sparrowwallet/sparrow/wallet/WalletForm.java b/src/main/java/com/sparrowwallet/sparrow/wallet/WalletForm.java index e6a60cfd..053d169b 100644 --- a/src/main/java/com/sparrowwallet/sparrow/wallet/WalletForm.java +++ b/src/main/java/com/sparrowwallet/sparrow/wallet/WalletForm.java @@ -100,11 +100,18 @@ public class WalletForm { log.debug(node == null ? wallet.getName() + " refreshing full wallet history" : wallet.getName() + " requesting node wallet history for " + node.getDerivationPath()); ElectrumServer.TransactionHistoryService historyService = new ElectrumServer.TransactionHistoryService(wallet, getWalletTransactionNodes(node)); historyService.setOnSucceeded(workerStateEvent -> { - EventManager.get().post(new WalletHistoryFinishedEvent(wallet)); - updateWallet(blockHeight, pastWallet, previousWallet); + if(historyService.getValue()) { + EventManager.get().post(new WalletHistoryFinishedEvent(wallet)); + updateWallet(blockHeight, pastWallet, previousWallet); + } }); historyService.setOnFailed(workerStateEvent -> { - log.error("Error retrieving wallet history", workerStateEvent.getSource().getException()); + if(AppServices.isConnected()) { + log.error("Error retrieving wallet history", workerStateEvent.getSource().getException()); + } else { + log.debug("Disconnected while retrieving wallet history", workerStateEvent.getSource().getException()); + } + EventManager.get().post(new WalletHistoryFailedEvent(wallet, workerStateEvent.getSource().getException())); });