poll local node for faster switching

This commit is contained in:
woodser 2023-11-21 12:50:53 -05:00
parent 3d0b8c0b09
commit 27bf72d432
3 changed files with 43 additions and 23 deletions

View file

@ -44,16 +44,13 @@ import java.util.stream.Collectors;
public final class CoreMoneroConnectionsService {
private static final int MIN_BROADCAST_CONNECTIONS = 0; // TODO: 0 for stagenet, 5+ for mainnet
private static final long REFRESH_PERIOD_LOCAL_MS = 5000; // refresh period when connected to local node
private static final long REFRESH_PERIOD_HTTP_MS = 20000; // refresh period when connected to remote node over http
private static final long REFRESH_PERIOD_ONION_MS = 30000; // refresh period when connected to remote node over tor
private static final long MIN_ERROR_LOG_PERIOD_MS = 300000; // minimum period between logging errors fetching daemon info
private static Long lastErrorTimestamp;
private final Object lock = new Object();
private final Object listenersLock = new Object();
private final Object listenerLock = new Object();
private final Config config;
private final CoreContext coreContext;
private final Preferences preferences;
@ -120,7 +117,7 @@ public final class CoreMoneroConnectionsService {
public void onShutDownStarted() {
log.info("{}.onShutDownStarted()", getClass().getSimpleName());
isShutDownStarted = true;
synchronized (this) {
synchronized (lock) {
// ensures request not in progress
}
}
@ -147,7 +144,7 @@ public final class CoreMoneroConnectionsService {
}
public void addConnectionListener(MoneroConnectionManagerListener listener) {
synchronized (listenersLock) {
synchronized (listenerLock) {
listeners.add(listener);
}
}
@ -319,10 +316,10 @@ public final class CoreMoneroConnectionsService {
private long getDefaultRefreshPeriodMs() {
MoneroRpcConnection connection = getConnection();
if (connection == null) return REFRESH_PERIOD_LOCAL_MS;
if (connection == null) return LocalMoneroNode.REFRESH_PERIOD_LOCAL_MS;
if (isConnectionLocal(connection)) {
if (lastInfo != null && (lastInfo.isBusySyncing() || (lastInfo.getHeightWithoutBootstrap() != null && lastInfo.getHeightWithoutBootstrap() > 0 && lastInfo.getHeightWithoutBootstrap() < lastInfo.getHeight()))) return REFRESH_PERIOD_HTTP_MS; // refresh slower if syncing or bootstrapped
else return REFRESH_PERIOD_LOCAL_MS; // TODO: announce faster refresh after done syncing
else return LocalMoneroNode.REFRESH_PERIOD_LOCAL_MS; // TODO: announce faster refresh after done syncing
} else if (useProxy(connection)) {
return REFRESH_PERIOD_ONION_MS;
} else {
@ -375,16 +372,23 @@ public final class CoreMoneroConnectionsService {
nodeService.addListener(new LocalMoneroNodeListener() {
@Override
public void onNodeStarted(MoneroDaemonRpc daemon) {
log.info(getClass() + ".onNodeStarted() called");
daemon.getRpcConnection().checkConnection(connectionManager.getTimeout());
setConnection(daemon.getRpcConnection());
checkConnection();
log.info("Local monero node started");
}
@Override
public void onNodeStopped() {
log.info(getClass() + ".onNodeStopped() called");
checkConnection();
log.info("Local monero node stopped");
}
@Override
public void onConnectionChanged(MoneroRpcConnection connection) {
log.info("Local monerod connection changed: " + connection);
if (isShutDownStarted || !connectionManager.getAutoSwitch() || !accountService.isAccountOpen()) return;
if (nodeService.isConnected()) {
setConnection(connection.getUri()); // switch to local node if connected
} else if (getConnection() != null && getConnection().getUri().equals(connection.getUri())) {
setConnection(getBestAvailableConnection()); // switch to best available if disconnected from local node
}
}
});
}
@ -514,7 +518,7 @@ public final class CoreMoneroConnectionsService {
updatePolling();
// notify listeners in parallel
synchronized (listenersLock) {
synchronized (listenerLock) {
for (MoneroConnectionManagerListener listener : listeners) {
new Thread(() -> listener.onConnectionChanged(currentConnection)).start();
}

View file

@ -23,6 +23,7 @@ import haveno.core.trade.HavenoUtils;
import haveno.core.user.Preferences;
import haveno.core.xmr.MoneroNodeSettings;
import lombok.extern.slf4j.Slf4j;
import monero.common.MoneroConnectionManager;
import monero.common.MoneroUtils;
import monero.daemon.MoneroDaemonRpc;
import javax.inject.Inject;
@ -39,11 +40,16 @@ import java.util.List;
@Singleton
public class LocalMoneroNode {
// constants
public static final long REFRESH_PERIOD_LOCAL_MS = 5000; // refresh period for local node
public static final String MONEROD_DIR = Config.baseCurrencyNetwork() == BaseCurrencyNetwork.XMR_LOCAL ? System.getProperty("user.dir") + File.separator + ".localnet" : Config.appDataDir().getAbsolutePath();
public static final String MONEROD_NAME = Utilities.isWindows() ? "monerod.exe" : "monerod";
public static final String MONEROD_PATH = MONEROD_DIR + File.separator + MONEROD_NAME;
private static final String MONEROD_DATADIR = Config.baseCurrencyNetwork() == BaseCurrencyNetwork.XMR_LOCAL ? MONEROD_DIR + File.separator + Config.baseCurrencyNetwork().toString().toLowerCase() + File.separator + "node1" : null; // use default directory unless local
// instance fields
private MoneroDaemonRpc daemon;
private MoneroConnectionManager connectionManager;
private final Config config;
private final Preferences preferences;
private final List<LocalMoneroNodeListener> listeners = new ArrayList<>();
@ -57,8 +63,7 @@ public class LocalMoneroNode {
if (!Config.baseCurrencyNetwork().isMainnet()) MONEROD_ARGS.add("--" + Config.baseCurrencyNetwork().getNetwork().toLowerCase());
}
// client to the local Monero node
private MoneroDaemonRpc daemon;
// default rpc ports
private static Integer rpcPort;
static {
if (Config.baseCurrencyNetwork().isMainnet()) rpcPort = 18081;
@ -72,6 +77,15 @@ public class LocalMoneroNode {
this.config = config;
this.preferences = preferences;
this.daemon = new MoneroDaemonRpc("http://" + HavenoUtils.LOOPBACK_HOST + ":" + rpcPort);
// initialize connection manager to listen to local connection
this.connectionManager = new MoneroConnectionManager().setConnection(daemon.getRpcConnection());
this.connectionManager.setTimeout(REFRESH_PERIOD_LOCAL_MS);
this.connectionManager.checkConnection();
this.connectionManager.addListener((connection) -> {
for (var listener : listeners) listener.onConnectionChanged(connection); // notify of connection changes
});
this.connectionManager.startPolling(REFRESH_PERIOD_LOCAL_MS);
}
/**
@ -106,10 +120,6 @@ public class LocalMoneroNode {
return daemon;
}
private boolean checkConnection() {
return daemon.getRpcConnection().checkConnection(5000);
}
public boolean equalsUri(String uri) {
return HavenoUtils.isLocalHost(uri) && MoneroUtils.parseUri(uri).getPort() == rpcPort;
}
@ -119,7 +129,7 @@ public class LocalMoneroNode {
*/
public boolean isDetected() {
checkConnection();
return daemon.getRpcConnection().isOnline();
return Boolean.TRUE.equals(connectionManager.getConnection().isOnline());
}
/**
@ -127,7 +137,11 @@ public class LocalMoneroNode {
*/
public boolean isConnected() {
checkConnection();
return daemon.getRpcConnection().isConnected();
return Boolean.TRUE.equals(connectionManager.isConnected());
}
private void checkConnection() {
connectionManager.checkConnection();
}
public MoneroNodeSettings getMoneroNodeSettings() {

View file

@ -16,9 +16,11 @@
*/
package haveno.core.api;
import monero.common.MoneroRpcConnection;
import monero.daemon.MoneroDaemonRpc;
public class LocalMoneroNodeListener {
public void onNodeStarted(MoneroDaemonRpc daemon) {}
public void onNodeStopped() {}
public void onConnectionChanged(MoneroRpcConnection connection) {}
}