From 971ef9532673c2a7640c7b0e2bb23b825cc66404 Mon Sep 17 00:00:00 2001 From: Manfred Karrer Date: Tue, 12 Jul 2016 16:37:15 +0200 Subject: [PATCH] Add bootstrap module --- bootstrap/pom.xml | 85 ++++++++++ .../io/bitsquare/bootstrap/Bootstrap.java | 153 ++++++++++++++++++ .../io/bitsquare/bootstrap/BootstrapMain.java | 90 +++++++++++ .../bitsquare/bootstrap/BootstrapModule.java | 110 +++++++++++++ bootstrap/src/main/resources/logback.xml | 42 +++++ pom.xml | 6 +- 6 files changed, 483 insertions(+), 3 deletions(-) create mode 100644 bootstrap/pom.xml create mode 100644 bootstrap/src/main/java/io/bitsquare/bootstrap/Bootstrap.java create mode 100644 bootstrap/src/main/java/io/bitsquare/bootstrap/BootstrapMain.java create mode 100644 bootstrap/src/main/java/io/bitsquare/bootstrap/BootstrapModule.java create mode 100644 bootstrap/src/main/resources/logback.xml diff --git a/bootstrap/pom.xml b/bootstrap/pom.xml new file mode 100644 index 0000000000..fc10205cd8 --- /dev/null +++ b/bootstrap/pom.xml @@ -0,0 +1,85 @@ + + + + parent + io.bitsquare + 0.4.9 + + 4.0.0 + + bootstrap + + + + + + false + ${basedir}/src/main/java + + **/*.fxml + **/*.css + + + + false + ${basedir}/src/main/resources + + **/*.* + + + + + + + org.apache.maven.plugins + maven-shade-plugin + 2.3 + + + false + + + io.bitsquare.bootstrap.BootstrapMain + + + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + + package + + shade + + + true + bundled + Bootstrap + + + + + + + + + + + io.bitsquare + core + ${project.parent.version} + + + \ No newline at end of file diff --git a/bootstrap/src/main/java/io/bitsquare/bootstrap/Bootstrap.java b/bootstrap/src/main/java/io/bitsquare/bootstrap/Bootstrap.java new file mode 100644 index 0000000000..33e81cda4e --- /dev/null +++ b/bootstrap/src/main/java/io/bitsquare/bootstrap/Bootstrap.java @@ -0,0 +1,153 @@ +package io.bitsquare.bootstrap; + +import ch.qos.logback.classic.Level; +import com.google.inject.Guice; +import com.google.inject.Injector; +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.UserThread; +import io.bitsquare.common.handlers.ResultHandler; +import io.bitsquare.common.util.Utilities; +import io.bitsquare.p2p.P2PService; +import io.bitsquare.p2p.P2PServiceListener; +import io.bitsquare.trade.offer.OpenOfferManager; +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.Security; + +public class Bootstrap { + private static final Logger log = LoggerFactory.getLogger(Bootstrap.class); + private static Environment env; + private final Injector injector; + private final BootstrapModule bootstrapModule; + + private P2PService p2pService; + + public static void setEnvironment(Environment env) { + Bootstrap.env = env; + } + + public Bootstrap() { + String logPath = Paths.get(env.getProperty(BitsquareEnvironment.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(io.bitsquare.common.OptionKeys.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); + + if (Utilities.isRestrictedCryptography()) + Utilities.removeCryptographyRestrictions(); + Security.addProvider(new BouncyCastleProvider()); + + + bootstrapModule = new BootstrapModule(env); + injector = Guice.createInjector(bootstrapModule); + Version.setBtcNetworkId(injector.getInstance(BitsquareEnvironment.class).getBitcoinNetwork().ordinal()); + p2pService = injector.getInstance(P2PService.class); + p2pService.start(false, new P2PServiceListener() { + @Override + public void onRequestingDataCompleted() { + } + + @Override + public void onNoSeedNodeAvailable() { + + } + + @Override + public void onNoPeersAvailable() { + + } + + @Override + public void onBootstrapComplete() { + + } + + @Override + public void onTorNodeReady() { + + } + + @Override + public void onHiddenServicePublished() { + + } + + @Override + public void onSetupFailed(Throwable throwable) { + + } + + @Override + public void onUseDefaultBridges() { + + } + + @Override + public void onRequestCustomBridges(Runnable resultHandler) { + + } + }); + } + + public void shutDown() { + gracefulShutDown(() -> { + log.info("Shutdown complete"); + System.exit(0); + }); + } + + private 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) -> { + bootstrapModule.close(injector); + log.info("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.info("App shutdown failed with exception"); + t.printStackTrace(); + System.exit(1); + } + } +} diff --git a/bootstrap/src/main/java/io/bitsquare/bootstrap/BootstrapMain.java b/bootstrap/src/main/java/io/bitsquare/bootstrap/BootstrapMain.java new file mode 100644 index 0000000000..2f75cbe21e --- /dev/null +++ b/bootstrap/src/main/java/io/bitsquare/bootstrap/BootstrapMain.java @@ -0,0 +1,90 @@ +/* + * This file is part of Bitsquare. + * + * Bitsquare is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bitsquare is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bitsquare. If not, see . + */ + +package io.bitsquare.bootstrap; + +import io.bitsquare.app.BitsquareEnvironment; +import io.bitsquare.app.BitsquareExecutable; +import joptsimple.OptionException; +import joptsimple.OptionParser; +import joptsimple.OptionSet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Scanner; + +import static io.bitsquare.app.BitsquareEnvironment.*; + +public class BootstrapMain extends BitsquareExecutable { + private static final Logger log = LoggerFactory.getLogger(BootstrapMain.class); + private io.bitsquare.bootstrap.Bootstrap bootstrap; + private boolean isStopped; + + public static void main(String[] args) throws Exception { + // We don't want to do the full argument parsing here as that might easily change in update versions + // So we only handle the absolute minimum which is APP_NAME, APP_DATA_DIR_KEY and USER_DATA_DIR + + BitsquareEnvironment.setDefaultAppName("Bitsquare_bootstrap"); + OptionParser parser = new OptionParser(); + parser.allowsUnrecognizedOptions(); + parser.accepts(USER_DATA_DIR_KEY, description("User data directory", DEFAULT_USER_DATA_DIR)) + .withRequiredArg(); + parser.accepts(APP_NAME_KEY, description("Application name", DEFAULT_APP_NAME)) + .withRequiredArg(); + + OptionSet options; + try { + options = parser.parse(args); + } catch (OptionException ex) { + System.out.println("error: " + ex.getMessage()); + System.out.println(); + parser.printHelpOn(System.out); + System.exit(EXIT_FAILURE); + return; + } + BitsquareEnvironment bitsquareEnvironment = new BitsquareEnvironment(options); + + // need to call that before BitsquareAppMain().execute(args) + BitsquareExecutable.initAppDir(bitsquareEnvironment.getProperty(BitsquareEnvironment.APP_DATA_DIR_KEY)); + + // For some reason the JavaFX launch process results in us losing the thread context class loader: reset it. + // In order to work around a bug in JavaFX 8u25 and below, you must include the following code as the first line of your realMain method: + Thread.currentThread().setContextClassLoader(BootstrapMain.class.getClassLoader()); + + new BootstrapMain().execute(args); + } + + @Override + protected void doExecute(OptionSet options) { + io.bitsquare.bootstrap.Bootstrap.setEnvironment(new BitsquareEnvironment(options)); + bootstrap = new io.bitsquare.bootstrap.Bootstrap(); + + while (!isStopped) { + try { + Scanner scanner = new Scanner(System.in); + while (scanner.hasNextLine()) { + String inputString = scanner.nextLine(); + if (inputString.equals("q")) { + bootstrap.shutDown(); + isStopped = true; + } + } + } catch (Throwable ignore) { + } + } + } +} diff --git a/bootstrap/src/main/java/io/bitsquare/bootstrap/BootstrapModule.java b/bootstrap/src/main/java/io/bitsquare/bootstrap/BootstrapModule.java new file mode 100644 index 0000000000..6ab47c28b5 --- /dev/null +++ b/bootstrap/src/main/java/io/bitsquare/bootstrap/BootstrapModule.java @@ -0,0 +1,110 @@ +/* + * This file is part of Bitsquare. + * + * Bitsquare is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bitsquare is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bitsquare. If not, see . + */ + +package io.bitsquare.bootstrap; + +import com.google.inject.Singleton; +import io.bitsquare.alert.AlertModule; +import io.bitsquare.app.AppModule; +import io.bitsquare.app.BitsquareEnvironment; +import io.bitsquare.arbitration.ArbitratorModule; +import io.bitsquare.btc.BitcoinModule; +import io.bitsquare.common.Clock; +import io.bitsquare.common.crypto.KeyRing; +import io.bitsquare.common.crypto.KeyStorage; +import io.bitsquare.crypto.EncryptionServiceModule; +import io.bitsquare.filter.FilterModule; +import io.bitsquare.p2p.P2PModule; +import io.bitsquare.storage.Storage; +import io.bitsquare.trade.TradeModule; +import io.bitsquare.trade.offer.OfferModule; +import io.bitsquare.user.Preferences; +import io.bitsquare.user.User; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; + +import java.io.File; + +import static com.google.inject.name.Names.named; + +class BootstrapModule extends AppModule { + private static final Logger log = LoggerFactory.getLogger(BootstrapModule.class); + + public BootstrapModule(Environment env) { + super(env); + } + + @Override + protected void configure() { + bind(KeyStorage.class).in(Singleton.class); + bind(KeyRing.class).in(Singleton.class); + bind(User.class).in(Singleton.class); + bind(Preferences.class).in(Singleton.class); + bind(Clock.class).in(Singleton.class); + + File storageDir = new File(env.getRequiredProperty(Storage.DIR_KEY)); + bind(File.class).annotatedWith(named(Storage.DIR_KEY)).toInstance(storageDir); + + File keyStorageDir = new File(env.getRequiredProperty(KeyStorage.DIR_KEY)); + bind(File.class).annotatedWith(named(KeyStorage.DIR_KEY)).toInstance(keyStorageDir); + + bind(BitsquareEnvironment.class).toInstance((BitsquareEnvironment) env); + + // ordering is used for shut down sequence + install(tradeModule()); + install(encryptionServiceModule()); + install(arbitratorModule()); + install(offerModule()); + install(torModule()); + install(bitcoinModule()); + install(alertModule()); + install(filterModule()); + } + + private TradeModule tradeModule() { + return new TradeModule(env); + } + + private EncryptionServiceModule encryptionServiceModule() { + return new EncryptionServiceModule(env); + } + + private ArbitratorModule arbitratorModule() { + return new ArbitratorModule(env); + } + + private AlertModule alertModule() { + return new AlertModule(env); + } + + private FilterModule filterModule() { + return new FilterModule(env); + } + + private OfferModule offerModule() { + return new OfferModule(env); + } + + private P2PModule torModule() { + return new P2PModule(env); + } + + private BitcoinModule bitcoinModule() { + return new BitcoinModule(env); + } +} diff --git a/bootstrap/src/main/resources/logback.xml b/bootstrap/src/main/resources/logback.xml new file mode 100644 index 0000000000..571a34df77 --- /dev/null +++ b/bootstrap/src/main/resources/logback.xml @@ -0,0 +1,42 @@ + + + + + + + %highlight(%d{MMM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{15}: %msg %xEx%n) + + + + + + + + + + + + + + + diff --git a/pom.xml b/pom.xml index 18e939fc44..65701a179d 100755 --- a/pom.xml +++ b/pom.xml @@ -44,10 +44,10 @@ jtorctl jtorproxy network - seednode - headless - monitor gui + headless + bootstrap + monitor jdkfix