mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-07-26 00:15:18 -04:00
Optimize RefreshTTLMessage, add UIClock
This commit is contained in:
parent
f5a61f9924
commit
79de2bcb11
18 changed files with 241 additions and 224 deletions
17
common/src/main/java/io/bitsquare/common/Clock.java
Normal file
17
common/src/main/java/io/bitsquare/common/Clock.java
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
package io.bitsquare.common;
|
||||||
|
|
||||||
|
public interface Clock {
|
||||||
|
void start();
|
||||||
|
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
void addListener(Listener listener);
|
||||||
|
|
||||||
|
void removeListener(Listener listener);
|
||||||
|
|
||||||
|
interface Listener {
|
||||||
|
void onSecondTick();
|
||||||
|
|
||||||
|
void onMinuteTick();
|
||||||
|
}
|
||||||
|
}
|
|
@ -54,7 +54,8 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
|
||||||
@JsonExclude
|
@JsonExclude
|
||||||
private static final Logger log = LoggerFactory.getLogger(Offer.class);
|
private static final Logger log = LoggerFactory.getLogger(Offer.class);
|
||||||
|
|
||||||
public static final long TTL = TimeUnit.SECONDS.toMillis(60);
|
// public static final long TTL = TimeUnit.SECONDS.toMillis(60);
|
||||||
|
public static final long TTL = TimeUnit.SECONDS.toMillis(10); //TODO
|
||||||
|
|
||||||
public final static String TAC_OFFERER = "When placing that offer I accept that anyone who fulfills my conditions can " +
|
public final static String TAC_OFFERER = "When placing that offer I accept that anyone who fulfills my conditions can " +
|
||||||
"take that offer.";
|
"take that offer.";
|
||||||
|
|
|
@ -30,9 +30,6 @@ import io.bitsquare.p2p.Message;
|
||||||
import io.bitsquare.p2p.NodeAddress;
|
import io.bitsquare.p2p.NodeAddress;
|
||||||
import io.bitsquare.p2p.P2PService;
|
import io.bitsquare.p2p.P2PService;
|
||||||
import io.bitsquare.p2p.messaging.SendDirectMessageListener;
|
import io.bitsquare.p2p.messaging.SendDirectMessageListener;
|
||||||
import io.bitsquare.p2p.network.CloseConnectionReason;
|
|
||||||
import io.bitsquare.p2p.network.Connection;
|
|
||||||
import io.bitsquare.p2p.network.ConnectionListener;
|
|
||||||
import io.bitsquare.p2p.network.NetworkNode;
|
import io.bitsquare.p2p.network.NetworkNode;
|
||||||
import io.bitsquare.storage.Storage;
|
import io.bitsquare.storage.Storage;
|
||||||
import io.bitsquare.trade.TradableList;
|
import io.bitsquare.trade.TradableList;
|
||||||
|
@ -61,6 +58,8 @@ import static io.bitsquare.util.Validator.nonEmptyStringOf;
|
||||||
public class OpenOfferManager {
|
public class OpenOfferManager {
|
||||||
private static final Logger log = LoggerFactory.getLogger(OpenOfferManager.class);
|
private static final Logger log = LoggerFactory.getLogger(OpenOfferManager.class);
|
||||||
|
|
||||||
|
private static final int MAX_MSG_SIZE = 100 * 1024;
|
||||||
|
|
||||||
private final KeyRing keyRing;
|
private final KeyRing keyRing;
|
||||||
private final User user;
|
private final User user;
|
||||||
private final P2PService p2PService;
|
private final P2PService p2PService;
|
||||||
|
@ -78,6 +77,7 @@ public class OpenOfferManager {
|
||||||
private boolean firstTimeConnection;
|
private boolean firstTimeConnection;
|
||||||
private boolean allowRefreshOffers;
|
private boolean allowRefreshOffers;
|
||||||
private boolean lostAllConnections;
|
private boolean lostAllConnections;
|
||||||
|
private long refreshOffersPeriod;
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -125,7 +125,7 @@ public class OpenOfferManager {
|
||||||
|
|
||||||
// TODO: Use check for detecting inactivity instead. run timer and check if elapsed time is in expected range,
|
// TODO: Use check for detecting inactivity instead. run timer and check if elapsed time is in expected range,
|
||||||
// if not we have been in standby and need a republish
|
// if not we have been in standby and need a republish
|
||||||
networkNode.addConnectionListener(new ConnectionListener() {
|
/* networkNode.addConnectionListener(new ConnectionListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onConnection(Connection connection) {
|
public void onConnection(Connection connection) {
|
||||||
if (lostAllConnections) {
|
if (lostAllConnections) {
|
||||||
|
@ -155,7 +155,7 @@ public class OpenOfferManager {
|
||||||
@Override
|
@Override
|
||||||
public void onError(Throwable throwable) {
|
public void onError(Throwable throwable) {
|
||||||
}
|
}
|
||||||
});
|
});*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -197,20 +197,6 @@ public class OpenOfferManager {
|
||||||
//startRepublishOffersThread();
|
//startRepublishOffersThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startRefreshOffersThread() {
|
|
||||||
allowRefreshOffers = true;
|
|
||||||
// refresh sufficiently before offer would expire
|
|
||||||
long period = (long) (Offer.TTL * 0.7);
|
|
||||||
TimerTask timerTask = new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
UserThread.execute(OpenOfferManager.this::refreshOffers);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
timer.scheduleAtFixedRate(timerTask, period, period);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void startRepublishOffersThread() {
|
private void startRepublishOffersThread() {
|
||||||
long period = Offer.TTL * 10;
|
long period = Offer.TTL * 10;
|
||||||
TimerTask timerTask = new TimerTask() {
|
TimerTask timerTask = new TimerTask() {
|
||||||
|
@ -226,12 +212,27 @@ public class OpenOfferManager {
|
||||||
Log.traceCall("Number of offer for republish: " + openOffers.size());
|
Log.traceCall("Number of offer for republish: " + openOffers.size());
|
||||||
for (OpenOffer openOffer : openOffers) {
|
for (OpenOffer openOffer : openOffers) {
|
||||||
offerBookService.republishOffers(openOffer.getOffer(),
|
offerBookService.republishOffers(openOffer.getOffer(),
|
||||||
() -> log.debug("Successful added offer to P2P network"),
|
() -> {
|
||||||
|
log.debug("Successful added offer to P2P network");
|
||||||
|
allowRefreshOffers = true;
|
||||||
|
},
|
||||||
errorMessage -> log.error("Add offer to P2P network failed. " + errorMessage));
|
errorMessage -> log.error("Add offer to P2P network failed. " + errorMessage));
|
||||||
openOffer.setStorage(openOffersStorage);
|
openOffer.setStorage(openOffersStorage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void startRefreshOffersThread() {
|
||||||
|
// refresh sufficiently before offer would expire
|
||||||
|
refreshOffersPeriod = (long) (Offer.TTL * 0.7);
|
||||||
|
TimerTask timerTask = new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
UserThread.execute(OpenOfferManager.this::refreshOffers);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
timer.scheduleAtFixedRate(timerTask, refreshOffersPeriod, refreshOffersPeriod);
|
||||||
|
}
|
||||||
|
|
||||||
private void refreshOffers() {
|
private void refreshOffers() {
|
||||||
if (allowRefreshOffers) {
|
if (allowRefreshOffers) {
|
||||||
Log.traceCall("Number of offer for refresh: " + openOffers.size());
|
Log.traceCall("Number of offer for refresh: " + openOffers.size());
|
||||||
|
|
|
@ -21,10 +21,12 @@ import com.google.inject.Singleton;
|
||||||
import io.bitsquare.alert.AlertModule;
|
import io.bitsquare.alert.AlertModule;
|
||||||
import io.bitsquare.arbitration.ArbitratorModule;
|
import io.bitsquare.arbitration.ArbitratorModule;
|
||||||
import io.bitsquare.btc.BitcoinModule;
|
import io.bitsquare.btc.BitcoinModule;
|
||||||
|
import io.bitsquare.common.Clock;
|
||||||
import io.bitsquare.common.crypto.KeyRing;
|
import io.bitsquare.common.crypto.KeyRing;
|
||||||
import io.bitsquare.common.crypto.KeyStorage;
|
import io.bitsquare.common.crypto.KeyStorage;
|
||||||
import io.bitsquare.crypto.EncryptionServiceModule;
|
import io.bitsquare.crypto.EncryptionServiceModule;
|
||||||
import io.bitsquare.gui.GuiModule;
|
import io.bitsquare.gui.GuiModule;
|
||||||
|
import io.bitsquare.gui.common.UIClock;
|
||||||
import io.bitsquare.gui.common.view.CachingViewLoader;
|
import io.bitsquare.gui.common.view.CachingViewLoader;
|
||||||
import io.bitsquare.gui.main.intructions.InstructionCenter;
|
import io.bitsquare.gui.main.intructions.InstructionCenter;
|
||||||
import io.bitsquare.gui.main.notifications.NotificationCenter;
|
import io.bitsquare.gui.main.notifications.NotificationCenter;
|
||||||
|
@ -62,6 +64,7 @@ class BitsquareAppModule extends AppModule {
|
||||||
bind(Preferences.class).in(Singleton.class);
|
bind(Preferences.class).in(Singleton.class);
|
||||||
bind(NotificationCenter.class).in(Singleton.class);
|
bind(NotificationCenter.class).in(Singleton.class);
|
||||||
bind(InstructionCenter.class).in(Singleton.class);
|
bind(InstructionCenter.class).in(Singleton.class);
|
||||||
|
bind(Clock.class).to(UIClock.class).in(Singleton.class);
|
||||||
|
|
||||||
File storageDir = new File(env.getRequiredProperty(Storage.DIR_KEY));
|
File storageDir = new File(env.getRequiredProperty(Storage.DIR_KEY));
|
||||||
bind(File.class).annotatedWith(named(Storage.DIR_KEY)).toInstance(storageDir);
|
bind(File.class).annotatedWith(named(Storage.DIR_KEY)).toInstance(storageDir);
|
||||||
|
|
52
gui/src/main/java/io/bitsquare/gui/common/UIClock.java
Normal file
52
gui/src/main/java/io/bitsquare/gui/common/UIClock.java
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
package io.bitsquare.gui.common;
|
||||||
|
|
||||||
|
import io.bitsquare.common.Clock;
|
||||||
|
import org.reactfx.util.FxTimer;
|
||||||
|
import org.reactfx.util.Timer;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class UIClock implements Clock {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(UIClock.class);
|
||||||
|
private Timer timer;
|
||||||
|
|
||||||
|
private final List<Listener> listeners = new LinkedList<>();
|
||||||
|
private long counter = 0;
|
||||||
|
|
||||||
|
public UIClock() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
if (timer == null)
|
||||||
|
timer = FxTimer.runPeriodically(Duration.ofSeconds(1), () -> {
|
||||||
|
listeners.stream().forEach(Listener::onSecondTick);
|
||||||
|
counter++;
|
||||||
|
if (counter >= 60) {
|
||||||
|
counter = 0;
|
||||||
|
listeners.stream().forEach(Listener::onMinuteTick);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop() {
|
||||||
|
timer.stop();
|
||||||
|
timer = null;
|
||||||
|
counter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addListener(Listener listener) {
|
||||||
|
listeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeListener(Listener listener) {
|
||||||
|
listeners.remove(listener);
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,6 +32,7 @@ import io.bitsquare.btc.TradeWalletService;
|
||||||
import io.bitsquare.btc.WalletService;
|
import io.bitsquare.btc.WalletService;
|
||||||
import io.bitsquare.btc.listeners.BalanceListener;
|
import io.bitsquare.btc.listeners.BalanceListener;
|
||||||
import io.bitsquare.btc.pricefeed.MarketPriceFeed;
|
import io.bitsquare.btc.pricefeed.MarketPriceFeed;
|
||||||
|
import io.bitsquare.common.Clock;
|
||||||
import io.bitsquare.common.UserThread;
|
import io.bitsquare.common.UserThread;
|
||||||
import io.bitsquare.gui.Navigation;
|
import io.bitsquare.gui.Navigation;
|
||||||
import io.bitsquare.gui.common.model.ViewModel;
|
import io.bitsquare.gui.common.model.ViewModel;
|
||||||
|
@ -93,6 +94,7 @@ public class MainViewModel implements ViewModel {
|
||||||
private final WalletPasswordPopup walletPasswordPopup;
|
private final WalletPasswordPopup walletPasswordPopup;
|
||||||
private final NotificationCenter notificationCenter;
|
private final NotificationCenter notificationCenter;
|
||||||
private final TacPopup tacPopup;
|
private final TacPopup tacPopup;
|
||||||
|
private Clock clock;
|
||||||
private final Navigation navigation;
|
private final Navigation navigation;
|
||||||
private final BSFormatter formatter;
|
private final BSFormatter formatter;
|
||||||
|
|
||||||
|
@ -132,12 +134,12 @@ public class MainViewModel implements ViewModel {
|
||||||
private final MarketPriceFeed marketPriceFeed;
|
private final MarketPriceFeed marketPriceFeed;
|
||||||
private final User user;
|
private final User user;
|
||||||
private int numBTCPeers = 0;
|
private int numBTCPeers = 0;
|
||||||
private Timer checkForBtcSyncStateTimer;
|
|
||||||
private ChangeListener<Number> numConnectedPeersListener, btcNumPeersListener;
|
private ChangeListener<Number> numConnectedPeersListener, btcNumPeersListener;
|
||||||
private java.util.Timer numberOfBtcPeersTimer;
|
private java.util.Timer numberOfBtcPeersTimer;
|
||||||
private java.util.Timer numberOfP2PNetworkPeersTimer;
|
private java.util.Timer numberOfP2PNetworkPeersTimer;
|
||||||
private Timer startupTimeout;
|
private Timer startupTimeout;
|
||||||
private final Map<String, Subscription> disputeIsClosedSubscriptionsMap = new HashMap<>();
|
private final Map<String, Subscription> disputeIsClosedSubscriptionsMap = new HashMap<>();
|
||||||
|
private Subscription downloadPercentageSubscription;
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -150,7 +152,7 @@ public class MainViewModel implements ViewModel {
|
||||||
ArbitratorManager arbitratorManager, P2PService p2PService, TradeManager tradeManager,
|
ArbitratorManager arbitratorManager, P2PService p2PService, TradeManager tradeManager,
|
||||||
OpenOfferManager openOfferManager, DisputeManager disputeManager, Preferences preferences,
|
OpenOfferManager openOfferManager, DisputeManager disputeManager, Preferences preferences,
|
||||||
User user, AlertManager alertManager, WalletPasswordPopup walletPasswordPopup,
|
User user, AlertManager alertManager, WalletPasswordPopup walletPasswordPopup,
|
||||||
NotificationCenter notificationCenter, TacPopup tacPopup,
|
NotificationCenter notificationCenter, TacPopup tacPopup, Clock clock,
|
||||||
Navigation navigation, BSFormatter formatter) {
|
Navigation navigation, BSFormatter formatter) {
|
||||||
this.marketPriceFeed = marketPriceFeed;
|
this.marketPriceFeed = marketPriceFeed;
|
||||||
this.user = user;
|
this.user = user;
|
||||||
|
@ -166,6 +168,7 @@ public class MainViewModel implements ViewModel {
|
||||||
this.walletPasswordPopup = walletPasswordPopup;
|
this.walletPasswordPopup = walletPasswordPopup;
|
||||||
this.notificationCenter = notificationCenter;
|
this.notificationCenter = notificationCenter;
|
||||||
this.tacPopup = tacPopup;
|
this.tacPopup = tacPopup;
|
||||||
|
this.clock = clock;
|
||||||
this.navigation = navigation;
|
this.navigation = navigation;
|
||||||
this.formatter = formatter;
|
this.formatter = formatter;
|
||||||
|
|
||||||
|
@ -215,9 +218,8 @@ public class MainViewModel implements ViewModel {
|
||||||
if (btcNumPeersListener != null)
|
if (btcNumPeersListener != null)
|
||||||
walletService.numPeersProperty().removeListener(btcNumPeersListener);
|
walletService.numPeersProperty().removeListener(btcNumPeersListener);
|
||||||
|
|
||||||
if (checkForBtcSyncStateTimer != null)
|
if (downloadPercentageSubscription != null)
|
||||||
checkForBtcSyncStateTimer.stop();
|
downloadPercentageSubscription.unsubscribe();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -320,7 +322,8 @@ public class MainViewModel implements ViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
private BooleanProperty initBitcoinWallet() {
|
private BooleanProperty initBitcoinWallet() {
|
||||||
EasyBind.subscribe(walletService.downloadPercentageProperty(), newValue -> setBitcoinNetworkSyncProgress((double) newValue));
|
downloadPercentageSubscription = EasyBind.subscribe(walletService.downloadPercentageProperty(),
|
||||||
|
percentage -> setBitcoinNetworkSyncProgress((double) percentage));
|
||||||
|
|
||||||
btcNumPeersListener = (observable, oldValue, newValue) -> {
|
btcNumPeersListener = (observable, oldValue, newValue) -> {
|
||||||
if ((int) oldValue > 0 && (int) newValue == 0) {
|
if ((int) oldValue > 0 && (int) newValue == 0) {
|
||||||
|
@ -340,8 +343,8 @@ public class MainViewModel implements ViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
numBTCPeers = (int) newValue;
|
numBTCPeers = (int) newValue;
|
||||||
setBitcoinNetworkSyncProgress(walletService.downloadPercentageProperty().get());
|
|
||||||
};
|
};
|
||||||
|
|
||||||
walletService.numPeersProperty().addListener(btcNumPeersListener);
|
walletService.numPeersProperty().addListener(btcNumPeersListener);
|
||||||
|
|
||||||
final BooleanProperty walletInitialized = new SimpleBooleanProperty();
|
final BooleanProperty walletInitialized = new SimpleBooleanProperty();
|
||||||
|
@ -357,6 +360,8 @@ public class MainViewModel implements ViewModel {
|
||||||
private void onAllServicesInitialized() {
|
private void onAllServicesInitialized() {
|
||||||
Log.traceCall();
|
Log.traceCall();
|
||||||
|
|
||||||
|
clock.start();
|
||||||
|
|
||||||
startupTimeout.stop();
|
startupTimeout.stop();
|
||||||
|
|
||||||
// disputeManager
|
// disputeManager
|
||||||
|
@ -395,9 +400,6 @@ public class MainViewModel implements ViewModel {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
setBitcoinNetworkSyncProgress(walletService.downloadPercentageProperty().get());
|
|
||||||
checkPeriodicallyForBtcSyncState();
|
|
||||||
|
|
||||||
openOfferManager.getOpenOffers().addListener((ListChangeListener<OpenOffer>) c -> updateBalance());
|
openOfferManager.getOpenOffers().addListener((ListChangeListener<OpenOffer>) c -> updateBalance());
|
||||||
openOfferManager.onAllServicesInitialized();
|
openOfferManager.onAllServicesInitialized();
|
||||||
arbitratorManager.onAllServicesInitialized();
|
arbitratorManager.onAllServicesInitialized();
|
||||||
|
@ -555,19 +557,6 @@ public class MainViewModel implements ViewModel {
|
||||||
typeProperty.bind(marketPriceFeed.typeProperty());
|
typeProperty.bind(marketPriceFeed.typeProperty());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkPeriodicallyForBtcSyncState() {
|
|
||||||
if (walletService.downloadPercentageProperty().get() == -1) {
|
|
||||||
checkForBtcSyncStateTimer = FxTimer.runPeriodically(Duration.ofSeconds(10),
|
|
||||||
() -> {
|
|
||||||
log.info("Bitcoin blockchain sync still not started.");
|
|
||||||
setBitcoinNetworkSyncProgress(walletService.downloadPercentageProperty().get());
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
stopCheckForBtcSyncStateTimer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateP2pNetworkInfoWithPeersChanged(int numPeers) {
|
private void updateP2pNetworkInfoWithPeersChanged(int numPeers) {
|
||||||
p2PNetworkInfo.set("Nr. of P2P network peers: " + numPeers);
|
p2PNetworkInfo.set("Nr. of P2P network peers: " + numPeers);
|
||||||
}
|
}
|
||||||
|
@ -690,12 +679,12 @@ public class MainViewModel implements ViewModel {
|
||||||
btcSplashInfo.set(numPeers + " / synchronized with " + btcNetworkAsString);
|
btcSplashInfo.set(numPeers + " / synchronized with " + btcNetworkAsString);
|
||||||
btcFooterInfo.set(btcSplashInfo.get());
|
btcFooterInfo.set(btcSplashInfo.get());
|
||||||
btcSplashSyncIconId.set("image-connection-synced");
|
btcSplashSyncIconId.set("image-connection-synced");
|
||||||
stopCheckForBtcSyncStateTimer();
|
if (downloadPercentageSubscription != null)
|
||||||
|
downloadPercentageSubscription.unsubscribe();
|
||||||
} else if (value > 0.0) {
|
} else if (value > 0.0) {
|
||||||
String percentage = formatter.formatToPercent(value);
|
String percentage = formatter.formatToPercent(value);
|
||||||
btcSplashInfo.set(numPeers + " / synchronizing with " + btcNetworkAsString + ": " + percentage);
|
btcSplashInfo.set(numPeers + " / synchronizing with " + btcNetworkAsString + ": " + percentage);
|
||||||
btcFooterInfo.set(numPeers + " / synchronizing " + btcNetworkAsString + ": " + percentage);
|
btcFooterInfo.set(numPeers + " / synchronizing " + btcNetworkAsString + ": " + percentage);
|
||||||
stopCheckForBtcSyncStateTimer();
|
|
||||||
} else if (value == -1) {
|
} else if (value == -1) {
|
||||||
btcSplashInfo.set(numPeers + " / connecting to " + btcNetworkAsString);
|
btcSplashInfo.set(numPeers + " / connecting to " + btcNetworkAsString);
|
||||||
btcFooterInfo.set(btcSplashInfo.get());
|
btcFooterInfo.set(btcSplashInfo.get());
|
||||||
|
@ -705,7 +694,6 @@ public class MainViewModel implements ViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setWalletServiceException(Throwable error) {
|
private void setWalletServiceException(Throwable error) {
|
||||||
setBitcoinNetworkSyncProgress(0);
|
|
||||||
btcSplashInfo.set("Nr. of Bitcoin network peers: " + numBTCPeers + " / connecting to " + btcNetworkAsString + " failed");
|
btcSplashInfo.set("Nr. of Bitcoin network peers: " + numBTCPeers + " / connecting to " + btcNetworkAsString + " failed");
|
||||||
btcFooterInfo.set(btcSplashInfo.get());
|
btcFooterInfo.set(btcSplashInfo.get());
|
||||||
if (error instanceof TimeoutException) {
|
if (error instanceof TimeoutException) {
|
||||||
|
@ -722,13 +710,6 @@ public class MainViewModel implements ViewModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stopCheckForBtcSyncStateTimer() {
|
|
||||||
if (checkForBtcSyncStateTimer != null) {
|
|
||||||
checkForBtcSyncStateTimer.stop();
|
|
||||||
checkForBtcSyncStateTimer = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupDevDummyPaymentAccount() {
|
private void setupDevDummyPaymentAccount() {
|
||||||
if (BitsquareApp.DEV_MODE && user.getPaymentAccounts().isEmpty()) {
|
if (BitsquareApp.DEV_MODE && user.getPaymentAccounts().isEmpty()) {
|
||||||
OKPayAccount okPayAccount = new OKPayAccount();
|
OKPayAccount okPayAccount = new OKPayAccount();
|
||||||
|
|
|
@ -20,6 +20,7 @@ package io.bitsquare.gui.main.portfolio.pendingtrades;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import io.bitsquare.app.Log;
|
import io.bitsquare.app.Log;
|
||||||
import io.bitsquare.btc.FeePolicy;
|
import io.bitsquare.btc.FeePolicy;
|
||||||
|
import io.bitsquare.common.Clock;
|
||||||
import io.bitsquare.gui.common.model.ActivatableWithDataModel;
|
import io.bitsquare.gui.common.model.ActivatableWithDataModel;
|
||||||
import io.bitsquare.gui.common.model.ViewModel;
|
import io.bitsquare.gui.common.model.ViewModel;
|
||||||
import io.bitsquare.gui.util.BSFormatter;
|
import io.bitsquare.gui.util.BSFormatter;
|
||||||
|
@ -69,6 +70,7 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
||||||
|
|
||||||
public final P2PService p2PService;
|
public final P2PService p2PService;
|
||||||
public final User user;
|
public final User user;
|
||||||
|
public final Clock clock;
|
||||||
|
|
||||||
private final ObjectProperty<BuyerState> buyerState = new SimpleObjectProperty<>();
|
private final ObjectProperty<BuyerState> buyerState = new SimpleObjectProperty<>();
|
||||||
private final ObjectProperty<SellerState> sellerState = new SimpleObjectProperty<>();
|
private final ObjectProperty<SellerState> sellerState = new SimpleObjectProperty<>();
|
||||||
|
@ -85,14 +87,15 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
||||||
BSFormatter formatter,
|
BSFormatter formatter,
|
||||||
BtcAddressValidator btcAddressValidator,
|
BtcAddressValidator btcAddressValidator,
|
||||||
P2PService p2PService,
|
P2PService p2PService,
|
||||||
User user
|
User user,
|
||||||
) {
|
Clock clock) {
|
||||||
super(dataModel);
|
super(dataModel);
|
||||||
|
|
||||||
this.formatter = formatter;
|
this.formatter = formatter;
|
||||||
this.btcAddressValidator = btcAddressValidator;
|
this.btcAddressValidator = btcAddressValidator;
|
||||||
this.p2PService = p2PService;
|
this.p2PService = p2PService;
|
||||||
this.user = user;
|
this.user = user;
|
||||||
|
this.clock = clock;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ChangeListener<Trade.State> tradeStateChangeListener;
|
private ChangeListener<Trade.State> tradeStateChangeListener;
|
||||||
|
|
|
@ -19,6 +19,7 @@ package io.bitsquare.gui.main.portfolio.pendingtrades.steps;
|
||||||
|
|
||||||
import io.bitsquare.app.Log;
|
import io.bitsquare.app.Log;
|
||||||
import io.bitsquare.arbitration.Dispute;
|
import io.bitsquare.arbitration.Dispute;
|
||||||
|
import io.bitsquare.common.Clock;
|
||||||
import io.bitsquare.gui.components.TitledGroupBg;
|
import io.bitsquare.gui.components.TitledGroupBg;
|
||||||
import io.bitsquare.gui.components.TxIdTextField;
|
import io.bitsquare.gui.components.TxIdTextField;
|
||||||
import io.bitsquare.gui.components.paymentmethods.PaymentMethodForm;
|
import io.bitsquare.gui.components.paymentmethods.PaymentMethodForm;
|
||||||
|
@ -34,12 +35,9 @@ import javafx.scene.layout.AnchorPane;
|
||||||
import javafx.scene.layout.GridPane;
|
import javafx.scene.layout.GridPane;
|
||||||
import org.fxmisc.easybind.EasyBind;
|
import org.fxmisc.easybind.EasyBind;
|
||||||
import org.fxmisc.easybind.Subscription;
|
import org.fxmisc.easybind.Subscription;
|
||||||
import org.reactfx.util.FxTimer;
|
|
||||||
import org.reactfx.util.Timer;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
@ -56,7 +54,6 @@ public abstract class TradeStepView extends AnchorPane {
|
||||||
private Subscription errorMessageSubscription;
|
private Subscription errorMessageSubscription;
|
||||||
private Subscription disputeStateSubscription;
|
private Subscription disputeStateSubscription;
|
||||||
private Subscription tradePeriodStateSubscription;
|
private Subscription tradePeriodStateSubscription;
|
||||||
private Timer timer;
|
|
||||||
protected int gridRow = 0;
|
protected int gridRow = 0;
|
||||||
protected TitledGroupBg tradeInfoTitledGroupBg;
|
protected TitledGroupBg tradeInfoTitledGroupBg;
|
||||||
private TextField timeLeftTextField;
|
private TextField timeLeftTextField;
|
||||||
|
@ -64,6 +61,7 @@ public abstract class TradeStepView extends AnchorPane {
|
||||||
private TxIdTextField txIdTextField;
|
private TxIdTextField txIdTextField;
|
||||||
protected TradeSubView.NotificationGroup notificationGroup;
|
protected TradeSubView.NotificationGroup notificationGroup;
|
||||||
private Subscription txIdSubscription;
|
private Subscription txIdSubscription;
|
||||||
|
private Clock.Listener clockListener;
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -113,7 +111,17 @@ public abstract class TradeStepView extends AnchorPane {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
timer = FxTimer.runPeriodically(Duration.ofMinutes(1), this::updateTimeLeft);
|
clockListener = new Clock.Listener() {
|
||||||
|
@Override
|
||||||
|
public void onSecondTick() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMinuteTick() {
|
||||||
|
updateTimeLeft();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
model.clock.addListener(clockListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deactivate() {
|
public void deactivate() {
|
||||||
|
@ -133,8 +141,8 @@ public abstract class TradeStepView extends AnchorPane {
|
||||||
if (tradePeriodStateSubscription != null)
|
if (tradePeriodStateSubscription != null)
|
||||||
tradePeriodStateSubscription.unsubscribe();
|
tradePeriodStateSubscription.unsubscribe();
|
||||||
|
|
||||||
if (timer != null)
|
if (clockListener != null)
|
||||||
timer.stop();
|
model.clock.removeListener(clockListener);
|
||||||
|
|
||||||
if (notificationGroup != null)
|
if (notificationGroup != null)
|
||||||
notificationGroup.button.setOnAction(null);
|
notificationGroup.button.setOnAction(null);
|
||||||
|
|
|
@ -20,6 +20,7 @@ package io.bitsquare.gui.main.settings.network;
|
||||||
import io.bitsquare.app.BitsquareApp;
|
import io.bitsquare.app.BitsquareApp;
|
||||||
import io.bitsquare.btc.BitcoinNetwork;
|
import io.bitsquare.btc.BitcoinNetwork;
|
||||||
import io.bitsquare.btc.WalletService;
|
import io.bitsquare.btc.WalletService;
|
||||||
|
import io.bitsquare.common.Clock;
|
||||||
import io.bitsquare.gui.common.model.Activatable;
|
import io.bitsquare.gui.common.model.Activatable;
|
||||||
import io.bitsquare.gui.common.view.ActivatableViewAndModel;
|
import io.bitsquare.gui.common.view.ActivatableViewAndModel;
|
||||||
import io.bitsquare.gui.common.view.FxmlView;
|
import io.bitsquare.gui.common.view.FxmlView;
|
||||||
|
@ -52,6 +53,7 @@ public class NetworkSettingsView extends ActivatableViewAndModel<GridPane, Activ
|
||||||
|
|
||||||
private final WalletService walletService;
|
private final WalletService walletService;
|
||||||
private final Preferences preferences;
|
private final Preferences preferences;
|
||||||
|
private Clock clock;
|
||||||
private final BSFormatter formatter;
|
private final BSFormatter formatter;
|
||||||
private final P2PService p2PService;
|
private final P2PService p2PService;
|
||||||
|
|
||||||
|
@ -79,11 +81,12 @@ public class NetworkSettingsView extends ActivatableViewAndModel<GridPane, Activ
|
||||||
private ChangeListener<List<Peer>> bitcoinPeersChangeListener;
|
private ChangeListener<List<Peer>> bitcoinPeersChangeListener;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public NetworkSettingsView(WalletService walletService, P2PService p2PService, Preferences preferences,
|
public NetworkSettingsView(WalletService walletService, P2PService p2PService, Preferences preferences, Clock clock,
|
||||||
BSFormatter formatter) {
|
BSFormatter formatter) {
|
||||||
this.walletService = walletService;
|
this.walletService = walletService;
|
||||||
this.p2PService = p2PService;
|
this.p2PService = p2PService;
|
||||||
this.preferences = preferences;
|
this.preferences = preferences;
|
||||||
|
this.clock = clock;
|
||||||
this.formatter = formatter;
|
this.formatter = formatter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,7 +217,7 @@ public class NetworkSettingsView extends ActivatableViewAndModel<GridPane, Activ
|
||||||
p2PPeerTable.getItems().forEach(NetworkStatisticListItem::cleanup);
|
p2PPeerTable.getItems().forEach(NetworkStatisticListItem::cleanup);
|
||||||
|
|
||||||
List<NetworkStatisticListItem> list = p2PService.getNetworkNode().getConfirmedConnections().stream()
|
List<NetworkStatisticListItem> list = p2PService.getNetworkNode().getConfirmedConnections().stream()
|
||||||
.map(connection -> new NetworkStatisticListItem(connection, formatter))
|
.map(connection -> new NetworkStatisticListItem(connection, clock, formatter))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
p2PPeerTable.setItems(FXCollections.observableArrayList(list));
|
p2PPeerTable.setItems(FXCollections.observableArrayList(list));
|
||||||
p2PPeerTable.sort();
|
p2PPeerTable.sort();
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
package io.bitsquare.gui.main.settings.network;
|
package io.bitsquare.gui.main.settings.network;
|
||||||
|
|
||||||
import io.bitsquare.common.UserThread;
|
import io.bitsquare.common.Clock;
|
||||||
import io.bitsquare.gui.util.BSFormatter;
|
import io.bitsquare.gui.util.BSFormatter;
|
||||||
import io.bitsquare.p2p.network.Connection;
|
import io.bitsquare.p2p.network.Connection;
|
||||||
import io.bitsquare.p2p.network.OutboundConnection;
|
import io.bitsquare.p2p.network.OutboundConnection;
|
||||||
|
@ -27,28 +27,26 @@ import javafx.beans.property.StringProperty;
|
||||||
import org.apache.commons.lang3.time.DurationFormatUtils;
|
import org.apache.commons.lang3.time.DurationFormatUtils;
|
||||||
import org.fxmisc.easybind.EasyBind;
|
import org.fxmisc.easybind.EasyBind;
|
||||||
import org.fxmisc.easybind.Subscription;
|
import org.fxmisc.easybind.Subscription;
|
||||||
import org.reactfx.util.FxTimer;
|
|
||||||
import org.reactfx.util.Timer;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
|
|
||||||
public class NetworkStatisticListItem {
|
public class NetworkStatisticListItem {
|
||||||
private static final Logger log = LoggerFactory.getLogger(NetworkStatisticListItem.class);
|
private static final Logger log = LoggerFactory.getLogger(NetworkStatisticListItem.class);
|
||||||
|
|
||||||
private final Statistic statistic;
|
private final Statistic statistic;
|
||||||
private final Connection connection;
|
private final Connection connection;
|
||||||
private final Subscription sentBytesSubscription, receivedBytesSubscription;
|
private final Subscription sentBytesSubscription, receivedBytesSubscription;
|
||||||
private final Timer timer;
|
private final Clock clock;
|
||||||
private final BSFormatter formatter;
|
private final BSFormatter formatter;
|
||||||
|
|
||||||
private final StringProperty lastActivity = new SimpleStringProperty();
|
private final StringProperty lastActivity = new SimpleStringProperty();
|
||||||
private final StringProperty sentBytes = new SimpleStringProperty();
|
private final StringProperty sentBytes = new SimpleStringProperty();
|
||||||
private final StringProperty receivedBytes = new SimpleStringProperty();
|
private final StringProperty receivedBytes = new SimpleStringProperty();
|
||||||
|
private final Clock.Listener listener;
|
||||||
|
|
||||||
public NetworkStatisticListItem(Connection connection, BSFormatter formatter) {
|
public NetworkStatisticListItem(Connection connection, Clock clock, BSFormatter formatter) {
|
||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
|
this.clock = clock;
|
||||||
this.formatter = formatter;
|
this.formatter = formatter;
|
||||||
this.statistic = connection.getStatistic();
|
this.statistic = connection.getStatistic();
|
||||||
|
|
||||||
|
@ -57,8 +55,18 @@ public class NetworkStatisticListItem {
|
||||||
receivedBytesSubscription = EasyBind.subscribe(statistic.receivedBytesProperty(),
|
receivedBytesSubscription = EasyBind.subscribe(statistic.receivedBytesProperty(),
|
||||||
e -> receivedBytes.set(formatter.formatBytes((int) e)));
|
e -> receivedBytes.set(formatter.formatBytes((int) e)));
|
||||||
|
|
||||||
timer = FxTimer.runPeriodically(Duration.ofMillis(1000),
|
listener = new Clock.Listener() {
|
||||||
() -> UserThread.execute(() -> onLastActivityChanged(statistic.getLastActivityTimestamp())));
|
@Override
|
||||||
|
public void onSecondTick() {
|
||||||
|
onLastActivityChanged(statistic.getLastActivityTimestamp());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMinuteTick() {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
clock.addListener(listener);
|
||||||
onLastActivityChanged(statistic.getLastActivityTimestamp());
|
onLastActivityChanged(statistic.getLastActivityTimestamp());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +77,7 @@ public class NetworkStatisticListItem {
|
||||||
public void cleanup() {
|
public void cleanup() {
|
||||||
sentBytesSubscription.unsubscribe();
|
sentBytesSubscription.unsubscribe();
|
||||||
receivedBytesSubscription.unsubscribe();
|
receivedBytesSubscription.unsubscribe();
|
||||||
timer.stop();
|
clock.removeListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getOnionAddress() {
|
public String getOnionAddress() {
|
||||||
|
|
|
@ -24,8 +24,12 @@ import io.bitsquare.p2p.peers.peerexchange.PeerExchangeManager;
|
||||||
import io.bitsquare.p2p.seed.SeedNodesRepository;
|
import io.bitsquare.p2p.seed.SeedNodesRepository;
|
||||||
import io.bitsquare.p2p.storage.HashMapChangedListener;
|
import io.bitsquare.p2p.storage.HashMapChangedListener;
|
||||||
import io.bitsquare.p2p.storage.P2PDataStorage;
|
import io.bitsquare.p2p.storage.P2PDataStorage;
|
||||||
import io.bitsquare.p2p.storage.data.*;
|
import io.bitsquare.p2p.storage.data.ExpirablePayload;
|
||||||
|
import io.bitsquare.p2p.storage.data.MailboxPayload;
|
||||||
|
import io.bitsquare.p2p.storage.data.ProtectedData;
|
||||||
|
import io.bitsquare.p2p.storage.data.ProtectedMailboxData;
|
||||||
import io.bitsquare.p2p.storage.messages.AddDataMessage;
|
import io.bitsquare.p2p.storage.messages.AddDataMessage;
|
||||||
|
import io.bitsquare.p2p.storage.messages.RefreshTTLMessage;
|
||||||
import javafx.beans.property.*;
|
import javafx.beans.property.*;
|
||||||
import javafx.beans.value.ChangeListener;
|
import javafx.beans.value.ChangeListener;
|
||||||
import org.fxmisc.easybind.EasyBind;
|
import org.fxmisc.easybind.EasyBind;
|
||||||
|
@ -651,8 +655,8 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
|
||||||
checkArgument(optionalKeyRing.isPresent(), "keyRing not set. Seems that is called on a seed node which must not happen.");
|
checkArgument(optionalKeyRing.isPresent(), "keyRing not set. Seems that is called on a seed node which must not happen.");
|
||||||
if (isBootstrapped()) {
|
if (isBootstrapped()) {
|
||||||
try {
|
try {
|
||||||
RefreshTTLBundle refreshTTLBundle = p2PDataStorage.getRefreshTTLPackage(expirablePayload, optionalKeyRing.get().getSignatureKeyPair());
|
RefreshTTLMessage refreshTTLMessage = p2PDataStorage.getRefreshTTLMessage(expirablePayload, optionalKeyRing.get().getSignatureKeyPair());
|
||||||
return p2PDataStorage.refreshTTL(refreshTTLBundle, networkNode.getNodeAddress());
|
return p2PDataStorage.refreshTTL(refreshTTLMessage, networkNode.getNodeAddress());
|
||||||
} catch (CryptoException e) {
|
} catch (CryptoException e) {
|
||||||
log.error("Signing at getDataWithSignedSeqNr failed. That should never happen.");
|
log.error("Signing at getDataWithSignedSeqNr failed. That should never happen.");
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -59,7 +59,9 @@ public class Connection implements MessageListener {
|
||||||
private static final int MAX_MSG_SIZE = 100 * 1024; // 100 kb of compressed data
|
private static final int MAX_MSG_SIZE = 100 * 1024; // 100 kb of compressed data
|
||||||
private static final int MSG_THROTTLE_PER_SEC = 10; // With MAX_MSG_SIZE of 100kb results in bandwidth of 10 mbit/sec
|
private static final int MSG_THROTTLE_PER_SEC = 10; // With MAX_MSG_SIZE of 100kb results in bandwidth of 10 mbit/sec
|
||||||
private static final int MSG_THROTTLE_PER_10SEC = 50; // With MAX_MSG_SIZE of 100kb results in bandwidth of 5 mbit/sec for 10 sec
|
private static final int MSG_THROTTLE_PER_10SEC = 50; // With MAX_MSG_SIZE of 100kb results in bandwidth of 5 mbit/sec for 10 sec
|
||||||
private static final int SOCKET_TIMEOUT = (int) TimeUnit.SECONDS.toMillis(60);
|
// private static final int SOCKET_TIMEOUT = (int) TimeUnit.SECONDS.toMillis(60);
|
||||||
|
//TODO
|
||||||
|
private static final int SOCKET_TIMEOUT = (int) TimeUnit.SECONDS.toMillis(10);
|
||||||
|
|
||||||
public static int getMaxMsgSize() {
|
public static int getMaxMsgSize() {
|
||||||
return MAX_MSG_SIZE;
|
return MAX_MSG_SIZE;
|
||||||
|
|
|
@ -19,14 +19,15 @@ import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Random;
|
|
||||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class KeepAliveManager implements MessageListener, ConnectionListener {
|
public class KeepAliveManager implements MessageListener, ConnectionListener {
|
||||||
private static final Logger log = LoggerFactory.getLogger(KeepAliveManager.class);
|
private static final Logger log = LoggerFactory.getLogger(KeepAliveManager.class);
|
||||||
|
|
||||||
private static final int INTERVAL_SEC = new Random().nextInt(10) + 10;
|
//private static final int INTERVAL_SEC = new Random().nextInt(10) + 10;
|
||||||
|
//TODO
|
||||||
|
private static final int INTERVAL_SEC = 5;
|
||||||
|
|
||||||
private final NetworkNode networkNode;
|
private final NetworkNode networkNode;
|
||||||
private final PeerManager peerManager;
|
private final PeerManager peerManager;
|
||||||
|
|
|
@ -38,7 +38,8 @@ public class P2PDataStorage implements MessageListener, ConnectionListener {
|
||||||
private static final Logger log = LoggerFactory.getLogger(P2PDataStorage.class);
|
private static final Logger log = LoggerFactory.getLogger(P2PDataStorage.class);
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public static int CHECK_TTL_INTERVAL_MILLIS = (int) TimeUnit.SECONDS.toMillis(30);
|
//public static int CHECK_TTL_INTERVAL_MILLIS = (int) TimeUnit.SECONDS.toMillis(30);
|
||||||
|
public static int CHECK_TTL_INTERVAL_MILLIS = (int) TimeUnit.SECONDS.toMillis(5);//TODO
|
||||||
|
|
||||||
private final Broadcaster broadcaster;
|
private final Broadcaster broadcaster;
|
||||||
private final Map<ByteArray, ProtectedData> map = new ConcurrentHashMap<>();
|
private final Map<ByteArray, ProtectedData> map = new ConcurrentHashMap<>();
|
||||||
|
@ -112,7 +113,7 @@ public class P2PDataStorage implements MessageListener, ConnectionListener {
|
||||||
} else if (message instanceof RemoveMailboxDataMessage) {
|
} else if (message instanceof RemoveMailboxDataMessage) {
|
||||||
removeMailboxData(((RemoveMailboxDataMessage) message).data, peersNodeAddress);
|
removeMailboxData(((RemoveMailboxDataMessage) message).data, peersNodeAddress);
|
||||||
} else if (message instanceof RefreshTTLMessage) {
|
} else if (message instanceof RefreshTTLMessage) {
|
||||||
refreshTTL(((RefreshTTLMessage) message).refreshTTLBundle, peersNodeAddress);
|
refreshTTL((RefreshTTLMessage) message, peersNodeAddress);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -215,48 +216,53 @@ public class P2PDataStorage implements MessageListener, ConnectionListener {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean refreshTTL(RefreshTTLBundle refreshTTLBundle, @Nullable NodeAddress sender) {
|
public boolean refreshTTL(RefreshTTLMessage refreshTTLMessage, @Nullable NodeAddress sender) {
|
||||||
Log.traceCall();
|
Log.traceCall();
|
||||||
|
|
||||||
PublicKey ownerPubKey = refreshTTLBundle.ownerPubKey;
|
byte[] hashOfDataAndSeqNr = refreshTTLMessage.hashOfDataAndSeqNr;
|
||||||
byte[] hashOfDataAndSeqNr = refreshTTLBundle.hashOfDataAndSeqNr;
|
byte[] signature = refreshTTLMessage.signature;
|
||||||
byte[] signature = refreshTTLBundle.signature;
|
ByteArray hashOfPayload = new ByteArray(refreshTTLMessage.hashOfPayload);
|
||||||
int sequenceNumber = refreshTTLBundle.sequenceNumber;
|
int sequenceNumber = refreshTTLMessage.sequenceNumber;
|
||||||
ByteArray hashOfPayload = new ByteArray(refreshTTLBundle.hashOfPayload);
|
|
||||||
|
|
||||||
if (map.containsKey(hashOfPayload)) {
|
if (map.containsKey(hashOfPayload)) {
|
||||||
|
ProtectedData storedData = map.get(hashOfPayload);
|
||||||
|
|
||||||
|
if (storedData.expirablePayload instanceof StoragePayload) {
|
||||||
if (sequenceNumberMap.containsKey(hashOfPayload) && sequenceNumberMap.get(hashOfPayload).sequenceNr == sequenceNumber) {
|
if (sequenceNumberMap.containsKey(hashOfPayload) && sequenceNumberMap.get(hashOfPayload).sequenceNr == sequenceNumber) {
|
||||||
log.warn("We got that message with that seq nr already from another peer. We ignore that message.");
|
log.warn("We got that message with that seq nr already from another peer. We ignore that message.");
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
PublicKey ownerPubKey = ((StoragePayload) storedData.expirablePayload).getOwnerPubKey();
|
||||||
boolean result = checkSignature(ownerPubKey, hashOfDataAndSeqNr, signature) &&
|
boolean result = checkSignature(ownerPubKey, hashOfDataAndSeqNr, signature) &&
|
||||||
isSequenceNrValid(sequenceNumber, hashOfPayload) &&
|
isSequenceNrValid(sequenceNumber, hashOfPayload) &&
|
||||||
checkIfStoredDataPubKeyMatchesNewDataPubKey(ownerPubKey, hashOfPayload);
|
checkIfStoredDataPubKeyMatchesNewDataPubKey(ownerPubKey, hashOfPayload);
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
log.error("OK");
|
|
||||||
ProtectedData storedData = map.get(hashOfPayload);
|
|
||||||
storedData.refreshDate();
|
storedData.refreshDate();
|
||||||
|
|
||||||
sequenceNumberMap.put(hashOfPayload, new MapValue(sequenceNumber, System.currentTimeMillis()));
|
sequenceNumberMap.put(hashOfPayload, new MapValue(sequenceNumber, System.currentTimeMillis()));
|
||||||
storage.queueUpForSave(sequenceNumberMap, 5000);
|
storage.queueUpForSave(sequenceNumberMap, 5000);
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder("\n\n------------------------------------------------------------\n");
|
StringBuilder sb = new StringBuilder("\n\n------------------------------------------------------------\n");
|
||||||
sb.append("Data set after reNew (truncated)");
|
sb.append("Data set after refreshTTL (truncated)");
|
||||||
map.values().stream().forEach(e -> sb.append("\n").append(StringUtils.abbreviate(e.toString(), 100)));
|
map.values().stream().forEach(e -> sb.append("\n").append(StringUtils.abbreviate(e.toString(), 100)));
|
||||||
sb.append("\n------------------------------------------------------------\n");
|
sb.append("\n------------------------------------------------------------\n");
|
||||||
log.trace(sb.toString());
|
log.trace(sb.toString());
|
||||||
log.info("Data set after addProtectedExpirableData: size=" + map.values().size());
|
log.info("Data set after addProtectedExpirableData: size=" + map.values().size());
|
||||||
|
|
||||||
broadcast(new RefreshTTLMessage(refreshTTLBundle), sender);
|
broadcast(refreshTTLMessage, sender);
|
||||||
} else {
|
} else {
|
||||||
log.warn("Checks for refresh failed");
|
log.warn("Checks for refreshTTL failed");
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
log.error("storedData.expirablePayload NOT instanceof StoragePayload. That must not happen.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
log.warn("We don't have data for that refresh message in our map.");
|
log.warn("We don't have data for that refresh message in our map.");
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,7 +335,7 @@ public class P2PDataStorage implements MessageListener, ConnectionListener {
|
||||||
return new ProtectedData(payload, payload.getTTL(), ownerStoragePubKey.getPublic(), sequenceNumber, signature);
|
return new ProtectedData(payload, payload.getTTL(), ownerStoragePubKey.getPublic(), sequenceNumber, signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RefreshTTLBundle getRefreshTTLPackage(ExpirablePayload payload, KeyPair ownerStoragePubKey)
|
public RefreshTTLMessage getRefreshTTLMessage(ExpirablePayload payload, KeyPair ownerStoragePubKey)
|
||||||
throws CryptoException {
|
throws CryptoException {
|
||||||
ByteArray hashOfPayload = getHashAsByteArray(payload);
|
ByteArray hashOfPayload = getHashAsByteArray(payload);
|
||||||
int sequenceNumber;
|
int sequenceNumber;
|
||||||
|
@ -340,8 +346,7 @@ public class P2PDataStorage implements MessageListener, ConnectionListener {
|
||||||
|
|
||||||
byte[] hashOfDataAndSeqNr = Hash.getHash(new DataAndSeqNrPair(payload, sequenceNumber));
|
byte[] hashOfDataAndSeqNr = Hash.getHash(new DataAndSeqNrPair(payload, sequenceNumber));
|
||||||
byte[] signature = Sig.sign(ownerStoragePubKey.getPrivate(), hashOfDataAndSeqNr);
|
byte[] signature = Sig.sign(ownerStoragePubKey.getPrivate(), hashOfDataAndSeqNr);
|
||||||
PublicKey ownerPubKey = ownerStoragePubKey.getPublic();
|
return new RefreshTTLMessage(hashOfDataAndSeqNr, signature, hashOfPayload.bytes, sequenceNumber);
|
||||||
return new RefreshTTLBundle(ownerPubKey, hashOfDataAndSeqNr, signature, hashOfPayload.bytes, sequenceNumber);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProtectedMailboxData getMailboxDataWithSignedSeqNr(MailboxPayload expirableMailboxPayload,
|
public ProtectedMailboxData getMailboxDataWithSignedSeqNr(MailboxPayload expirableMailboxPayload,
|
||||||
|
|
|
@ -2,7 +2,6 @@ package io.bitsquare.p2p.storage.data;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import io.bitsquare.common.wire.Payload;
|
import io.bitsquare.common.wire.Payload;
|
||||||
import io.bitsquare.p2p.storage.P2PDataStorage;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ -12,7 +11,7 @@ import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
public class ProtectedData implements Payload {
|
public class ProtectedData implements Payload {
|
||||||
private static final Logger log = LoggerFactory.getLogger(P2PDataStorage.class);
|
private static final Logger log = LoggerFactory.getLogger(ProtectedData.class);
|
||||||
|
|
||||||
public final ExpirablePayload expirablePayload;
|
public final ExpirablePayload expirablePayload;
|
||||||
|
|
||||||
|
|
|
@ -1,68 +0,0 @@
|
||||||
package io.bitsquare.p2p.storage.data;
|
|
||||||
|
|
||||||
import io.bitsquare.app.Version;
|
|
||||||
import io.bitsquare.common.crypto.Sig;
|
|
||||||
import io.bitsquare.common.wire.Payload;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.security.KeyFactory;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.NoSuchProviderException;
|
|
||||||
import java.security.PublicKey;
|
|
||||||
import java.security.spec.InvalidKeySpecException;
|
|
||||||
import java.security.spec.X509EncodedKeySpec;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
public class RefreshTTLBundle implements Payload {
|
|
||||||
// That object is sent over the wire, so we need to take care of version compatibility.
|
|
||||||
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(RefreshTTLBundle.class);
|
|
||||||
|
|
||||||
transient public PublicKey ownerPubKey;
|
|
||||||
public final byte[] hashOfDataAndSeqNr;
|
|
||||||
public final byte[] signature;
|
|
||||||
public final byte[] hashOfPayload;
|
|
||||||
public final int sequenceNumber;
|
|
||||||
private byte[] ownerPubKeyBytes;
|
|
||||||
|
|
||||||
public RefreshTTLBundle(PublicKey ownerPubKey,
|
|
||||||
byte[] hashOfDataAndSeqNr,
|
|
||||||
byte[] signature,
|
|
||||||
byte[] hashOfPayload,
|
|
||||||
int sequenceNumber) {
|
|
||||||
this.ownerPubKey = ownerPubKey;
|
|
||||||
this.hashOfDataAndSeqNr = hashOfDataAndSeqNr;
|
|
||||||
this.signature = signature;
|
|
||||||
this.hashOfPayload = hashOfPayload;
|
|
||||||
this.sequenceNumber = sequenceNumber;
|
|
||||||
|
|
||||||
ownerPubKeyBytes = new X509EncodedKeySpec(ownerPubKey.getEncoded()).getEncoded();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
|
||||||
try {
|
|
||||||
in.defaultReadObject();
|
|
||||||
ownerPubKey = KeyFactory.getInstance(Sig.KEY_ALGO, "BC").generatePublic(new X509EncodedKeySpec(ownerPubKeyBytes));
|
|
||||||
} catch (InvalidKeySpecException | NoSuchAlgorithmException | NoSuchProviderException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
log.error(e.getMessage());
|
|
||||||
} catch (Throwable t) {
|
|
||||||
log.trace("Cannot be deserialized." + t.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "RefreshTTLPackage{" +
|
|
||||||
"ownerPubKey.hashCode()=" + ownerPubKey.hashCode() +
|
|
||||||
", hashOfDataAndSeqNr.hashCode()=" + Arrays.hashCode(hashOfDataAndSeqNr) +
|
|
||||||
", hashOfPayload.hashCode()=" + Arrays.hashCode(hashOfPayload) +
|
|
||||||
", sequenceNumber=" + sequenceNumber +
|
|
||||||
", signature.hashCode()=" + Arrays.hashCode(signature) +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,38 +1,37 @@
|
||||||
package io.bitsquare.p2p.storage.messages;
|
package io.bitsquare.p2p.storage.messages;
|
||||||
|
|
||||||
import io.bitsquare.app.Version;
|
import io.bitsquare.app.Version;
|
||||||
import io.bitsquare.p2p.storage.data.RefreshTTLBundle;
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
public final class RefreshTTLMessage extends DataBroadcastMessage {
|
public final class RefreshTTLMessage extends DataBroadcastMessage {
|
||||||
// That object is sent over the wire, so we need to take care of version compatibility.
|
// That object is sent over the wire, so we need to take care of version compatibility.
|
||||||
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
||||||
|
|
||||||
public final RefreshTTLBundle refreshTTLBundle;
|
// Serialized data has 400 bytes instead of 114 bytes of the raw content ;-(
|
||||||
|
// When using Protobuffer that should bets much smaller
|
||||||
|
public final byte[] hashOfDataAndSeqNr; // 32 bytes
|
||||||
|
public final byte[] signature; // 46 bytes
|
||||||
|
public final byte[] hashOfPayload; // 32 bytes
|
||||||
|
public final int sequenceNumber; // 4 bytes
|
||||||
|
|
||||||
public RefreshTTLMessage(RefreshTTLBundle refreshTTLBundle) {
|
public RefreshTTLMessage(byte[] hashOfDataAndSeqNr,
|
||||||
this.refreshTTLBundle = refreshTTLBundle;
|
byte[] signature,
|
||||||
}
|
byte[] hashOfPayload,
|
||||||
|
int sequenceNumber) {
|
||||||
@Override
|
this.hashOfDataAndSeqNr = hashOfDataAndSeqNr;
|
||||||
public boolean equals(Object o) {
|
this.signature = signature;
|
||||||
if (this == o) return true;
|
this.hashOfPayload = hashOfPayload;
|
||||||
if (!(o instanceof RefreshTTLMessage)) return false;
|
this.sequenceNumber = sequenceNumber;
|
||||||
|
|
||||||
RefreshTTLMessage that = (RefreshTTLMessage) o;
|
|
||||||
|
|
||||||
return !(refreshTTLBundle != null ? !refreshTTLBundle.equals(that.refreshTTLBundle) : that.refreshTTLBundle != null);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return refreshTTLBundle != null ? refreshTTLBundle.hashCode() : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "RefreshTTLMessage{" +
|
return "RefreshTTLMessage{" +
|
||||||
"refreshTTLPackage=" + refreshTTLBundle +
|
", hashOfDataAndSeqNr.hashCode()=" + Arrays.hashCode(hashOfDataAndSeqNr) +
|
||||||
"} " + super.toString();
|
", hashOfPayload.hashCode()=" + Arrays.hashCode(hashOfPayload) +
|
||||||
|
", sequenceNumber=" + sequenceNumber +
|
||||||
|
", signature.hashCode()=" + Arrays.hashCode(signature) +
|
||||||
|
'}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,13 +10,10 @@ import io.bitsquare.p2p.TestUtils;
|
||||||
import io.bitsquare.p2p.network.NetworkNode;
|
import io.bitsquare.p2p.network.NetworkNode;
|
||||||
import io.bitsquare.p2p.peers.PeerManager;
|
import io.bitsquare.p2p.peers.PeerManager;
|
||||||
import io.bitsquare.p2p.storage.data.ProtectedData;
|
import io.bitsquare.p2p.storage.data.ProtectedData;
|
||||||
import io.bitsquare.p2p.storage.data.RefreshTTLBundle;
|
import io.bitsquare.p2p.storage.messages.RefreshTTLMessage;
|
||||||
import io.bitsquare.p2p.storage.mocks.MockData;
|
import io.bitsquare.p2p.storage.mocks.MockData;
|
||||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
import org.junit.After;
|
import org.junit.*;
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ -31,6 +28,7 @@ import java.util.Set;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
@Ignore
|
||||||
public class ProtectedDataStorageTest {
|
public class ProtectedDataStorageTest {
|
||||||
private static final Logger log = LoggerFactory.getLogger(ProtectedDataStorageTest.class);
|
private static final Logger log = LoggerFactory.getLogger(ProtectedDataStorageTest.class);
|
||||||
|
|
||||||
|
@ -58,7 +56,7 @@ public class ProtectedDataStorageTest {
|
||||||
dir2.mkdir();
|
dir2.mkdir();
|
||||||
|
|
||||||
UserThread.setExecutor(Executors.newSingleThreadExecutor());
|
UserThread.setExecutor(Executors.newSingleThreadExecutor());
|
||||||
P2PDataStorage.CHECK_TTL_INTERVAL_MILLIS = 300;
|
P2PDataStorage.CHECK_TTL_INTERVAL_MILLIS = 500;
|
||||||
|
|
||||||
keyRing1 = new KeyRing(new KeyStorage(dir1));
|
keyRing1 = new KeyRing(new KeyStorage(dir1));
|
||||||
|
|
||||||
|
@ -163,7 +161,7 @@ public class ProtectedDataStorageTest {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testRePublish() throws InterruptedException, NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException, CryptoException, SignatureException, InvalidKeyException, NoSuchProviderException {
|
public void testRefreshTTL() throws InterruptedException, NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException, CryptoException, SignatureException, InvalidKeyException, NoSuchProviderException {
|
||||||
mockData.ttl = (int) (P2PDataStorage.CHECK_TTL_INTERVAL_MILLIS * 1.5);
|
mockData.ttl = (int) (P2PDataStorage.CHECK_TTL_INTERVAL_MILLIS * 1.5);
|
||||||
ProtectedData data = dataStorage1.getProtectedData(mockData, storageSignatureKeyPair1);
|
ProtectedData data = dataStorage1.getProtectedData(mockData, storageSignatureKeyPair1);
|
||||||
Assert.assertTrue(dataStorage1.add(data, null));
|
Assert.assertTrue(dataStorage1.add(data, null));
|
||||||
|
@ -172,14 +170,14 @@ public class ProtectedDataStorageTest {
|
||||||
log.debug("test 1");
|
log.debug("test 1");
|
||||||
Assert.assertEquals(1, dataStorage1.getMap().size());
|
Assert.assertEquals(1, dataStorage1.getMap().size());
|
||||||
|
|
||||||
RefreshTTLBundle refreshTTLBundle = dataStorage1.getRefreshTTLPackage(mockData, storageSignatureKeyPair1);
|
RefreshTTLMessage refreshTTLMessage = dataStorage1.getRefreshTTLMessage(mockData, storageSignatureKeyPair1);
|
||||||
Assert.assertTrue(dataStorage1.refreshTTL(refreshTTLBundle, null));
|
Assert.assertTrue(dataStorage1.refreshTTL(refreshTTLMessage, null));
|
||||||
Thread.sleep(P2PDataStorage.CHECK_TTL_INTERVAL_MILLIS);
|
Thread.sleep(P2PDataStorage.CHECK_TTL_INTERVAL_MILLIS);
|
||||||
log.debug("test 2");
|
log.debug("test 2");
|
||||||
Assert.assertEquals(1, dataStorage1.getMap().size());
|
Assert.assertEquals(1, dataStorage1.getMap().size());
|
||||||
|
|
||||||
refreshTTLBundle = dataStorage1.getRefreshTTLPackage(mockData, storageSignatureKeyPair1);
|
refreshTTLMessage = dataStorage1.getRefreshTTLMessage(mockData, storageSignatureKeyPair1);
|
||||||
Assert.assertTrue(dataStorage1.refreshTTL(refreshTTLBundle, null));
|
Assert.assertTrue(dataStorage1.refreshTTL(refreshTTLMessage, null));
|
||||||
Thread.sleep(P2PDataStorage.CHECK_TTL_INTERVAL_MILLIS);
|
Thread.sleep(P2PDataStorage.CHECK_TTL_INTERVAL_MILLIS);
|
||||||
log.debug("test 3");
|
log.debug("test 3");
|
||||||
Assert.assertEquals(1, dataStorage1.getMap().size());
|
Assert.assertEquals(1, dataStorage1.getMap().size());
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue