diff --git a/common/pom.xml b/common/pom.xml index a9a8726a3ad..96abceb58e3 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -5,7 +5,7 @@ parent io.bitsquare - 0.4.9.1 + 0.4.9.2 4.0.0 diff --git a/common/src/main/java/io/bitsquare/app/Version.java b/common/src/main/java/io/bitsquare/app/Version.java index 72255cbaba6..d9e31bd348e 100644 --- a/common/src/main/java/io/bitsquare/app/Version.java +++ b/common/src/main/java/io/bitsquare/app/Version.java @@ -24,7 +24,7 @@ public class Version { private static final Logger log = LoggerFactory.getLogger(Version.class); // The application versions - public static final String VERSION = "0.4.9.1"; + public static final String VERSION = "0.4.9.2"; // The version nr. for the objects sent over the network. A change will break the serialization of old objects. // If objects are used for both network and database the network version is applied. diff --git a/common/src/main/java/io/bitsquare/common/crypto/KeyStorage.java b/common/src/main/java/io/bitsquare/common/crypto/KeyStorage.java index d4bffbd68cd..ee25b622b26 100644 --- a/common/src/main/java/io/bitsquare/common/crypto/KeyStorage.java +++ b/common/src/main/java/io/bitsquare/common/crypto/KeyStorage.java @@ -34,6 +34,7 @@ import java.security.interfaces.DSAPrivateKey; import java.security.interfaces.RSAPrivateCrtKey; import java.security.spec.*; +import java.util.Date; // TODO: use a password protection for key storage public class KeyStorage { @@ -124,7 +125,7 @@ public KeyPair loadKeyPair(KeyEntry keyEntry) { throw new RuntimeException("Unsupported key algo" + keyEntry.getAlgorithm()); } - //log.info("load completed in {} msec", System.currentTimeMillis() - now); + log.debug("load completed in {} msec", System.currentTimeMillis() - new Date().getTime()); return new KeyPair(publicKey, privateKey); } catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchProviderException e) { e.printStackTrace(); diff --git a/common/src/main/java/io/bitsquare/common/util/Profiler.java b/common/src/main/java/io/bitsquare/common/util/Profiler.java index 9ce0e0c698f..1e9dcc541c1 100644 --- a/common/src/main/java/io/bitsquare/common/util/Profiler.java +++ b/common/src/main/java/io/bitsquare/common/util/Profiler.java @@ -24,12 +24,11 @@ public class Profiler { private static final Logger log = LoggerFactory.getLogger(Profiler.class); public static void printSystemLoad(Logger log) { - log.warn(printSystemLoadString()); + log.info(printSystemLoadString()); } public static String printSystemLoadString() { - long used = getUsedMemoryInMB(); - return "System load: Memory (MB)): " + used + " / Nr. of threads: " + Thread.activeCount(); + return "System load: Memory (MB)): " + getUsedMemoryInMB() + " / Nr. of threads: " + Thread.activeCount(); } public static long getUsedMemoryInMB() { diff --git a/common/src/main/java/io/bitsquare/common/util/Utilities.java b/common/src/main/java/io/bitsquare/common/util/Utilities.java index 1a067e2c801..c644b875a5b 100644 --- a/common/src/main/java/io/bitsquare/common/util/Utilities.java +++ b/common/src/main/java/io/bitsquare/common/util/Utilities.java @@ -33,9 +33,7 @@ import java.io.*; import java.lang.reflect.Field; import java.net.URI; -import java.net.URISyntaxException; import java.net.URLConnection; -import java.net.URLEncoder; import java.security.Permission; import java.security.PermissionCollection; import java.util.Locale; @@ -207,26 +205,6 @@ public static void openDirectory(File directory) throws IOException { } } - public static void openWebPage(String target) { - try { - openURI(new URI(target)); - } catch (Exception e) { - e.printStackTrace(); - log.error(e.getMessage()); - } - } - - public static void openMail(String to, String subject, String body) { - try { - subject = URLEncoder.encode(subject, "UTF-8").replace("+", "%20"); - body = URLEncoder.encode(body, "UTF-8").replace("+", "%20"); - openURI(new URI("mailto:" + to + "?subject=" + subject + "&body=" + body)); - } catch (IOException | URISyntaxException e) { - log.error("openMail failed " + e.getMessage()); - e.printStackTrace(); - } - } - public static void printSystemLoad() { Runtime runtime = Runtime.getRuntime(); long free = runtime.freeMemory() / 1024 / 1024; diff --git a/common/src/main/java/io/bitsquare/storage/FileManager.java b/common/src/main/java/io/bitsquare/storage/FileManager.java index e17b3ab4eff..6dbcce6f712 100644 --- a/common/src/main/java/io/bitsquare/storage/FileManager.java +++ b/common/src/main/java/io/bitsquare/storage/FileManager.java @@ -197,12 +197,12 @@ private synchronized void saveToFile(T serializable, File dir, File storageFile) renameTempFileToFile(tempFile, storageFile); } catch (Throwable t) { - log.debug("storageFile " + storageFile.toString()); + log.error("storageFile " + storageFile.toString()); t.printStackTrace(); log.error("Error at saveToFile: " + t.getMessage()); } finally { if (tempFile != null && tempFile.exists()) { - log.warn("Temp file still exists after failed save. storageFile=" + storageFile); + log.warn("Temp file still exists after failed save. We will delete it now. storageFile=" + storageFile); if (!tempFile.delete()) log.error("Cannot delete temp file."); } diff --git a/core/pom.xml b/core/pom.xml index 7f9476b11ad..fa34ab2e2b1 100755 --- a/core/pom.xml +++ b/core/pom.xml @@ -6,7 +6,7 @@ parent io.bitsquare - 0.4.9.1 + 0.4.9.2 core diff --git a/core/src/main/java/io/bitsquare/app/BitsquareEnvironment.java b/core/src/main/java/io/bitsquare/app/BitsquareEnvironment.java index 574d9fc44eb..bbf180a62e9 100644 --- a/core/src/main/java/io/bitsquare/app/BitsquareEnvironment.java +++ b/core/src/main/java/io/bitsquare/app/BitsquareEnvironment.java @@ -62,7 +62,7 @@ public static void setDefaultAppName(String defaultAppName) { public static final String DEFAULT_USER_DATA_DIR = defaultUserDataDir(); public static final String DEFAULT_APP_DATA_DIR = appDataDir(DEFAULT_USER_DATA_DIR, DEFAULT_APP_NAME); - public static final String LOG_LEVEL_DEFAULT = (DevFlags.STRESS_TEST_MODE || DevFlags.DEV_MODE) ? Level.TRACE.levelStr : Level.WARN.levelStr; + public static final String LOG_LEVEL_DEFAULT = (DevFlags.STRESS_TEST_MODE || DevFlags.DEV_MODE) ? Level.TRACE.levelStr : Level.INFO.levelStr; static final String BITSQUARE_COMMANDLINE_PROPERTY_SOURCE_NAME = "bitsquareCommandLineProperties"; static final String BITSQUARE_APP_DIR_PROPERTY_SOURCE_NAME = "bitsquareAppDirProperties"; diff --git a/core/src/main/java/io/bitsquare/arbitration/Dispute.java b/core/src/main/java/io/bitsquare/arbitration/Dispute.java index 40c5672b2a0..ab468e0d3ad 100644 --- a/core/src/main/java/io/bitsquare/arbitration/Dispute.java +++ b/core/src/main/java/io/bitsquare/arbitration/Dispute.java @@ -159,19 +159,26 @@ public void setStorage(Storage> storage) { } public void setIsClosed(boolean isClosed) { + boolean changed = this.isClosed != isClosed; this.isClosed = isClosed; isClosedProperty.set(isClosed); - storage.queueUpForSave(); + if (changed) + storage.queueUpForSave(); } public void setDisputeResult(DisputeResult disputeResult) { + boolean changed = this.disputeResult == null || !this.disputeResult.equals(disputeResult); this.disputeResult = disputeResult; disputeResultProperty.set(disputeResult); - storage.queueUpForSave(); + if (changed) + storage.queueUpForSave(); } public void setDisputePayoutTxId(String disputePayoutTxId) { + boolean changed = this.disputePayoutTxId == null || !this.disputePayoutTxId.equals(disputePayoutTxId); this.disputePayoutTxId = disputePayoutTxId; + if (changed) + storage.queueUpForSave(); } diff --git a/core/src/main/java/io/bitsquare/arbitration/DisputeList.java b/core/src/main/java/io/bitsquare/arbitration/DisputeList.java index 6df6269699f..b1fb6a743b6 100644 --- a/core/src/main/java/io/bitsquare/arbitration/DisputeList.java +++ b/core/src/main/java/io/bitsquare/arbitration/DisputeList.java @@ -60,10 +60,11 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE @Override public boolean add(DisputeCase disputeCase) { if (!super.contains(disputeCase)) { - boolean result = super.add(disputeCase); + boolean changed = super.add(disputeCase); getObservableList().add(disputeCase); - storage.queueUpForSave(); - return result; + if (changed) + storage.queueUpForSave(); + return changed; } else { return false; } @@ -71,10 +72,11 @@ public boolean add(DisputeCase disputeCase) { @Override public boolean remove(Object disputeCase) { - boolean result = super.remove(disputeCase); + boolean changed = super.remove(disputeCase); getObservableList().remove(disputeCase); - storage.queueUpForSave(); - return result; + if (changed) + storage.queueUpForSave(); + return changed; } private ObservableList getObservableList() { diff --git a/core/src/main/java/io/bitsquare/btc/AddressEntryList.java b/core/src/main/java/io/bitsquare/btc/AddressEntryList.java index 86c0a3a5c3a..880c71accde 100644 --- a/core/src/main/java/io/bitsquare/btc/AddressEntryList.java +++ b/core/src/main/java/io/bitsquare/btc/AddressEntryList.java @@ -68,8 +68,9 @@ public void onWalletReady(Wallet wallet) { } public AddressEntry addAddressEntry(AddressEntry addressEntry) { - add(addressEntry); - storage.queueUpForSave(); + boolean changed = add(addressEntry); + if (changed) + storage.queueUpForSave(); return addressEntry; } @@ -78,17 +79,19 @@ public void swapTradeToSavings(String offerId) { Optional addressEntryOptional = this.stream().filter(addressEntry -> offerId.equals(addressEntry.getOfferId())).findAny(); if (addressEntryOptional.isPresent()) { AddressEntry addressEntry = addressEntryOptional.get(); - add(new AddressEntry(addressEntry.getKeyPair(), wallet.getParams(), AddressEntry.Context.AVAILABLE)); - remove(addressEntry); - storage.queueUpForSave(); + boolean changed1 = add(new AddressEntry(addressEntry.getKeyPair(), wallet.getParams(), AddressEntry.Context.AVAILABLE)); + boolean changed2 = remove(addressEntry); + if (changed1 || changed2) + storage.queueUpForSave(); } } public void swapToAvailable(AddressEntry addressEntry) { remove(addressEntry); - add(new AddressEntry(addressEntry.getKeyPair(), wallet.getParams(), AddressEntry.Context.AVAILABLE)); - remove(addressEntry); - storage.queueUpForSave(); + boolean changed1 = add(new AddressEntry(addressEntry.getKeyPair(), wallet.getParams(), AddressEntry.Context.AVAILABLE)); + boolean changed2 = remove(addressEntry); + if (changed1 || changed2) + storage.queueUpForSave(); } public void queueUpForSave() { diff --git a/core/src/main/java/io/bitsquare/btc/SeedPeersSocks5Dns.java b/core/src/main/java/io/bitsquare/btc/SeedPeersSocks5Dns.java index bfbdcb0eab2..b9dda25f662 100644 --- a/core/src/main/java/io/bitsquare/btc/SeedPeersSocks5Dns.java +++ b/core/src/main/java/io/bitsquare/btc/SeedPeersSocks5Dns.java @@ -145,7 +145,7 @@ public static InetSocketAddress lookup( Socks5Proxy proxy, InetSocketAddress add InetAddress addrResolved = proxySocket.getInetAddress(); proxySocket.close(); if( addrResolved != null ) { - log.info("Resolved " + addr.getHostString() + " to " + addrResolved.getHostAddress() ); + log.debug("Resolved " + addr.getHostString() + " to " + addrResolved.getHostAddress()); return new InetSocketAddress(addrResolved, addr.getPort() ); } else { diff --git a/core/src/main/java/io/bitsquare/btc/TradeWalletService.java b/core/src/main/java/io/bitsquare/btc/TradeWalletService.java index 918d37c2bd0..5c647a28fa0 100644 --- a/core/src/main/java/io/bitsquare/btc/TradeWalletService.java +++ b/core/src/main/java/io/bitsquare/btc/TradeWalletService.java @@ -981,7 +981,7 @@ private Transaction createPayoutTx(Transaction depositTx, transaction.addOutput(buyerPayoutAmount, new Address(params, buyerAddressString)); transaction.addOutput(sellerPayoutAmount, new Address(params, sellerAddressString)); if (lockTime != 0) { - log.info("We use a lockTime of " + lockTime); + log.debug("We use a lockTime of " + lockTime); // When using lockTime we need to set sequenceNumber to 0 transaction.getInputs().stream().forEach(i -> i.setSequenceNumber(0)); transaction.setLockTime(lockTime); diff --git a/core/src/main/java/io/bitsquare/btc/WalletService.java b/core/src/main/java/io/bitsquare/btc/WalletService.java index 9a59546006c..aa3b0d1c105 100644 --- a/core/src/main/java/io/bitsquare/btc/WalletService.java +++ b/core/src/main/java/io/bitsquare/btc/WalletService.java @@ -170,7 +170,7 @@ public void initialize(@Nullable DeterministicSeed seed, ResultHandler resultHan backupWallet(); final Socks5Proxy socks5Proxy = preferences.getUseTorForBitcoinJ() ? socks5ProxyProvider.getSocks5Proxy() : null; - log.info("Use socks5Proxy for bitcoinj: " + socks5Proxy); + log.debug("Use socks5Proxy for bitcoinj: " + socks5Proxy); // If seed is non-null it means we are restoring from backup. walletAppKit = new WalletAppKitBitSquare(params, socks5Proxy, walletDir, "Bitsquare") { @@ -714,7 +714,7 @@ public void doubleSpendTransaction(String txId, Runnable resultHandler, ErrorMes public void doubleSpendTransaction(Transaction txToDoubleSpend, Address toAddress, Runnable resultHandler, ErrorMessageHandler errorMessageHandler) throws InsufficientMoneyException, AddressFormatException, AddressEntryException { final TransactionConfidence.ConfidenceType confidenceType = txToDoubleSpend.getConfidence().getConfidenceType(); if (confidenceType == TransactionConfidence.ConfidenceType.PENDING) { - log.info("txToDoubleSpend nr. of inputs " + txToDoubleSpend.getInputs().size()); + log.debug("txToDoubleSpend nr. of inputs " + txToDoubleSpend.getInputs().size()); Transaction newTransaction = new Transaction(params); txToDoubleSpend.getInputs().stream().forEach(input -> { @@ -739,8 +739,8 @@ public void doubleSpendTransaction(Transaction txToDoubleSpend, Address toAddres } ); - log.info("newTransaction nr. of inputs " + newTransaction.getInputs().size()); - log.info("newTransaction size in kB " + newTransaction.bitcoinSerialize().length / 1024); + log.debug("newTransaction nr. of inputs " + newTransaction.getInputs().size()); + log.debug("newTransaction size in kB " + newTransaction.bitcoinSerialize().length / 1024); if (!newTransaction.getInputs().isEmpty()) { Coin amount = Coin.valueOf(newTransaction.getInputs().stream() @@ -795,7 +795,7 @@ public void doubleSpendTransaction(Transaction txToDoubleSpend, Address toAddres } } if (sendResult != null) { - log.info("Broadcasting double spending transaction. " + newTransaction); + log.debug("Broadcasting double spending transaction. " + newTransaction); Futures.addCallback(sendResult.broadcastComplete, new FutureCallback() { @Override public void onSuccess(Transaction result) { @@ -835,9 +835,9 @@ private Coin getFeeForDoubleSpend(Wallet.SendRequest sendRequest, newSendRequest.feePerKb = FeePolicy.getNonTradeFeePerKb(); wallet.completeTx(newSendRequest); - log.info("After fee check: amount " + amount.toFriendlyString()); - log.info("Output fee " + sendRequest.tx.getFee().toFriendlyString()); - sendRequest.tx.getOutputs().stream().forEach(o -> log.info("Output value " + o.getValue().toFriendlyString())); + log.debug("After fee check: amount " + amount.toFriendlyString()); + log.debug("Output fee " + sendRequest.tx.getFee().toFriendlyString()); + sendRequest.tx.getOutputs().stream().forEach(o -> log.debug("Output value " + o.getValue().toFriendlyString())); } catch (InsufficientMoneyException e) { if (e.missing != null) { log.trace("missing fee " + e.missing.toFriendlyString()); diff --git a/core/src/main/java/io/bitsquare/btc/blockchain/BlockchainService.java b/core/src/main/java/io/bitsquare/btc/blockchain/BlockchainService.java index 9e35d84fd45..04b63533209 100644 --- a/core/src/main/java/io/bitsquare/btc/blockchain/BlockchainService.java +++ b/core/src/main/java/io/bitsquare/btc/blockchain/BlockchainService.java @@ -38,7 +38,7 @@ public SettableFuture requestFee(String transactionId) { Futures.addCallback(future, new FutureCallback() { public void onSuccess(Coin fee) { if (!resultFuture.isDone()) { - log.info("Request fee from providers done after {} ms.", (System.currentTimeMillis() - startTime)); + log.debug("Request fee from providers done after {} ms.", (System.currentTimeMillis() - startTime)); resultFuture.set(fee); } } diff --git a/core/src/main/java/io/bitsquare/btc/blockchain/GetFeeRequest.java b/core/src/main/java/io/bitsquare/btc/blockchain/GetFeeRequest.java index c24b47518e2..35bbaa9a6e5 100644 --- a/core/src/main/java/io/bitsquare/btc/blockchain/GetFeeRequest.java +++ b/core/src/main/java/io/bitsquare/btc/blockchain/GetFeeRequest.java @@ -33,7 +33,7 @@ private SettableFuture request(String transactionId, FeeProvider provider, try { return provider.getFee(transactionId); } catch (IOException | HttpException e) { - log.info("Fee request failed for tx {} from provider {}\n" + + log.debug("Fee request failed for tx {} from provider {}\n" + "That is expected if the tx was not propagated yet to the provider.\n" + "error={}", transactionId, provider, e.getMessage()); @@ -43,7 +43,7 @@ private SettableFuture request(String transactionId, FeeProvider provider, Futures.addCallback(future, new FutureCallback() { public void onSuccess(Coin fee) { - log.info("Received fee of {}\nfor tx {}\nfrom provider {}", fee.toFriendlyString(), transactionId, provider); + log.debug("Received fee of {}\nfor tx {}\nfrom provider {}", fee.toFriendlyString(), transactionId, provider); resultFuture.set(fee); } diff --git a/core/src/main/java/io/bitsquare/btc/pricefeed/GetPriceRequest.java b/core/src/main/java/io/bitsquare/btc/pricefeed/GetPriceRequest.java index 2ee1dce48ef..cd4ea0fc57f 100644 --- a/core/src/main/java/io/bitsquare/btc/pricefeed/GetPriceRequest.java +++ b/core/src/main/java/io/bitsquare/btc/pricefeed/GetPriceRequest.java @@ -58,6 +58,7 @@ public void onSuccess(MarketPrice marketPrice) { } public void onFailure(@NotNull Throwable throwable) { + log.error("requestPrice.onFailure: throwable=" + throwable.toString()); resultFuture.setException(throwable); } }); diff --git a/core/src/main/java/io/bitsquare/btc/pricefeed/PriceFeedService.java b/core/src/main/java/io/bitsquare/btc/pricefeed/PriceFeedService.java index 7ea35a1af96..27c34f8f211 100644 --- a/core/src/main/java/io/bitsquare/btc/pricefeed/PriceFeedService.java +++ b/core/src/main/java/io/bitsquare/btc/pricefeed/PriceFeedService.java @@ -46,7 +46,7 @@ public enum Type { } } - private static final long PERIOD_FIAT_SEC = new Random().nextInt(5) + 90; + private static final long PERIOD_FIAT_SEC = new Random().nextInt(5) + 70; private static final long PERIOD_ALL_FIAT_SEC = new Random().nextInt(5) + 180; private static final long PERIOD_ALL_CRYPTO_SEC = new Random().nextInt(5) + 180; @@ -63,8 +63,7 @@ public enum Type { private long bitcoinAveragePriceProviderLastCallAllTs; private long poloniexPriceProviderLastCallAllTs; private long bitcoinAveragePriceProviderLastCallTs; - private Timer cryptoCurrenciesTime; - private Timer fiatCurrenciesTime; + private Timer requestFiatPriceTimer; /////////////////////////////////////////////////////////////////////////////////////////// @@ -86,20 +85,11 @@ public void init(Consumer resultHandler, FaultHandler faultHandler) { this.priceConsumer = resultHandler; this.faultHandler = faultHandler; - requestAllPrices(fiatPriceProvider, () -> { - applyPrice(); - if (fiatCurrenciesTime == null) - fiatCurrenciesTime = UserThread.runPeriodically(() -> requestPrice(fiatPriceProvider), PERIOD_FIAT_SEC); - }); + requestAllPrices(fiatPriceProvider, () -> applyPriceToConsumer()); + UserThread.runPeriodically(() -> requestAllPrices(fiatPriceProvider, this::applyPriceToConsumer), PERIOD_ALL_FIAT_SEC); - requestAllPrices(cryptoCurrenciesPriceProvider, () -> { - applyPrice(); - if (cryptoCurrenciesTime == null) - cryptoCurrenciesTime = UserThread.runPeriodically(() -> requestAllPrices(cryptoCurrenciesPriceProvider, this::applyPrice), - PERIOD_ALL_CRYPTO_SEC); - }); - - UserThread.runPeriodically(() -> requestAllPrices(fiatPriceProvider, this::applyPrice), PERIOD_ALL_FIAT_SEC); + requestAllPrices(cryptoCurrenciesPriceProvider, () -> applyPriceToConsumer()); + UserThread.runPeriodically(() -> requestAllPrices(cryptoCurrenciesPriceProvider, this::applyPriceToConsumer), PERIOD_ALL_CRYPTO_SEC); } @Nullable @@ -110,7 +100,6 @@ public MarketPrice getMarketPrice(String currencyCode) { return null; } - /////////////////////////////////////////////////////////////////////////////////////////// // Setter /////////////////////////////////////////////////////////////////////////////////////////// @@ -118,19 +107,21 @@ public MarketPrice getMarketPrice(String currencyCode) { public void setType(Type type) { this.type = type; typeProperty.set(type); - applyPrice(); + applyPriceToConsumer(); } public void setCurrencyCode(String currencyCode) { if (this.currencyCode == null || !this.currencyCode.equals(currencyCode)) { this.currencyCode = currencyCode; currencyCodeProperty.set(currencyCode); - applyPrice(); + applyPriceToConsumer(); if (CurrencyUtil.isCryptoCurrency(currencyCode)) { + stopRequestFiatPriceTimer(); // Poloniex does not support calls for one currency just for all which is quite a bit of data - requestAllPrices(cryptoCurrenciesPriceProvider, this::applyPrice); + requestAllPrices(cryptoCurrenciesPriceProvider, this::applyPriceToConsumer); } else { + startRequestFiatPriceTimer(); requestPrice(fiatPriceProvider); } } @@ -166,12 +157,27 @@ public IntegerProperty currenciesUpdateFlagProperty() { // Private /////////////////////////////////////////////////////////////////////////////////////////// - private void applyPrice() { + + private void startRequestFiatPriceTimer() { + stopRequestFiatPriceTimer(); + requestFiatPriceTimer = UserThread.runPeriodically(() -> requestPrice(fiatPriceProvider), PERIOD_FIAT_SEC); + } + + private void stopRequestFiatPriceTimer() { + if (requestFiatPriceTimer != null) + requestFiatPriceTimer.stop(); + } + + private void applyPriceToConsumer() { if (priceConsumer != null && currencyCode != null && type != null) { if (cache.containsKey(currencyCode)) { - MarketPrice marketPrice = cache.get(currencyCode); - if (marketPrice != null) + try { + MarketPrice marketPrice = cache.get(currencyCode); priceConsumer.accept(marketPrice.getPrice(type)); + } catch (Throwable t) { + log.warn("Error at applyPriceToConsumer " + t.getMessage()); + } + } else { String errorMessage = "We don't have a price for currencyCode " + currencyCode; log.debug(errorMessage); @@ -192,21 +198,25 @@ private void requestPrice(PriceProvider provider) { if (allowed) { GetPriceRequest getPriceRequest = new GetPriceRequest(); - SettableFuture future = getPriceRequest.requestPrice(currencyCode, provider); - Futures.addCallback(future, new FutureCallback() { - public void onSuccess(MarketPrice marketPrice) { - UserThread.execute(() -> { - if (marketPrice != null && priceConsumer != null) { - cache.put(marketPrice.currencyCode, marketPrice); - priceConsumer.accept(marketPrice.getPrice(type)); - } - }); - } - - public void onFailure(@NotNull Throwable throwable) { - log.debug("Could not load marketPrice\n" + throwable.getMessage()); - } - }); + if (CurrencyUtil.isFiatCurrency(currencyCode)) { + SettableFuture future = getPriceRequest.requestPrice(currencyCode, provider); + Futures.addCallback(future, new FutureCallback() { + public void onSuccess(MarketPrice marketPrice) { + UserThread.execute(() -> { + if (marketPrice != null && priceConsumer != null) { + cache.put(marketPrice.currencyCode, marketPrice); + priceConsumer.accept(marketPrice.getPrice(type)); + } + }); + } + + public void onFailure(@NotNull Throwable throwable) { + log.debug("Could not load marketPrice\n" + throwable.getMessage()); + } + }); + } else { + log.warn("We tried to call requestPrice with a non fiat currency selected: selectedCurrencyCode=" + currencyCode); + } } else { log.debug("Ignore request. Too many attempt to call the API provider " + provider); } diff --git a/core/src/main/java/io/bitsquare/crypto/ScryptUtil.java b/core/src/main/java/io/bitsquare/crypto/ScryptUtil.java index a16028bf997..387016619eb 100644 --- a/core/src/main/java/io/bitsquare/crypto/ScryptUtil.java +++ b/core/src/main/java/io/bitsquare/crypto/ScryptUtil.java @@ -30,11 +30,11 @@ public static KeyCrypterScrypt getKeyCrypterScrypt() { public static void deriveKeyWithScrypt(KeyCrypterScrypt keyCrypterScrypt, String password, DeriveKeyResultHandler resultHandler) { Utilities.getThreadPoolExecutor("ScryptUtil:deriveKeyWithScrypt-%d", 1, 2, 5L).submit(() -> { try { - log.info("Doing key derivation"); + log.debug("Doing key derivation"); long start = System.currentTimeMillis(); KeyParameter aesKey = keyCrypterScrypt.deriveKey(password); long duration = System.currentTimeMillis() - start; - log.info("Key derivation took {} msec", duration); + log.debug("Key derivation took {} msec", duration); UserThread.execute(() -> { try { resultHandler.handleResult(aesKey); diff --git a/core/src/main/java/io/bitsquare/locale/CurrencyTuple.java b/core/src/main/java/io/bitsquare/locale/CurrencyTuple.java new file mode 100644 index 00000000000..a124acd7b3c --- /dev/null +++ b/core/src/main/java/io/bitsquare/locale/CurrencyTuple.java @@ -0,0 +1,32 @@ +/* + * 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.locale; + +import java.io.Serializable; + +public class CurrencyTuple implements Serializable { + // That object is used for serializing to a Json file. + + public final String code; + public final String name; + + public CurrencyTuple(String code, String name) { + this.code = code; + this.name = name; + } +} diff --git a/core/src/main/java/io/bitsquare/trade/TradableList.java b/core/src/main/java/io/bitsquare/trade/TradableList.java index 4d05a20ac28..34355ec55cb 100644 --- a/core/src/main/java/io/bitsquare/trade/TradableList.java +++ b/core/src/main/java/io/bitsquare/trade/TradableList.java @@ -65,18 +65,20 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE @Override public boolean add(T tradable) { - boolean result = super.add(tradable); + boolean changed = super.add(tradable); getObservableList().add(tradable); - storage.queueUpForSave(); - return result; + if (changed) + storage.queueUpForSave(); + return changed; } @Override public boolean remove(Object tradable) { - boolean result = super.remove(tradable); + boolean changed = super.remove(tradable); getObservableList().remove(tradable); - storage.queueUpForSave(); - return result; + if (changed) + storage.queueUpForSave(); + return changed; } public ObservableList getObservableList() { diff --git a/core/src/main/java/io/bitsquare/trade/Trade.java b/core/src/main/java/io/bitsquare/trade/Trade.java index 0cbe7e7eb8d..784f85b9c01 100644 --- a/core/src/main/java/io/bitsquare/trade/Trade.java +++ b/core/src/main/java/io/bitsquare/trade/Trade.java @@ -316,16 +316,20 @@ public void setStorage(Storage storage) { /////////////////////////////////////////////////////////////////////////////////////////// public void setState(State state) { + boolean changed = this.state != state; this.state = state; stateProperty.set(state); - persist(); + if (changed) + persist(); } public void setDisputeState(DisputeState disputeState) { Log.traceCall("disputeState=" + disputeState + "\n\ttrade=" + this); + boolean changed = this.disputeState != disputeState; this.disputeState = disputeState; disputeStateProperty.set(disputeState); - persist(); + if (changed) + persist(); } public DisputeState getDisputeState() { @@ -333,9 +337,11 @@ public DisputeState getDisputeState() { } public void setTradePeriodState(TradePeriodState tradePeriodState) { + boolean changed = this.tradePeriodState != tradePeriodState; this.tradePeriodState = tradePeriodState; tradePeriodStateProperty.set(tradePeriodState); - persist(); + if (changed) + persist(); } public TradePeriodState getTradePeriodState() { diff --git a/core/src/main/java/io/bitsquare/trade/TradeManager.java b/core/src/main/java/io/bitsquare/trade/TradeManager.java index 46962b15aab..e1102eebe72 100644 --- a/core/src/main/java/io/bitsquare/trade/TradeManager.java +++ b/core/src/main/java/io/bitsquare/trade/TradeManager.java @@ -75,8 +75,6 @@ public class TradeManager { private static final Logger log = LoggerFactory.getLogger(TradeManager.class); - private static final long REPUBLISH_STATISTICS_INTERVAL_MIN = TimeUnit.HOURS.toMillis(1); - private final User user; private final KeyRing keyRing; private final WalletService walletService; @@ -223,17 +221,9 @@ private void initPendingTrades() { } // We start later to have better connectivity to the network - UserThread.runPeriodically(() -> publishTradeStatistics(tradesForStatistics), + UserThread.runAfter(() -> publishTradeStatistics(tradesForStatistics), 30, TimeUnit.SECONDS); - //TODO can be removed at next release - // For the first 2 weeks of the release we re publish the trades to get faster good distribution - // otherwise the trades would only be published again at restart and if a client dont do that the stats might be missing - // for a longer time as initially there are not many peer upgraded and supporting flooding of the stats data. - if (new Date().before(new Date(2016 - 1900, Calendar.AUGUST, 8))) - UserThread.runPeriodically(() -> publishTradeStatistics(tradesForStatistics), - REPUBLISH_STATISTICS_INTERVAL_MIN, TimeUnit.MILLISECONDS); - pendingTradesInitialized.set(true); } @@ -249,7 +239,8 @@ private void publishTradeStatistics(List trades) { tradeStatisticsManager.add(tradeStatistics); // Only trades from last 30 days - if ((new Date().getTime() - trade.getDate().getTime()) < TimeUnit.DAYS.toMillis(30)) { + //TODO we want to get old trades published so we dont do the 30 days check for the first few weeks of the new version + if (new Date().before(new Date(2016 - 1900, Calendar.AUGUST, 30)) || (new Date().getTime() - trade.getDate().getTime()) < TimeUnit.DAYS.toMillis(30)) { long delay = 3000; final long minDelay = (i + 1) * delay; final long maxDelay = (i + 2) * delay; @@ -289,7 +280,7 @@ private void handleInitialTakeOfferRequest(TradeMessage message, NodeAddress pee // TODO respond //(RequestDepositTxInputsMessage)message. // messageService.sendEncryptedMessage(peerAddress,messageWithPubKey.getMessage().); - log.info("We received a take offer request but don't have that offer anymore."); + log.debug("We received a take offer request but don't have that offer anymore."); } } @@ -391,7 +382,7 @@ public void onWithdrawRequest(String toAddress, Coin receiverAmount, KeyParamete @Override public void onSuccess(@javax.annotation.Nullable Transaction transaction) { if (transaction != null) { - log.info("onWithdraw onSuccess tx ID:" + transaction.getHashAsString()); + log.debug("onWithdraw onSuccess tx ID:" + transaction.getHashAsString()); addTradeToClosedTrades(trade); trade.setState(Trade.State.WITHDRAW_COMPLETED); resultHandler.handleResult(); diff --git a/core/src/main/java/io/bitsquare/trade/offer/OpenOffer.java b/core/src/main/java/io/bitsquare/trade/offer/OpenOffer.java index ce4e715bedb..d14f0e1aff6 100644 --- a/core/src/main/java/io/bitsquare/trade/offer/OpenOffer.java +++ b/core/src/main/java/io/bitsquare/trade/offer/OpenOffer.java @@ -68,6 +68,7 @@ private void readObject(java.io.ObjectInputStream in) throws IOException, ClassN log.warn("Cannot be deserialized." + t.getMessage()); } } + public Date getDate() { return offer.getDate(); } @@ -92,8 +93,10 @@ public void setStorage(Storage> storage) { public void setState(State state) { log.trace("setState" + state); + boolean changed = this.state != state; this.state = state; - storage.queueUpForSave(); + if (changed) + storage.queueUpForSave(); // We keep it reserved for a limited time, if trade preparation fails we revert to available state if (this.state == State.RESERVED) @@ -111,7 +114,7 @@ private void startTimeout() { stopTimeout(); timeoutTimer = UserThread.runAfter(() -> { - log.info("Timeout for resettin State.RESERVED reached"); + log.debug("Timeout for resettin State.RESERVED reached"); if (state == State.RESERVED) setState(State.AVAILABLE); }, TIMEOUT_SEC); diff --git a/core/src/main/java/io/bitsquare/trade/offer/OpenOfferManager.java b/core/src/main/java/io/bitsquare/trade/offer/OpenOfferManager.java index 7ccb74c1a26..4c6ff772504 100644 --- a/core/src/main/java/io/bitsquare/trade/offer/OpenOfferManager.java +++ b/core/src/main/java/io/bitsquare/trade/offer/OpenOfferManager.java @@ -152,7 +152,7 @@ public void shutDown(@Nullable Runnable completeHandler) { stopPeriodicRepublishOffersTimer(); stopRetryRepublishOffersTimer(); - log.info("remove all open offers at shutDown"); + log.debug("remove all open offers at shutDown"); // we remove own offers from offerbook when we go offline // Normally we use a delay for broadcasting to the peers, but at shut down we want to get it fast out @@ -407,12 +407,12 @@ public void onArrived() { @Override public void onFault() { - log.info("Sending OfferAvailabilityResponse failed."); + log.debug("Sending OfferAvailabilityResponse failed."); } }); } catch (Throwable t) { t.printStackTrace(); - log.info("Exception at handleRequestIsOfferAvailableMessage " + t.getMessage()); + log.debug("Exception at handleRequestIsOfferAvailableMessage " + t.getMessage()); } } else { log.debug("We have stopped already. We ignore that handleOfferAvailabilityRequest call."); @@ -505,7 +505,7 @@ private void startPeriodicRefreshOffersTimer() { // we delay to avoid reaching throttle limits // roughly 4 offers per second - long delay = 150; + long delay = 300; final long minDelay = (i + 1) * delay; final long maxDelay = (i + 2) * delay; final OpenOffer openOffer = openOffersList.get(i); @@ -532,7 +532,7 @@ private void refreshOffer(OpenOffer openOffer) { } private void restart() { - log.info("Restart after connection loss"); + log.debug("Restart after connection loss"); if (retryRepublishOffersTimer == null) retryRepublishOffersTimer = UserThread.runAfter(() -> { stopped = false; diff --git a/core/src/main/java/io/bitsquare/trade/protocol/availability/OfferAvailabilityProtocol.java b/core/src/main/java/io/bitsquare/trade/protocol/availability/OfferAvailabilityProtocol.java index 5873b845324..e1ba0c913de 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/availability/OfferAvailabilityProtocol.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/availability/OfferAvailabilityProtocol.java @@ -135,7 +135,7 @@ private void handle(OfferAvailabilityResponse message) { private void startTimeout() { if (timeoutTimer == null) { timeoutTimer = UserThread.runAfter(() -> { - log.warn("Timeout reached at " + this); + log.debug("Timeout reached at " + this); model.offer.setState(Offer.State.OFFERER_OFFLINE); errorMessageHandler.handleErrorMessage("Timeout reached: Peer has not responded."); }, TIMEOUT_SEC); diff --git a/core/src/main/java/io/bitsquare/trade/protocol/placeoffer/tasks/BroadcastCreateOfferFeeTx.java b/core/src/main/java/io/bitsquare/trade/protocol/placeoffer/tasks/BroadcastCreateOfferFeeTx.java index 0f0edaa3faa..4494bd6a3bb 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/placeoffer/tasks/BroadcastCreateOfferFeeTx.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/placeoffer/tasks/BroadcastCreateOfferFeeTx.java @@ -44,7 +44,7 @@ protected void run() { model.tradeWalletService.broadcastTx(model.getTransaction(), new FutureCallback() { @Override public void onSuccess(Transaction transaction) { - log.info("Broadcast of offer fee payment succeeded: transaction = " + transaction.toString()); + log.debug("Broadcast of offer fee payment succeeded: transaction = " + transaction.toString()); if (model.getTransaction().getHashAsString().equals(transaction.getHashAsString())) { model.offer.setState(Offer.State.OFFER_FEE_PAID); @@ -57,7 +57,7 @@ public void onSuccess(Transaction transaction) { // Normally we use a delay for broadcasting to the peers, but at shut down we want to get it fast out model.offerBookService.removeOffer(model.offer, () -> { - log.info("We store now the changed txID to the offer and add that again."); + log.debug("We store now the changed txID to the offer and add that again."); // We store now the changed txID to the offer and add that again. model.offer.setOfferFeePaymentTxID(transaction.getHashAsString()); model.setTransaction(transaction); @@ -106,7 +106,7 @@ private void updateStateOnFault() { if (!removeOfferFailed && !addOfferFailed) { // If broadcast fails we need to remove offer from offerbook model.offerBookService.removeOffer(model.offer, - () -> log.info("Offer removed from offerbook because broadcast failed."), + () -> log.debug("Offer removed from offerbook because broadcast failed."), errorMessage -> log.error("removeOffer failed. " + errorMessage)); } } diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/TradeTask.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/TradeTask.java index 6080911d40e..5e1b7f827ea 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/TradeTask.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/TradeTask.java @@ -64,7 +64,7 @@ protected void removeMailboxMessageAfterProcessing() { if (processModel.getTradeMessage() instanceof MailboxMessage) { DecryptedMsgWithPubKey mailboxMessage = trade.getMailboxMessage(); if (mailboxMessage != null && mailboxMessage.message.equals(processModel.getTradeMessage())) { - log.info("Remove mailboxMessage from P2P network. mailboxMessage = " + mailboxMessage); + log.debug("Remove mailboxMessage from P2P network. mailboxMessage = " + mailboxMessage); processModel.getP2PService().removeEntryFromMailbox(mailboxMessage); trade.setMailboxMessage(null); } diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/buyer/OffererCreatesAndSignsDepositTxAsBuyer.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/buyer/OffererCreatesAndSignsDepositTxAsBuyer.java index 7f23c5ca8ba..fbfc830b824 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/buyer/OffererCreatesAndSignsDepositTxAsBuyer.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/buyer/OffererCreatesAndSignsDepositTxAsBuyer.java @@ -46,7 +46,7 @@ protected void run() { Coin buyerInputAmount = FeePolicy.getSecurityDeposit().add(FeePolicy.getFixedTxFeeForTrades()); Coin msOutputAmount = buyerInputAmount.add(FeePolicy.getSecurityDeposit()).add(trade.getTradeAmount()); - log.info("\n\n------------------------------------------------------------\n" + log.debug("\n\n------------------------------------------------------------\n" + "Contract as json\n" + trade.getContractAsJson() + "\n------------------------------------------------------------\n"); diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/buyer/SendFiatTransferStartedMessage.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/buyer/SendFiatTransferStartedMessage.java index 5be594ef846..c91a832f796 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/buyer/SendFiatTransferStartedMessage.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/buyer/SendFiatTransferStartedMessage.java @@ -48,14 +48,14 @@ protected void run() { new SendMailboxMessageListener() { @Override public void onArrived() { - log.info("Message arrived at peer."); + log.debug("Message arrived at peer."); trade.setState(Trade.State.BUYER_SENT_FIAT_PAYMENT_INITIATED_MSG); complete(); } @Override public void onStoredInMailbox() { - log.info("Message stored in mailbox."); + log.debug("Message stored in mailbox."); trade.setState(Trade.State.BUYER_SENT_FIAT_PAYMENT_INITIATED_MSG); complete(); } diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/buyer/SignAndPublishDepositTxAsBuyer.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/buyer/SignAndPublishDepositTxAsBuyer.java index f26ce9c83d9..a758b54e37a 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/buyer/SignAndPublishDepositTxAsBuyer.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/buyer/SignAndPublishDepositTxAsBuyer.java @@ -47,7 +47,7 @@ protected void run() { try { runInterceptHook(); - log.info("\n\n------------------------------------------------------------\n" + log.debug("\n\n------------------------------------------------------------\n" + "Contract as json\n" + trade.getContractAsJson() + "\n------------------------------------------------------------\n"); diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/seller/OffererCreatesAndSignsDepositTxAsSeller.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/seller/OffererCreatesAndSignsDepositTxAsSeller.java index aac5a6ec426..38cebcabe8e 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/seller/OffererCreatesAndSignsDepositTxAsSeller.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/seller/OffererCreatesAndSignsDepositTxAsSeller.java @@ -46,7 +46,7 @@ protected void run() { Coin sellerInputAmount = FeePolicy.getSecurityDeposit().add(FeePolicy.getFixedTxFeeForTrades()).add(trade.getTradeAmount()); Coin msOutputAmount = sellerInputAmount.add(FeePolicy.getSecurityDeposit()); - log.info("\n\n------------------------------------------------------------\n" + log.debug("\n\n------------------------------------------------------------\n" + "Contract as json\n" + trade.getContractAsJson() + "\n------------------------------------------------------------\n"); diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/seller/SignAndPublishDepositTxAsSeller.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/seller/SignAndPublishDepositTxAsSeller.java index effae57e093..2e10a977053 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/seller/SignAndPublishDepositTxAsSeller.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/seller/SignAndPublishDepositTxAsSeller.java @@ -46,7 +46,7 @@ public SignAndPublishDepositTxAsSeller(TaskRunner taskHandler, Trade trade) { protected void run() { try { runInterceptHook(); - log.info("\n\n------------------------------------------------------------\n" + log.debug("\n\n------------------------------------------------------------\n" + "Contract as json\n" + trade.getContractAsJson() + "\n------------------------------------------------------------\n"); diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/taker/PublishTradeStatistics.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/taker/PublishTradeStatistics.java index 183ee30a720..1def1694d95 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/taker/PublishTradeStatistics.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/taker/PublishTradeStatistics.java @@ -64,7 +64,7 @@ protected void run() { } } if (!matches) { - log.warn("We publish tradeStatistics because the offerer uses an old version."); + log.debug("We publish tradeStatistics because the offerer uses an old version so we publish to have at least 1 data item published."); processModel.getP2PService().addData(tradeStatistics, true); } else { log.trace("We do not publish tradeStatistics because the offerer support the capabilities."); diff --git a/core/src/main/java/io/bitsquare/trade/statistics/TradeStatisticsManager.java b/core/src/main/java/io/bitsquare/trade/statistics/TradeStatisticsManager.java index 0fc31ff0660..a9ddfb707a8 100644 --- a/core/src/main/java/io/bitsquare/trade/statistics/TradeStatisticsManager.java +++ b/core/src/main/java/io/bitsquare/trade/statistics/TradeStatisticsManager.java @@ -4,6 +4,8 @@ import com.google.inject.name.Named; import io.bitsquare.app.CoreOptionKeys; import io.bitsquare.common.util.Utilities; +import io.bitsquare.locale.CurrencyTuple; +import io.bitsquare.locale.CurrencyUtil; import io.bitsquare.p2p.P2PService; import io.bitsquare.p2p.storage.HashMapChangedListener; import io.bitsquare.p2p.storage.payload.StoragePayload; @@ -14,6 +16,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.stream.Collectors; @@ -21,22 +24,44 @@ public class TradeStatisticsManager { private static final Logger log = LoggerFactory.getLogger(TradeStatisticsManager.class); - private final Storage> storage; - private Storage jsonStorage; + private final Storage> statisticsStorage; + private Storage fiatCurrencyListJsonStorage; + private Storage cryptoCurrencyListJsonStorage; + private Storage statisticsJsonStorage; private boolean dumpStatistics; private ObservableSet observableTradeStatisticsSet = FXCollections.observableSet(); private HashSet tradeStatisticsSet = new HashSet<>(); @Inject - public TradeStatisticsManager(Storage> storage, Storage jsonStorage, P2PService p2PService, @Named(CoreOptionKeys.DUMP_STATISTICS) boolean dumpStatistics) { - this.storage = storage; - this.jsonStorage = jsonStorage; + public TradeStatisticsManager(Storage> statisticsStorage, + Storage fiatCurrencyListJsonStorage, + Storage cryptoCurrencyListJsonStorage, + Storage statisticsJsonStorage, + P2PService p2PService, + @Named(CoreOptionKeys.DUMP_STATISTICS) boolean dumpStatistics) { + this.statisticsStorage = statisticsStorage; + this.fiatCurrencyListJsonStorage = fiatCurrencyListJsonStorage; + this.cryptoCurrencyListJsonStorage = cryptoCurrencyListJsonStorage; + this.statisticsJsonStorage = statisticsJsonStorage; this.dumpStatistics = dumpStatistics; - if (dumpStatistics) - this.jsonStorage.initAndGetPersistedWithFileName("trade_statistics.json"); + if (dumpStatistics) { + this.statisticsJsonStorage.initAndGetPersistedWithFileName("trade_statistics.json"); + + this.fiatCurrencyListJsonStorage.initAndGetPersistedWithFileName("fiat_currency_list.json"); + ArrayList fiatCurrencyList = new ArrayList<>(CurrencyUtil.getAllSortedFiatCurrencies().stream() + .map(e -> new CurrencyTuple(e.getCode(), e.getName())) + .collect(Collectors.toList())); + fiatCurrencyListJsonStorage.queueUpForSave(Utilities.objectToJson(fiatCurrencyList), 2000); + + this.cryptoCurrencyListJsonStorage.initAndGetPersistedWithFileName("crypto_currency_list.json"); + ArrayList cryptoCurrencyList = new ArrayList<>(CurrencyUtil.getAllSortedCryptoCurrencies().stream() + .map(e -> new CurrencyTuple(e.getCode(), e.getName())) + .collect(Collectors.toList())); + cryptoCurrencyListJsonStorage.queueUpForSave(Utilities.objectToJson(cryptoCurrencyList), 2000); + } - HashSet persisted = storage.initAndGetPersistedWithFileName("TradeStatistics"); + HashSet persisted = statisticsStorage.initAndGetPersistedWithFileName("TradeStatistics"); if (persisted != null) persisted.stream().forEach(this::add); @@ -44,7 +69,7 @@ public TradeStatisticsManager(Storage> storage, Storage @Override public void onAdded(ProtectedStorageEntry data) { final StoragePayload storagePayload = data.getStoragePayload(); - if (storagePayload instanceof TradeStatistics) + if (storagePayload instanceof TradeStatistics) add((TradeStatistics) storagePayload); } @@ -61,7 +86,7 @@ public void add(TradeStatistics tradeStatistics) { if (!itemAlreadyAdded) { tradeStatisticsSet.add(tradeStatistics); observableTradeStatisticsSet.add(tradeStatistics); - storage.queueUpForSave(tradeStatisticsSet, 2000); + statisticsStorage.queueUpForSave(new HashSet<>(tradeStatisticsSet), 2000); dump(); } else { @@ -86,7 +111,7 @@ private void dump() { list.sort((o1, o2) -> (o1.tradeDate < o2.tradeDate ? 1 : (o1.tradeDate == o2.tradeDate ? 0 : -1))); TradeStatistics[] array = new TradeStatistics[tradeStatisticsSet.size()]; list.toArray(array); - jsonStorage.queueUpForSave(Utilities.objectToJson(array), 5_000); + statisticsJsonStorage.queueUpForSave(Utilities.objectToJson(array), 5000); } } diff --git a/core/src/main/java/io/bitsquare/user/Preferences.java b/core/src/main/java/io/bitsquare/user/Preferences.java index 22070ac55d6..df93963de3b 100644 --- a/core/src/main/java/io/bitsquare/user/Preferences.java +++ b/core/src/main/java/io/bitsquare/user/Preferences.java @@ -121,8 +121,10 @@ public static TradeCurrency getDefaultTradeCurrency() { private long nonTradeTxFeePerKB = FeePolicy.getNonTradeFeePerKb().value; private double maxPriceDistanceInPercent; private boolean useInvertedMarketPrice; - private String marketScreenCurrencyCode = CurrencyUtil.getDefaultTradeCurrency().getCode(); - private String tradeStatisticsScreenCurrencyCode = CurrencyUtil.getDefaultTradeCurrency().getCode(); + + private String offerBookChartScreenCurrencyCode = CurrencyUtil.getDefaultTradeCurrency().getCode(); + private String tradeChartsScreenCurrencyCode = CurrencyUtil.getDefaultTradeCurrency().getCode(); + private String buyScreenCurrencyCode = CurrencyUtil.getDefaultTradeCurrency().getCode(); private String sellScreenCurrencyCode = CurrencyUtil.getDefaultTradeCurrency().getCode(); private int tradeStatisticsTickUnitIndex = 0; @@ -215,10 +217,10 @@ public Preferences(Storage storage, BitsquareEnvironment bitsquareE if (persisted.getPeerTagMap() != null) peerTagMap = persisted.getPeerTagMap(); - marketScreenCurrencyCode = persisted.getMarketScreenCurrencyCode(); + offerBookChartScreenCurrencyCode = persisted.getOfferBookChartScreenCurrencyCode(); buyScreenCurrencyCode = persisted.getBuyScreenCurrencyCode(); sellScreenCurrencyCode = persisted.getSellScreenCurrencyCode(); - tradeStatisticsScreenCurrencyCode = persisted.getTradeStatisticsScreenCurrencyCode(); + tradeChartsScreenCurrencyCode = persisted.getTradeChartsScreenCurrencyCode(); tradeStatisticsTickUnitIndex = persisted.getTradeStatisticsTickUnitIndex(); if (persisted.getIgnoreTradersList() != null) @@ -449,8 +451,8 @@ public void setBridgeAddressesAsString(@Nullable String bridgeAddressesAsString) } } - public void setMarketScreenCurrencyCode(String marketScreenCurrencyCode) { - this.marketScreenCurrencyCode = marketScreenCurrencyCode; + public void setOfferBookChartScreenCurrencyCode(String offerBookChartScreenCurrencyCode) { + this.offerBookChartScreenCurrencyCode = offerBookChartScreenCurrencyCode; storage.queueUpForSave(); } @@ -474,8 +476,8 @@ public void setDefaultPath(String defaultPath) { storage.queueUpForSave(); } - public void setTradeStatisticsScreenCurrencyCode(String tradeStatisticsScreenCurrencyCode) { - this.tradeStatisticsScreenCurrencyCode = tradeStatisticsScreenCurrencyCode; + public void setTradeChartsScreenCurrencyCode(String tradeChartsScreenCurrencyCode) { + this.tradeChartsScreenCurrencyCode = tradeChartsScreenCurrencyCode; storage.queueUpForSave(); } @@ -486,6 +488,7 @@ public void setTradeStatisticsTickUnitIndex(int tradeStatisticsTickUnitIndex) { public void setUseTorForHttpRequests(boolean useTorForHttpRequests) { useTorForHttpRequestsProperty.set(useTorForHttpRequests); + storage.queueUpForSave(); } /////////////////////////////////////////////////////////////////////////////////////////// @@ -620,8 +623,8 @@ public List getBridgeAddresses() { return bridgeAddresses; } - public String getMarketScreenCurrencyCode() { - return marketScreenCurrencyCode; + public String getOfferBookChartScreenCurrencyCode() { + return offerBookChartScreenCurrencyCode; } public String getBuyScreenCurrencyCode() { @@ -640,8 +643,8 @@ public String getDefaultPath() { return defaultPath; } - public String getTradeStatisticsScreenCurrencyCode() { - return tradeStatisticsScreenCurrencyCode; + public String getTradeChartsScreenCurrencyCode() { + return tradeChartsScreenCurrencyCode; } public int getTradeStatisticsTickUnitIndex() { @@ -679,11 +682,11 @@ private void setCryptoCurrencies(List currencies) { private void setBlockChainExplorerTestNet(BlockChainExplorer blockChainExplorerTestNet) { this.blockChainExplorerTestNet = blockChainExplorerTestNet; - storage.queueUpForSave(2000); + storage.queueUpForSave(); } private void setBlockChainExplorerMainNet(BlockChainExplorer blockChainExplorerMainNet) { this.blockChainExplorerMainNet = blockChainExplorerMainNet; - storage.queueUpForSave(2000); + storage.queueUpForSave(); } } diff --git a/core/src/main/java/io/bitsquare/user/User.java b/core/src/main/java/io/bitsquare/user/User.java index da83c045f90..c36a878015f 100644 --- a/core/src/main/java/io/bitsquare/user/User.java +++ b/core/src/main/java/io/bitsquare/user/User.java @@ -181,8 +181,9 @@ public boolean removeAcceptedLanguageLocale(String languageLocaleCode) { public void addAcceptedArbitrator(Arbitrator arbitrator) { if (!acceptedArbitrators.contains(arbitrator) && !isMyOwnRegisteredArbitrator(arbitrator)) { - acceptedArbitrators.add(arbitrator); - storage.queueUpForSave(); + boolean changed = acceptedArbitrators.add(arbitrator); + if (changed) + storage.queueUpForSave(); } } @@ -191,8 +192,9 @@ public boolean isMyOwnRegisteredArbitrator(Arbitrator arbitrator) { } public void removeAcceptedArbitrator(Arbitrator arbitrator) { - acceptedArbitrators.remove(arbitrator); - storage.queueUpForSave(); + boolean changed = acceptedArbitrators.remove(arbitrator); + if (changed) + storage.queueUpForSave(); } public void clearAcceptedArbitrators() { @@ -200,7 +202,7 @@ public void clearAcceptedArbitrators() { storage.queueUpForSave(); } - public void setRegisteredArbitrator(@org.jetbrains.annotations.Nullable Arbitrator arbitrator) { + public void setRegisteredArbitrator(@Nullable Arbitrator arbitrator) { this.registeredArbitrator = arbitrator; storage.queueUpForSave(); } @@ -330,7 +332,7 @@ public boolean hasPaymentAccountForCurrency(TradeCurrency tradeCurrency) { public void setDevelopersAlert(Alert developersAlert) { this.developersAlert = developersAlert; - storage.queueUpForSave(2000); + storage.queueUpForSave(); } public Alert getDevelopersAlert() { @@ -339,7 +341,7 @@ public Alert getDevelopersAlert() { public void setDisplayedAlert(Alert displayedAlert) { this.displayedAlert = displayedAlert; - storage.queueUpForSave(2000); + storage.queueUpForSave(); } public Alert getDisplayedAlert() { diff --git a/doc/build.md b/doc/build.md index 49b46386d1d..661ec87ebf8 100644 --- a/doc/build.md +++ b/doc/build.md @@ -71,11 +71,11 @@ You need to get the Bitsquare dependencies first as we need to copy the BountyCa ### 4. Copy the jdkfix jar file -Copy the jdkfix-0.4.9.1.jar from the Bitsquare jdkfix/target directory to $JAVA_HOME/jre/lib/ext/. -jdkfix-0.4.9.1.jar includes a bugfix of the SortedList class which will be released with the next JDK version. +Copy the jdkfix-0.4.9.2.jar from the Bitsquare jdkfix/target directory to $JAVA_HOME/jre/lib/ext/. +jdkfix-0.4.9.2.jar includes a bugfix of the SortedList class which will be released with the next JDK version. We need to load that class before the default java class. This step will be removed once the bugfix is in the official JDK. - $ sudo cp bitsquare/jdkfix/target/jdkfix-0.4.9.1.jar $JAVA_HOME/jre/lib/ext/jdkfix-0.4.9.1.jar + $ sudo cp bitsquare/jdkfix/target/jdkfix-0.4.9.2.jar $JAVA_HOME/jre/lib/ext/jdkfix-0.4.9.2.jar ### 5. Copy the BountyCastle provider jar file diff --git a/gui/pom.xml b/gui/pom.xml index cf870b7befe..0fe6f1ab14e 100644 --- a/gui/pom.xml +++ b/gui/pom.xml @@ -22,7 +22,7 @@ parent io.bitsquare - 0.4.9.1 + 0.4.9.2 4.0.0 diff --git a/gui/src/main/java/io/bitsquare/app/BitsquareApp.java b/gui/src/main/java/io/bitsquare/app/BitsquareApp.java index fdfadb32a22..1f4531bccf0 100644 --- a/gui/src/main/java/io/bitsquare/app/BitsquareApp.java +++ b/gui/src/main/java/io/bitsquare/app/BitsquareApp.java @@ -265,7 +265,7 @@ private void showEmptyWalletPopup() { private void showErrorPopup(Throwable throwable, boolean doShutDown) { if (!shutDownRequested) { if (scene == null) { - log.warn("Scene not available yet, we create a new scene. The bug might be caused by a guice circular dependency."); + log.warn("Scene not available yet, we create a new scene. The bug might be caused by an exception in a constructor or by a circular dependency in guice."); scene = new Scene(new StackPane(), 1000, 650); scene.getStylesheets().setAll( "/io/bitsquare/gui/bitsquare.css", @@ -357,7 +357,7 @@ public void stop() { .show(); UserThread.runAfter(() -> { gracefulShutDown(() -> { - log.info("App shutdown complete"); + log.debug("App shutdown complete"); System.exit(0); }); }, 200, TimeUnit.MILLISECONDS); @@ -376,7 +376,7 @@ private void gracefulShutDown(ResultHandler resultHandler) { injector.getInstance(P2PService.class).shutDown(() -> { injector.getInstance(WalletService.class).shutDownDone.addListener((ov, o, n) -> { bitsquareAppModule.close(injector); - log.info("Graceful shutdown completed"); + log.debug("Graceful shutdown completed"); resultHandler.handleResult(); }); injector.getInstance(WalletService.class).shutDown(); @@ -388,7 +388,7 @@ private void gracefulShutDown(ResultHandler resultHandler) { UserThread.runAfter(resultHandler::handleResult, 1); } } catch (Throwable t) { - log.info("App shutdown failed with exception"); + log.debug("App shutdown failed with exception"); t.printStackTrace(); System.exit(1); } diff --git a/gui/src/main/java/io/bitsquare/gui/CandleStickChart.css b/gui/src/main/java/io/bitsquare/gui/CandleStickChart.css index f76ede7e910..1e4326cac67 100644 --- a/gui/src/main/java/io/bitsquare/gui/CandleStickChart.css +++ b/gui/src/main/java/io/bitsquare/gui/CandleStickChart.css @@ -80,10 +80,6 @@ -fx-background-insets: 0, 1, 2; } -.volume-bar.bg { - -demo-bar-fill: #70bfc6; -} - .volume-bar { -fx-effect: dropshadow(two-pass-box, rgba(0, 0, 0, 0.4), 10, 0.0, 2, 4); } diff --git a/gui/src/main/java/io/bitsquare/gui/Navigation.java b/gui/src/main/java/io/bitsquare/gui/Navigation.java index 7c259a6901e..a5bac398d97 100644 --- a/gui/src/main/java/io/bitsquare/gui/Navigation.java +++ b/gui/src/main/java/io/bitsquare/gui/Navigation.java @@ -23,7 +23,7 @@ import io.bitsquare.gui.common.view.View; import io.bitsquare.gui.common.view.ViewPath; import io.bitsquare.gui.main.MainView; -import io.bitsquare.gui.main.markets.MarketView; +import io.bitsquare.gui.main.market.MarketView; import io.bitsquare.storage.Storage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -101,7 +101,7 @@ public void navigateTo(ViewPath newPath) { currentPath = newPath; previousPath = currentPath; - storage.queueUpForSave(2000); + storage.queueUpForSave(1000); listeners.stream().forEach((e) -> e.onNavigationRequested(currentPath)); } diff --git a/gui/src/main/java/io/bitsquare/gui/SystemTray.java b/gui/src/main/java/io/bitsquare/gui/SystemTray.java index b21aaec4632..f64185351ef 100644 --- a/gui/src/main/java/io/bitsquare/gui/SystemTray.java +++ b/gui/src/main/java/io/bitsquare/gui/SystemTray.java @@ -20,6 +20,7 @@ import io.bitsquare.BitsquareException; import io.bitsquare.common.UserThread; import io.bitsquare.common.util.Utilities; +import io.bitsquare.gui.util.GUIUtil; import io.bitsquare.gui.util.ImageUtil; import javafx.application.Platform; import javafx.stage.Stage; @@ -123,7 +124,7 @@ else if (Utilities.isWindows()) aboutItem.addActionListener(e -> { try { - Utilities.openWebPage("https://bitsquare.io"); + GUIUtil.openWebPage("https://bitsquare.io"); } catch (Exception e1) { e1.printStackTrace(); } diff --git a/gui/src/main/java/io/bitsquare/gui/bitsquare.css b/gui/src/main/java/io/bitsquare/gui/bitsquare.css index 86a7c6833fb..cc2e766aa14 100644 --- a/gui/src/main/java/io/bitsquare/gui/bitsquare.css +++ b/gui/src/main/java/io/bitsquare/gui/bitsquare.css @@ -3,8 +3,8 @@ Theme colors: logo colors: -new blue: 0f87c3 -new grey: 666666 +Bitsquare blue: 0f86c3 +Bitsquare grey: 666666 00abff orange web page quotes : ff7f00 diff --git a/gui/src/main/java/io/bitsquare/gui/components/TxIdTextField.java b/gui/src/main/java/io/bitsquare/gui/components/TxIdTextField.java index 965342bc041..85bfb560483 100644 --- a/gui/src/main/java/io/bitsquare/gui/components/TxIdTextField.java +++ b/gui/src/main/java/io/bitsquare/gui/components/TxIdTextField.java @@ -24,6 +24,7 @@ import io.bitsquare.common.util.Utilities; import io.bitsquare.gui.components.indicator.TxConfidenceIndicator; import io.bitsquare.gui.main.overlays.popups.Popup; +import io.bitsquare.gui.util.GUIUtil; import io.bitsquare.user.Preferences; import javafx.scene.control.Label; import javafx.scene.control.TextField; @@ -135,7 +136,7 @@ public void cleanup() { private void openBlockExplorer(String txID) { try { if (preferences != null) - Utilities.openWebPage(preferences.getBlockChainExplorer().txUrl + txID); + GUIUtil.openWebPage(preferences.getBlockChainExplorer().txUrl + txID); } catch (Exception e) { log.error(e.getMessage()); new Popup().warning("Opening browser failed. Please check your internet " + diff --git a/gui/src/main/java/io/bitsquare/gui/main/MainView.java b/gui/src/main/java/io/bitsquare/gui/main/MainView.java index 4f5f411bef0..b00c72f5738 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/MainView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/MainView.java @@ -24,20 +24,20 @@ import io.bitsquare.common.UserThread; import io.bitsquare.common.util.Tuple2; import io.bitsquare.common.util.Tuple3; -import io.bitsquare.common.util.Utilities; import io.bitsquare.gui.Navigation; import io.bitsquare.gui.common.view.*; import io.bitsquare.gui.components.BusyAnimation; import io.bitsquare.gui.main.account.AccountView; import io.bitsquare.gui.main.disputes.DisputesView; import io.bitsquare.gui.main.funds.FundsView; -import io.bitsquare.gui.main.markets.MarketView; +import io.bitsquare.gui.main.market.MarketView; import io.bitsquare.gui.main.offer.BuyOfferView; import io.bitsquare.gui.main.offer.SellOfferView; import io.bitsquare.gui.main.overlays.Overlay; import io.bitsquare.gui.main.overlays.popups.Popup; import io.bitsquare.gui.main.portfolio.PortfolioView; import io.bitsquare.gui.main.settings.SettingsView; +import io.bitsquare.gui.util.GUIUtil; import io.bitsquare.gui.util.Transitions; import javafx.beans.value.ChangeListener; import javafx.geometry.Insets; @@ -227,19 +227,24 @@ protected void initialize() { navigation.navigateToPreviousVisitedView(); if (!persistedFilesCorrupted.isEmpty()) { - // show warning that some files has been corrupted - new Popup().warning("We detected incompatible data base files!\n\n" + - "Those database file(s) are not compatible with our current code base:" + - "\n" + persistedFilesCorrupted.toString() + - "\n\nWe made a backup of the corrupted file(s) and applied the default values to a new " + - "database version." + - "\n\nThe backup is located at:\n[you local app data directory]/db/backup_of_corrupted_data.\n\n" + - "Please check if you have the latest version of Bitsquare installed.\n" + - "You can download it at:\nhttps://github.com/bitsquare/bitsquare/releases\n\n" + - "Please restart the application.") - .closeButtonText("Shut down") - .onClose(BitsquareApp.shutDownHandler::run) - .show(); + if (persistedFilesCorrupted.size() > 1 || !persistedFilesCorrupted.get(0).equals("Navigation")) { + // show warning that some files has been corrupted + new Popup().warning("We detected incompatible data base files!\n\n" + + "Those database file(s) are not compatible with our current code base:" + + "\n" + persistedFilesCorrupted.toString() + + "\n\nWe made a backup of the corrupted file(s) and applied the default values to a new " + + "database version." + + "\n\nThe backup is located at:\n[you local app data directory]/db/backup_of_corrupted_data.\n\n" + + "Please check if you have the latest version of Bitsquare installed.\n" + + "You can download it at:\nhttps://github.com/bitsquare/bitsquare/releases\n\n" + + "Please restart the application.") + .closeButtonText("Shut down") + .onClose(BitsquareApp.shutDownHandler::run) + .show(); + } else { + log.debug("We detected incompatible data base file for Navigation. That is a minor issue happening with refactoring of UI classes " + + "and we don't display a warning popup to the user."); + } } transitions.fadeOutAndRemove(splashScreen, 1500, actionEvent -> disposeSplashScreen()); @@ -320,7 +325,7 @@ private Tuple3, Label, VBox> getMarketPriceBox(S btcAverageIconButton.setFocusTraversable(false); btcAverageIconButton.setStyle("-fx-background-color: transparent;"); HBox.setMargin(btcAverageIconButton, new Insets(0, 27, 0, 0)); - btcAverageIconButton.setOnAction(e -> Utilities.openWebPage("https://bitcoinaverage.com")); + btcAverageIconButton.setOnAction(e -> GUIUtil.openWebPage("https://bitcoinaverage.com")); btcAverageIconButton.visibleProperty().bind(model.isFiatCurrencyPriceFeedSelected); btcAverageIconButton.managedProperty().bind(model.isFiatCurrencyPriceFeedSelected); btcAverageIconButton.setTooltip(new Tooltip("Market price is provided by https://bitcoinaverage.com")); @@ -332,7 +337,7 @@ private Tuple3, Label, VBox> getMarketPriceBox(S poloniexIconButton.setFocusTraversable(false); poloniexIconButton.setStyle("-fx-background-color: transparent;"); HBox.setMargin(poloniexIconButton, new Insets(1, 27, 0, 0)); - poloniexIconButton.setOnAction(e -> Utilities.openWebPage("https://poloniex.com")); + poloniexIconButton.setOnAction(e -> GUIUtil.openWebPage("https://poloniex.com")); poloniexIconButton.visibleProperty().bind(model.isCryptoCurrencyPriceFeedSelected); poloniexIconButton.managedProperty().bind(model.isCryptoCurrencyPriceFeedSelected); poloniexIconButton.setTooltip(new Tooltip("Market price is provided by https://poloniex.com")); diff --git a/gui/src/main/java/io/bitsquare/gui/main/MainViewModel.java b/gui/src/main/java/io/bitsquare/gui/main/MainViewModel.java index b2c72f368ea..779cf4a85e8 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/MainViewModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/MainViewModel.java @@ -39,7 +39,6 @@ import io.bitsquare.common.Timer; import io.bitsquare.common.UserThread; import io.bitsquare.common.crypto.*; -import io.bitsquare.common.util.Utilities; import io.bitsquare.filter.FilterManager; import io.bitsquare.gui.Navigation; import io.bitsquare.gui.common.model.ViewModel; @@ -53,6 +52,7 @@ import io.bitsquare.gui.main.overlays.windows.TacWindow; import io.bitsquare.gui.main.overlays.windows.WalletPasswordWindow; import io.bitsquare.gui.util.BSFormatter; +import io.bitsquare.gui.util.GUIUtil; import io.bitsquare.locale.CurrencyUtil; import io.bitsquare.locale.TradeCurrency; import io.bitsquare.p2p.P2PService; @@ -322,8 +322,8 @@ public void onDisconnect(CloseConnectionReason closeConnectionReason, Connection // Other disconnects might be caused by peers running an older version if (connection.getPeerType() == Connection.PeerType.SEED_NODE && closeConnectionReason == CloseConnectionReason.RULE_VIOLATION) { - log.warn("onDisconnect closeConnectionReason=" + closeConnectionReason); - log.warn("onDisconnect connection=" + connection); + log.warn("RULE_VIOLATION onDisconnect closeConnectionReason=" + closeConnectionReason); + log.warn("RULE_VIOLATION onDisconnect connection=" + connection); //TODO /* new Popup() .warning("You got disconnected from a seed node.\n\n" + @@ -590,7 +590,7 @@ public void run() { .actionButtonText("Shut down") .onAction(BitsquareApp.shutDownHandler::run) .closeButtonText("Report bug at Github issues") - .onClose(() -> Utilities.openWebPage("https://github.com/bitsquare/bitsquare/issues")) + .onClose(() -> GUIUtil.openWebPage("https://github.com/bitsquare/bitsquare/issues")) .show()); } } @@ -602,7 +602,7 @@ public void run() { .actionButtonText("Shut down") .onAction(BitsquareApp.shutDownHandler::run) .closeButtonText("Report bug at Github issues") - .onClose(() -> Utilities.openWebPage("https://github.com/bitsquare/bitsquare/issues")) + .onClose(() -> GUIUtil.openWebPage("https://github.com/bitsquare/bitsquare/issues")) .show(); } } @@ -846,6 +846,8 @@ public void setPriceFeedComboBoxItem(PriceFeedComboBoxItem item) { else findPriceFeedComboBoxItem(preferences.getPreferredTradeCurrency().getCode()) .ifPresent(item2 -> selectedPriceFeedComboBoxItemProperty.set(item2)); + + priceFeedService.setCurrencyCode(item.currencyCode); } else if (item != null) { selectedPriceFeedComboBoxItemProperty.set(item); priceFeedService.setCurrencyCode(item.currencyCode); diff --git a/gui/src/main/java/io/bitsquare/gui/main/account/content/altcoinaccounts/AltCoinAccountsView.java b/gui/src/main/java/io/bitsquare/gui/main/account/content/altcoinaccounts/AltCoinAccountsView.java index 5c9e8eb840b..e9a9d87cccf 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/account/content/altcoinaccounts/AltCoinAccountsView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/account/content/altcoinaccounts/AltCoinAccountsView.java @@ -20,17 +20,13 @@ import io.bitsquare.common.UserThread; import io.bitsquare.common.util.Tuple2; import io.bitsquare.common.util.Tuple3; -import io.bitsquare.common.util.Utilities; import io.bitsquare.gui.common.view.ActivatableViewAndModel; import io.bitsquare.gui.common.view.FxmlView; import io.bitsquare.gui.components.TitledGroupBg; import io.bitsquare.gui.components.paymentmethods.CryptoCurrencyForm; import io.bitsquare.gui.components.paymentmethods.PaymentMethodForm; import io.bitsquare.gui.main.overlays.popups.Popup; -import io.bitsquare.gui.util.BSFormatter; -import io.bitsquare.gui.util.FormBuilder; -import io.bitsquare.gui.util.ImageUtil; -import io.bitsquare.gui.util.Layout; +import io.bitsquare.gui.util.*; import io.bitsquare.gui.util.validation.*; import io.bitsquare.locale.CryptoCurrency; import io.bitsquare.locale.TradeCurrency; @@ -173,7 +169,7 @@ private void onSaveNewAccount(PaymentAccount paymentAccount) { new Popup().information("The EHT/ETC fork situation carries considerable risks.\n" + "Be sure you fully understand the situation and check out the information on the \"Ethereum Classic\" and \"Ethereum\" project web pages.") .closeButtonText("I understand") - .onAction(() -> Utilities.openWebPage("https://ethereumclassic.github.io/")) + .onAction(() -> GUIUtil.openWebPage("https://ethereumclassic.github.io/")) .actionButtonText("Open Ethereum Classic web page") .show(); } diff --git a/gui/src/main/java/io/bitsquare/gui/main/account/content/seedwords/SeedWordsView.java b/gui/src/main/java/io/bitsquare/gui/main/account/content/seedwords/SeedWordsView.java index 709bc697a31..ee3941488d4 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/account/content/seedwords/SeedWordsView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/account/content/seedwords/SeedWordsView.java @@ -263,7 +263,6 @@ private void checkIfEncrypted() { } private void doRestore() { - log.info("Attempting wallet restore using seed '{}' from date {}", restoreSeedWordsTextArea.getText(), restoreDatePicker.getValue()); long date = restoreDatePicker.getValue().atStartOfDay().toEpochSecond(ZoneOffset.UTC); DeterministicSeed seed = new DeterministicSeed(Splitter.on(" ").splitToList(restoreSeedWordsTextArea.getText()), null, "", date); walletService.restoreSeedWords(seed, diff --git a/gui/src/main/java/io/bitsquare/gui/main/funds/deposit/DepositView.java b/gui/src/main/java/io/bitsquare/gui/main/funds/deposit/DepositView.java index 64f5559cdac..4831e889753 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/funds/deposit/DepositView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/funds/deposit/DepositView.java @@ -25,7 +25,6 @@ import io.bitsquare.btc.listeners.BalanceListener; import io.bitsquare.common.UserThread; import io.bitsquare.common.util.Tuple2; -import io.bitsquare.common.util.Utilities; import io.bitsquare.gui.common.view.ActivatableView; import io.bitsquare.gui.common.view.FxmlView; import io.bitsquare.gui.components.AddressTextField; @@ -278,7 +277,7 @@ private void updateQRCode() { private void openBlockExplorer(DepositListItem item) { if (item.getAddressString() != null) { try { - Utilities.openWebPage(preferences.getBlockChainExplorer().addressUrl + item.getAddressString()); + GUIUtil.openWebPage(preferences.getBlockChainExplorer().addressUrl + item.getAddressString()); } catch (Exception e) { log.error(e.getMessage()); new Popup().warning("Opening browser failed. Please check your internet " + diff --git a/gui/src/main/java/io/bitsquare/gui/main/funds/locked/LockedView.java b/gui/src/main/java/io/bitsquare/gui/main/funds/locked/LockedView.java index 40cf9feb19b..9dc04182c30 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/funds/locked/LockedView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/funds/locked/LockedView.java @@ -21,7 +21,6 @@ import io.bitsquare.btc.AddressEntry; import io.bitsquare.btc.WalletService; import io.bitsquare.btc.listeners.BalanceListener; -import io.bitsquare.common.util.Utilities; import io.bitsquare.gui.common.view.ActivatableView; import io.bitsquare.gui.common.view.FxmlView; import io.bitsquare.gui.components.HyperlinkWithIcon; @@ -29,6 +28,7 @@ import io.bitsquare.gui.main.overlays.windows.OfferDetailsWindow; import io.bitsquare.gui.main.overlays.windows.TradeDetailsWindow; import io.bitsquare.gui.util.BSFormatter; +import io.bitsquare.gui.util.GUIUtil; import io.bitsquare.trade.Tradable; import io.bitsquare.trade.Trade; import io.bitsquare.trade.TradeManager; @@ -157,7 +157,7 @@ private void updateList() { private void openBlockExplorer(LockedListItem item) { try { - Utilities.openWebPage(preferences.getBlockChainExplorer().addressUrl + item.getAddressString()); + GUIUtil.openWebPage(preferences.getBlockChainExplorer().addressUrl + item.getAddressString()); } catch (Exception e) { log.error(e.getMessage()); new Popup().warning("Opening browser failed. Please check your internet " + diff --git a/gui/src/main/java/io/bitsquare/gui/main/funds/reserved/ReservedView.java b/gui/src/main/java/io/bitsquare/gui/main/funds/reserved/ReservedView.java index 1b33f6e0bf9..a672be03d6b 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/funds/reserved/ReservedView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/funds/reserved/ReservedView.java @@ -21,7 +21,6 @@ import io.bitsquare.btc.AddressEntry; import io.bitsquare.btc.WalletService; import io.bitsquare.btc.listeners.BalanceListener; -import io.bitsquare.common.util.Utilities; import io.bitsquare.gui.common.view.ActivatableView; import io.bitsquare.gui.common.view.FxmlView; import io.bitsquare.gui.components.HyperlinkWithIcon; @@ -29,6 +28,7 @@ import io.bitsquare.gui.main.overlays.windows.OfferDetailsWindow; import io.bitsquare.gui.main.overlays.windows.TradeDetailsWindow; import io.bitsquare.gui.util.BSFormatter; +import io.bitsquare.gui.util.GUIUtil; import io.bitsquare.trade.Tradable; import io.bitsquare.trade.Trade; import io.bitsquare.trade.TradeManager; @@ -157,7 +157,7 @@ private void updateList() { private void openBlockExplorer(ReservedListItem item) { try { - Utilities.openWebPage(preferences.getBlockChainExplorer().addressUrl + item.getAddressString()); + GUIUtil.openWebPage(preferences.getBlockChainExplorer().addressUrl + item.getAddressString()); } catch (Exception e) { log.error(e.getMessage()); new Popup().warning("Opening browser failed. Please check your internet " + diff --git a/gui/src/main/java/io/bitsquare/gui/main/funds/transactions/TransactionsView.java b/gui/src/main/java/io/bitsquare/gui/main/funds/transactions/TransactionsView.java index c0ff653794a..61108738b5e 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/funds/transactions/TransactionsView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/funds/transactions/TransactionsView.java @@ -294,7 +294,7 @@ else if (tradable instanceof Trade) { private void openTxInBlockExplorer(TransactionsListItem item) { if (item.getTxId() != null) { try { - Utilities.openWebPage(preferences.getBlockChainExplorer().txUrl + item.getTxId()); + GUIUtil.openWebPage(preferences.getBlockChainExplorer().txUrl + item.getTxId()); } catch (Exception e) { log.error(e.getMessage()); new Popup().warning("Opening browser failed. Please check your internet " + @@ -306,7 +306,7 @@ private void openTxInBlockExplorer(TransactionsListItem item) { private void openAddressInBlockExplorer(TransactionsListItem item) { if (item.getAddressString() != null) { try { - Utilities.openWebPage(preferences.getBlockChainExplorer().addressUrl + item.getAddressString()); + GUIUtil.openWebPage(preferences.getBlockChainExplorer().addressUrl + item.getAddressString()); } catch (Exception e) { log.error(e.getMessage()); new Popup().warning("Opening browser failed. Please check your internet " + diff --git a/gui/src/main/java/io/bitsquare/gui/main/funds/withdrawal/WithdrawalView.java b/gui/src/main/java/io/bitsquare/gui/main/funds/withdrawal/WithdrawalView.java index 6d95d996042..ee02ab75604 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/funds/withdrawal/WithdrawalView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/funds/withdrawal/WithdrawalView.java @@ -25,13 +25,13 @@ import io.bitsquare.btc.WalletService; import io.bitsquare.btc.listeners.BalanceListener; import io.bitsquare.common.UserThread; -import io.bitsquare.common.util.Utilities; import io.bitsquare.gui.common.view.ActivatableView; import io.bitsquare.gui.common.view.FxmlView; import io.bitsquare.gui.components.HyperlinkWithIcon; import io.bitsquare.gui.main.overlays.popups.Popup; import io.bitsquare.gui.main.overlays.windows.WalletPasswordWindow; import io.bitsquare.gui.util.BSFormatter; +import io.bitsquare.gui.util.GUIUtil; import io.bitsquare.gui.util.validation.BtcAddressValidator; import io.bitsquare.trade.Tradable; import io.bitsquare.trade.Trade; @@ -185,7 +185,7 @@ public void onWithdraw() { @Override public void onSuccess(@javax.annotation.Nullable Transaction transaction) { if (transaction != null) { - log.info("onWithdraw onSuccess tx ID:" + transaction.getHashAsString()); + log.debug("onWithdraw onSuccess tx ID:" + transaction.getHashAsString()); } else { log.error("onWithdraw transaction is null"); } @@ -287,7 +287,7 @@ private void selectForWithdrawal(WithdrawalListItem item, boolean isSelected) { private void openBlockExplorer(WithdrawalListItem item) { if (item.getAddressString() != null) { try { - Utilities.openWebPage(preferences.getBlockChainExplorer().addressUrl + item.getAddressString()); + GUIUtil.openWebPage(preferences.getBlockChainExplorer().addressUrl + item.getAddressString()); } catch (Exception e) { log.error(e.getMessage()); new Popup().warning("Opening browser failed. Please check your internet " + diff --git a/gui/src/main/java/io/bitsquare/gui/main/help/Help.java b/gui/src/main/java/io/bitsquare/gui/main/help/Help.java index e2ebe6f967f..c69f8d3e969 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/help/Help.java +++ b/gui/src/main/java/io/bitsquare/gui/main/help/Help.java @@ -17,8 +17,8 @@ package io.bitsquare.gui.main.help; -import io.bitsquare.common.util.Utilities; import io.bitsquare.gui.main.overlays.popups.Popup; +import io.bitsquare.gui.util.GUIUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,7 +34,7 @@ public class Help { public static void openWindow(HelpId id) { try { // TODO create user guide - Utilities.openWebPage("http://bitsquare.io/faq"); + GUIUtil.openWebPage("http://bitsquare.io/faq"); // Utilities.openWebPage("https://github.com/bitsquare/bitsquare/wiki/User-Guide"); } catch (Exception e) { log.error(e.getMessage()); diff --git a/gui/src/main/java/io/bitsquare/gui/main/markets/MarketView.fxml b/gui/src/main/java/io/bitsquare/gui/main/market/MarketView.fxml similarity index 98% rename from gui/src/main/java/io/bitsquare/gui/main/markets/MarketView.fxml rename to gui/src/main/java/io/bitsquare/gui/main/market/MarketView.fxml index bc67988576f..f9dce730974 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/markets/MarketView.fxml +++ b/gui/src/main/java/io/bitsquare/gui/main/market/MarketView.fxml @@ -20,7 +20,7 @@ - diff --git a/gui/src/main/java/io/bitsquare/gui/main/markets/MarketView.java b/gui/src/main/java/io/bitsquare/gui/main/market/MarketView.java similarity index 86% rename from gui/src/main/java/io/bitsquare/gui/main/markets/MarketView.java rename to gui/src/main/java/io/bitsquare/gui/main/market/MarketView.java index 632b41767e9..e31ecb0bf3f 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/markets/MarketView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/market/MarketView.java @@ -15,15 +15,15 @@ * along with Bitsquare. If not, see . */ -package io.bitsquare.gui.main.markets; +package io.bitsquare.gui.main.market; import io.bitsquare.gui.Navigation; import io.bitsquare.gui.common.model.Activatable; import io.bitsquare.gui.common.view.*; import io.bitsquare.gui.main.MainView; -import io.bitsquare.gui.main.markets.charts.MarketsChartsView; -import io.bitsquare.gui.main.markets.statistics.MarketsStatisticsView; -import io.bitsquare.gui.main.markets.trades.TradesChartsView; +import io.bitsquare.gui.main.market.offerbook.OfferBookChartView; +import io.bitsquare.gui.main.market.spread.SpreadView; +import io.bitsquare.gui.main.market.trades.TradesChartsView; import javafx.beans.value.ChangeListener; import javafx.fxml.FXML; import javafx.scene.control.Tab; @@ -55,11 +55,11 @@ public void initialize() { tabChangeListener = (ov, oldValue, newValue) -> { if (newValue == chartsTab) - navigation.navigateTo(MainView.class, MarketView.class, MarketsChartsView.class); + navigation.navigateTo(MainView.class, MarketView.class, OfferBookChartView.class); else if (newValue == tradesTab) navigation.navigateTo(MainView.class, MarketView.class, TradesChartsView.class); else if (newValue == statisticsTab) - navigation.navigateTo(MainView.class, MarketView.class, MarketsStatisticsView.class); + navigation.navigateTo(MainView.class, MarketView.class, SpreadView.class); }; } @@ -69,11 +69,11 @@ protected void activate() { navigation.addListener(navigationListener); if (root.getSelectionModel().getSelectedItem() == chartsTab) - navigation.navigateTo(MainView.class, MarketView.class, MarketsChartsView.class); + navigation.navigateTo(MainView.class, MarketView.class, OfferBookChartView.class); else if (root.getSelectionModel().getSelectedItem() == tradesTab) navigation.navigateTo(MainView.class, MarketView.class, TradesChartsView.class); else - navigation.navigateTo(MainView.class, MarketView.class, MarketsStatisticsView.class); + navigation.navigateTo(MainView.class, MarketView.class, SpreadView.class); } @Override @@ -86,9 +86,9 @@ private void loadView(Class viewClass) { final Tab tab; View view = viewLoader.load(viewClass); - if (view instanceof MarketsChartsView) tab = chartsTab; + if (view instanceof OfferBookChartView) tab = chartsTab; else if (view instanceof TradesChartsView) tab = tradesTab; - else if (view instanceof MarketsStatisticsView) tab = statisticsTab; + else if (view instanceof SpreadView) tab = statisticsTab; else throw new IllegalArgumentException("Navigation to " + viewClass + " is not supported"); tab.setContent(view.getRoot()); diff --git a/gui/src/main/java/io/bitsquare/gui/main/market/offerbook/OfferBookChartView.fxml b/gui/src/main/java/io/bitsquare/gui/main/market/offerbook/OfferBookChartView.fxml new file mode 100644 index 00000000000..8e3ad701dc5 --- /dev/null +++ b/gui/src/main/java/io/bitsquare/gui/main/market/offerbook/OfferBookChartView.fxml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/gui/src/main/java/io/bitsquare/gui/main/markets/charts/MarketsChartsView.java b/gui/src/main/java/io/bitsquare/gui/main/market/offerbook/OfferBookChartView.java similarity index 92% rename from gui/src/main/java/io/bitsquare/gui/main/markets/charts/MarketsChartsView.java rename to gui/src/main/java/io/bitsquare/gui/main/market/offerbook/OfferBookChartView.java index 607942bc5a6..d8295329388 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/markets/charts/MarketsChartsView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/market/offerbook/OfferBookChartView.java @@ -15,7 +15,7 @@ * along with Bitsquare. If not, see . */ -package io.bitsquare.gui.main.markets.charts; +package io.bitsquare.gui.main.market.offerbook; import io.bitsquare.common.UserThread; import io.bitsquare.common.util.Tuple3; @@ -27,7 +27,10 @@ import io.bitsquare.gui.main.offer.SellOfferView; import io.bitsquare.gui.main.offer.offerbook.OfferBookListItem; import io.bitsquare.gui.util.BSFormatter; -import io.bitsquare.locale.*; +import io.bitsquare.gui.util.GUIUtil; +import io.bitsquare.locale.BSResources; +import io.bitsquare.locale.CurrencyUtil; +import io.bitsquare.locale.TradeCurrency; import io.bitsquare.trade.offer.Offer; import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.beans.property.SimpleStringProperty; @@ -45,7 +48,6 @@ import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.util.Callback; -import javafx.util.StringConverter; import org.fxmisc.easybind.EasyBind; import org.fxmisc.easybind.Subscription; import org.slf4j.Logger; @@ -54,8 +56,8 @@ import javax.inject.Inject; @FxmlView -public class MarketsChartsView extends ActivatableViewAndModel { - private static final Logger log = LoggerFactory.getLogger(MarketsChartsView.class); +public class OfferBookChartView extends ActivatableViewAndModel { + private static final Logger log = LoggerFactory.getLogger(OfferBookChartView.class); private NumberAxis xAxis, yAxis; XYChart.Series seriesBuy, seriesSell; @@ -71,6 +73,8 @@ public class MarketsChartsView extends ActivatableViewAndModel selectedTabIndexListener; + private SingleSelectionModel tabPaneSelectionModel; /////////////////////////////////////////////////////////////////////////////////////////// @@ -78,7 +82,7 @@ public class MarketsChartsView extends ActivatableViewAndModel(); currencyComboBox.setPromptText("Select currency"); - currencyComboBox.setConverter(new StringConverter() { - @Override - public String toString(TradeCurrency tradeCurrency) { - // http://boschista.deviantart.com/journal/Cool-ASCII-Symbols-214218618 - if (tradeCurrency instanceof FiatCurrency) - return "★ " + tradeCurrency.getNameAndCode(); - else if (tradeCurrency instanceof CryptoCurrency) - return "✦ " + tradeCurrency.getNameAndCode(); - else - return "-"; - } - - @Override - public TradeCurrency fromString(String s) { - return null; - } - }); - + currencyComboBox.setConverter(GUIUtil.getCurrencyListConverter()); Label currencyLabel = new Label("Currency:"); HBox currencyHBox = new HBox(); @@ -135,8 +122,15 @@ public TradeCurrency fromString(String s) { @Override protected void activate() { + // root.getParent() is null at initialize + tabPaneSelectionModel = ((TabPane) root.getParent().getParent()).getSelectionModel(); + selectedTabIndexListener = (observable, oldValue, newValue) -> model.setSelectedTabIndex((int) newValue); + + model.setSelectedTabIndex(tabPaneSelectionModel.getSelectedIndex()); + tabPaneSelectionModel.selectedIndexProperty().addListener(selectedTabIndexListener); + currencyComboBox.setItems(model.getTradeCurrencies()); - currencyComboBox.getSelectionModel().select(model.getTradeCurrency()); + currencyComboBox.getSelectionModel().select(model.getSelectedTradeCurrencyProperty()); currencyComboBox.setVisibleRowCount(Math.min(currencyComboBox.getItems().size(), 25)); currencyComboBox.setOnAction(e -> { TradeCurrency tradeCurrency = currencyComboBox.getSelectionModel().getSelectedItem(); @@ -145,7 +139,7 @@ protected void activate() { }); model.getOfferBookListItems().addListener(changeListener); - tradeCurrencySubscriber = EasyBind.subscribe(model.tradeCurrency, + tradeCurrencySubscriber = EasyBind.subscribe(model.selectedTradeCurrencyProperty, tradeCurrency -> { String code = tradeCurrency.getCode(); String tradeCurrencyName = tradeCurrency.getName(); @@ -173,6 +167,7 @@ protected void activate() { @Override protected void deactivate() { model.getOfferBookListItems().removeListener(changeListener); + tabPaneSelectionModel.selectedIndexProperty().removeListener(selectedTabIndexListener); tradeCurrencySubscriber.unsubscribe(); currencyComboBox.setOnAction(null); } diff --git a/gui/src/main/java/io/bitsquare/gui/main/markets/charts/MarketsChartsViewModel.java b/gui/src/main/java/io/bitsquare/gui/main/market/offerbook/OfferBookChartViewModel.java similarity index 72% rename from gui/src/main/java/io/bitsquare/gui/main/markets/charts/MarketsChartsViewModel.java rename to gui/src/main/java/io/bitsquare/gui/main/market/offerbook/OfferBookChartViewModel.java index dcc07c7f4d7..93754a44e1c 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/markets/charts/MarketsChartsViewModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/market/offerbook/OfferBookChartViewModel.java @@ -15,14 +15,20 @@ * along with Bitsquare. If not, see . */ -package io.bitsquare.gui.main.markets.charts; +package io.bitsquare.gui.main.market.offerbook; import com.google.common.math.LongMath; import com.google.inject.Inject; import io.bitsquare.btc.pricefeed.PriceFeedService; +import io.bitsquare.gui.Navigation; import io.bitsquare.gui.common.model.ActivatableViewModel; +import io.bitsquare.gui.main.MainView; import io.bitsquare.gui.main.offer.offerbook.OfferBook; import io.bitsquare.gui.main.offer.offerbook.OfferBookListItem; +import io.bitsquare.gui.main.settings.SettingsView; +import io.bitsquare.gui.main.settings.preferences.PreferencesView; +import io.bitsquare.gui.util.GUIUtil; +import io.bitsquare.locale.CryptoCurrency; import io.bitsquare.locale.CurrencyUtil; import io.bitsquare.locale.TradeCurrency; import io.bitsquare.trade.offer.Offer; @@ -44,16 +50,17 @@ import java.util.Optional; import java.util.stream.Collectors; -class MarketsChartsViewModel extends ActivatableViewModel { - private static final Logger log = LoggerFactory.getLogger(MarketsChartsViewModel.class); +class OfferBookChartViewModel extends ActivatableViewModel { + private static final Logger log = LoggerFactory.getLogger(OfferBookChartViewModel.class); - final static String EDIT_FLAG = "EDIT_FLAG"; + private static final int TAB_INDEX = 0; private final OfferBook offerBook; private final Preferences preferences; final PriceFeedService priceFeedService; + private Navigation navigation; - final ObjectProperty tradeCurrency = new SimpleObjectProperty<>(); + final ObjectProperty selectedTradeCurrencyProperty = new SimpleObjectProperty<>(); private final List buyData = new ArrayList<>(); private final List sellData = new ArrayList<>(); private final ObservableList offerBookListItems; @@ -61,22 +68,25 @@ class MarketsChartsViewModel extends ActivatableViewModel { private final ObservableList top3BuyOfferList = FXCollections.observableArrayList(); private final ObservableList top3SellOfferList = FXCollections.observableArrayList(); private final ChangeListener currenciesUpdatedListener; + private int selectedTabIndex; + /////////////////////////////////////////////////////////////////////////////////////////// // Constructor, lifecycle /////////////////////////////////////////////////////////////////////////////////////////// @Inject - public MarketsChartsViewModel(OfferBook offerBook, Preferences preferences, PriceFeedService priceFeedService) { + public OfferBookChartViewModel(OfferBook offerBook, Preferences preferences, PriceFeedService priceFeedService, Navigation navigation) { this.offerBook = offerBook; this.preferences = preferences; this.priceFeedService = priceFeedService; + this.navigation = navigation; - Optional tradeCurrencyOptional = CurrencyUtil.getTradeCurrency(preferences.getMarketScreenCurrencyCode()); + Optional tradeCurrencyOptional = CurrencyUtil.getTradeCurrency(preferences.getOfferBookChartScreenCurrencyCode()); if (tradeCurrencyOptional.isPresent()) - tradeCurrency.set(tradeCurrencyOptional.get()); + selectedTradeCurrencyProperty.set(tradeCurrencyOptional.get()); else { - tradeCurrency.set(CurrencyUtil.getDefaultTradeCurrency()); + selectedTradeCurrencyProperty.set(CurrencyUtil.getDefaultTradeCurrency()); } offerBookListItems = offerBook.getOfferBookListItems(); @@ -87,7 +97,7 @@ public MarketsChartsViewModel(OfferBook offerBook, Preferences preferences, Pric list.addAll(c.getAddedSubList()); if (list.stream() .map(OfferBookListItem::getOffer) - .filter(e -> e.getCurrencyCode().equals(tradeCurrency.get().getCode())) + .filter(e -> e.getCurrencyCode().equals(selectedTradeCurrencyProperty.get().getCode())) .findAny() .isPresent()) updateChartData(); @@ -117,8 +127,7 @@ protected void activate() { if (isAnyPricePresent()) priceFeedService.currenciesUpdateFlagProperty().addListener(currenciesUpdatedListener); - if (!preferences.getUseStickyMarketPrice()) - priceFeedService.setCurrencyCode(tradeCurrency.get().getCode()); + syncPriceFeedCurrency(); } @Override @@ -126,6 +135,83 @@ protected void deactivate() { offerBookListItems.removeListener(listChangeListener); } + + /////////////////////////////////////////////////////////////////////////////////////////// + // UI actions + /////////////////////////////////////////////////////////////////////////////////////////// + + public void onSetTradeCurrency(TradeCurrency tradeCurrency) { + if (tradeCurrency != null) { + final String code = tradeCurrency.getCode(); + + if (isEditEntry(code)) { + navigation.navigateTo(MainView.class, SettingsView.class, PreferencesView.class); + } else { + selectedTradeCurrencyProperty.set(tradeCurrency); + preferences.setOfferBookChartScreenCurrencyCode(code); + + updateChartData(); + + if (!preferences.getUseStickyMarketPrice()) + priceFeedService.setCurrencyCode(code); + } + } + } + + void setSelectedTabIndex(int selectedTabIndex) { + this.selectedTabIndex = selectedTabIndex; + syncPriceFeedCurrency(); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Getters + /////////////////////////////////////////////////////////////////////////////////////////// + + public List getBuyData() { + return buyData; + } + + public List getSellData() { + return sellData; + } + + public String getCurrencyCode() { + return selectedTradeCurrencyProperty.get().getCode(); + } + + public ObservableList getOfferBookListItems() { + return offerBookListItems; + } + + public ObservableList getTop3BuyOfferList() { + return top3BuyOfferList; + } + + public ObservableList getTop3SellOfferList() { + return top3SellOfferList; + } + + public ObservableList getTradeCurrencies() { + final ObservableList list = FXCollections.observableArrayList(preferences.getTradeCurrenciesAsObservable()); + list.add(new CryptoCurrency(GUIUtil.EDIT_FLAG, GUIUtil.EDIT_FLAG)); + return list; + } + + public TradeCurrency getSelectedTradeCurrencyProperty() { + return selectedTradeCurrencyProperty.get(); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Private + /////////////////////////////////////////////////////////////////////////////////////////// + + private void syncPriceFeedCurrency() { + if (!preferences.getUseStickyMarketPrice() && selectedTabIndex == TAB_INDEX) + priceFeedService.setCurrencyCode(selectedTradeCurrencyProperty.get().getCode()); + } + private boolean isAnyPricePresent() { return offerBookListItems.stream().filter(item -> item.getOffer().getPrice() == null).findAny().isPresent(); } @@ -133,7 +219,7 @@ private boolean isAnyPricePresent() { private void updateChartData() { List allBuyOffers = offerBookListItems.stream() .map(OfferBookListItem::getOffer) - .filter(e -> e.getCurrencyCode().equals(tradeCurrency.get().getCode()) + .filter(e -> e.getCurrencyCode().equals(selectedTradeCurrencyProperty.get().getCode()) && e.getDirection().equals(Offer.Direction.BUY)) .sorted((o1, o2) -> { long a = o1.getPrice() != null ? o1.getPrice().value : 0; @@ -148,7 +234,7 @@ private void updateChartData() { List allSellOffers = offerBookListItems.stream() .map(OfferBookListItem::getOffer) - .filter(e -> e.getCurrencyCode().equals(tradeCurrency.get().getCode()) + .filter(e -> e.getCurrencyCode().equals(selectedTradeCurrencyProperty.get().getCode()) && e.getDirection().equals(Offer.Direction.SELL)) .sorted((o1, o2) -> { long a = o1.getPrice() != null ? o1.getPrice().value : 0; @@ -179,54 +265,7 @@ private void buildChartDataItems(List sortedList, Offer.Direction directi } } - - /////////////////////////////////////////////////////////////////////////////////////////// - // UI actions - /////////////////////////////////////////////////////////////////////////////////////////// - - public void onSetTradeCurrency(TradeCurrency tradeCurrency) { - this.tradeCurrency.set(tradeCurrency); - updateChartData(); - - if (!preferences.getUseStickyMarketPrice()) - priceFeedService.setCurrencyCode(tradeCurrency.getCode()); - - preferences.setMarketScreenCurrencyCode(tradeCurrency.getCode()); - } - - /////////////////////////////////////////////////////////////////////////////////////////// - // Getters - /////////////////////////////////////////////////////////////////////////////////////////// - - public List getBuyData() { - return buyData; - } - - public List getSellData() { - return sellData; - } - - public String getCurrencyCode() { - return tradeCurrency.get().getCode(); - } - - public ObservableList getOfferBookListItems() { - return offerBookListItems; - } - - public ObservableList getTop3BuyOfferList() { - return top3BuyOfferList; - } - - public ObservableList getTop3SellOfferList() { - return top3SellOfferList; - } - - public ObservableList getTradeCurrencies() { - return preferences.getTradeCurrenciesAsObservable(); - } - - public TradeCurrency getTradeCurrency() { - return tradeCurrency.get(); + private boolean isEditEntry(String id) { + return id.equals(GUIUtil.EDIT_FLAG); } } diff --git a/gui/src/main/java/io/bitsquare/gui/main/markets/statistics/MarketStatisticItem.java b/gui/src/main/java/io/bitsquare/gui/main/market/spread/SpreadItem.java similarity index 66% rename from gui/src/main/java/io/bitsquare/gui/main/markets/statistics/MarketStatisticItem.java rename to gui/src/main/java/io/bitsquare/gui/main/market/spread/SpreadItem.java index f11b364b506..8400262793e 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/markets/statistics/MarketStatisticItem.java +++ b/gui/src/main/java/io/bitsquare/gui/main/market/spread/SpreadItem.java @@ -1,4 +1,4 @@ -package io.bitsquare.gui.main.markets.statistics; +package io.bitsquare.gui.main.market.spread; import org.bitcoinj.core.Coin; import org.bitcoinj.utils.Fiat; @@ -7,8 +7,8 @@ import javax.annotation.Nullable; -public class MarketStatisticItem { - private static final Logger log = LoggerFactory.getLogger(MarketStatisticItem.class); +public class SpreadItem { + private static final Logger log = LoggerFactory.getLogger(SpreadItem.class); public final String currencyCode; public final int numberOfBuyOffers; public final int numberOfSellOffers; @@ -17,7 +17,7 @@ public class MarketStatisticItem { public final Fiat spread; public final Coin totalAmount; - public MarketStatisticItem(String currencyCode, int numberOfBuyOffers, int numberOfSellOffers, int numberOfOffers, @Nullable Fiat spread, Coin totalAmount) { + public SpreadItem(String currencyCode, int numberOfBuyOffers, int numberOfSellOffers, int numberOfOffers, @Nullable Fiat spread, Coin totalAmount) { this.currencyCode = currencyCode; this.numberOfBuyOffers = numberOfBuyOffers; this.numberOfSellOffers = numberOfSellOffers; diff --git a/gui/src/main/java/io/bitsquare/gui/main/markets/statistics/MarketsStatisticsView.fxml b/gui/src/main/java/io/bitsquare/gui/main/market/spread/SpreadView.fxml similarity index 96% rename from gui/src/main/java/io/bitsquare/gui/main/markets/statistics/MarketsStatisticsView.fxml rename to gui/src/main/java/io/bitsquare/gui/main/market/spread/SpreadView.fxml index 6ffc5e339ad..dc0cd2e8201 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/markets/statistics/MarketsStatisticsView.fxml +++ b/gui/src/main/java/io/bitsquare/gui/main/market/spread/SpreadView.fxml @@ -20,7 +20,7 @@ -. */ -package io.bitsquare.gui.main.markets.statistics; +package io.bitsquare.gui.main.market.spread; import io.bitsquare.gui.common.view.ActivatableViewAndModel; import io.bitsquare.gui.common.view.FxmlView; @@ -38,13 +38,13 @@ import javax.inject.Inject; @FxmlView -public class MarketsStatisticsView extends ActivatableViewAndModel { +public class SpreadView extends ActivatableViewAndModel { private final BSFormatter formatter; private final int gridRow = 0; - private TableView tableView; - private SortedList sortedList; - private ListChangeListener itemListChangeListener; - private TableColumn totalAmountColumn, numberOfOffersColumn, numberOfBuyOffersColumn, numberOfSellOffersColumn; + private TableView tableView; + private SortedList sortedList; + private ListChangeListener itemListChangeListener; + private TableColumn totalAmountColumn, numberOfOffersColumn, numberOfBuyOffersColumn, numberOfSellOffersColumn; /////////////////////////////////////////////////////////////////////////////////////////// @@ -52,7 +52,7 @@ public class MarketsStatisticsView extends ActivatableViewAndModel currencyColumn = getCurrencyColumn(); + TableColumn currencyColumn = getCurrencyColumn(); tableView.getColumns().add(currencyColumn); numberOfOffersColumn = getNumberOfOffersColumn(); tableView.getColumns().add(numberOfOffersColumn); @@ -84,7 +84,7 @@ public void initialize() { tableView.getColumns().add(numberOfSellOffersColumn); totalAmountColumn = getTotalAmountColumn(); tableView.getColumns().add(totalAmountColumn); - TableColumn spreadColumn = getSpreadColumn(); + TableColumn spreadColumn = getSpreadColumn(); tableView.getColumns().add(spreadColumn); tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); @@ -102,7 +102,7 @@ public void initialize() { @Override protected void activate() { - sortedList = new SortedList<>(model.marketStatisticItems); + sortedList = new SortedList<>(model.spreadItems); sortedList.comparatorProperty().bind(tableView.comparatorProperty()); tableView.setItems(sortedList); sortedList.addListener(itemListChangeListener); @@ -127,22 +127,22 @@ private void updateHeaders() { // Columns /////////////////////////////////////////////////////////////////////////////////////////// - private TableColumn getCurrencyColumn() { - TableColumn column = new TableColumn("Currency") { + private TableColumn getCurrencyColumn() { + TableColumn column = new TableColumn("Currency") { { setMinWidth(100); } }; column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue())); column.setCellFactory( - new Callback, TableCell>() { + new Callback, TableCell>() { @Override - public TableCell call( - TableColumn column) { - return new TableCell() { + public TableCell call( + TableColumn column) { + return new TableCell() { @Override - public void updateItem(final MarketStatisticItem item, boolean empty) { + public void updateItem(final SpreadItem item, boolean empty) { super.updateItem(item, empty); if (item != null && !empty) setText(CurrencyUtil.getNameByCode(item.currencyCode)); @@ -155,22 +155,22 @@ public void updateItem(final MarketStatisticItem item, boolean empty) { return column; } - private TableColumn getNumberOfOffersColumn() { - TableColumn column = new TableColumn("Total offers") { + private TableColumn getNumberOfOffersColumn() { + TableColumn column = new TableColumn("Total offers") { { setMinWidth(100); } }; column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue())); column.setCellFactory( - new Callback, TableCell>() { + new Callback, TableCell>() { @Override - public TableCell call( - TableColumn column) { - return new TableCell() { + public TableCell call( + TableColumn column) { + return new TableCell() { @Override - public void updateItem(final MarketStatisticItem item, boolean empty) { + public void updateItem(final SpreadItem item, boolean empty) { super.updateItem(item, empty); if (item != null && !empty) setText(String.valueOf(item.numberOfOffers)); @@ -183,22 +183,22 @@ public void updateItem(final MarketStatisticItem item, boolean empty) { return column; } - private TableColumn getNumberOfBuyOffersColumn() { - TableColumn column = new TableColumn("Buy offers") { + private TableColumn getNumberOfBuyOffersColumn() { + TableColumn column = new TableColumn("Buy offers") { { setMinWidth(100); } }; column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue())); column.setCellFactory( - new Callback, TableCell>() { + new Callback, TableCell>() { @Override - public TableCell call( - TableColumn column) { - return new TableCell() { + public TableCell call( + TableColumn column) { + return new TableCell() { @Override - public void updateItem(final MarketStatisticItem item, boolean empty) { + public void updateItem(final SpreadItem item, boolean empty) { super.updateItem(item, empty); if (item != null && !empty) setText(String.valueOf(item.numberOfBuyOffers)); @@ -211,22 +211,22 @@ public void updateItem(final MarketStatisticItem item, boolean empty) { return column; } - private TableColumn getNumberOfSellOffersColumn() { - TableColumn column = new TableColumn("Sell offers") { + private TableColumn getNumberOfSellOffersColumn() { + TableColumn column = new TableColumn("Sell offers") { { setMinWidth(100); } }; column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue())); column.setCellFactory( - new Callback, TableCell>() { + new Callback, TableCell>() { @Override - public TableCell call( - TableColumn column) { - return new TableCell() { + public TableCell call( + TableColumn column) { + return new TableCell() { @Override - public void updateItem(final MarketStatisticItem item, boolean empty) { + public void updateItem(final SpreadItem item, boolean empty) { super.updateItem(item, empty); if (item != null && !empty) setText(String.valueOf(item.numberOfSellOffers)); @@ -239,22 +239,22 @@ public void updateItem(final MarketStatisticItem item, boolean empty) { return column; } - private TableColumn getTotalAmountColumn() { - TableColumn column = new TableColumn("Total amount") { + private TableColumn getTotalAmountColumn() { + TableColumn column = new TableColumn("Total amount") { { setMinWidth(150); } }; column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue())); column.setCellFactory( - new Callback, TableCell>() { + new Callback, TableCell>() { @Override - public TableCell call( - TableColumn column) { - return new TableCell() { + public TableCell call( + TableColumn column) { + return new TableCell() { @Override - public void updateItem(final MarketStatisticItem item, boolean empty) { + public void updateItem(final SpreadItem item, boolean empty) { super.updateItem(item, empty); if (item != null && !empty) setText(formatter.formatCoin(item.totalAmount)); @@ -267,22 +267,22 @@ public void updateItem(final MarketStatisticItem item, boolean empty) { return column; } - private TableColumn getSpreadColumn() { - TableColumn column = new TableColumn("Spread") { + private TableColumn getSpreadColumn() { + TableColumn column = new TableColumn("Spread") { { setMinWidth(130); } }; column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue())); column.setCellFactory( - new Callback, TableCell>() { + new Callback, TableCell>() { @Override - public TableCell call( - TableColumn column) { - return new TableCell() { + public TableCell call( + TableColumn column) { + return new TableCell() { @Override - public void updateItem(final MarketStatisticItem item, boolean empty) { + public void updateItem(final SpreadItem item, boolean empty) { super.updateItem(item, empty); if (item != null && !empty) { if (item.spread != null) diff --git a/gui/src/main/java/io/bitsquare/gui/main/markets/statistics/MarketsStatisticViewModel.java b/gui/src/main/java/io/bitsquare/gui/main/market/spread/SpreadViewModel.java similarity index 90% rename from gui/src/main/java/io/bitsquare/gui/main/markets/statistics/MarketsStatisticViewModel.java rename to gui/src/main/java/io/bitsquare/gui/main/market/spread/SpreadViewModel.java index e965924e4fe..a3fbf20db0d 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/markets/statistics/MarketsStatisticViewModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/market/spread/SpreadViewModel.java @@ -15,7 +15,7 @@ * along with Bitsquare. If not, see . */ -package io.bitsquare.gui.main.markets.statistics; +package io.bitsquare.gui.main.market.spread; import com.google.inject.Inject; import io.bitsquare.gui.common.model.ActivatableViewModel; @@ -34,12 +34,12 @@ import java.util.Map; import java.util.stream.Collectors; -class MarketsStatisticViewModel extends ActivatableViewModel { +class SpreadViewModel extends ActivatableViewModel { private final OfferBook offerBook; private final ObservableList offerBookListItems; private final ListChangeListener listChangeListener; - final ObservableList marketStatisticItems = FXCollections.observableArrayList(); + final ObservableList spreadItems = FXCollections.observableArrayList(); /////////////////////////////////////////////////////////////////////////////////////////// @@ -47,7 +47,7 @@ class MarketsStatisticViewModel extends ActivatableViewModel { /////////////////////////////////////////////////////////////////////////////////////////// @Inject - public MarketsStatisticViewModel(OfferBook offerBook) { + public SpreadViewModel(OfferBook offerBook) { this.offerBook = offerBook; offerBookListItems = offerBook.getOfferBookListItems(); @@ -75,7 +75,7 @@ private void update(ObservableList offerBookListItems) { offersByCurrencyMap.put(currencyCode, new ArrayList<>()); offersByCurrencyMap.get(currencyCode).add(offer); } - marketStatisticItems.clear(); + spreadItems.clear(); for (String currencyCode : offersByCurrencyMap.keySet()) { List offers = offersByCurrencyMap.get(currencyCode); List buyOffers = offers @@ -109,7 +109,7 @@ private void update(ObservableList offerBookListItems) { spread = bestSellOfferPrice.subtract(bestBuyOfferPrice); Coin totalAmount = Coin.valueOf(offers.stream().mapToLong(offer -> offer.getAmount().getValue()).sum()); - marketStatisticItems.add(new MarketStatisticItem(currencyCode, buyOffers.size(), sellOffers.size(), offers.size(), spread, totalAmount)); + spreadItems.add(new SpreadItem(currencyCode, buyOffers.size(), sellOffers.size(), offers.size(), spread, totalAmount)); } } } diff --git a/gui/src/main/java/io/bitsquare/gui/main/markets/trades/TradesChartsView.fxml b/gui/src/main/java/io/bitsquare/gui/main/market/trades/TradesChartsView.fxml similarity index 92% rename from gui/src/main/java/io/bitsquare/gui/main/markets/trades/TradesChartsView.fxml rename to gui/src/main/java/io/bitsquare/gui/main/market/trades/TradesChartsView.fxml index 379a99420e5..3f79a8b902b 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/markets/trades/TradesChartsView.fxml +++ b/gui/src/main/java/io/bitsquare/gui/main/market/trades/TradesChartsView.fxml @@ -20,7 +20,7 @@ -. */ -package io.bitsquare.gui.main.markets.trades; +package io.bitsquare.gui.main.market.trades; import io.bitsquare.common.UserThread; import io.bitsquare.gui.common.view.ActivatableViewAndModel; import io.bitsquare.gui.common.view.FxmlView; -import io.bitsquare.gui.main.markets.trades.charts.price.CandleStickChart; -import io.bitsquare.gui.main.markets.trades.charts.volume.VolumeChart; +import io.bitsquare.gui.main.market.trades.charts.price.CandleStickChart; +import io.bitsquare.gui.main.market.trades.charts.volume.VolumeChart; import io.bitsquare.gui.util.BSFormatter; -import io.bitsquare.locale.CryptoCurrency; -import io.bitsquare.locale.FiatCurrency; +import io.bitsquare.gui.util.GUIUtil; import io.bitsquare.locale.TradeCurrency; import io.bitsquare.trade.statistics.TradeStatistics; import javafx.beans.property.ReadOnlyObjectWrapper; @@ -81,6 +80,11 @@ public class TradesChartsView extends ActivatableViewAndModel sortedList; private Label nrOfTradeStatisticsLabel; private ListChangeListener tradeStatisticsByCurrencyListener; + private TableColumn priceColumn; + private ChangeListener selectedTabIndexListener; + private SingleSelectionModel tabPaneSelectionModel; + private ChangeListener showAllTradeCurrenciesListener; + private TableColumn volumeColumn; /////////////////////////////////////////////////////////////////////////////////////////// @@ -122,12 +126,30 @@ public void initialize() { layoutChart(); }; tradeStatisticsByCurrencyListener = c -> nrOfTradeStatisticsLabel.setText("Nr. of trades: " + model.tradeStatisticsByCurrency.size()); + showAllTradeCurrenciesListener = (observable, oldValue, newValue) -> { + priceChart.setVisible(!newValue); + priceChart.setManaged(!newValue); + priceColumn.setSortable(!newValue); + priceColumnLabel.set("Price" + (newValue ? "" : (" (" + model.getCurrencyCode() + ")"))); + volumeColumn.setText("Volume" + (newValue ? "" : (" (" + model.getCurrencyCode() + ")"))); + }; } @Override protected void activate() { + // root.getParent() is null at initialize + tabPaneSelectionModel = ((TabPane) root.getParent().getParent()).getSelectionModel(); + selectedTabIndexListener = (observable, oldValue, newValue) -> model.setSelectedTabIndex((int) newValue); + model.setSelectedTabIndex(tabPaneSelectionModel.getSelectedIndex()); + tabPaneSelectionModel.selectedIndexProperty().addListener(selectedTabIndexListener); + currencyComboBox.setItems(model.getTradeCurrencies()); - currencyComboBox.getSelectionModel().select(model.getTradeCurrency()); + + if (model.showAllTradeCurrenciesProperty.get()) + currencyComboBox.getSelectionModel().select(0); + else + currencyComboBox.getSelectionModel().select(model.getSelectedTradeCurrency()); + currencyComboBox.setVisibleRowCount(Math.min(currencyComboBox.getItems().size(), 25)); currencyComboBox.setOnAction(e -> model.onSetTradeCurrency(currencyComboBox.getSelectionModel().getSelectedItem())); @@ -137,15 +159,22 @@ protected void activate() { toggleGroup.selectedToggleProperty().addListener(toggleChangeListener); priceAxisY.widthProperty().addListener(priceAxisYWidthListener); volumeAxisY.widthProperty().addListener(volumeAxisYWidthListener); + model.tradeStatisticsByCurrency.addListener(tradeStatisticsByCurrencyListener); + model.showAllTradeCurrenciesProperty.addListener(showAllTradeCurrenciesListener); - tradeCurrencySubscriber = EasyBind.subscribe(model.tradeCurrencyProperty, + priceAxisY.labelProperty().bind(priceColumnLabel); + priceColumn.textProperty().bind(priceColumnLabel); + + tradeCurrencySubscriber = EasyBind.subscribe(model.selectedTradeCurrencyProperty, tradeCurrency -> { String code = tradeCurrency.getCode(); String tradeCurrencyName = tradeCurrency.getName(); priceSeries.setName(tradeCurrencyName); final String currencyPair = formatter.getCurrencyPair(code); - priceColumnLabel.set("Price (" + currencyPair + ")"); + final boolean showAllTradeCurrencies = model.showAllTradeCurrenciesProperty.get(); + priceColumnLabel.set("Price" + (showAllTradeCurrencies ? "" : (" (" + currencyPair + ")"))); + volumeColumn.setText("Volume" + (showAllTradeCurrencies ? "" : (" (" + code + ")"))); }); sortedList = new SortedList<>(model.tradeStatisticsByCurrency); @@ -158,23 +187,30 @@ protected void activate() { priceAxisX.setTickLabelFormatter(getTimeAxisStringConverter()); volumeAxisX.setTickLabelFormatter(getTimeAxisStringConverter()); - model.tradeStatisticsByCurrency.addListener(tradeStatisticsByCurrencyListener); nrOfTradeStatisticsLabel.setText("Nr. of trades: " + model.tradeStatisticsByCurrency.size()); } @Override protected void deactivate() { + currencyComboBox.setOnAction(null); + + tabPaneSelectionModel.selectedIndexProperty().removeListener(selectedTabIndexListener); model.priceItems.removeListener(itemsChangeListener); toggleGroup.selectedToggleProperty().removeListener(toggleChangeListener); priceAxisY.widthProperty().removeListener(priceAxisYWidthListener); volumeAxisY.widthProperty().removeListener(volumeAxisYWidthListener); model.tradeStatisticsByCurrency.removeListener(tradeStatisticsByCurrencyListener); - tradeCurrencySubscriber.unsubscribe(); - currencyComboBox.setOnAction(null); + model.showAllTradeCurrenciesProperty.removeListener(showAllTradeCurrenciesListener); + priceAxisY.labelProperty().unbind(); + priceColumn.textProperty().unbind(); + + tradeCurrencySubscriber.unsubscribe(); + + sortedList.comparatorProperty().unbind(); + priceSeries.getData().clear(); priceChart.getData().clear(); - sortedList.comparatorProperty().unbind(); } @@ -194,7 +230,6 @@ private void createCharts() { priceAxisY = new NumberAxis(); priceAxisY.setForceZeroInRange(false); priceAxisY.setAutoRanging(true); - priceAxisY.labelProperty().bind(priceColumnLabel); priceAxisY.setTickLabelFormatter(new StringConverter() { @Override public String toString(Number object) { @@ -207,11 +242,7 @@ public Number fromString(String string) { } }); - priceChart = new CandleStickChart(priceAxisX, priceAxisY); - priceChart.setMinHeight(250); - priceChart.setLegendVisible(false); - priceChart.setData(FXCollections.observableArrayList(priceSeries)); - priceChart.setToolTipStringConverter(new StringConverter() { + priceChart = new CandleStickChart(priceAxisX, priceAxisY, new StringConverter() { @Override public String toString(Number object) { return formatter.formatFiatWithCode(Fiat.valueOf(model.getCurrencyCode(), (long) object)); @@ -222,6 +253,10 @@ public Number fromString(String string) { return null; } }); + priceChart.setMinHeight(250); + priceChart.setMaxHeight(300); + priceChart.setLegendVisible(false); + priceChart.setData(FXCollections.observableArrayList(priceSeries)); volumeSeries = new XYChart.Series<>(); @@ -248,14 +283,10 @@ public Number fromString(String string) { } }); - volumeChart = new VolumeChart(volumeAxisX, volumeAxisY); - volumeChart.setData(FXCollections.observableArrayList(volumeSeries)); - volumeChart.setMinHeight(140); - volumeChart.setLegendVisible(false); - volumeChart.setToolTipStringConverter(new StringConverter() { + volumeChart = new VolumeChart(volumeAxisX, volumeAxisY, new StringConverter() { @Override public String toString(Number object) { - return formatter.formatCoinWithCode(Coin.valueOf(new Double((double) object).longValue())); + return formatter.formatCoinWithCode(Coin.valueOf((long) object)); } @Override @@ -263,6 +294,10 @@ public Number fromString(String string) { return null; } }); + volumeChart.setData(FXCollections.observableArrayList(volumeSeries)); + volumeChart.setMinHeight(140); + volumeChart.setMaxHeight(200); + volumeChart.setLegendVisible(false); } private void updateChartData() { @@ -320,23 +355,7 @@ private HBox getToolBox() { currencyComboBox = new ComboBox<>(); currencyComboBox.setPromptText("Select currency"); - currencyComboBox.setConverter(new StringConverter() { - @Override - public String toString(TradeCurrency tradeCurrency) { - // http://boschista.deviantart.com/journal/Cool-ASCII-Symbols-214218618 - if (tradeCurrency instanceof FiatCurrency) - return "★ " + tradeCurrency.getNameAndCode(); - else if (tradeCurrency instanceof CryptoCurrency) - return "✦ " + tradeCurrency.getNameAndCode(); - else - return "-"; - } - - @Override - public TradeCurrency fromString(String s) { - return null; - } - }); + currencyComboBox.setConverter(GUIUtil.getCurrencyListConverter()); Pane spacer = new Pane(); HBox.setHgrow(spacer, Priority.ALWAYS); @@ -377,6 +396,7 @@ private ToggleButton getToggleButton(String label, TradesChartsViewModel.TickUni private void createTable() { tableView = new TableView<>(); tableView.setMinHeight(120); + VBox.setVgrow(tableView, Priority.ALWAYS); // date TableColumn dateColumn = new TableColumn<>("Date/Time"); @@ -427,9 +447,8 @@ public void updateItem(final TradeStatistics item, boolean empty) { tableView.getColumns().add(amountColumn); // price - TableColumn priceColumn = new TableColumn<>(); + priceColumn = new TableColumn<>(); priceColumn.setCellValueFactory((tradeStatistics) -> new ReadOnlyObjectWrapper<>(tradeStatistics.getValue())); - priceColumn.textProperty().bind(priceColumnLabel); priceColumn.setCellFactory( new Callback, TableCell>() { @@ -441,7 +460,9 @@ public TableCell call( public void updateItem(final TradeStatistics item, boolean empty) { super.updateItem(item, empty); if (item != null) - setText(formatter.formatFiat(item.getTradePrice())); + setText(model.showAllTradeCurrenciesProperty.get() ? + formatter.formatFiatWithCode(item.getTradePrice()) : + formatter.formatFiat(item.getTradePrice())); else setText(""); } @@ -452,9 +473,8 @@ public void updateItem(final TradeStatistics item, boolean empty) { tableView.getColumns().add(priceColumn); // volume - TableColumn volumeColumn = new TableColumn<>(); + volumeColumn = new TableColumn<>(); volumeColumn.setCellValueFactory((tradeStatistics) -> new ReadOnlyObjectWrapper<>(tradeStatistics.getValue())); - volumeColumn.setText("Volume (BTC)"); volumeColumn.setCellFactory( new Callback, TableCell>() { @@ -466,7 +486,9 @@ public TableCell call( public void updateItem(final TradeStatistics item, boolean empty) { super.updateItem(item, empty); if (item != null) - setText(formatter.formatFiatWithCode(item.getTradeVolume())); + setText(model.showAllTradeCurrenciesProperty.get() ? + formatter.formatFiatWithCode(item.getTradeVolume()) : + formatter.formatFiat(item.getTradeVolume())); else setText(""); } diff --git a/gui/src/main/java/io/bitsquare/gui/main/markets/trades/TradesChartsViewModel.java b/gui/src/main/java/io/bitsquare/gui/main/market/trades/TradesChartsViewModel.java similarity index 68% rename from gui/src/main/java/io/bitsquare/gui/main/markets/trades/TradesChartsViewModel.java rename to gui/src/main/java/io/bitsquare/gui/main/market/trades/TradesChartsViewModel.java index f9d16e2b201..a496deb04ca 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/markets/trades/TradesChartsViewModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/market/trades/TradesChartsViewModel.java @@ -15,19 +15,28 @@ * along with Bitsquare. If not, see . */ -package io.bitsquare.gui.main.markets.trades; +package io.bitsquare.gui.main.market.trades; import com.google.common.annotations.VisibleForTesting; import com.google.inject.Inject; import io.bitsquare.btc.pricefeed.PriceFeedService; +import io.bitsquare.gui.Navigation; import io.bitsquare.gui.common.model.ActivatableViewModel; -import io.bitsquare.gui.main.markets.trades.charts.CandleData; +import io.bitsquare.gui.main.MainView; +import io.bitsquare.gui.main.market.trades.charts.CandleData; +import io.bitsquare.gui.main.settings.SettingsView; +import io.bitsquare.gui.main.settings.preferences.PreferencesView; +import io.bitsquare.gui.util.BSFormatter; +import io.bitsquare.gui.util.GUIUtil; +import io.bitsquare.locale.CryptoCurrency; import io.bitsquare.locale.CurrencyUtil; import io.bitsquare.locale.TradeCurrency; import io.bitsquare.trade.statistics.TradeStatistics; import io.bitsquare.trade.statistics.TradeStatisticsManager; import io.bitsquare.user.Preferences; +import javafx.beans.property.BooleanProperty; import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; @@ -42,6 +51,8 @@ class TradesChartsViewModel extends ActivatableViewModel { private static final Logger log = LoggerFactory.getLogger(TradesChartsViewModel.class); + private static final int TAB_INDEX = 2; + /////////////////////////////////////////////////////////////////////////////////////////// // Enum @@ -59,9 +70,12 @@ public enum TickUnit { private final TradeStatisticsManager tradeStatisticsManager; final Preferences preferences; private PriceFeedService priceFeedService; + private Navigation navigation; + private BSFormatter formatter; private final SetChangeListener setChangeListener; - final ObjectProperty tradeCurrencyProperty = new SimpleObjectProperty<>(); + final ObjectProperty selectedTradeCurrencyProperty = new SimpleObjectProperty<>(); + final BooleanProperty showAllTradeCurrenciesProperty = new SimpleBooleanProperty(false); final ObservableList tradeStatisticsByCurrency = FXCollections.observableArrayList(); ObservableList> priceItems = FXCollections.observableArrayList(); @@ -69,6 +83,7 @@ public enum TickUnit { TickUnit tickUnit = TickUnit.MONTH; int maxTicks = 30; + private int selectedTabIndex; /////////////////////////////////////////////////////////////////////////////////////////// @@ -76,19 +91,20 @@ public enum TickUnit { /////////////////////////////////////////////////////////////////////////////////////////// @Inject - public TradesChartsViewModel(TradeStatisticsManager tradeStatisticsManager, Preferences preferences, PriceFeedService priceFeedService) { + public TradesChartsViewModel(TradeStatisticsManager tradeStatisticsManager, Preferences preferences, PriceFeedService priceFeedService, Navigation navigation, BSFormatter formatter) { this.tradeStatisticsManager = tradeStatisticsManager; this.preferences = preferences; this.priceFeedService = priceFeedService; + this.navigation = navigation; + this.formatter = formatter; setChangeListener = change -> updateChartData(); - Optional tradeCurrencyOptional = CurrencyUtil.getTradeCurrency(preferences.getTradeStatisticsScreenCurrencyCode()); + Optional tradeCurrencyOptional = CurrencyUtil.getTradeCurrency(preferences.getTradeChartsScreenCurrencyCode()); if (tradeCurrencyOptional.isPresent()) - tradeCurrencyProperty.set(tradeCurrencyOptional.get()); - else { - tradeCurrencyProperty.set(CurrencyUtil.getDefaultTradeCurrency()); - } + selectedTradeCurrencyProperty.set(tradeCurrencyOptional.get()); + else + selectedTradeCurrencyProperty.set(CurrencyUtil.getDefaultTradeCurrency()); tickUnit = TickUnit.values()[preferences.getTradeStatisticsTickUnitIndex()]; } @@ -105,9 +121,8 @@ public TradesChartsViewModel(TradeStatisticsManager tradeStatisticsManager, Pref protected void activate() { tradeStatisticsManager.getObservableTradeStatisticsSet().addListener(setChangeListener); updateChartData(); - - if (!preferences.getUseStickyMarketPrice()) - priceFeedService.setCurrencyCode(tradeCurrencyProperty.get().getCode()); + syncPriceFeedCurrency(); + setMarketPriceFeedCurrency(); } @Override @@ -120,37 +135,62 @@ protected void deactivate() { // UI actions /////////////////////////////////////////////////////////////////////////////////////////// - public void onSetTradeCurrency(TradeCurrency tradeCurrency) { - this.tradeCurrencyProperty.set(tradeCurrency); - preferences.setTradeStatisticsScreenCurrencyCode(tradeCurrency.getCode()); - updateChartData(); - - if (!preferences.getUseStickyMarketPrice()) - priceFeedService.setCurrencyCode(tradeCurrency.getCode()); + void onSetTradeCurrency(TradeCurrency tradeCurrency) { + if (tradeCurrency != null) { + final String code = tradeCurrency.getCode(); + if (isEditEntry(code)) { + navigation.navigateTo(MainView.class, SettingsView.class, PreferencesView.class); + } else { + boolean showAllEntry = isShowAllEntry(code); + showAllTradeCurrenciesProperty.set(showAllEntry); + if (!showAllEntry) { + selectedTradeCurrencyProperty.set(tradeCurrency); + preferences.setTradeChartsScreenCurrencyCode(code); + } + + updateChartData(); + + if (!preferences.getUseStickyMarketPrice()) { + if (showAllEntry) + priceFeedService.setCurrencyCode(CurrencyUtil.getDefaultTradeCurrency().getCode()); + else + priceFeedService.setCurrencyCode(code); + } + } + } } - public void setTickUnit(TickUnit tickUnit) { + void setTickUnit(TickUnit tickUnit) { this.tickUnit = tickUnit; preferences.setTradeStatisticsTickUnitIndex(tickUnit.ordinal()); updateChartData(); } + void setSelectedTabIndex(int selectedTabIndex) { + this.selectedTabIndex = selectedTabIndex; + syncPriceFeedCurrency(); + setMarketPriceFeedCurrency(); + } + /////////////////////////////////////////////////////////////////////////////////////////// // Getters /////////////////////////////////////////////////////////////////////////////////////////// public String getCurrencyCode() { - return tradeCurrencyProperty.get().getCode(); + return selectedTradeCurrencyProperty.get().getCode(); } public ObservableList getTradeCurrencies() { - return preferences.getTradeCurrenciesAsObservable(); + final ObservableList list = FXCollections.observableArrayList(preferences.getTradeCurrenciesAsObservable()); + list.add(0, new CryptoCurrency(GUIUtil.SHOW_ALL_FLAG, GUIUtil.SHOW_ALL_FLAG)); + list.add(new CryptoCurrency(GUIUtil.EDIT_FLAG, GUIUtil.EDIT_FLAG)); + return list; } - public TradeCurrency getTradeCurrency() { - return tradeCurrencyProperty.get(); + public TradeCurrency getSelectedTradeCurrency() { + return selectedTradeCurrencyProperty.get(); } @@ -158,10 +198,23 @@ public TradeCurrency getTradeCurrency() { // Private /////////////////////////////////////////////////////////////////////////////////////////// + private void setMarketPriceFeedCurrency() { + if (!preferences.getUseStickyMarketPrice() && selectedTabIndex == TAB_INDEX) { + if (showAllTradeCurrenciesProperty.get()) + priceFeedService.setCurrencyCode(CurrencyUtil.getDefaultTradeCurrency().getCode()); + else + priceFeedService.setCurrencyCode(getCurrencyCode()); + } + } + + private void syncPriceFeedCurrency() { + if (!preferences.getUseStickyMarketPrice() && selectedTabIndex == TAB_INDEX) + priceFeedService.setCurrencyCode(selectedTradeCurrencyProperty.get().getCode()); + } private void updateChartData() { tradeStatisticsByCurrency.setAll(tradeStatisticsManager.getObservableTradeStatisticsSet().stream() - .filter(e -> e.currency.equals(getCurrencyCode())) + .filter(e -> showAllTradeCurrenciesProperty.get() || e.currency.equals(getCurrencyCode())) .collect(Collectors.toList())); // Get all entries for the defined time interval @@ -183,6 +236,7 @@ private void updateChartData() { // create CandleData for defined time interval List candleDataList = itemsPerInterval.entrySet().stream() .map(entry -> getCandleData(entry.getKey(), entry.getValue())) + .filter(e -> e.tick >= 0) .collect(Collectors.toList()); candleDataList.sort((o1, o2) -> (o1.tick < o2.tick ? -1 : (o1.tick == o2.tick ? 0 : 1))); @@ -221,7 +275,12 @@ CandleData getCandleData(long tick, Set set) { close = list.get(list.size() - 1).tradePrice; } boolean isBullish = close > open; - return new CandleData(tick, open, close, high, low, averagePrice, accumulatedAmount, accumulatedVolume, isBullish); + final Date date = new Date(getTimeFromTickIndex(tick)); + String dateString = tickUnit.ordinal() > TickUnit.DAY.ordinal() ? + formatter.formatDateTime(date) : + formatter.formatDate(date); + return new CandleData(tick, open, close, high, low, averagePrice, accumulatedAmount, accumulatedVolume, + isBullish, dateString); } long getTickFromTime(long tradeDateAsTime, TickUnit tickUnit) { @@ -267,4 +326,12 @@ long getTimeFromTickIndex(long index) { long tick = now - (maxTicks - index); return getTimeFromTick(tick, tickUnit); } + + private boolean isShowAllEntry(String id) { + return id.equals(GUIUtil.SHOW_ALL_FLAG); + } + + private boolean isEditEntry(String id) { + return id.equals(GUIUtil.EDIT_FLAG); + } } diff --git a/gui/src/main/java/io/bitsquare/gui/main/markets/trades/charts/CandleData.java b/gui/src/main/java/io/bitsquare/gui/main/market/trades/charts/CandleData.java similarity index 90% rename from gui/src/main/java/io/bitsquare/gui/main/markets/trades/charts/CandleData.java rename to gui/src/main/java/io/bitsquare/gui/main/market/trades/charts/CandleData.java index 14f77bbf7a4..e40cce0fb3e 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/markets/trades/charts/CandleData.java +++ b/gui/src/main/java/io/bitsquare/gui/main/market/trades/charts/CandleData.java @@ -15,7 +15,7 @@ * along with Bitsquare. If not, see . */ -package io.bitsquare.gui.main.markets.trades.charts; +package io.bitsquare.gui.main.market.trades.charts; public class CandleData { public final long tick; // Is the time tick in the chosen time interval @@ -27,8 +27,9 @@ public class CandleData { public final long accumulatedAmount; public final long accumulatedVolume; public final boolean isBullish; + public final String date; - public CandleData(long tick, long open, long close, long high, long low, long average, long accumulatedAmount, long accumulatedVolume, boolean isBullish) { + public CandleData(long tick, long open, long close, long high, long low, long average, long accumulatedAmount, long accumulatedVolume, boolean isBullish, String date) { this.tick = tick; this.open = open; this.close = close; @@ -38,5 +39,6 @@ public CandleData(long tick, long open, long close, long high, long low, long av this.accumulatedAmount = accumulatedAmount; this.accumulatedVolume = accumulatedVolume; this.isBullish = isBullish; + this.date = date; } } diff --git a/gui/src/main/java/io/bitsquare/gui/main/markets/trades/charts/price/Candle.java b/gui/src/main/java/io/bitsquare/gui/main/market/trades/charts/price/Candle.java similarity index 92% rename from gui/src/main/java/io/bitsquare/gui/main/markets/trades/charts/price/Candle.java rename to gui/src/main/java/io/bitsquare/gui/main/market/trades/charts/price/Candle.java index dd4022a56c9..163ad30c1c0 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/markets/trades/charts/price/Candle.java +++ b/gui/src/main/java/io/bitsquare/gui/main/market/trades/charts/price/Candle.java @@ -29,9 +29,9 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.bitsquare.gui.main.markets.trades.charts.price; +package io.bitsquare.gui.main.market.trades.charts.price; -import io.bitsquare.gui.main.markets.trades.charts.CandleData; +import io.bitsquare.gui.main.market.trades.charts.CandleData; import javafx.scene.Group; import javafx.scene.control.Tooltip; import javafx.scene.layout.Region; @@ -48,7 +48,7 @@ public class Candle extends Group { private String seriesStyleClass; private String dataStyleClass; - private final TooltipContent tooltipContent; + private final CandleTooltip candleTooltip; private final Line highLowLine = new Line(); private final Region bar = new Region(); @@ -65,8 +65,8 @@ public class Candle extends Group { getStyleClass().setAll("candlestick-candle", seriesStyleClass, dataStyleClass); updateStyleClasses(); - tooltipContent = new TooltipContent(priceStringConverter); - tooltip.setGraphic(tooltipContent); + candleTooltip = new CandleTooltip(priceStringConverter); + tooltip.setGraphic(candleTooltip); Tooltip.install(this, tooltip); } @@ -91,7 +91,7 @@ public void update(double closeOffset, double highOffset, double lowOffset, doub } public void updateTooltip(CandleData candleData) { - tooltipContent.update(candleData); + candleTooltip.update(candleData); } private void updateStyleClasses() { diff --git a/gui/src/main/java/io/bitsquare/gui/main/markets/trades/charts/price/CandleStickChart.java b/gui/src/main/java/io/bitsquare/gui/main/market/trades/charts/price/CandleStickChart.java similarity index 98% rename from gui/src/main/java/io/bitsquare/gui/main/markets/trades/charts/price/CandleStickChart.java rename to gui/src/main/java/io/bitsquare/gui/main/market/trades/charts/price/CandleStickChart.java index ba8c2b1298b..c5c9e6a7b3f 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/markets/trades/charts/price/CandleStickChart.java +++ b/gui/src/main/java/io/bitsquare/gui/main/market/trades/charts/price/CandleStickChart.java @@ -29,9 +29,9 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.bitsquare.gui.main.markets.trades.charts.price; +package io.bitsquare.gui.main.market.trades.charts.price; -import io.bitsquare.gui.main.markets.trades.charts.CandleData; +import io.bitsquare.gui.main.market.trades.charts.CandleData; import javafx.animation.FadeTransition; import javafx.event.ActionEvent; import javafx.scene.Node; @@ -70,16 +70,13 @@ public class CandleStickChart extends XYChart { * @param xAxis The x axis to use * @param yAxis The y axis to use */ - public CandleStickChart(Axis xAxis, Axis yAxis) { + public CandleStickChart(Axis xAxis, Axis yAxis, StringConverter priceStringConverter) { super(xAxis, yAxis); + this.priceStringConverter = priceStringConverter; } // -------------- METHODS ------------------------------------------------------------------------------------------ - public final void setToolTipStringConverter(StringConverter priceStringConverter) { - this.priceStringConverter = priceStringConverter; - } - /** * Called to update and layout the content for the plot */ diff --git a/gui/src/main/java/io/bitsquare/gui/main/markets/trades/charts/price/TooltipContent.java b/gui/src/main/java/io/bitsquare/gui/main/market/trades/charts/price/CandleTooltip.java similarity index 77% rename from gui/src/main/java/io/bitsquare/gui/main/markets/trades/charts/price/TooltipContent.java rename to gui/src/main/java/io/bitsquare/gui/main/market/trades/charts/price/CandleTooltip.java index 31a736977c0..8020bb8b7d7 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/markets/trades/charts/price/TooltipContent.java +++ b/gui/src/main/java/io/bitsquare/gui/main/market/trades/charts/price/CandleTooltip.java @@ -29,29 +29,34 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.bitsquare.gui.main.markets.trades.charts.price; +package io.bitsquare.gui.main.market.trades.charts.price; -import io.bitsquare.gui.main.markets.trades.charts.CandleData; +import io.bitsquare.gui.main.market.trades.charts.CandleData; import io.bitsquare.gui.util.Layout; +import javafx.geometry.HPos; import javafx.scene.control.Label; +import javafx.scene.layout.ColumnConstraints; import javafx.scene.layout.GridPane; +import javafx.scene.layout.Priority; import javafx.util.StringConverter; /** * The content for Candle tool tips */ -public class TooltipContent extends GridPane { +public class CandleTooltip extends GridPane { private final StringConverter priceStringConverter; private final Label openValue = new Label(); private final Label closeValue = new Label(); private final Label highValue = new Label(); private final Label lowValue = new Label(); private final Label averageValue = new Label(); + private final Label dateValue = new Label(); - TooltipContent(StringConverter priceStringConverter) { + CandleTooltip(StringConverter priceStringConverter) { this.priceStringConverter = priceStringConverter; setHgap(Layout.GRID_GAP); + setVgap(2); Label open = new Label("Open:"); @@ -59,10 +64,7 @@ public class TooltipContent extends GridPane { Label high = new Label("High:"); Label low = new Label("Low:"); Label average = new Label("Average:"); - /* open.getStyleClass().add("candlestick-tooltip-label"); - close.getStyleClass().add("candlestick-tooltip-label"); - high.getStyleClass().add("candlestick-tooltip-label"); - low.getStyleClass().add("candlestick-tooltip-label");*/ + Label date = new Label("Date:"); setConstraints(open, 0, 0); setConstraints(openValue, 1, 0); setConstraints(close, 0, 1); @@ -73,7 +75,17 @@ public class TooltipContent extends GridPane { setConstraints(lowValue, 1, 3); setConstraints(average, 0, 4); setConstraints(averageValue, 1, 4); - getChildren().addAll(open, openValue, close, closeValue, high, highValue, low, lowValue, average, averageValue); + setConstraints(date, 0, 5); + setConstraints(dateValue, 1, 5); + + ColumnConstraints columnConstraints1 = new ColumnConstraints(); + columnConstraints1.setHalignment(HPos.RIGHT); + columnConstraints1.setHgrow(Priority.NEVER); + ColumnConstraints columnConstraints2 = new ColumnConstraints(); + columnConstraints2.setHgrow(Priority.ALWAYS); + getColumnConstraints().addAll(columnConstraints1, columnConstraints2); + + getChildren().addAll(open, openValue, close, closeValue, high, highValue, low, lowValue, average, averageValue, date, dateValue); } public void update(CandleData candleData) { @@ -82,5 +94,6 @@ public void update(CandleData candleData) { highValue.setText(priceStringConverter.toString(candleData.high)); lowValue.setText(priceStringConverter.toString(candleData.low)); averageValue.setText(priceStringConverter.toString(candleData.average)); + dateValue.setText(candleData.date); } } \ No newline at end of file diff --git a/gui/src/main/java/io/bitsquare/gui/main/markets/trades/charts/volume/VolumeBar.java b/gui/src/main/java/io/bitsquare/gui/main/market/trades/charts/volume/VolumeBar.java similarity index 88% rename from gui/src/main/java/io/bitsquare/gui/main/markets/trades/charts/volume/VolumeBar.java rename to gui/src/main/java/io/bitsquare/gui/main/market/trades/charts/volume/VolumeBar.java index 1bad8152543..e552af13b24 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/markets/trades/charts/volume/VolumeBar.java +++ b/gui/src/main/java/io/bitsquare/gui/main/market/trades/charts/volume/VolumeBar.java @@ -14,8 +14,9 @@ * You should have received a copy of the GNU Affero General Public License * along with Bitsquare. If not, see . */ -package io.bitsquare.gui.main.markets.trades.charts.volume; +package io.bitsquare.gui.main.market.trades.charts.volume; +import io.bitsquare.gui.main.market.trades.charts.CandleData; import javafx.scene.Group; import javafx.scene.control.Tooltip; import javafx.scene.layout.Region; @@ -51,9 +52,10 @@ public void setSeriesAndDataStyleClasses(String seriesStyleClass, String dataSty updateStyleClasses(); } - public void update(double height, double candleWidth, double accumulatedAmount) { + public void update(double height, double candleWidth, CandleData candleData) { bar.resizeRelocate(-candleWidth / 2, 0, candleWidth, height); - tooltip.setText("Volume: " + volumeStringConverter.toString(accumulatedAmount)); + tooltip.setText("Volume: " + volumeStringConverter.toString(candleData.accumulatedAmount) + "\n" + + "Date: " + candleData.date); } private void updateStyleClasses() { diff --git a/gui/src/main/java/io/bitsquare/gui/main/markets/trades/charts/volume/VolumeChart.java b/gui/src/main/java/io/bitsquare/gui/main/market/trades/charts/volume/VolumeChart.java similarity index 94% rename from gui/src/main/java/io/bitsquare/gui/main/markets/trades/charts/volume/VolumeChart.java rename to gui/src/main/java/io/bitsquare/gui/main/market/trades/charts/volume/VolumeChart.java index f86466453ae..eb5a38c0d54 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/markets/trades/charts/volume/VolumeChart.java +++ b/gui/src/main/java/io/bitsquare/gui/main/market/trades/charts/volume/VolumeChart.java @@ -14,10 +14,10 @@ * You should have received a copy of the GNU Affero General Public License * along with Bitsquare. If not, see . */ -package io.bitsquare.gui.main.markets.trades.charts.volume; +package io.bitsquare.gui.main.market.trades.charts.volume; -import io.bitsquare.gui.main.markets.trades.charts.CandleData; -import io.bitsquare.gui.main.markets.trades.charts.price.CandleStickChart; +import io.bitsquare.gui.main.market.trades.charts.CandleData; +import io.bitsquare.gui.main.market.trades.charts.price.CandleStickChart; import javafx.animation.FadeTransition; import javafx.event.ActionEvent; import javafx.scene.Node; @@ -38,11 +38,8 @@ public class VolumeChart extends XYChart { private StringConverter toolTipStringConverter; - public VolumeChart(Axis xAxis, Axis yAxis) { + public VolumeChart(Axis xAxis, Axis yAxis, StringConverter toolTipStringConverter) { super(xAxis, yAxis); - } - - public final void setToolTipStringConverter(StringConverter toolTipStringConverter) { this.toolTipStringConverter = toolTipStringConverter; } @@ -73,7 +70,7 @@ protected void layoutPlotChildren() { // Did not find a way how to request the chart data height final double height = getHeight() - 43; double upperYPos = Math.min(height - 5, y); // We want min 5px height to allow tooltips - volumeBar.update(height - upperYPos, candleWidth, candleData.accumulatedAmount); + volumeBar.update(height - upperYPos, candleWidth, candleData); volumeBar.setLayoutX(x); volumeBar.setLayoutY(upperYPos); } diff --git a/gui/src/main/java/io/bitsquare/gui/main/markets/charts/MarketsChartsView.fxml b/gui/src/main/java/io/bitsquare/gui/main/markets/offerbook/OfferBookChartView.fxml similarity index 97% rename from gui/src/main/java/io/bitsquare/gui/main/markets/charts/MarketsChartsView.fxml rename to gui/src/main/java/io/bitsquare/gui/main/markets/offerbook/OfferBookChartView.fxml index 459bb21edf5..917cde886ed 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/markets/charts/MarketsChartsView.fxml +++ b/gui/src/main/java/io/bitsquare/gui/main/markets/offerbook/OfferBookChartView.fxml @@ -20,7 +20,7 @@ - Utilities.openWebPage("https://bitsquare.io/faq#6")) + .onAction(() -> GUIUtil.openWebPage("https://bitsquare.io/faq#6")) .closeButtonText("I understand") .dontShowAgainId(key, preferences) .show(); diff --git a/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferViewModel.java b/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferViewModel.java index f0c3f547657..94086218271 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferViewModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferViewModel.java @@ -22,7 +22,6 @@ import io.bitsquare.btc.pricefeed.PriceFeedService; import io.bitsquare.common.Timer; import io.bitsquare.common.UserThread; -import io.bitsquare.common.util.Utilities; import io.bitsquare.gui.Navigation; import io.bitsquare.gui.common.model.ActivatableWithDataModel; import io.bitsquare.gui.common.model.ViewModel; @@ -33,6 +32,7 @@ import io.bitsquare.gui.main.settings.SettingsView; import io.bitsquare.gui.main.settings.preferences.PreferencesView; import io.bitsquare.gui.util.BSFormatter; +import io.bitsquare.gui.util.GUIUtil; import io.bitsquare.gui.util.validation.BtcValidator; import io.bitsquare.gui.util.validation.FiatValidator; import io.bitsquare.gui.util.validation.InputValidator; @@ -355,7 +355,7 @@ private void applyCurrencyCode(String newValue) { "Be sure you fully understand the situation and check out the information on the \"Ethereum Classic\" and \"Ethereum\" project web pages.\n\n" + "Please note, that the price is denominated as ETC/BTC not BTC/ETC!") .closeButtonText("I understand") - .onAction(() -> Utilities.openWebPage("https://ethereumclassic.github.io/")) + .onAction(() -> GUIUtil.openWebPage("https://ethereumclassic.github.io/")) .actionButtonText("Open Ethereum Classic web page") .dontShowAgainId(key, preferences) .show(); diff --git a/gui/src/main/java/io/bitsquare/gui/main/offer/offerbook/OfferBookView.java b/gui/src/main/java/io/bitsquare/gui/main/offer/offerbook/OfferBookView.java index c8dff227b88..80daf3581db 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/offer/offerbook/OfferBookView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/offer/offerbook/OfferBookView.java @@ -35,9 +35,9 @@ import io.bitsquare.gui.main.overlays.popups.Popup; import io.bitsquare.gui.main.overlays.windows.OfferDetailsWindow; import io.bitsquare.gui.util.BSFormatter; +import io.bitsquare.gui.util.GUIUtil; import io.bitsquare.gui.util.Layout; import io.bitsquare.locale.BSResources; -import io.bitsquare.locale.CryptoCurrency; import io.bitsquare.locale.FiatCurrency; import io.bitsquare.locale.TradeCurrency; import io.bitsquare.payment.PaymentMethod; @@ -107,28 +107,7 @@ public void initialize() { currencyComboBox = addLabelComboBox(root, gridRow, "Filter by currency:", Layout.FIRST_ROW_DISTANCE).second; currencyComboBox.setPromptText("Select currency"); - currencyComboBox.setConverter(new StringConverter() { - @Override - public String toString(TradeCurrency tradeCurrency) { - String code = tradeCurrency.getCode(); - // http://boschista.deviantart.com/journal/Cool-ASCII-Symbols-214218618 - if (code.equals(OfferBookViewModel.SHOW_ALL_FLAG)) - return "▶ Show all"; - else if (code.equals(OfferBookViewModel.EDIT_FLAG)) - return "▼ Edit currency list"; - else if (tradeCurrency instanceof FiatCurrency) - return "★ " + tradeCurrency.getNameAndCode(); - else if (tradeCurrency instanceof CryptoCurrency) - return "✦ " + tradeCurrency.getNameAndCode(); - else - return "-"; - } - - @Override - public TradeCurrency fromString(String s) { - return null; - } - }); + currencyComboBox.setConverter(GUIUtil.getCurrencyListConverter()); paymentMethodComboBox = addLabelComboBox(root, ++gridRow, "Filter by payment method:").second; paymentMethodComboBox.setPromptText("Select payment method"); @@ -136,7 +115,7 @@ public TradeCurrency fromString(String s) { @Override public String toString(PaymentMethod paymentMethod) { String id = paymentMethod.getId(); - if (id.equals(OfferBookViewModel.SHOW_ALL_FLAG)) + if (id.equals(GUIUtil.SHOW_ALL_FLAG)) return "▶ Show all"; else if (paymentMethod.equals(PaymentMethod.BLOCK_CHAINS)) return "✦ " + BSResources.get(id); diff --git a/gui/src/main/java/io/bitsquare/gui/main/offer/offerbook/OfferBookViewModel.java b/gui/src/main/java/io/bitsquare/gui/main/offer/offerbook/OfferBookViewModel.java index 89bd568adc7..de07cc8b111 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/offer/offerbook/OfferBookViewModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/offer/offerbook/OfferBookViewModel.java @@ -30,6 +30,7 @@ import io.bitsquare.gui.main.settings.SettingsView; import io.bitsquare.gui.main.settings.preferences.PreferencesView; import io.bitsquare.gui.util.BSFormatter; +import io.bitsquare.gui.util.GUIUtil; import io.bitsquare.locale.*; import io.bitsquare.p2p.NodeAddress; import io.bitsquare.p2p.P2PService; @@ -60,9 +61,6 @@ class OfferBookViewModel extends ActivatableViewModel { protected final static Logger log = LoggerFactory.getLogger(OfferBookViewModel.class); - final static String SHOW_ALL_FLAG = "SHOW_ALL_FLAG"; - final static String EDIT_FLAG = "EDIT_FLAG"; - private final OpenOfferManager openOfferManager; private final User user; private final OfferBook offerBook; @@ -87,8 +85,7 @@ class OfferBookViewModel extends ActivatableViewModel { // If id is empty string we ignore filter (display all methods) - PaymentMethod selectedPaymentMethod = new PaymentMethod(SHOW_ALL_FLAG, 0, 0, null); - private CryptoCurrency showAllCurrenciesItem = new CryptoCurrency(SHOW_ALL_FLAG, SHOW_ALL_FLAG); + PaymentMethod selectedPaymentMethod = new PaymentMethod(GUIUtil.SHOW_ALL_FLAG, 0, 0, null); private final ObservableList offerBookListItems; private boolean isTabSelected; @@ -146,9 +143,9 @@ protected void deactivate() { private void fillAllTradeCurrencies() { allTradeCurrencies.clear(); // Used for ignoring filter (show all) - allTradeCurrencies.add(showAllCurrenciesItem); + allTradeCurrencies.add(new CryptoCurrency(GUIUtil.SHOW_ALL_FLAG, GUIUtil.SHOW_ALL_FLAG)); allTradeCurrencies.addAll(preferences.getTradeCurrenciesAsObservable()); - allTradeCurrencies.add(new CryptoCurrency(EDIT_FLAG, EDIT_FLAG)); + allTradeCurrencies.add(new CryptoCurrency(GUIUtil.EDIT_FLAG, GUIUtil.EDIT_FLAG)); } private void setMarketPriceFeedCurrency() { @@ -254,7 +251,7 @@ public TradeCurrency getSelectedTradeCurrency() { public ObservableList getPaymentMethods() { ObservableList list = FXCollections.observableArrayList(PaymentMethod.ALL_VALUES); - list.add(0, new PaymentMethod(SHOW_ALL_FLAG, 0, 0, null)); + list.add(0, new PaymentMethod(GUIUtil.SHOW_ALL_FLAG, 0, 0, null)); return list; } @@ -418,11 +415,11 @@ boolean hasSameProtocolVersion(Offer offer) { } private boolean isShowAllEntry(String id) { - return id.equals(SHOW_ALL_FLAG); + return id.equals(GUIUtil.SHOW_ALL_FLAG); } private boolean isEditEntry(String id) { - return id.equals(EDIT_FLAG); + return id.equals(GUIUtil.EDIT_FLAG); } int getNumPastTrades(Offer offer) { diff --git a/gui/src/main/java/io/bitsquare/gui/main/offer/takeoffer/TakeOfferView.java b/gui/src/main/java/io/bitsquare/gui/main/offer/takeoffer/TakeOfferView.java index 1e2d99172ab..0335faad572 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/offer/takeoffer/TakeOfferView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/offer/takeoffer/TakeOfferView.java @@ -334,7 +334,7 @@ private void onShowPayFundsScreen() { "The deposit will stay in your local trading wallet until the offer gets accepted by another trader.\n" + "It will be refunded to you after the trade has successfully completed.") .actionButtonText("Visit FAQ web page") - .onAction(() -> Utilities.openWebPage("https://bitsquare.io/faq#6")) + .onAction(() -> GUIUtil.openWebPage("https://bitsquare.io/faq#6")) .closeButtonText("I understand") .dontShowAgainId(key, preferences) .show(); diff --git a/gui/src/main/java/io/bitsquare/gui/main/offer/takeoffer/TakeOfferViewModel.java b/gui/src/main/java/io/bitsquare/gui/main/offer/takeoffer/TakeOfferViewModel.java index 1ad9ff7d350..638b866b158 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/offer/takeoffer/TakeOfferViewModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/offer/takeoffer/TakeOfferViewModel.java @@ -19,7 +19,6 @@ import io.bitsquare.arbitration.Arbitrator; import io.bitsquare.btc.pricefeed.PriceFeedService; -import io.bitsquare.common.util.Utilities; import io.bitsquare.gui.Navigation; import io.bitsquare.gui.common.model.ActivatableWithDataModel; import io.bitsquare.gui.common.model.ViewModel; @@ -28,6 +27,7 @@ import io.bitsquare.gui.main.funds.deposit.DepositView; import io.bitsquare.gui.main.overlays.popups.Popup; import io.bitsquare.gui.util.BSFormatter; +import io.bitsquare.gui.util.GUIUtil; import io.bitsquare.gui.util.validation.BtcValidator; import io.bitsquare.gui.util.validation.InputValidator; import io.bitsquare.locale.BSResources; @@ -148,7 +148,7 @@ protected void activate() { "Be sure you fully understand the situation and check out the information on the \"Ethereum Classic\" and \"Ethereum\" project web pages.\n\n" + "Please note, that the price is denominated as ETC/BTC not BTC/ETC!") .closeButtonText("I understand") - .onAction(() -> Utilities.openWebPage("https://ethereumclassic.github.io/")) + .onAction(() -> GUIUtil.openWebPage("https://ethereumclassic.github.io/")) .actionButtonText("Open Ethereum Classic web page") .dontShowAgainId(key, dataModel.getPreferences()) .show(); diff --git a/gui/src/main/java/io/bitsquare/gui/main/overlays/Overlay.java b/gui/src/main/java/io/bitsquare/gui/main/overlays/Overlay.java index c84ba8d9a7b..93367e166d9 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/overlays/Overlay.java +++ b/gui/src/main/java/io/bitsquare/gui/main/overlays/Overlay.java @@ -22,6 +22,7 @@ import io.bitsquare.common.util.Utilities; import io.bitsquare.gui.components.BusyAnimation; import io.bitsquare.gui.main.MainView; +import io.bitsquare.gui.util.GUIUtil; import io.bitsquare.gui.util.Transitions; import io.bitsquare.locale.BSResources; import io.bitsquare.user.Preferences; @@ -680,7 +681,7 @@ private void addReportErrorButtons() { githubButton.setOnAction(event -> { Utilities.copyToClipboard(message); - Utilities.openWebPage("https://github.com/bitsquare/bitsquare/issues"); + GUIUtil.openWebPage("https://github.com/bitsquare/bitsquare/issues"); }); Button mailButton = new Button("Report by email"); @@ -690,7 +691,7 @@ private void addReportErrorButtons() { gridPane.getChildren().add(mailButton); mailButton.setOnAction(event -> { Utilities.copyToClipboard(message); - Utilities.openMail("manfred@bitsquare.io", + GUIUtil.openMail("manfred@bitsquare.io", "Error report", "Error message:\n" + message); }); diff --git a/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/AddBridgeEntriesWindow.java b/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/AddBridgeEntriesWindow.java index fb4e3170232..752e6805984 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/AddBridgeEntriesWindow.java +++ b/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/AddBridgeEntriesWindow.java @@ -19,8 +19,8 @@ import io.bitsquare.alert.Alert; import io.bitsquare.common.util.Tuple2; -import io.bitsquare.common.util.Utilities; import io.bitsquare.gui.main.overlays.Overlay; +import io.bitsquare.gui.util.GUIUtil; import io.bitsquare.user.Preferences; import javafx.geometry.HPos; import javafx.geometry.Insets; @@ -90,7 +90,7 @@ protected void addCloseButton() { actionButton.setOnAction(event -> save()); Button urlButton = new Button("Open Tor project web page"); - urlButton.setOnAction(event -> Utilities.openWebPage("https://bridges.torproject.org/bridges")); + urlButton.setOnAction(event -> GUIUtil.openWebPage("https://bridges.torproject.org/bridges")); Pane spacer = new Pane(); HBox hBox = new HBox(); diff --git a/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/OfferDetailsWindow.java b/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/OfferDetailsWindow.java index f7a5891b608..05e64c3ea37 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/OfferDetailsWindow.java +++ b/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/OfferDetailsWindow.java @@ -199,18 +199,23 @@ private void addContent() { final PaymentMethod paymentMethod = offer.getPaymentMethod(); final String offererPaymentAccountId = offer.getOffererPaymentAccountId(); final PaymentAccount paymentAccount = user.getPaymentAccount(offererPaymentAccountId); - final String bankId = offer.getBankId(); + String bankId = offer.getBankId(); + if (bankId == null || bankId.equals("null")) + bankId = ""; + else + bankId = " (" + bankId + ")"; final boolean isSpecificBanks = paymentMethod.equals(PaymentMethod.SPECIFIC_BANKS); final boolean isNationalBanks = paymentMethod.equals(PaymentMethod.NATIONAL_BANK); + final boolean isSepa = paymentMethod.equals(PaymentMethod.SEPA); if (offer.isMyOffer(keyRing) && offererPaymentAccountId != null && paymentAccount != null) { addLabelTextField(gridPane, ++rowIndex, "Payment account:", paymentAccount.getAccountName()); } else { final String method = BSResources.get(paymentMethod.getId()); - if (isNationalBanks || isSpecificBanks) { + if (isNationalBanks || isSpecificBanks || isSepa) { if (BankUtil.isBankIdRequired(offer.getCountryCode())) - addLabelTextField(gridPane, ++rowIndex, "Payment method (offerers bank ID):", method + " (" + bankId + ")"); + addLabelTextField(gridPane, ++rowIndex, "Payment method (offerers bank ID):", method + bankId); else if (BankUtil.isBankNameRequired(offer.getCountryCode())) - addLabelTextField(gridPane, ++rowIndex, "Payment method (offerers bank name):", method + " (" + bankId + ")"); + addLabelTextField(gridPane, ++rowIndex, "Payment method (offerers bank name):", method + bankId); } else { addLabelTextField(gridPane, ++rowIndex, "Payment method:", method); } diff --git a/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/WalletPasswordWindow.java b/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/WalletPasswordWindow.java index 3c7bdd46b98..f245530e810 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/WalletPasswordWindow.java +++ b/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/WalletPasswordWindow.java @@ -372,7 +372,6 @@ private void checkIfEncrypted() { } private void doRestore() { - log.info("Attempting wallet restore using seed '{}' from date {}", restoreSeedWordsTextArea.getText(), restoreDatePicker.getValue()); long date = restoreDatePicker.getValue().atStartOfDay().toEpochSecond(ZoneOffset.UTC); DeterministicSeed seed = new DeterministicSeed(Splitter.on(" ").splitToList(restoreSeedWordsTextArea.getText()), null, "", date); walletService.restoreSeedWords(seed, diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/closedtrades/ClosedTradesView.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/closedtrades/ClosedTradesView.java index e0b3f2e4e2a..6b979b005fd 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/closedtrades/ClosedTradesView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/closedtrades/ClosedTradesView.java @@ -92,14 +92,15 @@ public void initialize() { dateColumn.setComparator((o1, o2) -> o1.getTradable().getDate().compareTo(o2.getTradable().getDate())); directionColumn.setComparator((o1, o2) -> o1.getTradable().getOffer().getDirection().compareTo(o2.getTradable().getOffer().getDirection())); priceColumn.setComparator((o1, o2) -> { - Tradable tradable = o1.getTradable(); - if (tradable instanceof Trade) - return ((Trade) o1.getTradable()).getTradePrice().compareTo(((Trade) o2.getTradable()).getTradePrice()); - else { - Fiat price1 = o1.getTradable().getOffer().getPrice(); - Fiat price2 = o2.getTradable().getOffer().getPrice(); - return price1 != null && price2 != null ? price1.compareTo(price2) : 0; - } + final Tradable tradable1 = o1.getTradable(); + final Tradable tradable2 = o2.getTradable(); + Fiat price1 = null; + Fiat price2 = null; + if (tradable1 != null) + price1 = tradable1 instanceof Trade ? ((Trade) tradable1).getTradePrice() : tradable1.getOffer().getPrice(); + if (tradable2 != null) + price2 = tradable2 instanceof Trade ? ((Trade) tradable2).getTradePrice() : tradable2.getOffer().getPrice(); + return price1 != null && price2 != null ? price1.compareTo(price2) : 0; }); volumeColumn.setComparator((o1, o2) -> { if (o1.getTradable() instanceof Trade && o2.getTradable() instanceof Trade) { diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesDataModel.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesDataModel.java index b07d0203e3c..67f4ae0e46a 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesDataModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesDataModel.java @@ -304,7 +304,7 @@ private void tryOpenDispute(boolean isSupportTicket) { if (depositTx != null) { doOpenDispute(isSupportTicket, getTrade().getDepositTx()); } else { - log.warn("Trade.depositTx is null. We try to find the tx in our wallet."); + log.info("Trade.depositTx is null. We try to find the tx in our wallet."); List candidates = new ArrayList<>(); List transactions = walletService.getWallet().getRecentTransactions(100, true); transactions.stream().forEach(transaction -> { diff --git a/gui/src/main/java/io/bitsquare/gui/util/FormBuilder.java b/gui/src/main/java/io/bitsquare/gui/util/FormBuilder.java index 2b6c5b0f39d..b85868c3b63 100644 --- a/gui/src/main/java/io/bitsquare/gui/util/FormBuilder.java +++ b/gui/src/main/java/io/bitsquare/gui/util/FormBuilder.java @@ -21,7 +21,6 @@ import io.bitsquare.common.util.Tuple2; import io.bitsquare.common.util.Tuple3; import io.bitsquare.common.util.Tuple4; -import io.bitsquare.common.util.Utilities; import io.bitsquare.gui.components.*; import javafx.geometry.HPos; import javafx.geometry.Insets; @@ -170,7 +169,7 @@ public static HyperlinkWithIcon addHyperlinkWithIcon(GridPane gridPane, int rowI public static HyperlinkWithIcon addHyperlinkWithIcon(GridPane gridPane, int rowIndex, String title, String url, double top) { HyperlinkWithIcon hyperlinkWithIcon = new HyperlinkWithIcon(title, AwesomeIcon.EXTERNAL_LINK); - hyperlinkWithIcon.setOnAction(e -> Utilities.openWebPage(url)); + hyperlinkWithIcon.setOnAction(e -> GUIUtil.openWebPage(url)); GridPane.setRowIndex(hyperlinkWithIcon, rowIndex); GridPane.setColumnIndex(hyperlinkWithIcon, 0); GridPane.setMargin(hyperlinkWithIcon, new Insets(top, 0, 0, -4)); @@ -191,7 +190,7 @@ public static Tuple2 addLabelHyperlinkWithIcon(GridPan Label label = addLabel(gridPane, rowIndex, labelTitle, top); HyperlinkWithIcon hyperlinkWithIcon = new HyperlinkWithIcon(title, AwesomeIcon.EXTERNAL_LINK); - hyperlinkWithIcon.setOnAction(e -> Utilities.openWebPage(url)); + hyperlinkWithIcon.setOnAction(e -> GUIUtil.openWebPage(url)); GridPane.setRowIndex(hyperlinkWithIcon, rowIndex); GridPane.setColumnIndex(hyperlinkWithIcon, 1); GridPane.setMargin(hyperlinkWithIcon, new Insets(top, 0, 0, -4)); diff --git a/gui/src/main/java/io/bitsquare/gui/util/GUIUtil.java b/gui/src/main/java/io/bitsquare/gui/util/GUIUtil.java index 42210574590..01c40763994 100644 --- a/gui/src/main/java/io/bitsquare/gui/util/GUIUtil.java +++ b/gui/src/main/java/io/bitsquare/gui/util/GUIUtil.java @@ -23,7 +23,11 @@ import com.googlecode.jcsv.writer.CSVWriter; import com.googlecode.jcsv.writer.internal.CSVWriterBuilder; import io.bitsquare.app.DevFlags; +import io.bitsquare.common.util.Utilities; import io.bitsquare.gui.main.overlays.popups.Popup; +import io.bitsquare.locale.CryptoCurrency; +import io.bitsquare.locale.FiatCurrency; +import io.bitsquare.locale.TradeCurrency; import io.bitsquare.payment.PaymentAccount; import io.bitsquare.storage.Storage; import io.bitsquare.user.Preferences; @@ -34,6 +38,7 @@ import javafx.stage.DirectoryChooser; import javafx.stage.FileChooser; import javafx.stage.Stage; +import javafx.util.StringConverter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -41,6 +46,9 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URLEncoder; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; @@ -48,6 +56,9 @@ public class GUIUtil { private static final Logger log = LoggerFactory.getLogger(GUIUtil.class); + public final static String SHOW_ALL_FLAG = "SHOW_ALL_FLAG"; + public final static String EDIT_FLAG = "EDIT_FLAG"; + public static double getScrollbarWidth(Node scrollablePane) { Node node = scrollablePane.lookup(".scroll-bar"); if (node instanceof ScrollBar) { @@ -81,7 +92,7 @@ public static void exportAccounts(ArrayList accounts, String fil String directory = getDirectoryFormChooser(preferences, stage); Storage> paymentAccountsStorage = new Storage<>(new File(directory)); paymentAccountsStorage.initAndGetPersisted(accounts, fileName); - paymentAccountsStorage.queueUpForSave(20); + paymentAccountsStorage.queueUpForSave(); new Popup<>().feedback("Payment accounts saved to path:\n" + Paths.get(directory, fileName).toAbsolutePath()).show(); } else { new Popup<>().warning("You don't have payment accounts set up for exporting.").show(); @@ -163,4 +174,73 @@ public static String getDirectoryFormChooser(Preferences preferences, Stage stag return ""; } } + + public static StringConverter getCurrencyListConverter() { + return new StringConverter() { + @Override + public String toString(TradeCurrency tradeCurrency) { + String code = tradeCurrency.getCode(); + // http://boschista.deviantart.com/journal/Cool-ASCII-Symbols-214218618 + if (code.equals(GUIUtil.SHOW_ALL_FLAG)) + return "▶ Show all"; + else if (code.equals(GUIUtil.EDIT_FLAG)) + return "▼ Edit currency list"; + else if (tradeCurrency instanceof FiatCurrency) + return "★ " + tradeCurrency.getNameAndCode(); + else if (tradeCurrency instanceof CryptoCurrency) + return "✦ " + tradeCurrency.getNameAndCode(); + else + return "-"; + } + + @Override + public TradeCurrency fromString(String s) { + return null; + } + }; + } + + + public static void openWebPage(String target) { + String key = "warnOpenURLWhenTorEnabled"; + final Preferences preferences = Preferences.INSTANCE; + if (preferences.getUseTorForHttpRequests() && preferences.showAgain(key)) { + new Popup<>().information("You have Tor enabled for Http requests and are going to open a web page " + + "in your system web browser.\n" + + "Do you want to open the web page now?\n\n" + + "If you are not using the \"Tor Browser\" as your default system web browser you " + + "will connect to the web page in clear net.\n\n" + + "URL: \"" + target) + .actionButtonText("Open the web page and don't ask again") + .onAction(() -> { + preferences.dontShowAgain(key, true); + doOpenWebPage(target); + }) + .closeButtonText("Copy URL and cancel") + .onClose(() -> Utilities.copyToClipboard(target)) + .show(); + } else { + doOpenWebPage(target); + } + } + + private static void doOpenWebPage(String target) { + try { + Utilities.openURI(new URI(target)); + } catch (Exception e) { + e.printStackTrace(); + log.error(e.getMessage()); + } + } + + public static void openMail(String to, String subject, String body) { + try { + subject = URLEncoder.encode(subject, "UTF-8").replace("+", "%20"); + body = URLEncoder.encode(body, "UTF-8").replace("+", "%20"); + Utilities.openURI(new URI("mailto:" + to + "?subject=" + subject + "&body=" + body)); + } catch (IOException | URISyntaxException e) { + log.error("openMail failed " + e.getMessage()); + e.printStackTrace(); + } + } } diff --git a/gui/src/main/java/io/bitsquare/gui/util/ImageUtil.java b/gui/src/main/java/io/bitsquare/gui/util/ImageUtil.java index ca17b26fd9e..800e57f4425 100644 --- a/gui/src/main/java/io/bitsquare/gui/util/ImageUtil.java +++ b/gui/src/main/java/io/bitsquare/gui/util/ImageUtil.java @@ -57,7 +57,7 @@ public static ImageView getCountryIconImageView(Country country) { public static boolean isRetina() { float maxRenderScale = ((QuantumToolkit) QuantumToolkit.getToolkit()).getMaxRenderScale(); boolean isRetina = maxRenderScale > 1.9f; - //log.info("isRetina=" + isRetina + " / maxRenderScale=" + maxRenderScale); + //log.debug("isRetina=" + isRetina + " / maxRenderScale=" + maxRenderScale); return isRetina; } } diff --git a/gui/src/main/resources/logback.xml b/gui/src/main/resources/logback.xml index be9c7f69e38..a45da6fd6b3 100644 --- a/gui/src/main/resources/logback.xml +++ b/gui/src/main/resources/logback.xml @@ -10,21 +10,21 @@ - - - - - - - - - - - - - - - + diff --git a/gui/src/test/java/io/bitsquare/gui/main/markets/trades/TradesChartsViewModelTest.java b/gui/src/test/java/io/bitsquare/gui/main/market/trades/TradesChartsViewModelTest.java similarity index 96% rename from gui/src/test/java/io/bitsquare/gui/main/markets/trades/TradesChartsViewModelTest.java rename to gui/src/test/java/io/bitsquare/gui/main/market/trades/TradesChartsViewModelTest.java index 1989885cbf3..0ff8999bad7 100644 --- a/gui/src/test/java/io/bitsquare/gui/main/markets/trades/TradesChartsViewModelTest.java +++ b/gui/src/test/java/io/bitsquare/gui/main/market/trades/TradesChartsViewModelTest.java @@ -1,6 +1,6 @@ -package io.bitsquare.gui.main.markets.trades; +package io.bitsquare.gui.main.market.trades; -import io.bitsquare.gui.main.markets.trades.charts.CandleData; +import io.bitsquare.gui.main.market.trades.charts.CandleData; import io.bitsquare.trade.offer.Offer; import io.bitsquare.trade.statistics.TradeStatistics; import org.bitcoinj.core.Coin; diff --git a/headless/pom.xml b/headless/pom.xml index 9f14bd1e5d2..b9a6c446c33 100644 --- a/headless/pom.xml +++ b/headless/pom.xml @@ -5,7 +5,7 @@ parent io.bitsquare - 0.4.9.1 + 0.4.9.2 4.0.0 diff --git a/headless/src/main/java/io/bitsquare/headless/Headless.java b/headless/src/main/java/io/bitsquare/headless/Headless.java index 32f7aac0165..967787838a8 100644 --- a/headless/src/main/java/io/bitsquare/headless/Headless.java +++ b/headless/src/main/java/io/bitsquare/headless/Headless.java @@ -127,7 +127,7 @@ public void onRequestCustomBridges(Runnable resultHandler) { public void shutDown() { gracefulShutDown(() -> { - log.info("Shutdown complete"); + log.debug("Shutdown complete"); System.exit(0); }); } @@ -141,7 +141,7 @@ private void gracefulShutDown(ResultHandler resultHandler) { injector.getInstance(P2PService.class).shutDown(() -> { injector.getInstance(WalletService.class).shutDownDone.addListener((ov, o, n) -> { headlessModule.close(injector); - log.info("Graceful shutdown completed"); + log.debug("Graceful shutdown completed"); resultHandler.handleResult(); }); injector.getInstance(WalletService.class).shutDown(); @@ -153,7 +153,7 @@ private void gracefulShutDown(ResultHandler resultHandler) { UserThread.runAfter(resultHandler::handleResult, 1); } } catch (Throwable t) { - log.info("App shutdown failed with exception"); + log.debug("App shutdown failed with exception"); t.printStackTrace(); System.exit(1); } diff --git a/jdkfix/pom.xml b/jdkfix/pom.xml index 4b77cc46166..6049733bab5 100644 --- a/jdkfix/pom.xml +++ b/jdkfix/pom.xml @@ -22,7 +22,7 @@ parent io.bitsquare - 0.4.9.1 + 0.4.9.2 4.0.0 diff --git a/jsocks/pom.xml b/jsocks/pom.xml index 45cde96e048..0c7778f150f 100644 --- a/jsocks/pom.xml +++ b/jsocks/pom.xml @@ -5,7 +5,7 @@ parent io.bitsquare - 0.4.9.1 + 0.4.9.2 4.0.0 diff --git a/jsocks/src/main/java/com/runjva/sourceforge/jsocks/main/SOCKS.java b/jsocks/src/main/java/com/runjva/sourceforge/jsocks/main/SOCKS.java index e94bf3e2390..ce071f24d1e 100644 --- a/jsocks/src/main/java/com/runjva/sourceforge/jsocks/main/SOCKS.java +++ b/jsocks/src/main/java/com/runjva/sourceforge/jsocks/main/SOCKS.java @@ -257,7 +257,7 @@ static int readInt(Properties props, String name) { // ///////////////// static void inform(String s) { - log.info(s); + log.debug(s); } static void exit(String msg) { diff --git a/jsocks/src/main/java/com/runjva/sourceforge/jsocks/protocol/ProxyServer.java b/jsocks/src/main/java/com/runjva/sourceforge/jsocks/protocol/ProxyServer.java index 66b46268eec..3ea1913560e 100644 --- a/jsocks/src/main/java/com/runjva/sourceforge/jsocks/protocol/ProxyServer.java +++ b/jsocks/src/main/java/com/runjva/sourceforge/jsocks/protocol/ProxyServer.java @@ -158,13 +158,13 @@ public void start(final int port, final int backlog, ss = new ServerSocket(port, backlog, localIP); final String address = ss.getInetAddress().getHostAddress(); final int localPort = ss.getLocalPort(); - log.info("Starting SOCKS Proxy on: {}:{}", address, localPort); + log.debug("Starting SOCKS Proxy on: {}:{}", address, localPort); while (true) { final Socket s = ss.accept(); final String hostName = s.getInetAddress().getHostName(); final int port2 = s.getPort(); - log.info("Accepted from:{}:{}", hostName, port2); + log.debug("Accepted from:{}:{}", hostName, port2); final ProxyServer ps = new ProxyServer(auth, s); (new Thread(ps)).start(); @@ -203,7 +203,7 @@ public void run() { if (auth != null) { auth.endSession(); } - log.info("Main thread(client->remote)stopped."); + log.debug("Main thread(client->remote)stopped."); } break; case ACCEPT_MODE: @@ -219,7 +219,7 @@ public void run() { handleException(ioe); } finally { abort(); - log.info("Accept thread(remote->client) stopped"); + log.debug("Accept thread(remote->client) stopped"); } break; case PIPE_MODE: @@ -228,7 +228,7 @@ public void run() { } catch (final IOException ioe) { } finally { abort(); - log.info("Support thread(remote->client) stopped"); + log.debug("Support thread(remote->client) stopped"); } break; case ABORT_MODE: @@ -252,7 +252,7 @@ private void startSession() throws IOException { } if (auth == null) { // Authentication failed - log.info("Authentication failed"); + log.debug("Authentication failed"); return; } @@ -336,7 +336,7 @@ private void onConnect(final ProxyMessage msg) throws IOException { s = new SocksSocket(proxy, msg.ip, msg.port); } - log.info("Connected to " + s.getInetAddress() + ":" + s.getPort()); + log.debug("Connected to " + s.getInetAddress() + ":" + s.getPort()); ProxyMessage response = null; final InetAddress localAddress = s.getLocalAddress(); @@ -367,7 +367,7 @@ private void onBind(final ProxyMessage msg) throws IOException { final InetAddress inetAddress = ss.getInetAddress(); final int localPort = ss.getLocalPort(); - log.info("Trying accept on {}:{}", inetAddress, localPort); + log.debug("Trying accept on {}:{}", inetAddress, localPort); if (msg.version == 5) { final int cmd = SocksProxyBase.SOCKS_SUCCESS; @@ -425,7 +425,7 @@ private void onUDP(final ProxyMessage msg) throws IOException { if (msg.ip.getHostAddress().equals("0.0.0.0")) { msg.ip = sock.getInetAddress(); } - log.info("Creating UDP relay server for {}:{}", msg.ip, msg.port); + log.debug("Creating UDP relay server for {}:{}", msg.ip, msg.port); relayServer = new UDPRelayServer(msg.ip, msg.port, Thread.currentThread(), sock, auth); @@ -494,7 +494,7 @@ private void doAccept() throws IOException { final InetAddress inetAddress = s.getInetAddress(); final int port = s.getPort(); - log.info("Accepted from {}:{}", s.getInetAddress(), port); + log.debug("Accepted from {}:{}", s.getInetAddress(), port); ProxyMessage response; @@ -564,7 +564,7 @@ private synchronized void abort() { } mode = ABORT_MODE; try { - log.info("Aborting operation"); + log.debug("Aborting operation"); if (remote_sock != null) { remote_sock.close(); } diff --git a/jsocks/src/main/java/com/runjva/sourceforge/jsocks/protocol/UDPRelayServer.java b/jsocks/src/main/java/com/runjva/sourceforge/jsocks/protocol/UDPRelayServer.java index d510ad8c741..b496f41dc1c 100644 --- a/jsocks/src/main/java/com/runjva/sourceforge/jsocks/protocol/UDPRelayServer.java +++ b/jsocks/src/main/java/com/runjva/sourceforge/jsocks/protocol/UDPRelayServer.java @@ -115,8 +115,8 @@ public void start() throws IOException { remote_sock.setSoTimeout(iddleTimeout); client_sock.setSoTimeout(iddleTimeout); - log.info("Starting UDP relay server on {}:{}", relayIP, relayPort); - log.info("Remote socket {}:{}", remote_sock.getLocalAddress(), + log.debug("Starting UDP relay server on {}:{}", relayIP, relayPort); + log.debug("Remote socket {}:{}", remote_sock.getLocalAddress(), remote_sock.getLocalPort()); pipe_thread1 = new Thread(this, "pipe1"); @@ -151,7 +151,7 @@ public void run() { } catch (final IOException ioe) { } finally { abort(); - log.info("UDP Pipe thread " + Thread.currentThread().getName() + log.debug("UDP Pipe thread " + Thread.currentThread().getName() + " stopped."); } @@ -164,7 +164,7 @@ private synchronized void abort() { return; } - log.info("Aborting UDP Relay Server"); + log.debug("Aborting UDP Relay Server"); remote_sock.close(); client_sock.close(); @@ -201,7 +201,7 @@ private void pipe(DatagramSocket from, DatagramSocket to, boolean out) } } catch (final UnknownHostException uhe) { - log.info("Dropping datagram for unknown host"); + log.debug("Dropping datagram for unknown host"); } catch (final InterruptedIOException iioe) { // log("Interrupted: "+iioe); // If we were interrupted by other thread. diff --git a/jtorctl/pom.xml b/jtorctl/pom.xml index a0aecdf65e7..9cb46129278 100644 --- a/jtorctl/pom.xml +++ b/jtorctl/pom.xml @@ -5,7 +5,7 @@ parent io.bitsquare - 0.4.9.1 + 0.4.9.2 4.0.0 diff --git a/jtorproxy/pom.xml b/jtorproxy/pom.xml index bf5ad37b7f0..1e842882d78 100644 --- a/jtorproxy/pom.xml +++ b/jtorproxy/pom.xml @@ -5,7 +5,7 @@ parent io.bitsquare - 0.4.9.1 + 0.4.9.2 4.0.0 diff --git a/jtorproxy/src/main/java/com/msopentech/thali/toronionproxy/OnionProxyManager.java b/jtorproxy/src/main/java/com/msopentech/thali/toronionproxy/OnionProxyManager.java index d7cb4b7b019..03ef2949b44 100644 --- a/jtorproxy/src/main/java/com/msopentech/thali/toronionproxy/OnionProxyManager.java +++ b/jtorproxy/src/main/java/com/msopentech/thali/toronionproxy/OnionProxyManager.java @@ -128,7 +128,7 @@ public synchronized boolean startWithRepeat(int secondsBeforeTimeOut, int number if (isBootstrapped() == false) { Thread.sleep(1000, 0); } else { - log.info("Tor has bootstrapped"); + log.debug("Tor has bootstrapped"); return true; } } @@ -211,7 +211,7 @@ public synchronized String publishHiddenService(int hiddenServicePort, int local + "this."); } - log.info("Creating hidden service"); + log.debug("Creating hidden service"); File hostnameFile = onionProxyContext.getHostNameFile(); if (hostnameFile.getParentFile().exists() == false && hostnameFile.getParentFile().mkdirs() == false) { @@ -257,7 +257,7 @@ public synchronized String publishHiddenService(int hiddenServicePort, int local // Publish the hidden service's onion hostname in transport properties String hostname = new String(FileUtilities.read(hostnameFile), "UTF-8").trim(); - log.info("Hidden service config has completed."); + log.debug("Hidden service config has completed."); return hostname; } @@ -285,7 +285,7 @@ public synchronized void stop() throws IOException { if (controlConnection == null) { return; } - log.info("Stopping Tor"); + log.debug("Stopping Tor"); controlConnection.setConf("DisableNetwork", "1"); controlConnection.shutdownTor("TERM"); } finally { @@ -319,7 +319,7 @@ public synchronized void enableNetwork(boolean enable) throws IOException { if (controlConnection == null) { throw new RuntimeException("Tor is not running!"); } - log.info("Enabling network: " + enable); + log.debug("Enabling network: " + enable); controlConnection.setConf("DisableNetwork", enable ? "0" : "1"); } @@ -390,18 +390,18 @@ public synchronized boolean installAndStartTorOp(boolean useBridges) throws IOEx // then Tor is dead. This assumes, of course, that takeOwnership works // and we can't end up with Zombies. if (controlConnection != null) { - log.info("Tor is already running"); + log.debug("Tor is already running"); return true; } // The code below is why this method is synchronized, we don't want two // instances of it running at once // as the result would be a mess of screwed up files and connections. - log.info("Tor is not running"); + log.debug("Tor is not running"); installAndConfigureFiles(useBridges); - log.info("Starting Tor"); + log.debug("Starting Tor"); File cookieFile = onionProxyContext.getCookieFile(); if (cookieFile.getParentFile().exists() == false && cookieFile.getParentFile().mkdirs() == false) { throw new RuntimeException("Could not create cookieFile parent directory"); @@ -536,7 +536,7 @@ public void run() { nextLine.substring(nextLine.lastIndexOf(" ") + 1, nextLine.length() - 1)); countDownLatch.countDown(); } - log.info(nextLine); + log.debug(nextLine); } } } finally { diff --git a/jtorproxy/src/main/java/io/nucleo/net/Node.java b/jtorproxy/src/main/java/io/nucleo/net/Node.java index 26e9afb5646..e21d3e94d21 100644 --- a/jtorproxy/src/main/java/io/nucleo/net/Node.java +++ b/jtorproxy/src/main/java/io/nucleo/net/Node.java @@ -165,7 +165,7 @@ public void run() { try { while (running) { final Socket socket = serverSocket.accept(); - log.info("Accepting Client on port " + socket.getLocalPort()); + log.debug("Accepting Client on port " + socket.getLocalPort()); executorService.submit(new Acceptor(socket)); } } catch (IOException e) { @@ -237,7 +237,7 @@ public void run() { out = prepareOOSForSocket(socket); objectInputStream = new ObjectInputStream(socket.getInputStream()); } catch (EOFException e) { - log.info("Got bogus incoming connection"); + log.debug("Got bogus incoming connection"); } catch (IOException e) { e.printStackTrace(); try { diff --git a/jtorproxy/src/main/java/io/nucleo/net/TorNode.java b/jtorproxy/src/main/java/io/nucleo/net/TorNode.java index 8dc31adf6df..66f50183a11 100644 --- a/jtorproxy/src/main/java/io/nucleo/net/TorNode.java +++ b/jtorproxy/src/main/java/io/nucleo/net/TorNode.java @@ -30,7 +30,7 @@ public TorNode(M mgr, boolean useBridges) throws IOException { log.debug("Running Tornode with " + mgr.getClass().getSimpleName() + " and " + ctx.getClass().getSimpleName()); tor = initTor(mgr, ctx, useBridges); int proxyPort = tor.getIPv4LocalHostSocksPort(); - log.info("TorSocks running on port " + proxyPort); + log.debug("TorSocks running on port " + proxyPort); this.proxy = setupSocksProxy(proxyPort); } @@ -58,7 +58,7 @@ private Socket connectToHiddenService(String onionUrl, int port, int numTries, b try { SocksSocket ssock = new SocksSocket(proxy, onionUrl, port); if (debug) - log.info("Took " + (GregorianCalendar.getInstance().getTimeInMillis() - before) + log.debug("Took " + (GregorianCalendar.getInstance().getTimeInMillis() - before) + " milliseconds to connect to " + onionUrl + ":" + port); ssock.setTcpNoDelay(true); return ssock; @@ -89,7 +89,7 @@ public HiddenServiceDescriptor createHiddenService(final int localPort, final in public HiddenServiceDescriptor createHiddenService(final int localPort, final int servicePort, final HiddenServiceReadyListener listener) throws IOException { - log.info("Publishing Hidden Service. This will at least take half a minute..."); + log.debug("Publishing Hidden Service. This will at least take half a minute..."); final String hiddenServiceName = tor.publishHiddenService(servicePort, localPort); final HiddenServiceDescriptor hiddenServiceDescriptor = new HiddenServiceDescriptor(hiddenServiceName, localPort, servicePort); diff --git a/monitor/pom.xml b/monitor/pom.xml index b2b97615057..89889054a16 100644 --- a/monitor/pom.xml +++ b/monitor/pom.xml @@ -5,7 +5,7 @@ parent io.bitsquare - 0.4.9.1 + 0.4.9.2 4.0.0 diff --git a/monitor/src/main/java/io/bitsquare/monitor/Monitor.java b/monitor/src/main/java/io/bitsquare/monitor/Monitor.java index 01eb395954a..dd7114041ce 100644 --- a/monitor/src/main/java/io/bitsquare/monitor/Monitor.java +++ b/monitor/src/main/java/io/bitsquare/monitor/Monitor.java @@ -130,7 +130,7 @@ public void onRequestCustomBridges(Runnable resultHandler) { public void shutDown() { gracefulShutDown(() -> { - log.info("Shutdown complete"); + log.debug("Shutdown complete"); System.exit(0); }); } @@ -144,7 +144,7 @@ private void gracefulShutDown(ResultHandler resultHandler) { injector.getInstance(P2PService.class).shutDown(() -> { injector.getInstance(WalletService.class).shutDownDone.addListener((ov, o, n) -> { monitorModule.close(injector); - log.info("Graceful shutdown completed"); + log.debug("Graceful shutdown completed"); resultHandler.handleResult(); }); injector.getInstance(WalletService.class).shutDown(); @@ -156,7 +156,7 @@ private void gracefulShutDown(ResultHandler resultHandler) { UserThread.runAfter(resultHandler::handleResult, 1); } } catch (Throwable t) { - log.info("App shutdown failed with exception"); + log.debug("App shutdown failed with exception"); t.printStackTrace(); System.exit(1); } diff --git a/network/pom.xml b/network/pom.xml index 104ecc310e0..e2305bbfdb8 100644 --- a/network/pom.xml +++ b/network/pom.xml @@ -5,7 +5,7 @@ parent io.bitsquare - 0.4.9.1 + 0.4.9.2 4.0.0 diff --git a/network/src/main/java/io/bitsquare/http/HttpClient.java b/network/src/main/java/io/bitsquare/http/HttpClient.java index 69f6a735000..8bb38507bf4 100644 --- a/network/src/main/java/io/bitsquare/http/HttpClient.java +++ b/network/src/main/java/io/bitsquare/http/HttpClient.java @@ -57,13 +57,13 @@ public String requestWithGET(String param) throws IOException, HttpException { socks5Proxy = socks5ProxyProvider.getSocks5Proxy(); if (ignoreSocks5Proxy) { - log.info("Use clear net for HttpClient because ignoreSocks5Proxy is set to true"); + log.debug("Use clear net for HttpClient because ignoreSocks5Proxy is set to true"); return requestWithGETNoProxy(param); } else if (socks5Proxy == null) { - log.info("Use clear net for HttpClient because socks5Proxy is null"); + log.debug("Use clear net for HttpClient because socks5Proxy is null"); return requestWithGETNoProxy(param); } else { - log.info("Use socks5Proxy for HttpClient: " + socks5Proxy); + log.debug("Use socks5Proxy for HttpClient: " + socks5Proxy); return requestWithGETProxy(param, socks5Proxy); } } diff --git a/network/src/main/java/io/bitsquare/p2p/P2PService.java b/network/src/main/java/io/bitsquare/p2p/P2PService.java index 5fdc3ed8ce8..13c1561cb6a 100644 --- a/network/src/main/java/io/bitsquare/p2p/P2PService.java +++ b/network/src/main/java/io/bitsquare/p2p/P2PService.java @@ -446,7 +446,7 @@ public void onMessage(Message message, Connection connection) { DecryptedMsgWithPubKey decryptedMsgWithPubKey = optionalEncryptionService.get().decryptAndVerify( prefixedSealedAndSignedMessage.sealedAndSigned); - log.info("\n\nDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\n" + + log.debug("\n\nDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\n" + "Decrypted SealedAndSignedMessage:\ndecryptedMsgWithPubKey={}" + "\nDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\n", decryptedMsgWithPubKey); if (connection.getPeersNodeAddressOptional().isPresent()) @@ -455,12 +455,12 @@ public void onMessage(Message message, Connection connection) { else log.error("peersNodeAddress is not available at onMessage."); } else { - log.info("Wrong receiverAddressMaskHash. The message is not intended for us."); + log.debug("Wrong receiverAddressMaskHash. The message is not intended for us."); } } catch (CryptoException e) { - log.info(message.toString()); - log.info(e.toString()); - log.info("Decryption of prefixedSealedAndSignedMessage.sealedAndSigned failed. " + + log.debug(message.toString()); + log.debug(e.toString()); + log.debug("Decryption of prefixedSealedAndSignedMessage.sealedAndSigned failed. " + "That is expected if the message is not intended for us."); } } @@ -505,7 +505,7 @@ private void doSendEncryptedDirectMessage(@NotNull NodeAddress peersNodeAddress, checkArgument(optionalEncryptionService.isPresent(), "EncryptionService not set. Seems that is called on a seed node which must not happen."); checkNotNull(networkNode.getNodeAddress(), "My node address must not be null at doSendEncryptedDirectMessage"); try { - log.info("\n\nEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" + + log.debug("\n\nEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" + "Encrypt message:\nmessage={}" + "\nEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n", message); PrefixedSealedAndSignedMessage prefixedSealedAndSignedMessage = new PrefixedSealedAndSignedMessage(networkNode.getNodeAddress(), @@ -564,12 +564,12 @@ private void processProtectedMailboxStorageEntry(ProtectedMailboxStorageEntry pr "decryptedMsgWithPubKey.message=", decryptedMsgWithPubKey.message); } } catch (CryptoException e) { - log.info(e.toString()); - log.info("Decryption of prefixedSealedAndSignedMessage.sealedAndSigned failed. " + + log.debug(e.toString()); + log.debug("Decryption of prefixedSealedAndSignedMessage.sealedAndSigned failed. " + "That is expected if the message is not intended for us."); } } else { - log.info("Wrong blurredAddressHash. The message is not intended for us."); + log.debug("Wrong blurredAddressHash. The message is not intended for us."); } } } @@ -592,7 +592,7 @@ public void sendEncryptedMailboxMessage(NodeAddress peersNodeAddress, PubKeyRing if (isBootstrapped()) { if (!networkNode.getAllConnections().isEmpty()) { try { - log.info("\n\nEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" + + log.debug("\n\nEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n" + "Encrypt message:\nmessage={}" + "\nEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n", message); PrefixedSealedAndSignedMessage prefixedSealedAndSignedMessage = new PrefixedSealedAndSignedMessage( @@ -611,7 +611,7 @@ public void onSuccess(@Nullable Connection connection) { public void onFailure(@NotNull Throwable throwable) { log.trace("SendEncryptedMailboxMessage onFailure"); log.debug(throwable.toString()); - log.info("We cannot send message to peer. Peer might be offline. We will store message in mailbox."); + log.debug("We cannot send message to peer. Peer might be offline. We will store message in mailbox."); log.trace("create MailboxEntry with peerAddress " + peersNodeAddress); PublicKey receiverStoragePublicKey = peersPubKeyRing.getSignaturePubKey(); addMailboxData(new MailboxStoragePayload(prefixedSealedAndSignedMessage, diff --git a/network/src/main/java/io/bitsquare/p2p/network/Connection.java b/network/src/main/java/io/bitsquare/p2p/network/Connection.java index 542d2aabe96..137ad436c16 100644 --- a/network/src/main/java/io/bitsquare/p2p/network/Connection.java +++ b/network/src/main/java/io/bitsquare/p2p/network/Connection.java @@ -174,14 +174,13 @@ public void sendMessage(Message message) { if (!stopped) { if (!isCapabilityRequired(message) || isCapabilitySupported(message)) { try { - log.info("sendMessage message=" + Utilities.toTruncatedString(message)); Log.traceCall(); // Throttle outbound messages long now = System.currentTimeMillis(); long elapsed = now - lastSendTimeStamp; if (elapsed < 20) { - log.info("We got 2 sendMessage requests in less than 20 ms. We set the thread to sleep " + + log.debug("We got 2 sendMessage requests in less than 20 ms. We set the thread to sleep " + "for 50 ms to avoid flooding our peer. lastSendTimeStamp={}, now={}, elapsed={}", lastSendTimeStamp, now, elapsed); Thread.sleep(50); @@ -201,13 +200,13 @@ public void sendMessage(Message message) { } else if (message instanceof PrefixedSealedAndSignedMessage && peersNodeAddressOptional.isPresent()) { setPeerType(Connection.PeerType.DIRECT_MSG_PEER); - log.info("\n\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" + + log.debug("\n\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" + "Sending direct message to peer" + "Write object to outputStream to peer: {} (uid={})\ntruncated message={} / size={}" + "\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n", peersNodeAddress, uid, Utilities.toTruncatedString(message), size); } else { - log.info("\n\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" + + log.debug("\n\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" + "Write object to outputStream to peer: {} (uid={})\ntruncated message={} / size={}" + "\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n", peersNodeAddress, uid, Utilities.toTruncatedString(message), size); @@ -370,7 +369,7 @@ public void setPeersNodeAddress(NodeAddress peerNodeAddress) { String peersNodeAddress = getPeersNodeAddressOptional().isPresent() ? getPeersNodeAddressOptional().get().getFullAddress() : ""; if (this instanceof InboundConnection) { - log.info("\n\n############################################################\n" + + log.debug("\n\n############################################################\n" + "We got the peers node address set.\n" + "peersNodeAddress= " + peersNodeAddress + "\nconnection.uid=" + getUid() + @@ -435,7 +434,7 @@ public void shutDown(CloseConnectionReason closeConnectionReason, @Nullable Runn Log.traceCall(this.toString()); if (!stopped) { String peersNodeAddress = peersNodeAddressOptional.isPresent() ? peersNodeAddressOptional.get().toString() : "null"; - log.info("\n\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" + + log.debug("\n\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" + "ShutDown connection:" + "\npeersNodeAddress=" + peersNodeAddress + "\ncloseConnectionReason=" + closeConnectionReason @@ -681,6 +680,7 @@ private static class InputHandler implements Runnable { private volatile boolean stopped; private long lastReadTimeStamp; + private boolean threadNameSet; public InputHandler(SharedModel sharedModel, ObjectInputStream objectInputStream, String portInfo, MessageListener messageListener) { this.sharedModel = sharedModel; @@ -705,8 +705,19 @@ public void stop() { @Override public void run() { try { - Thread.currentThread().setName("InputHandler-" + portInfo); + Thread.currentThread().setName("InputHandler"); while (!stopped && !Thread.currentThread().isInterrupted()) { + if (!threadNameSet && sharedModel.connection.getPeersNodeAddressOptional().isPresent()) { + Thread.currentThread().setName("InputHandler-" + sharedModel.connection.getPeersNodeAddressOptional().get().getFullAddress()); + threadNameSet = true; + } + + if (objectInputStream.available() < 0) { + log.warn("Shutdown because objectInputStream.available() < 0. objectInputStream.available()=" + objectInputStream.available()); + sharedModel.shutDown(CloseConnectionReason.TERMINATED); + return; + } + Connection connection = sharedModel.connection; log.trace("InputHandler waiting for incoming messages.\n\tConnection=" + connection); try { @@ -716,7 +727,7 @@ public void run() { long now = System.currentTimeMillis(); long elapsed = now - lastReadTimeStamp; if (elapsed < 10) { - log.info("We got 2 messages received in less than 10 ms. We set the thread to sleep " + + log.debug("We got 2 messages received in less than 10 ms. We set the thread to sleep " + "for 20 ms to avoid getting flooded by our peer. lastReadTimeStamp={}, now={}, elapsed={}", lastReadTimeStamp, now, elapsed); Thread.sleep(20); @@ -737,7 +748,8 @@ public void run() { } else if (rawInputObject instanceof Message) { // We want to log all incoming messages (except Pong and RefreshTTLMessage) // so we log before the data type checks - log.info("\n\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n" + + //log.info("size={}; object={}", size, Utilities.toTruncatedString(rawInputObject.toString(), 100)); + log.debug("\n\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n" + "New data arrived at inputHandler of connection {}.\n" + "Received object (truncated)={} / size={}" + "\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n", @@ -752,6 +764,7 @@ public void run() { connection, size); try { + // Don't call toString on rawInputObject log.error("rawInputObject.className=" + rawInputObject.getClass().getName()); } catch (Throwable ignore) { } @@ -823,7 +836,7 @@ public void run() { if (message instanceof CloseConnectionMessage) { // If we get a CloseConnectionMessage we shut down - log.info("CloseConnectionMessage received. Reason={}\n\t" + + log.debug("CloseConnectionMessage received. Reason={}\n\t" + "connection={}", ((CloseConnectionMessage) message).reason, connection); stop(); if (CloseConnectionReason.PEER_BANNED.name().equals(((CloseConnectionMessage) message).reason)) { diff --git a/network/src/main/java/io/bitsquare/p2p/network/LocalhostNetworkNode.java b/network/src/main/java/io/bitsquare/p2p/network/LocalhostNetworkNode.java index be8dc5c609b..07bda11f72c 100644 --- a/network/src/main/java/io/bitsquare/p2p/network/LocalhostNetworkNode.java +++ b/network/src/main/java/io/bitsquare/p2p/network/LocalhostNetworkNode.java @@ -91,7 +91,7 @@ private void createTorNode(final Consumer resultHandler) { long ts = System.currentTimeMillis(); if (simulateTorDelayTorNode > 0) Uninterruptibles.sleepUninterruptibly(simulateTorDelayTorNode, TimeUnit.MILLISECONDS); - log.info("\n\n############################################################\n" + + log.debug("\n\n############################################################\n" + "TorNode created [simulation]:" + "\nTook " + (System.currentTimeMillis() - ts) + " ms" + "\n############################################################\n"); @@ -120,7 +120,7 @@ private void createHiddenService(final Consumer resultH long ts = System.currentTimeMillis(); if (simulateTorDelayHiddenService > 0) Uninterruptibles.sleepUninterruptibly(simulateTorDelayHiddenService, TimeUnit.MILLISECONDS); - log.info("\n\n############################################################\n" + + log.debug("\n\n############################################################\n" + "Hidden service published [simulation]:" + "\nTook " + (System.currentTimeMillis() - ts) + " ms" + "\n############################################################\n"); diff --git a/network/src/main/java/io/bitsquare/p2p/network/NetworkNode.java b/network/src/main/java/io/bitsquare/p2p/network/NetworkNode.java index a50aad440b7..6f73d504f0c 100644 --- a/network/src/main/java/io/bitsquare/p2p/network/NetworkNode.java +++ b/network/src/main/java/io/bitsquare/p2p/network/NetworkNode.java @@ -75,7 +75,7 @@ public SettableFuture sendMessage(@NotNull NodeAddress peersNodeAddr if (connection != null) { return sendMessage(connection, message); } else { - log.info("We have not found any connection for peerAddress {}.\n\t" + + log.debug("We have not found any connection for peerAddress {}.\n\t" + "We will create a new outbound connection.", peersNodeAddress); final SettableFuture resultFuture = SettableFuture.create(); @@ -85,10 +85,10 @@ public SettableFuture sendMessage(@NotNull NodeAddress peersNodeAddr try { // can take a while when using tor long startTs = System.currentTimeMillis(); - log.info("Start create socket to peersNodeAddress {}", peersNodeAddress.getFullAddress()); + log.debug("Start create socket to peersNodeAddress {}", peersNodeAddress.getFullAddress()); Socket socket = createSocket(peersNodeAddress); long duration = System.currentTimeMillis() - startTs; - log.info("Socket creation to peersNodeAddress {} took {} ms", peersNodeAddress.getFullAddress(), + log.debug("Socket creation to peersNodeAddress {} took {} ms", peersNodeAddress.getFullAddress(), duration); if (duration > CREATE_SOCKET_TIMEOUT_MILLIS) @@ -101,7 +101,7 @@ public SettableFuture sendMessage(@NotNull NodeAddress peersNodeAddr existingConnection = getOutboundConnection(peersNodeAddress); if (existingConnection != null) { - log.info("We found in the meantime a connection for peersNodeAddress {}, " + + log.debug("We found in the meantime a connection for peersNodeAddress {}, " + "so we use that for sending the message.\n" + "That can happen if Tor needs long for creating a new outbound connection.\n" + "We might have got a new inbound or outbound connection.", @@ -141,7 +141,7 @@ public void onError(Throwable throwable) { } }, peersNodeAddress); - log.info("\n\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" + + log.debug("\n\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" + "NetworkNode created new outbound connection:" + "\nmyNodeAddress=" + getNodeAddress() + "\npeersNodeAddress=" + peersNodeAddress @@ -278,7 +278,7 @@ public void shutDown(Runnable shutDownCompleteHandler) { } getAllConnections().stream().forEach(c -> c.shutDown(CloseConnectionReason.APP_SHUT_DOWN)); - log.info("NetworkNode shutdown complete"); + log.debug("NetworkNode shutdown complete"); } if (shutDownCompleteHandler != null) shutDownCompleteHandler.run(); } diff --git a/network/src/main/java/io/bitsquare/p2p/network/Server.java b/network/src/main/java/io/bitsquare/p2p/network/Server.java index ca4246e582a..4770cbd0419 100644 --- a/network/src/main/java/io/bitsquare/p2p/network/Server.java +++ b/network/src/main/java/io/bitsquare/p2p/network/Server.java @@ -39,13 +39,13 @@ public void run() { Thread.currentThread().setName("Server-" + serverSocket.getLocalPort()); try { while (!stopped && !Thread.currentThread().isInterrupted()) { - log.info("Ready to accept new clients on port " + serverSocket.getLocalPort()); + log.debug("Ready to accept new clients on port " + serverSocket.getLocalPort()); final Socket socket = serverSocket.accept(); if (!stopped && !Thread.currentThread().isInterrupted()) { - log.info("Accepted new client on localPort/port " + socket.getLocalPort() + "/" + socket.getPort()); + log.debug("Accepted new client on localPort/port " + socket.getLocalPort() + "/" + socket.getPort()); InboundConnection connection = new InboundConnection(socket, messageListener, connectionListener); - log.info("\n\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" + + log.debug("\n\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" + "Server created new inbound connection:" + "\nlocalPort/port=" + serverSocket.getLocalPort() + "/" + socket.getPort() @@ -78,12 +78,12 @@ public void shutDown() { try { serverSocket.close(); } catch (SocketException e) { - log.warn("SocketException at shutdown might be expected " + e.getMessage()); + log.debug("SocketException at shutdown might be expected " + e.getMessage()); } catch (IOException e) { log.error("Exception at shutdown. " + e.getMessage()); e.printStackTrace(); } finally { - log.info("Server shutdown complete"); + log.debug("Server shutdown complete"); } } else { log.warn("stopped already called ast shutdown"); diff --git a/network/src/main/java/io/bitsquare/p2p/network/TorNetworkNode.java b/network/src/main/java/io/bitsquare/p2p/network/TorNetworkNode.java index 85568b0cbad..6677e025dd6 100644 --- a/network/src/main/java/io/bitsquare/p2p/network/TorNetworkNode.java +++ b/network/src/main/java/io/bitsquare/p2p/network/TorNetworkNode.java @@ -121,7 +121,7 @@ public void shutDown(@Nullable Runnable shutDownCompleteHandler) { try { MoreExecutors.shutdownAndAwaitTermination(executorService, 500, TimeUnit.MILLISECONDS); log.debug("Shutdown executorService done after " + (System.currentTimeMillis() - ts) + " ms."); - log.info("Shutdown completed"); + log.debug("Shutdown completed"); } catch (Throwable t) { log.error("Shutdown executorService failed with exception: " + t.getMessage()); t.printStackTrace(); @@ -138,11 +138,11 @@ private BooleanProperty torNetworkNodeShutDown() { executorService.submit(() -> { Utilities.setThreadName("torNetworkNodeShutDown"); long ts = System.currentTimeMillis(); - log.info("Shutdown torNetworkNode"); + log.debug("Shutdown torNetworkNode"); try { if (torNetworkNode != null) torNetworkNode.shutdown(); - log.info("Shutdown torNetworkNode done after " + (System.currentTimeMillis() - ts) + " ms."); + log.debug("Shutdown torNetworkNode done after " + (System.currentTimeMillis() - ts) + " ms."); } catch (Throwable e) { log.error("Shutdown torNetworkNode failed with exception: " + e.getMessage()); e.printStackTrace(); @@ -221,7 +221,7 @@ private void createTorNode(final File torDir, boolean useBridges, final Consumer if (torDir.mkdirs()) log.trace("Created directory for tor at {}", torDir.getAbsolutePath()); TorNode torNode = new JavaTorNode(torDir, useBridges); - log.info("\n\n############################################################\n" + + log.debug("\n\n############################################################\n" + "TorNode created:" + "\nTook " + (System.currentTimeMillis() - ts) + " ms" + "\n############################################################\n"); @@ -250,7 +250,7 @@ private void createHiddenService(TorNode torNode, int localPort, int servicePort long ts = System.currentTimeMillis(); HiddenServiceDescriptor hiddenServiceDescriptor = torNode.createHiddenService(localPort, servicePort); torNode.addHiddenServiceReadyListener(hiddenServiceDescriptor, descriptor -> { - log.info("\n\n############################################################\n" + + log.debug("\n\n############################################################\n" + "Hidden service published:" + "\nAddress=" + descriptor.getFullAddress() + "\nTook " + (System.currentTimeMillis() - ts) + " ms" diff --git a/network/src/main/java/io/bitsquare/p2p/peers/BroadcastHandler.java b/network/src/main/java/io/bitsquare/p2p/peers/BroadcastHandler.java index 54322d88f22..7897f70fa08 100644 --- a/network/src/main/java/io/bitsquare/p2p/peers/BroadcastHandler.java +++ b/network/src/main/java/io/bitsquare/p2p/peers/BroadcastHandler.java @@ -126,7 +126,7 @@ public void broadcast(BroadcastMessage message, @Nullable NodeAddress sender, Re onFault(errorMessage, false); }, timeoutDelay); - log.info("Broadcast message to {} peers out of {} total connected peers.", numOfPeers, connectedPeersSet.size()); + log.debug("Broadcast message to {} peers out of {} total connected peers.", numOfPeers, connectedPeersSet.size()); for (int i = 0; i < numOfPeers; i++) { if (stopped) break; // do not continue sending after a timeout or a cancellation @@ -181,7 +181,7 @@ public void onSuccess(Connection connection) { public void onFailure(@NotNull Throwable throwable) { numOfFailedBroadcasts++; if (!stopped) { - log.info("Broadcast to " + nodeAddress + " failed.\n\t" + + log.debug("Broadcast to " + nodeAddress + " failed.\n\t" + "ErrorMessage=" + throwable.getMessage()); if (numOfCompletedBroadcasts + numOfFailedBroadcasts == numOfPeers) onFault("stopped at onFailure: " + errorMessage); @@ -241,7 +241,7 @@ private void onFault(String errorMessage, boolean logWarning) { if (logWarning) log.warn(errorMessage); else - log.trace(errorMessage); + log.debug(errorMessage); if (listener != null) listener.onBroadcastFailed(errorMessage); diff --git a/network/src/main/java/io/bitsquare/p2p/peers/PeerManager.java b/network/src/main/java/io/bitsquare/p2p/peers/PeerManager.java index 83fbc36641d..394499b5b42 100644 --- a/network/src/main/java/io/bitsquare/p2p/peers/PeerManager.java +++ b/network/src/main/java/io/bitsquare/p2p/peers/PeerManager.java @@ -97,7 +97,7 @@ public PeerManager(NetworkNode networkNode, int maxConnections, Set dbStorage = new Storage<>(storageDir); HashSet persistedPeers = dbStorage.initAndGetPersistedWithFileName("PersistedPeers"); if (persistedPeers != null) { - log.info("We have persisted reported peers. persistedPeers.size()=" + persistedPeers.size()); + log.debug("We have persisted reported peers. persistedPeers.size()=" + persistedPeers.size()); this.persistedPeers.addAll(persistedPeers); } @@ -114,7 +114,7 @@ public void onMinuteTick() { @Override public void onMissedSecondTick(long missed) { if (missed > Clock.IDLE_TOLERANCE) { - log.warn("We have been in standby mode for {} sec", missed / 1000); + log.info("We have been in standby mode for {} sec", missed / 1000); stopped = false; listeners.stream().forEach(Listener::onAwakeFromStandby); } @@ -162,8 +162,7 @@ public void onConnection(Connection connection) { final boolean seedNode = isSeedNode(connection); final Optional addressOptional = connection.getPeersNodeAddressOptional(); - log.warn("++ Connection created: peer = {}{}", (addressOptional.isPresent() ? addressOptional.get().hostName : "unknown address"), seedNode ? " (SeedNode)" : ""); - + log.info("onConnection: peer = {}{}", (addressOptional.isPresent() ? addressOptional.get().hostName : "unknown address"), seedNode ? " (SeedNode)" : ""); if (seedNode) connection.setPeerType(Connection.PeerType.SEED_NODE); @@ -185,7 +184,7 @@ public void onDisconnect(CloseConnectionReason closeConnectionReason, Connection " / closeConnectionReason: " + closeConnectionReason); final Optional addressOptional = connection.getPeersNodeAddressOptional(); - log.warn("-- Connection closed: peer = {}{}", (addressOptional.isPresent() ? addressOptional.get().hostName : "unknown address"), isSeedNode(connection) ? " (SeedNode)" : ""); + log.info("onDisconnect: peer = {}{}", (addressOptional.isPresent() ? addressOptional.get().hostName : "not known yet"), isSeedNode(connection) ? " (SeedNode)" : ""); handleConnectionFault(connection); @@ -239,10 +238,10 @@ private boolean checkMaxConnections(int limit) { Log.traceCall("limit=" + limit); Set allConnections = networkNode.getAllConnections(); int size = allConnections.size(); - log.info("We have {} connections open. Our limit is {}", size, limit); + log.debug("We have {} connections open. Our limit is {}", size, limit); if (size > limit) { - log.info("We have too many connections open.\n\t" + + log.debug("We have too many connections open.\n\t" + "Lets try first to remove the inbound connections of type PEER."); List candidates = allConnections.stream() .filter(e -> e instanceof InboundConnection) @@ -250,28 +249,28 @@ private boolean checkMaxConnections(int limit) { .collect(Collectors.toList()); if (candidates.size() == 0) { - log.info("No candidates found. We check if we exceed our " + + log.debug("No candidates found. We check if we exceed our " + "maxConnectionsPeer limit of {}", maxConnectionsPeer); if (size > maxConnectionsPeer) { - log.info("Lets try to remove ANY connection of type PEER."); + log.debug("Lets try to remove ANY connection of type PEER."); candidates = allConnections.stream() .filter(e -> e.getPeerType() == Connection.PeerType.PEER) .collect(Collectors.toList()); if (candidates.size() == 0) { - log.info("No candidates found. We check if we exceed our " + + log.debug("No candidates found. We check if we exceed our " + "maxConnectionsNonDirect limit of {}", maxConnectionsNonDirect); if (size > maxConnectionsNonDirect) { - log.info("Lets try to remove any connection which is not of type DIRECT_MSG_PEER."); + log.debug("Lets try to remove any connection which is not of type DIRECT_MSG_PEER."); candidates = allConnections.stream() .filter(e -> e.getPeerType() != Connection.PeerType.DIRECT_MSG_PEER) .collect(Collectors.toList()); if (candidates.size() == 0) { - log.info("No candidates found. We check if we exceed our " + + log.debug("No candidates found. We check if we exceed our " + "maxConnectionsAbsolute limit of {}", maxConnectionsAbsolute); if (size > maxConnectionsAbsolute) { - log.info("Lets try to remove any connection."); + log.debug("Lets try to remove any connection."); candidates = allConnections.stream().collect(Collectors.toList()); } } @@ -282,9 +281,9 @@ private boolean checkMaxConnections(int limit) { if (candidates.size() > 0) { candidates.sort((o1, o2) -> ((Long) o1.getStatistic().getLastActivityTimestamp()).compareTo(((Long) o2.getStatistic().getLastActivityTimestamp()))); - log.info("Candidates.size() for shut down=" + candidates.size()); + log.debug("Candidates.size() for shut down=" + candidates.size()); Connection connection = candidates.remove(0); - log.info("We are going to shut down the oldest connection.\n\tconnection=" + connection.toString()); + log.debug("We are going to shut down the oldest connection.\n\tconnection=" + connection.toString()); if (!connection.isStopped()) connection.shutDown(CloseConnectionReason.TOO_MANY_CONNECTIONS_OPEN, () -> checkMaxConnections(limit)); return true; @@ -307,7 +306,7 @@ private void removeAnonymousPeers() { .forEach(connection -> UserThread.runAfter(() -> { // We give 30 seconds delay and check again if still no address is set if (!connection.hasPeersNodeAddress() && !connection.isStopped()) { - log.info("We close the connection as the peer address is still unknown.\n\t" + + log.debug("We close the connection as the peer address is still unknown.\n\t" + "connection=" + connection); connection.shutDown(CloseConnectionReason.UNKNOWN_PEER_ADDRESS); } @@ -325,9 +324,9 @@ private void removeSuperfluousSeedNodes() { if (candidates.size() > 1) { candidates.sort((o1, o2) -> ((Long) o1.getStatistic().getLastActivityTimestamp()).compareTo(((Long) o2.getStatistic().getLastActivityTimestamp()))); - log.info("Number of connections exceeding MAX_CONNECTIONS_EXTENDED_1. Current size=" + candidates.size()); + log.debug("Number of connections exceeding MAX_CONNECTIONS_EXTENDED_1. Current size=" + candidates.size()); Connection connection = candidates.remove(0); - log.info("We are going to shut down the oldest connection.\n\tconnection=" + connection.toString()); + log.debug("We are going to shut down the oldest connection.\n\tconnection=" + connection.toString()); connection.shutDown(CloseConnectionReason.TOO_MANY_SEED_NODES_CONNECTED, this::removeSuperfluousSeedNodes); } } @@ -383,7 +382,7 @@ public void addToReportedPeers(HashSet reportedPeersToAdd, Connection conn persistedPeers.addAll(reportedPeersToAdd); purgePersistedPeersIfExceeds(); if (dbStorage != null) - dbStorage.queueUpForSave(persistedPeers, 2000); + dbStorage.queueUpForSave(new HashSet<>(persistedPeers), 2000); // We clone it to avoid ConcurrentModificationExceptions at save printReportedPeers(); } else { @@ -423,7 +422,7 @@ private void printReportedPeers() { result.append("\n------------------------------------------------------------\n"); log.debug(result.toString()); } - log.info("Number of collected reported peers: {}", reportedPeers.size()); + log.debug("Number of collected reported peers: {}", reportedPeers.size()); } } @@ -434,7 +433,7 @@ private void printNewReportedPeers(HashSet reportedPeers) { reportedPeersClone.stream().forEach(e -> result.append("\n\t").append(e)); log.debug(result.toString()); } - log.info("Number of new arrived reported peers: {}", reportedPeers.size()); + log.debug("Number of new arrived reported peers: {}", reportedPeers.size()); } @@ -447,7 +446,7 @@ private boolean removePersistedPeer(Peer persistedPeer) { persistedPeers.remove(persistedPeer); if (dbStorage != null) - dbStorage.queueUpForSave(persistedPeers, 2000); + dbStorage.queueUpForSave(new HashSet<>(persistedPeers), 2000); return true; } else { @@ -612,7 +611,7 @@ private void printConnectedPeers() { networkNode.getConfirmedConnections().stream().forEach(e -> result.append("\n") .append(e.getPeersNodeAddressOptional().get()).append(" ").append(e.getPeerType())); result.append("\n------------------------------------------------------------\n"); - log.info(result.toString()); + log.debug(result.toString()); } } } diff --git a/network/src/main/java/io/bitsquare/p2p/peers/getdata/GetDataRequestHandler.java b/network/src/main/java/io/bitsquare/p2p/peers/getdata/GetDataRequestHandler.java index 150e4425964..70d70a5eb1f 100644 --- a/network/src/main/java/io/bitsquare/p2p/peers/getdata/GetDataRequestHandler.java +++ b/network/src/main/java/io/bitsquare/p2p/peers/getdata/GetDataRequestHandler.java @@ -152,7 +152,7 @@ public void stop() { private void handleFault(String errorMessage, CloseConnectionReason closeConnectionReason, Connection connection) { if (!stopped) { - log.info(errorMessage + "\n\tcloseConnectionReason=" + closeConnectionReason); + log.debug(errorMessage + "\n\tcloseConnectionReason=" + closeConnectionReason); cleanup(); listener.onFault(errorMessage, connection); } else { diff --git a/network/src/main/java/io/bitsquare/p2p/peers/getdata/RequestDataHandler.java b/network/src/main/java/io/bitsquare/p2p/peers/getdata/RequestDataHandler.java index 353a18db095..55648bb2438 100644 --- a/network/src/main/java/io/bitsquare/p2p/peers/getdata/RequestDataHandler.java +++ b/network/src/main/java/io/bitsquare/p2p/peers/getdata/RequestDataHandler.java @@ -18,12 +18,13 @@ import io.bitsquare.p2p.peers.getdata.messages.GetUpdatedDataRequest; import io.bitsquare.p2p.peers.getdata.messages.PreliminaryGetDataRequest; import io.bitsquare.p2p.storage.P2PDataStorage; +import io.bitsquare.p2p.storage.payload.StoragePayload; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Random; +import java.util.*; import static com.google.common.base.Preconditions.checkArgument; @@ -93,7 +94,7 @@ public void requestData(NodeAddress nodeAddress) { if (!stopped) { String errorMessage = "A timeout occurred at sending getDataRequest:" + getDataRequest + " on nodeAddress:" + nodeAddress; - log.info(errorMessage + " / RequestDataHandler=" + RequestDataHandler.this); + log.debug(errorMessage + " / RequestDataHandler=" + RequestDataHandler.this); handleFault(errorMessage, nodeAddress, CloseConnectionReason.SEND_MSG_TIMEOUT); } else { log.trace("We have stopped already. We ignore that timeoutTimer.run call. " + @@ -103,7 +104,7 @@ public void requestData(NodeAddress nodeAddress) { TIME_OUT_SEC); } - log.info("We send a {} to peer {}. ", getDataRequest.getClass().getSimpleName(), nodeAddress); + log.debug("We send a {} to peer {}. ", getDataRequest.getClass().getSimpleName(), nodeAddress); SettableFuture future = networkNode.sendMessage(nodeAddress, getDataRequest); Futures.addCallback(future, new FutureCallback() { @Override @@ -125,7 +126,7 @@ public void onFailure(@NotNull Throwable throwable) { " failed. That is expected if the peer is offline.\n\t" + "getDataRequest=" + getDataRequest + "." + "\n\tException=" + throwable.getMessage(); - log.info(errorMessage); + log.debug(errorMessage); handleFault(errorMessage, nodeAddress, CloseConnectionReason.SEND_MSG_FAILURE); } else { log.trace("We have stopped already. We ignore that networkNode.sendMessage.onFailure call. " + @@ -149,6 +150,19 @@ public void onMessage(Message message, Connection connection) { Log.traceCall(message.toString() + "\n\tconnection=" + connection); if (!stopped) { GetDataResponse getDataResponse = (GetDataResponse) message; + Map> payloadByClassName = new HashMap<>(); + getDataResponse.dataSet.stream().forEach(e -> { + final StoragePayload storagePayload = e.getStoragePayload(); + String className = storagePayload.getClass().getSimpleName(); + if (!payloadByClassName.containsKey(className)) + payloadByClassName.put(className, new HashSet<>()); + + payloadByClassName.get(className).add(storagePayload); + }); + StringBuilder sb = new StringBuilder("Received data size: ").append(getDataResponse.dataSet.size()).append(", data items: "); + payloadByClassName.entrySet().stream().forEach(e -> sb.append(e.getValue().size()).append(" items of ").append(e.getKey()).append("; ")); + log.info(sb.toString()); + if (getDataResponse.requestNonce == nonce) { stopTimeoutTimer(); checkArgument(connection.getPeersNodeAddressOptional().isPresent(), @@ -156,7 +170,7 @@ public void onMessage(Message message, Connection connection) { "at that moment"); final NodeAddress sender = connection.getPeersNodeAddressOptional().get(); - ((GetDataResponse) message).dataSet.stream().forEach(protectedStorageEntry -> { + getDataResponse.dataSet.stream().forEach(protectedStorageEntry -> { // We dont broadcast here as we are only connected to the seed node and would be pointless dataStorage.add(protectedStorageEntry, sender, null, false, false); }); diff --git a/network/src/main/java/io/bitsquare/p2p/peers/getdata/RequestDataManager.java b/network/src/main/java/io/bitsquare/p2p/peers/getdata/RequestDataManager.java index 68c348f4855..dc9ac896913 100644 --- a/network/src/main/java/io/bitsquare/p2p/peers/getdata/RequestDataManager.java +++ b/network/src/main/java/io/bitsquare/p2p/peers/getdata/RequestDataManager.java @@ -277,13 +277,13 @@ public void onFault(String errorMessage, @Nullable Connection connection) { handlerMap.remove(nodeAddress); if (!remainingNodeAddresses.isEmpty()) { - log.info("There are remaining nodes available for requesting data. " + + log.debug("There are remaining nodes available for requesting data. " + "We will try requestDataFromPeers again."); NodeAddress nextCandidate = remainingNodeAddresses.get(0); remainingNodeAddresses.remove(nextCandidate); requestData(nextCandidate, remainingNodeAddresses); } else { - log.info("There is no remaining node available for requesting data. " + + log.debug("There is no remaining node available for requesting data. " + "That is expected if no other node is online.\n\t" + "We will try to use reported peers (if no available we use persisted peers) " + "and try again to request data from our seed nodes after a random pause."); diff --git a/network/src/main/java/io/bitsquare/p2p/peers/keepalive/KeepAliveHandler.java b/network/src/main/java/io/bitsquare/p2p/peers/keepalive/KeepAliveHandler.java index a270c649477..a05b4140592 100644 --- a/network/src/main/java/io/bitsquare/p2p/peers/keepalive/KeepAliveHandler.java +++ b/network/src/main/java/io/bitsquare/p2p/peers/keepalive/KeepAliveHandler.java @@ -100,7 +100,7 @@ public void onFailure(@NotNull Throwable throwable) { String errorMessage = "Sending ping to " + connection + " failed. That is expected if the peer is offline.\n\tping=" + ping + ".\n\tException=" + throwable.getMessage(); - log.info(errorMessage); + log.debug(errorMessage); cleanup(); //peerManager.shutDownConnection(connection, CloseConnectionReason.SEND_MSG_FAILURE); peerManager.handleConnectionFault(connection); diff --git a/network/src/main/java/io/bitsquare/p2p/peers/keepalive/KeepAliveManager.java b/network/src/main/java/io/bitsquare/p2p/peers/keepalive/KeepAliveManager.java index a695ad8e158..86c4cb658c0 100644 --- a/network/src/main/java/io/bitsquare/p2p/peers/keepalive/KeepAliveManager.java +++ b/network/src/main/java/io/bitsquare/p2p/peers/keepalive/KeepAliveManager.java @@ -93,7 +93,7 @@ public void onFailure(@NotNull Throwable throwable) { String errorMessage = "Sending pong to " + connection + " failed. That is expected if the peer is offline. pong=" + pong + "." + "Exception: " + throwable.getMessage(); - log.info(errorMessage); + log.debug(errorMessage); peerManager.handleConnectionFault(connection); } else { log.warn("We have stopped already. We ignore that networkNode.sendMessage.onFailure call."); @@ -200,7 +200,7 @@ public void onFault(String errorMessage) { }); int size = handlerMap.size(); - log.info("handlerMap size=" + size); + log.debug("handlerMap size=" + size); if (size > peerManager.getMaxConnections()) log.warn("Seems we didn't clean up out map correctly.\n" + "handlerMap size={}, peerManager.getMaxConnections()={}", size, peerManager.getMaxConnections()); diff --git a/network/src/main/java/io/bitsquare/p2p/peers/peerexchange/GetPeersRequestHandler.java b/network/src/main/java/io/bitsquare/p2p/peers/peerexchange/GetPeersRequestHandler.java index 580fe492c76..32a9b8b0087 100644 --- a/network/src/main/java/io/bitsquare/p2p/peers/peerexchange/GetPeersRequestHandler.java +++ b/network/src/main/java/io/bitsquare/p2p/peers/peerexchange/GetPeersRequestHandler.java @@ -75,9 +75,9 @@ public void handle(GetPeersRequest getPeersRequest, final Connection connection) timeoutTimer = UserThread.runAfter(() -> { // setup before sending to avoid race conditions if (!stopped) { String errorMessage = "A timeout occurred at sending getPeersResponse:" + getPeersResponse + " on connection:" + connection; - log.info(errorMessage + " / PeerExchangeHandshake=" + + log.debug(errorMessage + " / PeerExchangeHandshake=" + GetPeersRequestHandler.this); - log.info("timeoutTimer called. this=" + this); + log.debug("timeoutTimer called. this=" + this); handleFault(errorMessage, CloseConnectionReason.SEND_MSG_TIMEOUT, connection); } else { log.trace("We have stopped already. We ignore that timeoutTimer.run call."); @@ -105,7 +105,7 @@ public void onFailure(@NotNull Throwable throwable) { String errorMessage = "Sending getPeersResponse to " + connection + " failed. That is expected if the peer is offline. getPeersResponse=" + getPeersResponse + "." + "Exception: " + throwable.getMessage(); - log.info(errorMessage); + log.debug(errorMessage); handleFault(errorMessage, CloseConnectionReason.SEND_MSG_FAILURE, connection); } else { log.trace("We have stopped already. We ignore that networkNode.sendMessage.onFailure call."); diff --git a/network/src/main/java/io/bitsquare/p2p/peers/peerexchange/PeerExchangeHandler.java b/network/src/main/java/io/bitsquare/p2p/peers/peerexchange/PeerExchangeHandler.java index 4aab9de3be2..f675caf2902 100644 --- a/network/src/main/java/io/bitsquare/p2p/peers/peerexchange/PeerExchangeHandler.java +++ b/network/src/main/java/io/bitsquare/p2p/peers/peerexchange/PeerExchangeHandler.java @@ -89,9 +89,9 @@ private void sendGetPeersRequest(NodeAddress nodeAddress) { timeoutTimer = UserThread.runAfter(() -> { // setup before sending to avoid race conditions if (!stopped) { String errorMessage = "A timeout occurred at sending getPeersRequest:" + getPeersRequest + " for nodeAddress:" + nodeAddress; - log.info(errorMessage + " / PeerExchangeHandler=" + + log.debug(errorMessage + " / PeerExchangeHandler=" + PeerExchangeHandler.this); - log.info("timeoutTimer called on " + this); + log.debug("timeoutTimer called on " + this); handleFault(errorMessage, CloseConnectionReason.SEND_MSG_TIMEOUT, nodeAddress); } else { log.trace("We have stopped that handler already. We ignore that timeoutTimer.run call."); @@ -125,7 +125,7 @@ public void onFailure(@NotNull Throwable throwable) { String errorMessage = "Sending getPeersRequest to " + nodeAddress + " failed. That is expected if the peer is offline.\n\tgetPeersRequest=" + getPeersRequest + ".\n\tException=" + throwable.getMessage(); - log.info(errorMessage); + log.debug(errorMessage); handleFault(errorMessage, CloseConnectionReason.SEND_MSG_FAILURE, nodeAddress); } else { log.trace("We have stopped that handler already. We ignore that sendGetPeersRequest.onFailure call."); diff --git a/network/src/main/java/io/bitsquare/p2p/peers/peerexchange/PeerExchangeManager.java b/network/src/main/java/io/bitsquare/p2p/peers/peerexchange/PeerExchangeManager.java index 9fba6ded065..df9531346e2 100644 --- a/network/src/main/java/io/bitsquare/p2p/peers/peerexchange/PeerExchangeManager.java +++ b/network/src/main/java/io/bitsquare/p2p/peers/peerexchange/PeerExchangeManager.java @@ -202,17 +202,17 @@ public void onFault(String errorMessage, @Nullable Connection connection) { handlerMap.remove(nodeAddress); if (!remainingNodeAddresses.isEmpty()) { if (!peerManager.hasSufficientConnections()) { - log.info("There are remaining nodes available for requesting peers. " + + log.debug("There are remaining nodes available for requesting peers. " + "We will try getReportedPeers again."); NodeAddress nextCandidate = remainingNodeAddresses.get(new Random().nextInt(remainingNodeAddresses.size())); remainingNodeAddresses.remove(nextCandidate); requestReportedPeers(nextCandidate, remainingNodeAddresses); } else { // That path will rarely be reached - log.info("We have already sufficient connections."); + log.debug("We have already sufficient connections."); } } else { - log.info("There is no remaining node available for requesting peers. " + + log.debug("There is no remaining node available for requesting peers. " + "That is expected if no other node is online.\n\t" + "We will try again after a pause."); if (retryTimer == null) @@ -259,7 +259,7 @@ private void requestWithAvailablePeers() { Collections.shuffle(filteredSeedNodeAddresses); list.addAll(filteredSeedNodeAddresses); - log.info("Number of peers in list for connectToMorePeers: {}", list.size()); + log.debug("Number of peers in list for connectToMorePeers: {}", list.size()); log.trace("Filtered connectToMorePeers list: list=" + list); if (!list.isEmpty()) { // Dont shuffle as we want the seed nodes at the last entries @@ -267,7 +267,7 @@ private void requestWithAvailablePeers() { list.remove(nextCandidate); requestReportedPeers(nextCandidate, list); } else { - log.info("No more peers are available for requestReportedPeers. We will try again after a pause."); + log.debug("No more peers are available for requestReportedPeers. We will try again after a pause."); if (retryTimer == null) retryTimer = UserThread.runAfter(() -> { if (!stopped) { @@ -281,7 +281,7 @@ private void requestWithAvailablePeers() { }, RETRY_DELAY_SEC); } } else { - log.info("We have already sufficient connections."); + log.debug("We have already sufficient connections."); } } else { log.trace("We have stopped already. We ignore that requestWithAvailablePeers call."); diff --git a/network/src/main/java/io/bitsquare/p2p/seed/SeedNodesRepository.java b/network/src/main/java/io/bitsquare/p2p/seed/SeedNodesRepository.java index 097a46ab2e1..e5eaea40df5 100644 --- a/network/src/main/java/io/bitsquare/p2p/seed/SeedNodesRepository.java +++ b/network/src/main/java/io/bitsquare/p2p/seed/SeedNodesRepository.java @@ -87,7 +87,7 @@ public Set getSeedNodeAddresses(boolean useLocalhost, int networkId .filter(e -> String.valueOf(e.port).endsWith(networkIdAsString)) .filter(e -> !e.equals(nodeAddressToExclude)) .collect(Collectors.toSet()); - log.info("SeedNodeAddresses (useLocalhost={}) for networkId {}:\nnetworkId={}", useLocalhost, networkId, filtered); + log.debug("SeedNodeAddresses (useLocalhost={}) for networkId {}:\nnetworkId={}", useLocalhost, networkId, filtered); return filtered; } diff --git a/network/src/main/java/io/bitsquare/p2p/storage/P2PDataStorage.java b/network/src/main/java/io/bitsquare/p2p/storage/P2PDataStorage.java index 03cadccbc7f..05d98515827 100644 --- a/network/src/main/java/io/bitsquare/p2p/storage/P2PDataStorage.java +++ b/network/src/main/java/io/bitsquare/p2p/storage/P2PDataStorage.java @@ -28,6 +28,7 @@ import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.spongycastle.util.encoders.Hex; import javax.annotation.Nullable; import java.io.File; @@ -98,7 +99,7 @@ public void onBootstrapComplete() { ByteArray hashOfPayload = entry.getKey(); ProtectedStorageEntry protectedStorageEntry = map.get(hashOfPayload); toRemoveSet.add(protectedStorageEntry); - log.info("We found an expired data entry. We remove the protectedData:\n\t" + Utilities.toTruncatedString(protectedStorageEntry)); + log.debug("We found an expired data entry. We remove the protectedData:\n\t" + Utilities.toTruncatedString(protectedStorageEntry)); map.remove(hashOfPayload); }); @@ -160,7 +161,7 @@ public void onDisconnect(CloseConnectionReason closeConnectionReason, Connection ByteArray hashOfPayload = getHashAsByteArray(expirablePayload); boolean containsKey = map.containsKey(hashOfPayload); if (containsKey) { - log.info("We remove the data as the data owner got disconnected with " + + log.debug("We remove the data as the data owner got disconnected with " + "closeConnectionReason=" + closeConnectionReason); Log.logIfStressTests("We remove the data as the data owner got disconnected with " + @@ -234,7 +235,7 @@ && checkSignature(protectedStorageEntry) if (hasSequenceNrIncreased) { sequenceNumberMap.put(hashOfPayload, new MapValue(protectedStorageEntry.sequenceNumber, System.currentTimeMillis())); // We set the delay higher as we might receive a batch of items - storage.queueUpForSave(sequenceNumberMap, 2000); + storage.queueUpForSave(new HashMap<>(sequenceNumberMap), 2000); if (allowBroadcast) broadcast(new AddDataMessage(protectedStorageEntry), sender, listener, isDataOwner); @@ -278,7 +279,7 @@ public boolean refreshTTL(RefreshTTLMessage refreshTTLMessage, @Nullable NodeAdd storedData.updateSignature(signature); printData("after refreshTTL"); sequenceNumberMap.put(hashOfPayload, new MapValue(sequenceNumber, System.currentTimeMillis())); - storage.queueUpForSave(sequenceNumberMap, 1000); + storage.queueUpForSave(new HashMap<>(sequenceNumberMap), 1000); broadcast(refreshTTLMessage, sender, null, isDataOwner); } @@ -307,7 +308,7 @@ && checkSignature(protectedStorageEntry) doRemoveProtectedExpirableData(protectedStorageEntry, hashOfPayload); printData("after remove"); sequenceNumberMap.put(hashOfPayload, new MapValue(protectedStorageEntry.sequenceNumber, System.currentTimeMillis())); - storage.queueUpForSave(sequenceNumberMap, 300); + storage.queueUpForSave(new HashMap<>(sequenceNumberMap), 300); broadcast(new RemoveDataMessage(protectedStorageEntry), sender, null, isDataOwner); } else { @@ -334,7 +335,7 @@ && checkSignature(protectedMailboxStorageEntry) doRemoveProtectedExpirableData(protectedMailboxStorageEntry, hashOfData); printData("after removeMailboxData"); sequenceNumberMap.put(hashOfData, new MapValue(protectedMailboxStorageEntry.sequenceNumber, System.currentTimeMillis())); - storage.queueUpForSave(sequenceNumberMap, 300); + storage.queueUpForSave(new HashMap<>(sequenceNumberMap), 300); broadcast(new RemoveMailboxDataMessage(protectedMailboxStorageEntry), sender, null, isDataOwner); } else { @@ -415,6 +416,8 @@ private boolean isSequenceNrValid(int newSequenceNumber, ByteArray hashOfData) { if (sequenceNumberMap.containsKey(hashOfData)) { int storedSequenceNumber = sequenceNumberMap.get(hashOfData).sequenceNr; if (newSequenceNumber >= storedSequenceNumber) { + log.trace("Sequence number is valid (>=). sequenceNumber = " + + newSequenceNumber + " / storedSequenceNumber=" + storedSequenceNumber); return true; } else { log.debug("Sequence number is invalid. sequenceNumber = " @@ -423,6 +426,7 @@ private boolean isSequenceNrValid(int newSequenceNumber, ByteArray hashOfData) { return false; } } else { + log.trace("Sequence number is valid (!sequenceNumberMap.containsKey(hashOfData)). sequenceNumber = " + newSequenceNumber); return true; } } @@ -431,6 +435,8 @@ private boolean hasSequenceNrIncreased(int newSequenceNumber, ByteArray hashOfDa if (sequenceNumberMap.containsKey(hashOfData)) { int storedSequenceNumber = sequenceNumberMap.get(hashOfData).sequenceNr; if (newSequenceNumber > storedSequenceNumber) { + log.trace("Sequence number has increased (>). sequenceNumber = " + + newSequenceNumber + " / storedSequenceNumber=" + storedSequenceNumber + " / hashOfData=" + hashOfData.toString()); return true; } else if (newSequenceNumber == storedSequenceNumber) { String msg; @@ -450,6 +456,7 @@ private boolean hasSequenceNrIncreased(int newSequenceNumber, ByteArray hashOfDa return false; } } else { + log.trace("Sequence number has increased (!sequenceNumberMap.containsKey(hashOfData)). sequenceNumber = " + newSequenceNumber + " / hashOfData=" + hashOfData.toString()); return true; } } @@ -589,7 +596,7 @@ private void printData(String info) { }); sb.append("\n------------------------------------------------------------\n"); log.debug(sb.toString()); - log.info("Data set " + info + " operation: size=" + map.values().size()); + log.debug("Data set " + info + " operation: size=" + map.values().size()); } } @@ -652,6 +659,13 @@ public boolean equals(Object o) { public int hashCode() { return bytes != null ? Arrays.hashCode(bytes) : 0; } + + @Override + public String toString() { + return "ByteArray{" + + "bytes as Hex=" + Hex.toHexString(bytes) + + '}'; + } } diff --git a/network/src/test/java/io/bitsquare/p2p/DummySeedNode.java b/network/src/test/java/io/bitsquare/p2p/DummySeedNode.java index 023457a7ac8..18fa8807442 100644 --- a/network/src/test/java/io/bitsquare/p2p/DummySeedNode.java +++ b/network/src/test/java/io/bitsquare/p2p/DummySeedNode.java @@ -82,28 +82,28 @@ public void processArgs(String[] args) { arg = arg.substring(NetworkOptionKeys.MY_ADDRESS.length() + 1); checkArgument(arg.contains(":") && arg.split(":").length == 2 && arg.split(":")[1].length() > 3, "Wrong program argument: " + arg); mySeedNodeAddress = new NodeAddress(arg); - log.info("From processArgs: mySeedNodeAddress=" + mySeedNodeAddress); + log.debug("From processArgs: mySeedNodeAddress=" + mySeedNodeAddress); } else if (arg.startsWith(NetworkOptionKeys.NETWORK_ID)) { arg = arg.substring(NetworkOptionKeys.NETWORK_ID.length() + 1); networkId = Integer.parseInt(arg); - log.info("From processArgs: networkId=" + networkId); + log.debug("From processArgs: networkId=" + networkId); checkArgument(networkId > -1 && networkId < 3, "networkId out of scope (Mainnet = 0, TestNet = 1, Regtest = 2)"); Version.setBtcNetworkId(networkId); } else if (arg.startsWith(NetworkOptionKeys.MAX_CONNECTIONS)) { arg = arg.substring(NetworkOptionKeys.MAX_CONNECTIONS.length() + 1); maxConnections = Integer.parseInt(arg); - log.info("From processArgs: maxConnections=" + maxConnections); + log.debug("From processArgs: maxConnections=" + maxConnections); checkArgument(maxConnections < MAX_CONNECTIONS_LIMIT, "maxConnections seems to be a bit too high..."); } else if (arg.startsWith(NetworkOptionKeys.USE_LOCALHOST)) { arg = arg.substring(NetworkOptionKeys.USE_LOCALHOST.length() + 1); checkArgument(arg.equals("true") || arg.equals("false")); useLocalhost = ("true").equals(arg); - log.info("From processArgs: useLocalhost=" + useLocalhost); + log.debug("From processArgs: useLocalhost=" + useLocalhost); } else if (arg.startsWith(CommonOptionKeys.LOG_LEVEL_KEY)) { arg = arg.substring(CommonOptionKeys.LOG_LEVEL_KEY.length() + 1); logLevel = Level.toLevel(arg.toUpperCase()); - log.info("From processArgs: logLevel=" + logLevel); + log.debug("From processArgs: logLevel=" + logLevel); } else if (arg.startsWith(SEED_NODES_LIST)) { arg = arg.substring(SEED_NODES_LIST.length() + 1); checkArgument(arg.contains(":") && arg.split(":").length > 1 && arg.split(":")[1].length() > 3, @@ -115,7 +115,7 @@ public void processArgs(String[] args) { "Wrong program argument " + e); progArgSeedNodes.add(new NodeAddress(e)); }); - log.info("From processArgs: progArgSeedNodes=" + progArgSeedNodes); + log.debug("From processArgs: progArgSeedNodes=" + progArgSeedNodes); progArgSeedNodes.remove(mySeedNodeAddress); } else if (arg.startsWith(NetworkOptionKeys.BAN_LIST)) { arg = arg.substring(NetworkOptionKeys.BAN_LIST.length() + 1); @@ -127,9 +127,9 @@ public void processArgs(String[] args) { "Wrong program argument " + e); BanList.add(new NodeAddress(e)); }); - log.info("From processArgs: ignoreList=" + list); + log.debug("From processArgs: ignoreList=" + list); } else if (arg.startsWith(HELP)) { - log.info(USAGE); + log.debug(USAGE); } else { log.error("Invalid argument. " + arg + "\n" + USAGE); } @@ -164,7 +164,7 @@ public void createAndStartP2PService(NodeAddress mySeedNodeAddress, String logPath = Paths.get(appPath.toString(), "logs").toString(); Log.setup(logPath); - log.info("Log files under: " + logPath); + log.debug("Log files under: " + logPath); Version.printVersion(); Utilities.printSysInfo(); Log.setLevel(logLevel); @@ -179,11 +179,11 @@ public void createAndStartP2PService(NodeAddress mySeedNodeAddress, File storageDir = Paths.get(appPath.toString(), "db").toFile(); if (storageDir.mkdirs()) - log.info("Created storageDir at " + storageDir.getAbsolutePath()); + log.debug("Created storageDir at " + storageDir.getAbsolutePath()); File torDir = Paths.get(appPath.toString(), "tor").toFile(); if (torDir.mkdirs()) - log.info("Created torDir at " + torDir.getAbsolutePath()); + log.debug("Created torDir at " + torDir.getAbsolutePath()); seedNodesRepository.setNodeAddressToExclude(mySeedNodeAddress); seedNodeP2PService = new P2PService(seedNodesRepository, mySeedNodeAddress.port, maxConnections, diff --git a/package/linux/32bitBuild.sh b/package/linux/32bitBuild.sh index ba66ac61def..bd709b67d29 100644 --- a/package/linux/32bitBuild.sh +++ b/package/linux/32bitBuild.sh @@ -6,7 +6,7 @@ mkdir -p gui/deploy set -e # Edit version -version=0.4.9.1 +version=0.4.9.2 jarFile="/media/sf_vm_shared_ubuntu14_32bit/Bitsquare-$version.jar" jdkfixFile="/media/sf_vm_shared_ubuntu14_32bit/jdkfix-$version.jar" diff --git a/package/linux/64bitBuild.sh b/package/linux/64bitBuild.sh index e93d1eb64d7..993283dec79 100644 --- a/package/linux/64bitBuild.sh +++ b/package/linux/64bitBuild.sh @@ -6,7 +6,7 @@ mkdir -p gui/deploy set -e # Edit version -version=0.4.9.1 +version=0.4.9.2 jarFile="/media/sf_vm_shared_ubuntu/Bitsquare-$version.jar" jdkfixFile="/media/sf_vm_shared_ubuntu/jdkfix-$version.jar" diff --git a/package/mac/create_app.sh b/package/mac/create_app.sh index 3faea57551d..61131206408 100755 --- a/package/mac/create_app.sh +++ b/package/mac/create_app.sh @@ -5,7 +5,7 @@ mkdir -p gui/deploy set -e -version="0.4.9.1" +version="0.4.9.2" mvn clean package -DskipTests -Dmaven.javadoc.skip=true diff --git a/package/mac/finalize.sh b/package/mac/finalize.sh index 35835e2920e..d86a69c7f32 100644 --- a/package/mac/finalize.sh +++ b/package/mac/finalize.sh @@ -1,6 +1,6 @@ #!/bin/bash -version="0.4.9.1" +version="0.4.9.2" target_dir="/Users/mk/Documents/__bitsquare/_releases/$version" src_dir="/Users/mk/Documents/_intellij/bitsquare" diff --git a/package/windows/32bitBuild.bat b/package/windows/32bitBuild.bat index 926e920090e..ce2d898c32d 100644 --- a/package/windows/32bitBuild.bat +++ b/package/windows/32bitBuild.bat @@ -6,7 +6,7 @@ :: 64 bit build :: Needs Inno Setup 5 or later (http://www.jrsoftware.org/isdl.php) -SET version=0.4.9.1 +SET version=0.4.9.2 SET jdk=C:\Program Files\Java\jdk1.8.0_92 SET outdir=\\VBOXSVR\vm_shared_windows_32bit diff --git a/package/windows/64bitBuild.bat b/package/windows/64bitBuild.bat index e650e4c0f1f..0312e9a328e 100644 --- a/package/windows/64bitBuild.bat +++ b/package/windows/64bitBuild.bat @@ -8,7 +8,7 @@ :: Did not get -BjvmOptions=-Xbootclasspath working on windows, but if the jdkfix jar is copied into the jdk/jre dir it will override the default classes -SET version=0.4.9.1 +SET version=0.4.9.2 SET jdk=C:\Program Files\Java\jdk1.8.0_92 SET outdir=\\VBOXSVR\vm_shared_windows diff --git a/package/windows/Bitsquare.iss b/package/windows/Bitsquare.iss index 7858f989318..2a229d3b286 100755 --- a/package/windows/Bitsquare.iss +++ b/package/windows/Bitsquare.iss @@ -3,7 +3,7 @@ [Setup] AppId={{bitsquare}} AppName=Bitsquare -AppVersion=0.4.9.1 +AppVersion=0.4.9.2 AppVerName=Bitsquare AppPublisher=Bitsquare AppComments=Bitsquare diff --git a/pom.xml b/pom.xml index f903c034288..ec29562ce6a 100755 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ io.bitsquare parent pom - 0.4.9.1 + 0.4.9.2 Bitsquare - The decentralized bitcoin exchange https://bitsquare.io diff --git a/seednode/pom.xml b/seednode/pom.xml index 3f7fc07580d..0c20d443011 100644 --- a/seednode/pom.xml +++ b/seednode/pom.xml @@ -5,7 +5,7 @@ parent io.bitsquare - 0.4.9.1 + 0.4.9.2 4.0.0 diff --git a/seednode/src/main/java/io/bitsquare/seednode/SeedNode.java b/seednode/src/main/java/io/bitsquare/seednode/SeedNode.java index 82f4678ecb9..c594edece47 100644 --- a/seednode/src/main/java/io/bitsquare/seednode/SeedNode.java +++ b/seednode/src/main/java/io/bitsquare/seednode/SeedNode.java @@ -126,7 +126,7 @@ public void onRequestCustomBridges(Runnable resultHandler) { public void shutDown() { gracefulShutDown(() -> { - log.info("Shutdown complete"); + log.debug("Shutdown complete"); System.exit(0); }); } @@ -140,7 +140,7 @@ public void gracefulShutDown(ResultHandler resultHandler) { injector.getInstance(P2PService.class).shutDown(() -> { injector.getInstance(WalletService.class).shutDownDone.addListener((ov, o, n) -> { seedNodeModule.close(injector); - log.info("Graceful shutdown completed"); + log.debug("Graceful shutdown completed"); resultHandler.handleResult(); }); injector.getInstance(WalletService.class).shutDown(); @@ -152,7 +152,7 @@ public void gracefulShutDown(ResultHandler resultHandler) { UserThread.runAfter(resultHandler::handleResult, 1); } } catch (Throwable t) { - log.info("App shutdown failed with exception"); + log.debug("App shutdown failed with exception"); t.printStackTrace(); System.exit(1); }