package io.bitsquare.seednode;
import ch.qos.logback.classic.Level;
import com.google.inject.Guice;
import com.google.inject.Injector;
import io.bitsquare.app.AppOptionKeys;
import io.bitsquare.app.BitsquareEnvironment;
import io.bitsquare.app.Log;
import io.bitsquare.app.Version;
import io.bitsquare.arbitration.ArbitratorManager;
import io.bitsquare.btc.WalletService;
import io.bitsquare.common.CommonOptionKeys;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.handlers.ResultHandler;
import io.bitsquare.common.util.LimitedKeyStrengthException;
import io.bitsquare.common.util.Utilities;
import io.bitsquare.p2p.BootstrapListener;
import io.bitsquare.p2p.P2PService;
import io.bitsquare.trade.offer.OpenOfferManager;
import io.bitsquare.trade.statistics.TradeStatisticsManager;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.bitcoinj.store.BlockStoreException;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.Environment;
import java.nio.file.Paths;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
public class SeedNode {
private static final Logger log = LoggerFactory.getLogger(SeedNode.class);
private static Environment env;
private final Injector injector;
private final SeedNodeModule seedNodeModule;
private final TradeStatisticsManager tradeStatisticsManager;
private P2PService p2pService;
public static void setEnvironment(Environment env) {
SeedNode.env = env;
}
public SeedNode() {
String logPath = Paths.get(env.getProperty(AppOptionKeys.APP_DATA_DIR_KEY), "bitsquare").toString();
Log.setup(logPath);
log.info("Log files under: " + logPath);
Version.printVersion();
Utilities.printSysInfo();
Log.setLevel(Level.toLevel(env.getRequiredProperty(CommonOptionKeys.LOG_LEVEL_KEY)));
// setup UncaughtExceptionHandler
Thread.UncaughtExceptionHandler handler = (thread, throwable) -> {
// Might come from another thread
if (throwable.getCause() != null && throwable.getCause().getCause() != null &&
throwable.getCause().getCause() instanceof BlockStoreException) {
log.error(throwable.getMessage());
} else {
log.error("Uncaught Exception from thread " + Thread.currentThread().getName());
log.error("throwableMessage= " + throwable.getMessage());
log.error("throwableClass= " + throwable.getClass());
log.error("Stack trace:\n" + ExceptionUtils.getStackTrace(throwable));
throwable.printStackTrace();
}
};
Thread.setDefaultUncaughtExceptionHandler(handler);
Thread.currentThread().setUncaughtExceptionHandler(handler);
try {
Utilities.checkCryptoPolicySetup();
} catch (NoSuchAlgorithmException | LimitedKeyStrengthException e) {
e.printStackTrace();
UserThread.execute(this::shutDown);
}
Security.addProvider(new BouncyCastleProvider());
seedNodeModule = new SeedNodeModule(env);
injector = Guice.createInjector(seedNodeModule);
Version.setBtcNetworkId(injector.getInstance(BitsquareEnvironment.class).getBitcoinNetwork().ordinal());
p2pService = injector.getInstance(P2PService.class);
p2pService.start(new BootstrapListener() {
@Override
public void onBootstrapComplete() {
}
});
// We want to persist trade statistics so we need to instantiate the tradeStatisticsManager
tradeStatisticsManager = injector.getInstance(TradeStatisticsManager.class);
}
public void shutDown() {
gracefulShutDown(() -> {
log.debug("Shutdown complete");
System.exit(0);
});
}
public void gracefulShutDown(ResultHandler resultHandler) {
log.debug("gracefulShutDown");
try {
if (injector != null) {
injector.getInstance(ArbitratorManager.class).shutDown();
injector.getInstance(OpenOfferManager.class).shutDown(() -> {
injector.getInstance(P2PService.class).shutDown(() -> {
injector.getInstance(WalletService.class).shutDownDone.addListener((ov, o, n) -> {
seedNodeModule.close(injector);
log.debug("Graceful shutdown completed");
resultHandler.handleResult();
});
injector.getInstance(WalletService.class).shutDown();
});
});
// we wait max 5 sec.
UserThread.runAfter(resultHandler::handleResult, 5);
} else {
UserThread.runAfter(resultHandler::handleResult, 1);
}
} catch (Throwable t) {
log.debug("App shutdown failed with exception");
t.printStackTrace();
System.exit(1);
}
}
}