Remove peerAddress on shutdown

This commit is contained in:
Manfred Karrer 2015-03-19 21:12:33 +01:00
parent b416408f89
commit ea1afdebee
8 changed files with 104 additions and 56 deletions

View file

@ -17,19 +17,19 @@
package io.bitsquare.app; package io.bitsquare.app;
import io.bitsquare.user.AccountSettings; import io.bitsquare.common.viewfx.view.CachingViewLoader;
import io.bitsquare.common.viewfx.view.View;
import io.bitsquare.common.viewfx.view.ViewLoader;
import io.bitsquare.common.viewfx.view.guice.InjectorViewFactory;
import io.bitsquare.gui.SystemTray; import io.bitsquare.gui.SystemTray;
import io.bitsquare.gui.components.Popups; import io.bitsquare.gui.components.Popups;
import io.bitsquare.gui.main.MainView; import io.bitsquare.gui.main.MainView;
import io.bitsquare.gui.main.debug.DebugView; import io.bitsquare.gui.main.debug.DebugView;
import io.bitsquare.gui.util.ImageUtil; import io.bitsquare.gui.util.ImageUtil;
import io.bitsquare.persistence.Persistence; import io.bitsquare.persistence.Persistence;
import io.bitsquare.user.AccountSettings;
import io.bitsquare.user.User; import io.bitsquare.user.User;
import io.bitsquare.util.Utilities; import io.bitsquare.util.Utilities;
import io.bitsquare.common.viewfx.view.CachingViewLoader;
import io.bitsquare.common.viewfx.view.View;
import io.bitsquare.common.viewfx.view.ViewLoader;
import io.bitsquare.common.viewfx.view.guice.InjectorViewFactory;
import com.google.common.base.Throwables; import com.google.common.base.Throwables;
@ -109,8 +109,11 @@ public class BitsquareApp extends Application {
// configure the system tray // configure the system tray
SystemTray systemTray = new SystemTray(primaryStage, this::stop); SystemTray.create(primaryStage, this::stop);
primaryStage.setOnCloseRequest(e -> stop()); primaryStage.setOnCloseRequest(e -> {
e.consume();
stop();
});
scene.setOnKeyReleased(keyEvent -> { scene.setOnKeyReleased(keyEvent -> {
// For now we exit when closing/quit the app. // For now we exit when closing/quit the app.
// Later we will only hide the window (systemTray.hideStage()) and use the exit item in the system tray for // Later we will only hide the window (systemTray.hideStage()) and use the exit item in the system tray for

View file

@ -48,11 +48,17 @@ public class SystemTray {
private static final String SHOW_WINDOW_LABEL = "Show exchange window"; private static final String SHOW_WINDOW_LABEL = "Show exchange window";
private static final String HIDE_WINDOW_LABEL = "Hide exchange window"; private static final String HIDE_WINDOW_LABEL = "Hide exchange window";
private static SystemTray systemTray;
private final Stage stage; private final Stage stage;
private final Runnable onExit; private final Runnable onExit;
private final MenuItem toggleShowHideItem = new MenuItem(HIDE_WINDOW_LABEL); private final MenuItem toggleShowHideItem = new MenuItem(HIDE_WINDOW_LABEL);
public static void create(Stage stage, Runnable onExit) {
systemTray = new SystemTray(stage, onExit);
}
public SystemTray(Stage stage, Runnable onExit) { public SystemTray(Stage stage, Runnable onExit) {
this.stage = stage; this.stage = stage;
this.onExit = onExit; this.onExit = onExit;
@ -126,4 +132,5 @@ public class SystemTray {
stage.hide(); stage.hide();
toggleShowHideItem.setLabel(SHOW_WINDOW_LABEL); toggleShowHideItem.setLabel(SHOW_WINDOW_LABEL);
} }
} }

View file

@ -64,6 +64,8 @@ public class TomP2PNetworkModule extends NetworkModule {
protected void doClose(Injector injector) { protected void doClose(Injector injector) {
super.doClose(injector); super.doClose(injector);
// First shut down TomP2PNode to remove address from DHT
injector.getInstance(TomP2PNode.class).shutDown();
injector.getInstance(BootstrappedPeerBuilder.class).shutDown(); injector.getInstance(BootstrappedPeerBuilder.class).shutDown();
} }
} }

View file

@ -72,11 +72,16 @@ import static com.google.common.base.Preconditions.checkNotNull;
*/ */
public class TomP2PNode implements ClientNode { public class TomP2PNode implements ClientNode {
private static final Logger log = LoggerFactory.getLogger(TomP2PNode.class); private static final Logger log = LoggerFactory.getLogger(TomP2PNode.class);
private static final int IP_CHECK_PERIOD = 2 * 60 * 1000; // Cheap call if nothing changes, so set it short to 2 min.
private static final int STORE_ADDRESS_PERIOD = 5 * 60 * 1000; // Save every 5 min.
private static final int ADDRESS_TTL = STORE_ADDRESS_PERIOD * 2; // TTL 10 min.
private KeyPair keyPair; private KeyPair keyPair;
private PeerAddress storedPeerAddress; private PeerAddress storedPeerAddress;
private PeerDHT peerDHT; private PeerDHT peerDHT;
private BootstrappedPeerBuilder bootstrappedPeerBuilder; private BootstrappedPeerBuilder bootstrappedPeerBuilder;
private Timer timerForStoreAddress;
private Timer timerForIPCheck;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -119,6 +124,7 @@ public class TomP2PNode implements ClientNode {
if (peerDHT != null) { if (peerDHT != null) {
TomP2PNode.this.peerDHT = peerDHT; TomP2PNode.this.peerDHT = peerDHT;
setupTimerForIPCheck(); setupTimerForIPCheck();
setupTimerForStoreAddress();
setupReplyHandler(messageBroker); setupReplyHandler(messageBroker);
try { try {
storeAddress(); storeAddress();
@ -143,6 +149,44 @@ public class TomP2PNode implements ClientNode {
return bootstrapStateSubject.asObservable(); return bootstrapStateSubject.asObservable();
} }
void shutDown() {
timerForIPCheck.cancel();
timerForStoreAddress.cancel();
removeAddress();
}
@Override
public ConnectionType getConnectionType() {
BootstrapState bootstrapState = bootstrappedPeerBuilder.getBootstrapState().get();
switch (bootstrapState) {
case DISCOVERY_DIRECT_SUCCEEDED:
return ConnectionType.DIRECT;
case DISCOVERY_MANUAL_PORT_FORWARDING_SUCCEEDED:
return ConnectionType.MANUAL_PORT_FORWARDING;
case DISCOVERY_AUTO_PORT_FORWARDING_SUCCEEDED:
return ConnectionType.AUTO_PORT_FORWARDING;
case RELAY_SUCCEEDED:
return ConnectionType.RELAY;
default:
throw new BitsquareException("Invalid bootstrap state: %s", bootstrapState);
}
}
@Override
public Node getAddress() {
PeerAddress peerAddress = peerDHT.peerBean().serverPeerAddress();
return Node.at(
peerDHT.peerID().toString(),
peerAddress.inetAddress().getHostAddress(),
peerAddress.peerSocketAddress().tcpPort());
}
@Override
public Node getBootstrapNodeAddress() {
return bootstrappedPeerBuilder.getBootstrapNode();
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Generic DHT methods // Generic DHT methods
@ -306,26 +350,44 @@ public class TomP2PNode implements ClientNode {
}); });
} }
private void setupTimerForIPCheck() { private void setupTimerForStoreAddress() {
Timer timer = new Timer(); timerForStoreAddress = new Timer();
long checkIfIPChangedPeriod = 600 * 1000; timerForStoreAddress.scheduleAtFixedRate(new TimerTask() {
timer.scheduleAtFixedRate(new TimerTask() {
@Override @Override
public void run() { public void run() {
if (storedPeerAddress != null && peerDHT != null if (storedPeerAddress != null && peerDHT != null && !storedPeerAddress.equals(peerDHT.peerAddress()))
&& !storedPeerAddress.equals(peerDHT.peerAddress()))
try { try {
storeAddress(); storeAddress();
} catch (NetworkException e) { } catch (NetworkException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
}, checkIfIPChangedPeriod, checkIfIPChangedPeriod); }, STORE_ADDRESS_PERIOD, STORE_ADDRESS_PERIOD);
}
private void setupTimerForIPCheck() {
timerForIPCheck = new Timer();
timerForIPCheck.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
if (storedPeerAddress != null && peerDHT != null && !storedPeerAddress.equals(peerDHT.peerAddress()))
try {
storeAddress();
} catch (NetworkException e) {
e.printStackTrace();
}
}
}, IP_CHECK_PERIOD, IP_CHECK_PERIOD);
} }
private void storeAddress() throws NetworkException { private void storeAddress() throws NetworkException {
try { try {
FuturePut futurePut = saveAddress(); Number160 locationKey = Utils.makeSHAHash(keyPair.getPublic().getEncoded());
Data data = new Data(new TomP2PPeer(peerDHT.peerAddress()));
// We set a short time-to-live to make getAddress checks fail fast in case if the offerer is offline and to support cheap offerbook state updates
data.ttlSeconds(ADDRESS_TTL);
log.debug("storePeerAddress " + peerDHT.peerAddress().toString());
FuturePut futurePut = putDomainProtectedData(locationKey, data);
futurePut.addListener(new BaseFutureListener<BaseFuture>() { futurePut.addListener(new BaseFutureListener<BaseFuture>() {
@Override @Override
public void operationComplete(BaseFuture future) throws Exception { public void operationComplete(BaseFuture future) throws Exception {
@ -335,8 +397,7 @@ public class TomP2PNode implements ClientNode {
} }
else { else {
log.error("storedPeerAddress not successful"); log.error("storedPeerAddress not successful");
throw new NetworkException("Storing address was not successful. Reason: " throw new NetworkException("Storing address was not successful. Reason: " + future.failedReason());
+ future.failedReason());
} }
} }
@ -353,41 +414,15 @@ public class TomP2PNode implements ClientNode {
} }
} }
private FuturePut saveAddress() throws IOException {
private void removeAddress() {
try {
Number160 locationKey = Utils.makeSHAHash(keyPair.getPublic().getEncoded()); Number160 locationKey = Utils.makeSHAHash(keyPair.getPublic().getEncoded());
Data data = new Data(new TomP2PPeer(peerDHT.peerAddress())); Data data = new Data(new TomP2PPeer(peerDHT.peerAddress()));
log.debug("storePeerAddress " + peerDHT.peerAddress().toString()); removeFromDataMap(locationKey, data).awaitUninterruptibly(2000); // give it max. 2 sec. to remove the address at shut down
return putDomainProtectedData(locationKey, data); } catch (IOException e) {
e.printStackTrace();
log.error("Exception at removeAddress " + e.toString());
} }
@Override
public ConnectionType getConnectionType() {
BootstrapState bootstrapState = bootstrappedPeerBuilder.getBootstrapState().get();
switch (bootstrapState) {
case DISCOVERY_DIRECT_SUCCEEDED:
return ConnectionType.DIRECT;
case DISCOVERY_MANUAL_PORT_FORWARDING_SUCCEEDED:
return ConnectionType.MANUAL_PORT_FORWARDING;
case DISCOVERY_AUTO_PORT_FORWARDING_SUCCEEDED:
return ConnectionType.AUTO_PORT_FORWARDING;
case RELAY_SUCCEEDED:
return ConnectionType.RELAY;
default:
throw new BitsquareException("Invalid bootstrap state: %s", bootstrapState);
}
}
@Override
public Node getAddress() {
PeerAddress peerAddress = peerDHT.peerBean().serverPeerAddress();
return Node.at(
peerDHT.peerID().toString(),
peerAddress.inetAddress().getHostAddress(),
peerAddress.peerSocketAddress().tcpPort());
}
@Override
public Node getBootstrapNodeAddress() {
return bootstrappedPeerBuilder.getBootstrapNode();
} }
} }

View file

@ -38,5 +38,5 @@ public interface TradeMessageService extends MessageBroker {
void removeMessageHandler(MessageHandler listener); void removeMessageHandler(MessageHandler listener);
void getPeerAddress(PublicKey messagePublicKey, GetPeerAddressListener getPeerAddressListener); void findPeerAddress(PublicKey messagePublicKey, GetPeerAddressListener getPeerAddressListener);
} }

View file

@ -39,7 +39,7 @@ public class GetPeerAddress extends Task<CheckOfferAvailabilityModel> {
@Override @Override
protected void doRun() { protected void doRun() {
try { try {
model.tradeMessageService.getPeerAddress(model.offer.getMessagePublicKey(), new GetPeerAddressListener() { model.tradeMessageService.findPeerAddress(model.offer.getMessagePublicKey(), new GetPeerAddressListener() {
@Override @Override
public void onResult(Peer peer) { public void onResult(Peer peer) {
model.setPeer(peer); model.setPeer(peer);

View file

@ -75,15 +75,16 @@ public class TomP2PTradeMessageService implements TradeMessageService {
// Find peer address by publicKey // Find peer address by publicKey
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public void getPeerAddress(PublicKey publicKey, GetPeerAddressListener listener) { public void findPeerAddress(PublicKey publicKey, GetPeerAddressListener listener) {
final Number160 locationKey = Utils.makeSHAHash(publicKey.getEncoded()); final Number160 locationKey = Utils.makeSHAHash(publicKey.getEncoded());
FutureGet futureGet = tomP2PNode.getDomainProtectedData(locationKey, publicKey); FutureGet futureGet = tomP2PNode.getDomainProtectedData(locationKey, publicKey);
log.trace("findPeerAddress called");
futureGet.addListener(new BaseFutureAdapter<BaseFuture>() { futureGet.addListener(new BaseFutureAdapter<BaseFuture>() {
@Override @Override
public void operationComplete(BaseFuture baseFuture) throws Exception { public void operationComplete(BaseFuture baseFuture) throws Exception {
if (baseFuture.isSuccess() && futureGet.data() != null) { if (baseFuture.isSuccess() && futureGet.data() != null) {
final Peer peer = (Peer) futureGet.data().object(); final Peer peer = (Peer) futureGet.data().object();
log.trace("Peer found in DHT. Peer = " + peer);
executor.execute(() -> listener.onResult(peer)); executor.execute(() -> listener.onResult(peer));
} }
else { else {

View file

@ -34,7 +34,7 @@
<logger name="io.bitsquare.locale.BSResources" level="ERROR"/> <logger name="io.bitsquare.locale.BSResources" level="ERROR"/>
<logger name="org.bitcoinj" level="TRACE"/> <logger name="org.bitcoinj" level="TRACE"/>
<logger name="net.tomp2p" level="ERROR"/> <logger name="net.tomp2p" level="INFO"/>
<logger name="org.bitcoinj.core.BitcoinSerializer" level="WARN"/> <logger name="org.bitcoinj.core.BitcoinSerializer" level="WARN"/>
<logger name="org.bitcoinj.core.Peer" level="WARN"/> <logger name="org.bitcoinj.core.Peer" level="WARN"/>