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()));
tabs.getTabs().stream().filter(tab -> tab.getUserData() instanceof WalletTabData && ((WalletTabData) tab.getUserData()).getWallet() == event.getWallet()).forEach(this::tabLabelAddFailure);
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 : "")));
}
}
}
@Subscribe
public void bwtBootStatus(BwtBootStatusEvent event) {

View file

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

View file

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

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());
ElectrumServer.TransactionHistoryService historyService = new ElectrumServer.TransactionHistoryService(wallet, getWalletTransactionNodes(node));
historyService.setOnSucceeded(workerStateEvent -> {
if(historyService.getValue()) {
EventManager.get().post(new WalletHistoryFinishedEvent(wallet));
updateWallet(blockHeight, pastWallet, previousWallet);
}
});
historyService.setOnFailed(workerStateEvent -> {
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()));
});