refactor transport and speedup private server delay on connection failure

This commit is contained in:
Craig Raw 2022-07-27 11:02:01 +02:00
parent 04917c45b6
commit 258fe34101
5 changed files with 53 additions and 28 deletions

View file

@ -73,9 +73,11 @@ public class AppServices {
private static final int SERVER_PING_PERIOD_SECS = 60;
private static final int PUBLIC_SERVER_RETRY_PERIOD_SECS = 3;
private static final int PRIVATE_SERVER_RETRY_PERIOD_SECS = 15;
public static final int ENUMERATE_HW_PERIOD_SECS = 30;
private static final int RATES_PERIOD_SECS = 5 * 60;
private static final int VERSION_CHECK_PERIOD_HOURS = 24;
private static final int CONNECTION_DELAY_SECS = 2;
private static final ExchangeSource DEFAULT_EXCHANGE_SOURCE = ExchangeSource.COINGECKO;
private static final Currency DEFAULT_FIAT_CURRENCY = Currency.getInstance("USD");
private static final String TOR_DEFAULT_PROXY_CIRCUIT_ID = "default";
@ -251,7 +253,7 @@ public class AppServices {
private ElectrumServer.ConnectionService createConnectionService() {
ElectrumServer.ConnectionService connectionService = new ElectrumServer.ConnectionService();
//Delay startup on first connection to Bitcoin Core to allow any unencrypted wallets to open first
connectionService.setDelay(Config.get().getServerType() == ServerType.BITCOIN_CORE ? Duration.seconds(2) : Duration.ZERO);
connectionService.setDelay(Config.get().getServerType() == ServerType.BITCOIN_CORE ? Duration.seconds(CONNECTION_DELAY_SECS) : Duration.ZERO);
connectionService.setPeriod(Duration.seconds(SERVER_PING_PERIOD_SECS));
connectionService.setRestartOnFailure(true);
EventManager.get().register(connectionService);
@ -323,6 +325,8 @@ public class AppServices {
if(Config.get().getServerType() == ServerType.PUBLIC_ELECTRUM_SERVER) {
Config.get().changePublicServer();
connectionService.setPeriod(Duration.seconds(PUBLIC_SERVER_RETRY_PERIOD_SECS));
} else {
connectionService.setPeriod(Duration.seconds(PRIVATE_SERVER_RETRY_PERIOD_SECS));
}
log.debug("Connection failed", failEvent.getSource().getException());

View file

@ -0,0 +1,11 @@
package com.sparrowwallet.sparrow.net;
import com.github.arteam.simplejsonrpc.client.Transport;
import java.io.Closeable;
public interface CloseableTransport extends Transport, Closeable {
void connect() throws ServerException;
boolean isConnected();
boolean isClosed();
}

View file

@ -47,7 +47,7 @@ public class ElectrumServer {
public static final BlockTransaction UNFETCHABLE_BLOCK_TRANSACTION = new BlockTransaction(Sha256Hash.ZERO_HASH, 0, null, null, null);
private static Transport transport;
private static CloseableTransport transport;
private static final Map<String, List<String>> subscribedScriptHashes = Collections.synchronizedMap(new HashMap<>());
@ -63,7 +63,7 @@ public class ElectrumServer {
private static final Pattern RPC_WALLET_LOADING_PATTERN = Pattern.compile(".*\"(Wallet loading failed:[^\"]*)\".*");
private static synchronized Transport getTransport() throws ServerException {
private static synchronized CloseableTransport getTransport() throws ServerException {
if(transport == null) {
try {
String electrumServer = null;
@ -133,8 +133,8 @@ public class ElectrumServer {
}
public void connect() throws ServerException {
TcpTransport tcpTransport = (TcpTransport)getTransport();
tcpTransport.connect();
CloseableTransport closeableTransport = getTransport();
closeableTransport.connect();
}
public void ping() throws ServerException {
@ -163,12 +163,15 @@ public class ElectrumServer {
}
public static synchronized void closeActiveConnection() throws ServerException {
if(transport != null) {
closeConnection(transport);
transport = null;
}
}
private static void closeConnection(Closeable closeableTransport) throws ServerException {
try {
if(transport != null) {
Closeable closeableTransport = (Closeable)transport;
closeableTransport.close();
transport = null;
}
closeableTransport.close();
} catch (IOException e) {
throw new ServerException(e);
}

View file

@ -13,7 +13,7 @@ import java.security.cert.CertificateException;
public enum Protocol {
TCP {
@Override
public Transport getTransport(HostAndPort server) {
public CloseableTransport getTransport(HostAndPort server) {
if(isOnionAddress(server)) {
return new TorTcpTransport(server);
}
@ -22,24 +22,24 @@ public enum Protocol {
}
@Override
public Transport getTransport(HostAndPort server, File serverCert) {
public CloseableTransport getTransport(HostAndPort server, File serverCert) {
return getTransport(server);
}
@Override
public Transport getTransport(HostAndPort server, HostAndPort proxy) {
public CloseableTransport getTransport(HostAndPort server, HostAndPort proxy) {
//Avoid using a TorSocket if a proxy is specified, even if a .onion address
return new TcpTransport(server, proxy);
}
@Override
public Transport getTransport(HostAndPort server, File serverCert, HostAndPort proxy) {
public CloseableTransport getTransport(HostAndPort server, File serverCert, HostAndPort proxy) {
return getTransport(server, proxy);
}
},
SSL {
@Override
public Transport getTransport(HostAndPort server) throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
public CloseableTransport getTransport(HostAndPort server) throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
if(isOnionAddress(server)) {
return new TorTcpOverTlsTransport(server);
}
@ -48,7 +48,7 @@ public enum Protocol {
}
@Override
public Transport getTransport(HostAndPort server, File serverCert) throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
public CloseableTransport getTransport(HostAndPort server, File serverCert) throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
if(isOnionAddress(server)) {
return new TorTcpOverTlsTransport(server, serverCert);
}
@ -57,44 +57,44 @@ public enum Protocol {
}
@Override
public Transport getTransport(HostAndPort server, HostAndPort proxy) throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
public CloseableTransport getTransport(HostAndPort server, HostAndPort proxy) throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
return new ProxyTcpOverTlsTransport(server, proxy);
}
@Override
public Transport getTransport(HostAndPort server, File serverCert, HostAndPort proxy) throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
public CloseableTransport getTransport(HostAndPort server, File serverCert, HostAndPort proxy) throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
return new ProxyTcpOverTlsTransport(server, serverCert, proxy);
}
},
HTTP {
@Override
public Transport getTransport(HostAndPort server) {
public CloseableTransport getTransport(HostAndPort server) {
throw new UnsupportedOperationException("No transport supported for HTTP");
}
@Override
public Transport getTransport(HostAndPort server, File serverCert) {
public CloseableTransport getTransport(HostAndPort server, File serverCert) {
throw new UnsupportedOperationException("No transport supported for HTTP");
}
@Override
public Transport getTransport(HostAndPort server, HostAndPort proxy) {
public CloseableTransport getTransport(HostAndPort server, HostAndPort proxy) {
throw new UnsupportedOperationException("No transport supported for HTTP");
}
@Override
public Transport getTransport(HostAndPort server, File serverCert, HostAndPort proxy) {
public CloseableTransport getTransport(HostAndPort server, File serverCert, HostAndPort proxy) {
throw new UnsupportedOperationException("No transport supported for HTTP");
}
};
public abstract Transport getTransport(HostAndPort server) throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException;
public abstract CloseableTransport getTransport(HostAndPort server) throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException;
public abstract Transport getTransport(HostAndPort server, File serverCert) throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException;
public abstract CloseableTransport getTransport(HostAndPort server, File serverCert) throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException;
public abstract Transport getTransport(HostAndPort server, HostAndPort proxy) throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException;
public abstract CloseableTransport getTransport(HostAndPort server, HostAndPort proxy) throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException;
public abstract Transport getTransport(HostAndPort server, File serverCert, HostAndPort proxy) throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException;
public abstract CloseableTransport getTransport(HostAndPort server, File serverCert, HostAndPort proxy) throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException;
public HostAndPort getServerHostAndPort(String url) {
return HostAndPort.fromString(url.substring(this.toUrlString().length()));

View file

@ -22,7 +22,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class TcpTransport implements Transport, Closeable, TimeoutCounter {
public class TcpTransport implements CloseableTransport, TimeoutCounter {
private static final Logger log = LoggerFactory.getLogger(TcpTransport.class);
public static final int DEFAULT_PORT = 50001;
@ -46,6 +46,7 @@ public class TcpTransport implements Transport, Closeable, TimeoutCounter {
private final ReentrantLock clientRequestLock = new ReentrantLock();
private boolean running = false;
private volatile boolean reading = true;
private boolean closed = false;
private boolean firstRead = true;
private int readTimeoutIndex;
private int requestIdCount = 1;
@ -223,6 +224,7 @@ public class TcpTransport implements Transport, Closeable, TimeoutCounter {
public void connect() throws ServerException {
try {
socket = createSocket();
log.debug("Created " + socket);
socket.setSoTimeout(SOCKET_READ_TIMEOUT_MILLIS);
running = true;
} catch(SSLHandshakeException e) {
@ -237,18 +239,23 @@ public class TcpTransport implements Transport, Closeable, TimeoutCounter {
}
public boolean isConnected() {
return socket != null && running;
return socket != null && running && !closed;
}
protected Socket createSocket() throws IOException {
return socketFactory.createSocket(server.getHost(), server.getPortOrDefault(DEFAULT_PORT));
}
public boolean isClosed() {
return closed;
}
@Override
public void close() throws IOException {
if(socket != null) {
socket.close();
}
closed = true;
}
@Override