use read timeout to improve disconnection behaviour, especially while refreshing a wallet

This commit is contained in:
Craig Raw 2021-04-29 08:02:56 +02:00
parent b6f7483bf9
commit 55181165c8
4 changed files with 38 additions and 11 deletions

View file

@ -1627,9 +1627,11 @@ public class AppController implements Initializable {
walletHistoryFinished(new WalletHistoryFinishedEvent(event.getWallet())); walletHistoryFinished(new WalletHistoryFinishedEvent(event.getWallet()));
tabs.getTabs().stream().filter(tab -> tab.getUserData() instanceof WalletTabData && ((WalletTabData) tab.getUserData()).getWallet() == event.getWallet()).forEach(this::tabLabelAddFailure); tabs.getTabs().stream().filter(tab -> tab.getUserData() instanceof WalletTabData && ((WalletTabData) tab.getUserData()).getWallet() == event.getWallet()).forEach(this::tabLabelAddFailure);
if(getOpenWallets().containsKey(event.getWallet())) { if(getOpenWallets().containsKey(event.getWallet())) {
if(AppServices.isConnected()) {
statusUpdated(new StatusEvent("Error retrieving wallet history" + (Config.get().getServerType() == ServerType.PUBLIC_ELECTRUM_SERVER ? ", " + TRYING_ANOTHER_SERVER_MESSAGE : ""))); statusUpdated(new StatusEvent("Error retrieving wallet history" + (Config.get().getServerType() == ServerType.PUBLIC_ELECTRUM_SERVER ? ", " + TRYING_ANOTHER_SERVER_MESSAGE : "")));
} }
} }
}
@Subscribe @Subscribe
public void bwtBootStatus(BwtBootStatusEvent event) { public void bwtBootStatus(BwtBootStatusEvent event) {

View file

@ -1032,12 +1032,16 @@ public class ElectrumServer {
protected Boolean call() throws ServerException { protected Boolean call() throws ServerException {
walletSynchronizeLocks.putIfAbsent(wallet, new Object()); walletSynchronizeLocks.putIfAbsent(wallet, new Object());
synchronized(walletSynchronizeLocks.get(wallet)) { synchronized(walletSynchronizeLocks.get(wallet)) {
if(isConnected()) {
ElectrumServer electrumServer = new ElectrumServer(); ElectrumServer electrumServer = new ElectrumServer();
Map<WalletNode, Set<BlockTransactionHash>> nodeTransactionMap = (nodes == null ? electrumServer.getHistory(wallet) : electrumServer.getHistory(wallet, nodes)); Map<WalletNode, Set<BlockTransactionHash>> nodeTransactionMap = (nodes == null ? electrumServer.getHistory(wallet) : electrumServer.getHistory(wallet, nodes));
electrumServer.getReferencedTransactions(wallet, nodeTransactionMap); electrumServer.getReferencedTransactions(wallet, nodeTransactionMap);
electrumServer.calculateNodeHistory(wallet, nodeTransactionMap); electrumServer.calculateNodeHistory(wallet, nodeTransactionMap);
return true; return true;
} }
return false;
}
} }
}; };
} }

View file

@ -13,6 +13,7 @@ import javax.net.SocketFactory;
import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.SSLHandshakeException;
import java.io.*; import java.io.*;
import java.net.Socket; import java.net.Socket;
import java.net.SocketTimeoutException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -24,6 +25,7 @@ public class TcpTransport implements Transport, Closeable {
public static final int DEFAULT_PORT = 50001; public static final int DEFAULT_PORT = 50001;
private static final int[] READ_TIMEOUT_SECS = {3, 8, 16, 34}; 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 HostAndPort server;
protected final SocketFactory socketFactory; protected final SocketFactory socketFactory;
@ -181,7 +183,7 @@ public class TcpTransport implements Transport, Closeable {
} }
protected String readInputStream(BufferedReader in) throws IOException { protected String readInputStream(BufferedReader in) throws IOException {
String response = in.readLine(); String response = readLine(in);
if(response == null) { if(response == null) {
throw new IOException("Could not connect to server at " + Config.get().getServerAddress()); throw new IOException("Could not connect to server at " + Config.get().getServerAddress());
@ -190,9 +192,22 @@ public class TcpTransport implements Transport, Closeable {
return response; 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 { public void connect() throws ServerException {
try { try {
socket = createSocket(); socket = createSocket();
socket.setSoTimeout(SOCKET_READ_TIMEOUT_MILLIS);
running = true; running = true;
} catch(SSLHandshakeException e) { } catch(SSLHandshakeException e) {
throw new TlsServerException(server, e); throw new TlsServerException(server, e);
@ -216,7 +231,6 @@ public class TcpTransport implements Transport, Closeable {
@Override @Override
public void close() throws IOException { public void close() throws IOException {
if(socket != null) { if(socket != null) {
running = false;
socket.close(); socket.close();
} }
} }

View file

@ -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()); 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)); ElectrumServer.TransactionHistoryService historyService = new ElectrumServer.TransactionHistoryService(wallet, getWalletTransactionNodes(node));
historyService.setOnSucceeded(workerStateEvent -> { historyService.setOnSucceeded(workerStateEvent -> {
if(historyService.getValue()) {
EventManager.get().post(new WalletHistoryFinishedEvent(wallet)); EventManager.get().post(new WalletHistoryFinishedEvent(wallet));
updateWallet(blockHeight, pastWallet, previousWallet); updateWallet(blockHeight, pastWallet, previousWallet);
}
}); });
historyService.setOnFailed(workerStateEvent -> { historyService.setOnFailed(workerStateEvent -> {
if(AppServices.isConnected()) {
log.error("Error retrieving wallet history", workerStateEvent.getSource().getException()); 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())); EventManager.get().post(new WalletHistoryFailedEvent(wallet, workerStateEvent.getSource().getException()));
}); });