mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-07-27 00:45:23 -04:00
Use FXTimer instead of Java Timer, add idle detection for republish offers
This commit is contained in:
parent
79de2bcb11
commit
bd3b55cf47
25 changed files with 331 additions and 112 deletions
|
@ -13,5 +13,7 @@ public interface Clock {
|
|||
void onSecondTick();
|
||||
|
||||
void onMinuteTick();
|
||||
|
||||
void onMissedSecondTick(long missed);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
package io.bitsquare.common;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Random;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class DefaultJavaTimer implements Timer {
|
||||
private final Logger log = LoggerFactory.getLogger(DefaultJavaTimer.class);
|
||||
private java.util.Timer timer;
|
||||
|
||||
public DefaultJavaTimer() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Timer runLater(Duration delay, Runnable runnable) {
|
||||
checkArgument(timer == null, "runLater or runPeriodically already called on that timer");
|
||||
timer = new java.util.Timer();
|
||||
timer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
Thread.currentThread().setName("TimerTask-" + new Random().nextInt(10000));
|
||||
try {
|
||||
UserThread.execute(runnable::run);
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
log.error("Executing timerTask failed. " + t.getMessage());
|
||||
}
|
||||
}
|
||||
}, delay.toMillis());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Timer runPeriodically(java.time.Duration interval, Runnable runnable) {
|
||||
checkArgument(timer == null, "runLater or runPeriodically already called on that timer");
|
||||
timer = new java.util.Timer();
|
||||
timer.scheduleAtFixedRate(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
Thread.currentThread().setName("TimerTask-" + new Random().nextInt(10000));
|
||||
try {
|
||||
UserThread.execute(runnable::run);
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
log.error("Executing timerTask failed. " + t.getMessage());
|
||||
}
|
||||
}
|
||||
}, interval.toMillis(), interval.toMillis());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
checkNotNull(timer, "Timer must not be null");
|
||||
timer.cancel();
|
||||
timer = null;
|
||||
}
|
||||
}
|
11
common/src/main/java/io/bitsquare/common/Timer.java
Normal file
11
common/src/main/java/io/bitsquare/common/Timer.java
Normal file
|
@ -0,0 +1,11 @@
|
|||
package io.bitsquare.common;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
public interface Timer {
|
||||
Timer runLater(java.time.Duration delay, Runnable action);
|
||||
|
||||
Timer runPeriodically(Duration interval, Runnable runnable);
|
||||
|
||||
void stop();
|
||||
}
|
|
@ -21,14 +21,15 @@ import com.google.common.util.concurrent.MoreExecutors;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.time.Duration;
|
||||
import java.util.Random;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class UserThread {
|
||||
private static final Logger log = LoggerFactory.getLogger(UserThread.class);
|
||||
private static Class<? extends Timer> timerClass;
|
||||
|
||||
public static Executor getExecutor() {
|
||||
return executor;
|
||||
|
@ -38,9 +39,14 @@ public class UserThread {
|
|||
UserThread.executor = executor;
|
||||
}
|
||||
|
||||
public static void setTimerClass(Class<? extends Timer> timerClass) {
|
||||
UserThread.timerClass = timerClass;
|
||||
}
|
||||
|
||||
static {
|
||||
// If not defined we use same thread as caller thread
|
||||
executor = MoreExecutors.directExecutor();
|
||||
timerClass = DefaultJavaTimer.class;
|
||||
}
|
||||
|
||||
private static Executor executor;
|
||||
|
@ -65,19 +71,25 @@ public class UserThread {
|
|||
}
|
||||
|
||||
public static Timer runAfter(Runnable runnable, long delay, TimeUnit timeUnit) {
|
||||
Timer timer = new Timer();
|
||||
timer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
Thread.currentThread().setName("TimerTask-" + new Random().nextInt(10000));
|
||||
return getTimer().runLater(Duration.ofMillis(timeUnit.toMillis(delay)), runnable);
|
||||
}
|
||||
|
||||
public static Timer runPeriodically(Runnable runnable, long interval) {
|
||||
return UserThread.runPeriodically(runnable, interval, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
public static Timer runPeriodically(Runnable runnable, long interval, TimeUnit timeUnit) {
|
||||
return getTimer().runPeriodically(Duration.ofMillis(timeUnit.toMillis(interval)), runnable);
|
||||
}
|
||||
|
||||
private static Timer getTimer() {
|
||||
try {
|
||||
UserThread.execute(runnable::run);
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
log.error("Executing timerTask failed. " + t.getMessage());
|
||||
return timerClass.getDeclaredConstructor().newInstance();
|
||||
} catch (InstantiationException | NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
|
||||
String message = "Could not instantiate timer bsTimerClass=" + timerClass;
|
||||
log.error(message);
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(message);
|
||||
}
|
||||
}
|
||||
}, timeUnit.toMillis(delay));
|
||||
return timer;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import com.google.common.util.concurrent.Service;
|
|||
import io.bitsquare.btc.listeners.AddressConfidenceListener;
|
||||
import io.bitsquare.btc.listeners.BalanceListener;
|
||||
import io.bitsquare.btc.listeners.TxConfidenceListener;
|
||||
import io.bitsquare.common.Timer;
|
||||
import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.common.handlers.ErrorMessageHandler;
|
||||
import io.bitsquare.common.handlers.ExceptionHandler;
|
||||
|
@ -187,7 +188,7 @@ public class WalletService {
|
|||
|
||||
// set after wallet is ready
|
||||
tradeWalletService.setWalletAppKit(walletAppKit);
|
||||
timeoutTimer.cancel();
|
||||
timeoutTimer.stop();
|
||||
|
||||
// onSetupCompleted in walletAppKit is not the called on the last invocations, so we add a bit of delay
|
||||
UserThread.runAfter(resultHandler::handleResult, 100, TimeUnit.MILLISECONDS);
|
||||
|
@ -242,7 +243,7 @@ public class WalletService {
|
|||
public void failed(@NotNull Service.State from, @NotNull Throwable failure) {
|
||||
walletAppKit = null;
|
||||
log.error("walletAppKit failed");
|
||||
timeoutTimer.cancel();
|
||||
timeoutTimer.stop();
|
||||
UserThread.execute(() -> exceptionHandler.handleException(failure));
|
||||
}
|
||||
}, Threading.USER_THREAD);
|
||||
|
|
|
@ -2,6 +2,7 @@ package io.bitsquare.btc.blockchain;
|
|||
|
||||
import com.google.common.util.concurrent.*;
|
||||
import io.bitsquare.btc.blockchain.providers.FeeProvider;
|
||||
import io.bitsquare.common.Timer;
|
||||
import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.common.util.Utilities;
|
||||
import io.bitsquare.http.HttpException;
|
||||
|
@ -11,7 +12,6 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Timer;
|
||||
|
||||
class GetFeeRequest {
|
||||
private static final Logger log = LoggerFactory.getLogger(GetFeeRequest.class);
|
||||
|
@ -72,7 +72,7 @@ class GetFeeRequest {
|
|||
}
|
||||
|
||||
private void stopTimer() {
|
||||
timer.cancel();
|
||||
timer.stop();
|
||||
timer = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
package io.bitsquare.trade.offer;
|
||||
|
||||
import io.bitsquare.app.Version;
|
||||
import io.bitsquare.common.Timer;
|
||||
import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.storage.Storage;
|
||||
import io.bitsquare.trade.Tradable;
|
||||
|
@ -36,7 +37,7 @@ public final class OpenOffer implements Tradable {
|
|||
|
||||
// Timeout for offer reservation during takeoffer process. If deposit tx is not completed in that time we reset the offer to AVAILABLE state.
|
||||
private static final long TIMEOUT_SEC = 30;
|
||||
transient private java.util.Timer timeoutTimer;
|
||||
transient private Timer timeoutTimer;
|
||||
|
||||
public enum State {
|
||||
AVAILABLE,
|
||||
|
@ -118,7 +119,7 @@ public final class OpenOffer implements Tradable {
|
|||
|
||||
private void stopTimeout() {
|
||||
if (timeoutTimer != null) {
|
||||
timeoutTimer.cancel();
|
||||
timeoutTimer.stop();
|
||||
timeoutTimer = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,8 @@ import com.google.inject.Inject;
|
|||
import io.bitsquare.app.Log;
|
||||
import io.bitsquare.btc.TradeWalletService;
|
||||
import io.bitsquare.btc.WalletService;
|
||||
import io.bitsquare.common.Clock;
|
||||
import io.bitsquare.common.Timer;
|
||||
import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.common.crypto.KeyRing;
|
||||
import io.bitsquare.common.handlers.ErrorMessageHandler;
|
||||
|
@ -30,6 +32,9 @@ import io.bitsquare.p2p.Message;
|
|||
import io.bitsquare.p2p.NodeAddress;
|
||||
import io.bitsquare.p2p.P2PService;
|
||||
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.storage.Storage;
|
||||
import io.bitsquare.trade.TradableList;
|
||||
|
@ -48,8 +53,6 @@ import javax.annotation.Nullable;
|
|||
import javax.inject.Named;
|
||||
import java.io.File;
|
||||
import java.util.Optional;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.google.inject.internal.util.$Preconditions.checkNotNull;
|
||||
|
@ -67,17 +70,19 @@ public class OpenOfferManager {
|
|||
private final TradeWalletService tradeWalletService;
|
||||
private final OfferBookService offerBookService;
|
||||
private final ClosedTradableManager closedTradableManager;
|
||||
private Clock clock;
|
||||
|
||||
private final TradableList<OpenOffer> openOffers;
|
||||
private final Storage<TradableList<OpenOffer>> openOffersStorage;
|
||||
private boolean shutDownRequested;
|
||||
private BootstrapListener bootstrapListener;
|
||||
private final Timer timer = new Timer();
|
||||
private Timer republishOffersTime;
|
||||
private boolean firstTimeConnection;
|
||||
//private final Timer republishOffersTimer = new Timer();
|
||||
private Timer refreshOffersTimer;
|
||||
private Timer republishOffersTimer;
|
||||
private boolean allowRefreshOffers;
|
||||
private boolean lostAllConnections;
|
||||
private long refreshOffersPeriod;
|
||||
private Clock.Listener listener;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -92,6 +97,7 @@ public class OpenOfferManager {
|
|||
TradeWalletService tradeWalletService,
|
||||
OfferBookService offerBookService,
|
||||
ClosedTradableManager closedTradableManager,
|
||||
Clock clock,
|
||||
@Named("storage.dir") File storageDir) {
|
||||
this.keyRing = keyRing;
|
||||
this.user = user;
|
||||
|
@ -100,6 +106,7 @@ public class OpenOfferManager {
|
|||
this.tradeWalletService = tradeWalletService;
|
||||
this.offerBookService = offerBookService;
|
||||
this.closedTradableManager = closedTradableManager;
|
||||
this.clock = clock;
|
||||
|
||||
openOffersStorage = new Storage<>(storageDir);
|
||||
this.openOffers = new TradableList<>(openOffersStorage, "OpenOffers");
|
||||
|
@ -120,42 +127,6 @@ public class OpenOfferManager {
|
|||
if (message instanceof OfferAvailabilityRequest)
|
||||
handleOfferAvailabilityRequest((OfferAvailabilityRequest) message, peersNodeAddress);
|
||||
});
|
||||
|
||||
NetworkNode networkNode = p2PService.getNetworkNode();
|
||||
|
||||
// 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
|
||||
/* networkNode.addConnectionListener(new ConnectionListener() {
|
||||
@Override
|
||||
public void onConnection(Connection connection) {
|
||||
if (lostAllConnections) {
|
||||
lostAllConnections = false;
|
||||
allowRefreshOffers = false;
|
||||
|
||||
// We repeat a rePublishOffers call after 10 seconds if we have more than 3 peers
|
||||
if (republishOffersTime == null) {
|
||||
republishOffersTime = UserThread.runAfter(() -> {
|
||||
if (networkNode.getAllConnections().size() > 3)
|
||||
republishOffers();
|
||||
|
||||
allowRefreshOffers = true;
|
||||
republishOffersTime = null;
|
||||
}, 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnect(CloseConnectionReason closeConnectionReason, Connection connection) {
|
||||
lostAllConnections = networkNode.getAllConnections().isEmpty();
|
||||
if (lostAllConnections)
|
||||
allowRefreshOffers = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable throwable) {
|
||||
}
|
||||
});*/
|
||||
}
|
||||
|
||||
|
||||
|
@ -195,8 +166,62 @@ public class OpenOfferManager {
|
|||
|
||||
//TODO should not be needed
|
||||
//startRepublishOffersThread();
|
||||
|
||||
// we check if app was idle for more then 5 sec.
|
||||
listener = new Clock.Listener() {
|
||||
@Override
|
||||
public void onSecondTick() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMinuteTick() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMissedSecondTick(long missed) {
|
||||
if (missed > 5000) {
|
||||
log.error("We have been idle for {} sec", missed / 1000);
|
||||
|
||||
// We have been idle for at least 5 sec.
|
||||
//republishOffers();
|
||||
// run again after 5 sec as it might be that the app needs a bit for getting all re-animated again
|
||||
if (republishOffersTimer == null)
|
||||
republishOffersTimer = UserThread.runAfter(OpenOfferManager.this::republishOffers, 5);
|
||||
}
|
||||
}
|
||||
};
|
||||
clock.addListener(listener);
|
||||
|
||||
// We also check if we got completely disconnected
|
||||
NetworkNode networkNode = p2PService.getNetworkNode();
|
||||
networkNode.addConnectionListener(new ConnectionListener() {
|
||||
@Override
|
||||
public void onConnection(Connection connection) {
|
||||
if (lostAllConnections) {
|
||||
lostAllConnections = false;
|
||||
|
||||
if (republishOffersTimer != null)
|
||||
republishOffersTimer.stop();
|
||||
|
||||
//republishOffers();
|
||||
// run again after 5 sec as it might be that the app needs a bit for getting all re-animated again
|
||||
republishOffersTimer = UserThread.runAfter(OpenOfferManager.this::republishOffers, 5);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnect(CloseConnectionReason closeConnectionReason, Connection connection) {
|
||||
lostAllConnections = networkNode.getAllConnections().isEmpty();
|
||||
if (lostAllConnections)
|
||||
allowRefreshOffers = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable throwable) {
|
||||
}
|
||||
});
|
||||
}
|
||||
/*
|
||||
private void startRepublishOffersThread() {
|
||||
long period = Offer.TTL * 10;
|
||||
TimerTask timerTask = new TimerTask() {
|
||||
|
@ -205,18 +230,27 @@ public class OpenOfferManager {
|
|||
UserThread.execute(OpenOfferManager.this::republishOffers);
|
||||
}
|
||||
};
|
||||
timer.scheduleAtFixedRate(timerTask, period, period);
|
||||
}
|
||||
republishOffersTimer.scheduleAtFixedRate(timerTask, period, period);
|
||||
}*/
|
||||
|
||||
private void republishOffers() {
|
||||
Log.traceCall("Number of offer for republish: " + openOffers.size());
|
||||
allowRefreshOffers = false;
|
||||
if (republishOffersTimer != null) {
|
||||
republishOffersTimer.stop();
|
||||
republishOffersTimer = null;
|
||||
}
|
||||
|
||||
for (OpenOffer openOffer : openOffers) {
|
||||
offerBookService.republishOffers(openOffer.getOffer(),
|
||||
() -> {
|
||||
log.debug("Successful added offer to P2P network");
|
||||
allowRefreshOffers = true;
|
||||
},
|
||||
errorMessage -> log.error("Add offer to P2P network failed. " + errorMessage));
|
||||
errorMessage -> {
|
||||
//TODO handle with retry
|
||||
log.error("Add offer to P2P network failed. " + errorMessage);
|
||||
});
|
||||
openOffer.setStorage(openOffersStorage);
|
||||
}
|
||||
}
|
||||
|
@ -224,13 +258,7 @@ public class OpenOfferManager {
|
|||
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);
|
||||
refreshOffersTimer = UserThread.runPeriodically(OpenOfferManager.this::refreshOffers, refreshOffersPeriod, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
private void refreshOffers() {
|
||||
|
@ -251,8 +279,14 @@ public class OpenOfferManager {
|
|||
}
|
||||
|
||||
public void shutDown(@Nullable Runnable completeHandler) {
|
||||
if (timer != null)
|
||||
timer.cancel();
|
||||
if (republishOffersTimer != null)
|
||||
republishOffersTimer.stop();
|
||||
|
||||
if (refreshOffersTimer != null)
|
||||
refreshOffersTimer.stop();
|
||||
|
||||
if (listener != null)
|
||||
clock.removeListener(listener);
|
||||
|
||||
if (!shutDownRequested) {
|
||||
log.info("remove all open offers at shutDown");
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package io.bitsquare.trade.protocol.availability;
|
||||
|
||||
import io.bitsquare.common.Timer;
|
||||
import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.common.handlers.ErrorMessageHandler;
|
||||
import io.bitsquare.common.handlers.ResultHandler;
|
||||
|
@ -44,7 +45,7 @@ public class OfferAvailabilityProtocol {
|
|||
private final DecryptedDirectMessageListener decryptedDirectMessageListener;
|
||||
|
||||
private TaskRunner<OfferAvailabilityModel> taskRunner;
|
||||
private java.util.Timer timeoutTimer;
|
||||
private Timer timeoutTimer;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -145,7 +146,7 @@ public class OfferAvailabilityProtocol {
|
|||
|
||||
private void stopTimeout() {
|
||||
if (timeoutTimer != null) {
|
||||
timeoutTimer.cancel();
|
||||
timeoutTimer.stop();
|
||||
timeoutTimer = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package io.bitsquare.trade.protocol.trade;
|
||||
|
||||
import io.bitsquare.common.Timer;
|
||||
import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.common.crypto.PubKeyRing;
|
||||
import io.bitsquare.p2p.Message;
|
||||
|
@ -42,7 +43,7 @@ public abstract class TradeProtocol {
|
|||
protected final ProcessModel processModel;
|
||||
private final DecryptedDirectMessageListener decryptedDirectMessageListener;
|
||||
protected Trade trade;
|
||||
private java.util.Timer timeoutTimer;
|
||||
private Timer timeoutTimer;
|
||||
|
||||
public TradeProtocol(Trade trade) {
|
||||
this.trade = trade;
|
||||
|
@ -116,7 +117,7 @@ public abstract class TradeProtocol {
|
|||
|
||||
protected void stopTimeout() {
|
||||
if (timeoutTimer != null) {
|
||||
timeoutTimer.cancel();
|
||||
timeoutTimer.stop();
|
||||
timeoutTimer = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import io.bitsquare.common.UserThread;
|
|||
import io.bitsquare.common.handlers.ResultHandler;
|
||||
import io.bitsquare.common.util.Utilities;
|
||||
import io.bitsquare.gui.SystemTray;
|
||||
import io.bitsquare.gui.common.UITimer;
|
||||
import io.bitsquare.gui.common.view.CachingViewLoader;
|
||||
import io.bitsquare.gui.common.view.View;
|
||||
import io.bitsquare.gui.common.view.ViewLoader;
|
||||
|
@ -105,6 +106,7 @@ public class BitsquareApp extends Application {
|
|||
Version.printVersion();
|
||||
|
||||
UserThread.setExecutor(Platform::runLater);
|
||||
UserThread.setTimerClass(UITimer.class);
|
||||
|
||||
// setup UncaughtExceptionHandler
|
||||
Thread.UncaughtExceptionHandler handler = (thread, throwable) -> {
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
package io.bitsquare.gui.common;
|
||||
|
||||
import io.bitsquare.common.Clock;
|
||||
import org.reactfx.util.FxTimer;
|
||||
import org.reactfx.util.Timer;
|
||||
import io.bitsquare.common.Timer;
|
||||
import io.bitsquare.common.UserThread;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class UIClock implements Clock {
|
||||
private static final Logger log = LoggerFactory.getLogger(UIClock.class);
|
||||
|
@ -16,21 +16,48 @@ public class UIClock implements Clock {
|
|||
|
||||
private final List<Listener> listeners = new LinkedList<>();
|
||||
private long counter = 0;
|
||||
private long lastSecondTick;
|
||||
|
||||
public UIClock() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if (timer == null)
|
||||
timer = FxTimer.runPeriodically(Duration.ofSeconds(1), () -> {
|
||||
if (timer == null) {
|
||||
lastSecondTick = System.currentTimeMillis();
|
||||
timer = UserThread.runPeriodically(() -> {
|
||||
listeners.stream().forEach(Listener::onSecondTick);
|
||||
counter++;
|
||||
if (counter >= 60) {
|
||||
counter = 0;
|
||||
listeners.stream().forEach(Listener::onMinuteTick);
|
||||
}
|
||||
});
|
||||
|
||||
long currentTimeMillis = System.currentTimeMillis();
|
||||
long diff = currentTimeMillis - lastSecondTick;
|
||||
if (diff > 1000)
|
||||
listeners.stream().forEach(listener -> listener.onMissedSecondTick(diff - 1000));
|
||||
|
||||
lastSecondTick = currentTimeMillis;
|
||||
}, 1, TimeUnit.SECONDS);
|
||||
|
||||
/* timer = FxTimer.runPeriodically(Duration.ofSeconds(1), () -> {
|
||||
listeners.stream().forEach(Listener::onSecondTick);
|
||||
|
||||
counter++;
|
||||
if (counter >= 60) {
|
||||
counter = 0;
|
||||
listeners.stream().forEach(Listener::onMinuteTick);
|
||||
}
|
||||
|
||||
long currentTimeMillis = System.currentTimeMillis();
|
||||
long diff = currentTimeMillis - lastSecondTick;
|
||||
if (diff > 1000)
|
||||
listeners.stream().forEach(listener -> listener.onMissedSecondTick(diff - 1000));
|
||||
|
||||
lastSecondTick = currentTimeMillis;
|
||||
});*/
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
42
gui/src/main/java/io/bitsquare/gui/common/UITimer.java
Normal file
42
gui/src/main/java/io/bitsquare/gui/common/UITimer.java
Normal file
|
@ -0,0 +1,42 @@
|
|||
package io.bitsquare.gui.common;
|
||||
|
||||
import io.bitsquare.common.Timer;
|
||||
import org.reactfx.util.FxTimer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class UITimer implements Timer {
|
||||
private final Logger log = LoggerFactory.getLogger(UITimer.class);
|
||||
private org.reactfx.util.Timer timer;
|
||||
|
||||
public UITimer() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Timer runLater(Duration delay, Runnable runnable) {
|
||||
checkArgument(timer == null, "runLater or runPeriodically already called on that timer");
|
||||
timer = FxTimer.create(delay, runnable);
|
||||
timer.restart();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Timer runPeriodically(Duration interval, Runnable runnable) {
|
||||
checkArgument(timer == null, "runLater or runPeriodically already called on that timer");
|
||||
timer = FxTimer.createPeriodic(interval, runnable);
|
||||
timer.restart();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
checkNotNull(timer, "Timer must not be null");
|
||||
timer.stop();
|
||||
timer = null;
|
||||
}
|
||||
}
|
|
@ -33,6 +33,7 @@ import io.bitsquare.btc.WalletService;
|
|||
import io.bitsquare.btc.listeners.BalanceListener;
|
||||
import io.bitsquare.btc.pricefeed.MarketPriceFeed;
|
||||
import io.bitsquare.common.Clock;
|
||||
import io.bitsquare.common.Timer;
|
||||
import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.gui.Navigation;
|
||||
import io.bitsquare.gui.common.model.ViewModel;
|
||||
|
@ -67,13 +68,10 @@ import org.bitcoinj.store.BlockStoreException;
|
|||
import org.fxmisc.easybind.EasyBind;
|
||||
import org.fxmisc.easybind.Subscription;
|
||||
import org.fxmisc.easybind.monadic.MonadicBinding;
|
||||
import org.reactfx.util.FxTimer;
|
||||
import org.reactfx.util.Timer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -135,8 +133,8 @@ public class MainViewModel implements ViewModel {
|
|||
private final User user;
|
||||
private int numBTCPeers = 0;
|
||||
private ChangeListener<Number> numConnectedPeersListener, btcNumPeersListener;
|
||||
private java.util.Timer numberOfBtcPeersTimer;
|
||||
private java.util.Timer numberOfP2PNetworkPeersTimer;
|
||||
private Timer numberOfBtcPeersTimer;
|
||||
private Timer numberOfP2PNetworkPeersTimer;
|
||||
private Timer startupTimeout;
|
||||
private final Map<String, Subscription> disputeIsClosedSubscriptionsMap = new HashMap<>();
|
||||
private Subscription downloadPercentageSubscription;
|
||||
|
@ -199,7 +197,7 @@ public class MainViewModel implements ViewModel {
|
|||
onAllServicesInitialized();
|
||||
});
|
||||
|
||||
startupTimeout = FxTimer.runLater(Duration.ofMinutes(3), () -> {
|
||||
startupTimeout = UserThread.runAfter(() -> {
|
||||
log.warn("startupTimeout called");
|
||||
MainView.blur();
|
||||
new Popup().warning("The application could not startup after 3 minutes.\n" +
|
||||
|
@ -208,7 +206,18 @@ public class MainViewModel implements ViewModel {
|
|||
.closeButtonText("Shut down")
|
||||
.onClose(BitsquareApp.shutDownHandler::run)
|
||||
.show();
|
||||
});
|
||||
}, 3);
|
||||
|
||||
/*startupTimeout = FxTimer.runLater(Duration.ofMinutes(3), () -> {
|
||||
log.warn("startupTimeout called");
|
||||
MainView.blur();
|
||||
new Popup().warning("The application could not startup after 3 minutes.\n" +
|
||||
"There might be some network connection problems or a unstable Tor path.\n\n" +
|
||||
"Please restart and try again.")
|
||||
.closeButtonText("Shut down")
|
||||
.onClose(BitsquareApp.shutDownHandler::run)
|
||||
.show();
|
||||
});*/
|
||||
}
|
||||
|
||||
public void shutDown() {
|
||||
|
@ -329,7 +338,7 @@ public class MainViewModel implements ViewModel {
|
|||
if ((int) oldValue > 0 && (int) newValue == 0) {
|
||||
// give a bit of tolerance
|
||||
if (numberOfBtcPeersTimer != null)
|
||||
numberOfBtcPeersTimer.cancel();
|
||||
numberOfBtcPeersTimer.stop();
|
||||
numberOfBtcPeersTimer = UserThread.runAfter(() -> {
|
||||
if (walletService.numPeersProperty().get() == 0) {
|
||||
walletServiceErrorMsg.set("You lost the connection to all bitcoin network peers.\n" +
|
||||
|
@ -520,7 +529,7 @@ public class MainViewModel implements ViewModel {
|
|||
if ((int) oldValue > 0 && (int) newValue == 0) {
|
||||
// give a bit of tolerance
|
||||
if (numberOfP2PNetworkPeersTimer != null)
|
||||
numberOfP2PNetworkPeersTimer.cancel();
|
||||
numberOfP2PNetworkPeersTimer.stop();
|
||||
numberOfP2PNetworkPeersTimer = UserThread.runAfter(() -> {
|
||||
if (p2PService.getNumConnectedPeers().get() == 0) {
|
||||
p2PNetworkWarnMsg.set("You lost the connection to all P2P network peers.\n" +
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package io.bitsquare.gui.main.popups;
|
||||
|
||||
import io.bitsquare.common.Timer;
|
||||
import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.common.util.Utilities;
|
||||
import io.bitsquare.gui.main.MainView;
|
||||
|
@ -42,7 +43,6 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import java.time.Duration;
|
||||
import java.util.Optional;
|
||||
import java.util.Timer;
|
||||
|
||||
import static io.bitsquare.gui.util.FormBuilder.addCheckBox;
|
||||
|
||||
|
@ -109,7 +109,7 @@ public class Popup {
|
|||
window.widthProperty().removeListener(positionListener);
|
||||
|
||||
if (centerTime != null)
|
||||
centerTime.cancel();
|
||||
centerTime.stop();
|
||||
|
||||
removeEffectFromBackground();
|
||||
|
||||
|
@ -268,7 +268,7 @@ public class Popup {
|
|||
if (stage != null) {
|
||||
layout();
|
||||
if (centerTime != null)
|
||||
centerTime.cancel();
|
||||
centerTime.stop();
|
||||
|
||||
centerTime = UserThread.runAfter(this::layout, 3);
|
||||
}
|
||||
|
|
|
@ -120,6 +120,10 @@ public abstract class TradeStepView extends AnchorPane {
|
|||
public void onMinuteTick() {
|
||||
updateTimeLeft();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMissedSecondTick(long missed) {
|
||||
}
|
||||
};
|
||||
model.clock.addListener(clockListener);
|
||||
}
|
||||
|
|
|
@ -63,7 +63,10 @@ public class NetworkStatisticListItem {
|
|||
|
||||
@Override
|
||||
public void onMinuteTick() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMissedSecondTick(long missed) {
|
||||
}
|
||||
};
|
||||
clock.addListener(listener);
|
||||
|
|
|
@ -8,6 +8,7 @@ import com.google.inject.Inject;
|
|||
import com.google.inject.name.Named;
|
||||
import io.bitsquare.app.Log;
|
||||
import io.bitsquare.app.ProgramArguments;
|
||||
import io.bitsquare.common.Timer;
|
||||
import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.common.crypto.CryptoException;
|
||||
import io.bitsquare.common.crypto.KeyRing;
|
||||
|
@ -550,7 +551,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
|
|||
if (message instanceof AddDataMessage &&
|
||||
((AddDataMessage) message).data.equals(protectedMailboxData)) {
|
||||
sendMailboxMessageListener.onStoredInMailbox();
|
||||
sendMailboxMessageTimeoutTimer.cancel();
|
||||
sendMailboxMessageTimeoutTimer.stop();
|
||||
}
|
||||
};
|
||||
broadcaster.addListener(listener);
|
||||
|
@ -572,7 +573,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
|
|||
|
||||
boolean result = p2PDataStorage.add(protectedMailboxData, networkNode.getNodeAddress());
|
||||
if (!result) {
|
||||
sendMailboxMessageTimeoutTimer.cancel();
|
||||
sendMailboxMessageTimeoutTimer.stop();
|
||||
broadcaster.removeListener(listener);
|
||||
broadcaster.getNumOfBroadcastsProperty().removeListener(numOfBroadcastsChangeListener);
|
||||
sendMailboxMessageListener.onFault("Data already exists in our local database");
|
||||
|
|
|
@ -7,6 +7,7 @@ import com.google.common.util.concurrent.MoreExecutors;
|
|||
import com.msopentech.thali.java.toronionproxy.JavaOnionProxyContext;
|
||||
import com.msopentech.thali.java.toronionproxy.JavaOnionProxyManager;
|
||||
import io.bitsquare.app.Log;
|
||||
import io.bitsquare.common.Timer;
|
||||
import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.common.util.Utilities;
|
||||
import io.bitsquare.p2p.NodeAddress;
|
||||
|
@ -26,7 +27,6 @@ import org.slf4j.LoggerFactory;
|
|||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.util.Timer;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
|
@ -116,7 +116,7 @@ public class TorNetworkNode extends NetworkNode {
|
|||
allShutDown = EasyBind.combine(torNetworkNodeShutDown, networkNodeShutDown, shutDownTimerTriggered, (a, b, c) -> (a && b) || c);
|
||||
allShutDown.subscribe((observable, oldValue, newValue) -> {
|
||||
if (newValue) {
|
||||
shutDownTimeoutTimer.cancel();
|
||||
shutDownTimeoutTimer.stop();
|
||||
long ts = System.currentTimeMillis();
|
||||
log.debug("Shutdown executorService");
|
||||
try {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package io.bitsquare.p2p.peers;
|
||||
|
||||
import io.bitsquare.app.Log;
|
||||
import io.bitsquare.common.Timer;
|
||||
import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.p2p.Message;
|
||||
import io.bitsquare.p2p.NodeAddress;
|
||||
|
@ -507,7 +508,7 @@ public class PeerManager implements ConnectionListener, MessageListener {
|
|||
|
||||
private void stopCheckMaxConnectionsTimer() {
|
||||
if (checkMaxConnectionsTimer != null) {
|
||||
checkMaxConnectionsTimer.cancel();
|
||||
checkMaxConnectionsTimer.stop();
|
||||
checkMaxConnectionsTimer = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import com.google.common.util.concurrent.FutureCallback;
|
|||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.SettableFuture;
|
||||
import io.bitsquare.app.Log;
|
||||
import io.bitsquare.common.Timer;
|
||||
import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.p2p.Message;
|
||||
import io.bitsquare.p2p.NodeAddress;
|
||||
|
@ -24,7 +25,6 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import java.util.HashSet;
|
||||
import java.util.Random;
|
||||
import java.util.Timer;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
@ -200,7 +200,7 @@ public class RequestDataHandshake implements MessageListener {
|
|||
|
||||
private void stopTimeoutTimer() {
|
||||
if (timeoutTimer != null) {
|
||||
timeoutTimer.cancel();
|
||||
timeoutTimer.stop();
|
||||
timeoutTimer = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package io.bitsquare.p2p.peers.getdata;
|
||||
|
||||
import io.bitsquare.app.Log;
|
||||
import io.bitsquare.common.Timer;
|
||||
import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.p2p.Message;
|
||||
import io.bitsquare.p2p.NodeAddress;
|
||||
|
@ -250,7 +251,7 @@ public class RequestDataManager implements MessageListener {
|
|||
|
||||
private void stopRequestDataTimer() {
|
||||
if (requestDataTimer != null) {
|
||||
requestDataTimer.cancel();
|
||||
requestDataTimer.stop();
|
||||
requestDataTimer = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import com.google.common.util.concurrent.FutureCallback;
|
|||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.SettableFuture;
|
||||
import io.bitsquare.app.Log;
|
||||
import io.bitsquare.common.Timer;
|
||||
import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.p2p.network.CloseConnectionReason;
|
||||
import io.bitsquare.p2p.network.Connection;
|
||||
|
@ -15,7 +16,6 @@ import org.jetbrains.annotations.NotNull;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Timer;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
@ -116,7 +116,7 @@ class GetPeersRequestHandler {
|
|||
|
||||
private void cleanup() {
|
||||
if (timeoutTimer != null) {
|
||||
timeoutTimer.cancel();
|
||||
timeoutTimer.stop();
|
||||
timeoutTimer = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import com.google.common.util.concurrent.FutureCallback;
|
|||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.SettableFuture;
|
||||
import io.bitsquare.app.Log;
|
||||
import io.bitsquare.common.Timer;
|
||||
import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.p2p.Message;
|
||||
import io.bitsquare.p2p.NodeAddress;
|
||||
|
@ -20,7 +21,6 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Random;
|
||||
import java.util.Timer;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
@ -70,7 +70,7 @@ class PeerExchangeHandler implements MessageListener {
|
|||
connection.removeMessageListener(this);
|
||||
|
||||
if (timeoutTimer != null) {
|
||||
timeoutTimer.cancel();
|
||||
timeoutTimer.stop();
|
||||
timeoutTimer = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package io.bitsquare.p2p.peers.peerexchange;
|
|||
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import io.bitsquare.app.Log;
|
||||
import io.bitsquare.common.Timer;
|
||||
import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.common.util.Utilities;
|
||||
import io.bitsquare.p2p.Message;
|
||||
|
@ -101,7 +102,7 @@ public class PeerExchangeManager implements MessageListener, ConnectionListener
|
|||
if (lostAllConnections || connectToMorePeersTimer == null) {
|
||||
long delaySec = lostAllConnections ? RETRY_DELAY_AFTER_ALL_CON_LOST_SEC : RETRY_DELAY_SEC;
|
||||
if (lostAllConnections && connectToMorePeersTimer != null)
|
||||
connectToMorePeersTimer.cancel();
|
||||
connectToMorePeersTimer.stop();
|
||||
|
||||
connectToMorePeersTimer = UserThread.runAfter(() -> {
|
||||
log.trace("ConnectToMorePeersTimer called from onDisconnect code path");
|
||||
|
@ -292,7 +293,7 @@ public class PeerExchangeManager implements MessageListener, ConnectionListener
|
|||
|
||||
private void stopConnectToMorePeersTimer() {
|
||||
if (connectToMorePeersTimer != null) {
|
||||
connectToMorePeersTimer.cancel();
|
||||
connectToMorePeersTimer.stop();
|
||||
connectToMorePeersTimer = null;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue