Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor ExecutableForAppWithP2p [E] #7183

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 121 additions & 1 deletion core/src/main/java/bisq/core/app/misc/ExecutableForAppWithP2p.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,30 @@
package bisq.core.app.misc;

import bisq.core.app.BisqExecutable;
import bisq.core.app.TorSetup;
import bisq.core.btc.setup.WalletsSetup;
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.dao.DaoSetup;
import bisq.core.dao.monitoring.DaoStateMonitoringService;
import bisq.core.dao.node.full.RpcService;
import bisq.core.offer.OpenOfferManager;
import bisq.core.offer.bsq_swap.OpenBsqSwapOfferService;
import bisq.core.payment.TradeLimits;
import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager;
import bisq.core.user.Cookie;
import bisq.core.user.CookieKey;
import bisq.core.user.User;

import bisq.network.p2p.P2PService;
import bisq.network.p2p.P2PServiceListener;
import bisq.network.p2p.peers.PeerManager;

import bisq.common.Timer;
import bisq.common.UserThread;
import bisq.common.app.AppModule;
import bisq.common.app.DevEnv;
import bisq.common.config.BaseCurrencyNetwork;
import bisq.common.config.Config;
import bisq.common.file.JsonFileManager;
import bisq.common.handlers.ResultHandler;
Expand All @@ -41,6 +50,9 @@
import bisq.common.util.Profiler;
import bisq.common.util.SingleThreadExecutorUtils;

import com.google.inject.Key;
import com.google.inject.name.Names;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;

Expand All @@ -51,9 +63,18 @@ public abstract class ExecutableForAppWithP2p extends BisqExecutable {
private static final long CHECK_MEMORY_PERIOD_SEC = 300;
protected static final long CHECK_SHUTDOWN_SEC = TimeUnit.HOURS.toSeconds(1);
protected static final long SHUTDOWN_INTERVAL = TimeUnit.HOURS.toMillis(24);
private static final long CHECK_CONNECTION_LOSS_SEC = 30;

private volatile boolean stopped;
private final long startTime = System.currentTimeMillis();
private TradeLimits tradeLimits;
private AppSetupWithP2PAndDAO appSetupWithP2PAndDAO;
protected P2PService p2PService;
protected DaoStateMonitoringService daoStateMonitoringService;

protected Cookie cookie;
private Timer checkConnectionLossTimer;
private Boolean preventPeriodicShutdownAtSeedNode;

public ExecutableForAppWithP2p(String fullName, String scriptName, String appName, String version) {
super(fullName, scriptName, appName, version);
Expand All @@ -71,9 +92,71 @@ protected AppModule getModule() {
}

@Override
protected void startApplication() {
protected void applyInjector() {
super.applyInjector();

appSetupWithP2PAndDAO = injector.getInstance(AppSetupWithP2PAndDAO.class);
p2PService = injector.getInstance(P2PService.class);
cookie = injector.getInstance(User.class).getCookie();
// Pin that as it is used in PaymentMethods and verification in TradeStatistics
tradeLimits = injector.getInstance(TradeLimits.class);
daoStateMonitoringService = injector.getInstance(DaoStateMonitoringService.class);
preventPeriodicShutdownAtSeedNode = injector.getInstance(Key.get(boolean.class,
Names.named(Config.PREVENT_PERIODIC_SHUTDOWN_AT_SEED_NODE)));
}

@Override
protected void startApplication() {
cookie.getAsOptionalBoolean(CookieKey.CLEAN_TOR_DIR_AT_RESTART).ifPresent(cleanTorDirAtRestart -> {
if (cleanTorDirAtRestart) {
injector.getInstance(TorSetup.class).cleanupTorFiles(() ->
cookie.remove(CookieKey.CLEAN_TOR_DIR_AT_RESTART),
log::error);
}
});

daoStateMonitoringService.addListener(new DaoStateMonitoringService.Listener() {
@Override
public void onCheckpointFailed() {
gracefulShutDown();
}
});

p2PService.addP2PServiceListener(new P2PServiceListener() {
@Override
public void onDataReceived() {
}

@Override
public void onNoSeedNodeAvailable() {
}

@Override
public void onNoPeersAvailable() {
}

@Override
public void onUpdatedDataReceived() {
}

@Override
public void onTorNodeReady() {
}

@Override
public void onHiddenServicePublished() {
ExecutableForAppWithP2p.this.onHiddenServicePublished();
}
});

appSetupWithP2PAndDAO.start();
}

protected void onHiddenServicePublished() {
if (!preventPeriodicShutdownAtSeedNode) {
startShutDownInterval();
}
UserThread.runAfter(this::setupConnectionLossCheck, 60);
}

@Override
Expand All @@ -86,10 +169,26 @@ public void onSetupComplete() {
log.info("onSetupComplete");
}


///////////////////////////////////////////////////////////////////////////////////////////
// UncaughtExceptionHandler implementation
///////////////////////////////////////////////////////////////////////////////////////////

@Override
public void handleUncaughtException(Throwable throwable, boolean doShutDown) {
if (throwable instanceof OutOfMemoryError || doShutDown) {
log.error("We got an OutOfMemoryError and shut down");
gracefulShutDown(() -> log.info("gracefulShutDown complete"));
}
}

// We don't use the gracefulShutDown implementation of the super class as we have a limited set of modules
@Override
public void gracefulShutDown(ResultHandler resultHandler) {
log.info("gracefulShutDown");
if (checkConnectionLossTimer != null) {
checkConnectionLossTimer.stop();
}
try {
if (injector != null) {
JsonFileManager.shutDownAllInstances();
Expand Down Expand Up @@ -207,4 +306,25 @@ protected void shutDown(GracefulShutDownHandler gracefulShutDownHandler) {
System.exit(1);
});
}

protected void setupConnectionLossCheck() {
// For dev testing (usually on BTC_REGTEST) we don't want to get the seed shut
// down as it is normal that the seed is the only actively running node.
if (Config.baseCurrencyNetwork() == BaseCurrencyNetwork.BTC_REGTEST) {
return;
}

if (checkConnectionLossTimer != null) {
return;
}

checkConnectionLossTimer = UserThread.runPeriodically(() -> {
if (injector.getInstance(PeerManager.class).getNumAllConnectionsLostEvents() > 1) {
// We set a flag to clear tor cache files at re-start. We cannot clear it now as Tor is used and
// that can cause problems.
injector.getInstance(User.class).getCookie().putAsBoolean(CookieKey.CLEAN_TOR_DIR_AT_RESTART, true);
shutDown(this);
}
}, CHECK_CONNECTION_LOSS_SEC);
}
}
127 changes: 13 additions & 114 deletions restapi/src/main/java/bisq/restapi/RestApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,42 +19,22 @@


import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.app.TorSetup;
import bisq.core.app.misc.AppSetupWithP2PAndDAO;
import bisq.core.app.misc.ExecutableForAppWithP2p;
import bisq.core.dao.SignVerifyService;
import bisq.core.dao.governance.bond.reputation.BondedReputationRepository;
import bisq.core.dao.governance.bond.role.BondedRolesRepository;
import bisq.core.dao.state.DaoStateService;
import bisq.core.dao.state.DaoStateSnapshotService;
import bisq.core.user.Cookie;
import bisq.core.user.CookieKey;
import bisq.core.user.Preferences;
import bisq.core.user.User;

import bisq.network.p2p.P2PService;
import bisq.network.p2p.P2PServiceListener;
import bisq.network.p2p.peers.PeerManager;

import bisq.common.Timer;
import bisq.common.UserThread;
import bisq.common.app.Version;
import bisq.common.config.BaseCurrencyNetwork;
import bisq.common.config.Config;
import bisq.common.handlers.ResultHandler;

import com.google.inject.Key;
import com.google.inject.name.Names;

import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
//todo not sure if the restart handling from seed nodes is required

@Slf4j
public class RestApi extends ExecutableForAppWithP2p {
private static final long CHECK_CONNECTION_LOSS_SEC = 30;

private Timer checkConnectionLossTime;
@Getter
private DaoStateService daoStateService;
@Getter
Expand All @@ -65,6 +45,8 @@ public class RestApi extends ExecutableForAppWithP2p {
private BondedRolesRepository bondedRolesRepository;
@Getter
private SignVerifyService signVerifyService;
private DaoStateSnapshotService daoStateSnapshotService;
private Preferences preferences;

public RestApi() {
super("Bisq Rest Api", "bisq_restapi", "bisq_restapi", Version.VERSION);
Expand All @@ -81,114 +63,31 @@ protected void doExecute() {
checkMemory(config, this);
}


///////////////////////////////////////////////////////////////////////////////////////////
// We continue with a series of synchronous execution tasks
///////////////////////////////////////////////////////////////////////////////////////////

@Override
protected void applyInjector() {
super.applyInjector();

injector.getInstance(DaoStateSnapshotService.class).setResyncDaoStateFromResourcesHandler(this::gracefulShutDown);
}

@Override
protected void startApplication() {
super.startApplication();

Cookie cookie = injector.getInstance(User.class).getCookie();
cookie.getAsOptionalBoolean(CookieKey.CLEAN_TOR_DIR_AT_RESTART).ifPresent(cleanTorDirAtRestart -> {
if (cleanTorDirAtRestart) {
injector.getInstance(TorSetup.class).cleanupTorFiles(() ->
cookie.remove(CookieKey.CLEAN_TOR_DIR_AT_RESTART),
log::error);
}
});

injector.getInstance(Preferences.class).setUseFullModeDaoMonitor(false);
injector.getInstance(AppSetupWithP2PAndDAO.class).start();

preferences = injector.getInstance(Preferences.class);
daoStateService = injector.getInstance(DaoStateService.class);
accountAgeWitnessService = injector.getInstance(AccountAgeWitnessService.class);
bondedReputationRepository = injector.getInstance(BondedReputationRepository.class);
bondedRolesRepository = injector.getInstance(BondedRolesRepository.class);
signVerifyService = injector.getInstance(SignVerifyService.class);

injector.getInstance(P2PService.class).addP2PServiceListener(new P2PServiceListener() {
@Override
public void onDataReceived() {
// Do nothing
}

@Override
public void onNoSeedNodeAvailable() {
// Do nothing
}

@Override
public void onNoPeersAvailable() {
// Do nothing
}

@Override
public void onUpdatedDataReceived() {
// Do nothing
}

@Override
public void onTorNodeReady() {
// Do nothing
}

@Override
public void onHiddenServicePublished() {
boolean preventPeriodicShutdownAtSeedNode = injector.getInstance(Key.get(boolean.class,
Names.named(Config.PREVENT_PERIODIC_SHUTDOWN_AT_SEED_NODE)));
if (!preventPeriodicShutdownAtSeedNode) {
startShutDownInterval();
}
UserThread.runAfter(() -> setupConnectionLossCheck(), 60);

accountAgeWitnessService.onAllServicesInitialized();
}

@Override
public void onSetupFailed(Throwable throwable) {
// Do nothing
}

@Override
public void onRequestCustomBridges() {
// Do nothing
}
});
daoStateSnapshotService = injector.getInstance(DaoStateSnapshotService.class);
}

private void setupConnectionLossCheck() {
// For dev testing (usually on BTC_REGTEST) we don't want to get the seed shut
// down as it is normal that the seed is the only actively running node.
if (Config.baseCurrencyNetwork() == BaseCurrencyNetwork.BTC_REGTEST) {
return;
}

if (checkConnectionLossTime != null) {
return;
}

checkConnectionLossTime = UserThread.runPeriodically(() -> {
if (injector.getInstance(PeerManager.class).getNumAllConnectionsLostEvents() > 1) {
// We set a flag to clear tor cache files at re-start. We cannot clear it now as Tor is used and
// that can cause problems.
injector.getInstance(User.class).getCookie().putAsBoolean(CookieKey.CLEAN_TOR_DIR_AT_RESTART, true);
shutDown(this);
}
}, CHECK_CONNECTION_LOSS_SEC);
@Override
protected void startApplication() {
super.startApplication();

preferences.setUseFullModeDaoMonitor(false);
daoStateSnapshotService.setResyncDaoStateFromResourcesHandler(this::gracefulShutDown);
}

@Override
public void gracefulShutDown(ResultHandler resultHandler) {
super.gracefulShutDown(resultHandler);
protected void onHiddenServicePublished() {
super.onHiddenServicePublished();

accountAgeWitnessService.onAllServicesInitialized();
}
}
5 changes: 0 additions & 5 deletions seednode/src/main/java/bisq/seednode/SeedNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@

import bisq.seednode.reporting.SeedNodeReportingService;

import bisq.core.app.misc.AppSetup;
import bisq.core.app.misc.AppSetupWithP2PAndDAO;
import bisq.core.network.p2p.inventory.GetInventoryRequestHandler;

import bisq.common.config.Config;
Expand All @@ -33,13 +31,11 @@

@Slf4j
public class SeedNode {
private final AppSetup appSetup;
private final GetInventoryRequestHandler getInventoryRequestHandler;
private final SeedNodeReportingService seedNodeReportingService;
private final boolean useSeedNodeReportingService;

public SeedNode(Injector injector) {
appSetup = injector.getInstance(AppSetupWithP2PAndDAO.class);
getInventoryRequestHandler = injector.getInstance(GetInventoryRequestHandler.class);
seedNodeReportingService = injector.getInstance(SeedNodeReportingService.class);

Expand All @@ -48,7 +44,6 @@ public SeedNode(Injector injector) {
}

public void startApplication() {
appSetup.start();
if (useSeedNodeReportingService) {
seedNodeReportingService.initialize();
}
Expand Down
Loading
Loading