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;
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.components.Popups;
import io.bitsquare.gui.main.MainView;
import io.bitsquare.gui.main.debug.DebugView;
import io.bitsquare.gui.util.ImageUtil;
import io.bitsquare.persistence.Persistence;
import io.bitsquare.user.AccountSettings;
import io.bitsquare.user.User;
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;
@ -109,8 +109,11 @@ public class BitsquareApp extends Application {
// configure the system tray
SystemTray systemTray = new SystemTray(primaryStage, this::stop);
primaryStage.setOnCloseRequest(e -> stop());
SystemTray.create(primaryStage, this::stop);
primaryStage.setOnCloseRequest(e -> {
e.consume();
stop();
});
scene.setOnKeyReleased(keyEvent -> {
// 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

View File

@ -48,11 +48,17 @@ public class SystemTray {
private static final String SHOW_WINDOW_LABEL = "Show exchange window";
private static final String HIDE_WINDOW_LABEL = "Hide exchange window";
private static SystemTray systemTray;
private final Stage stage;
private final Runnable onExit;
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) {
this.stage = stage;
this.onExit = onExit;
@ -126,4 +132,5 @@ public class SystemTray {
stage.hide();
toggleShowHideItem.setLabel(SHOW_WINDOW_LABEL);
}
}

View File

@ -64,6 +64,8 @@ public class TomP2PNetworkModule extends NetworkModule {
protected void doClose(Injector injector) {
super.doClose(injector);
// First shut down TomP2PNode to remove address from DHT
injector.getInstance(TomP2PNode.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 {
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 PeerAddress storedPeerAddress;
private PeerDHT peerDHT;
private BootstrappedPeerBuilder bootstrappedPeerBuilder;
private Timer timerForStoreAddress;
private Timer timerForIPCheck;
///////////////////////////////////////////////////////////////////////////////////////////
@ -119,6 +124,7 @@ public class TomP2PNode implements ClientNode {
if (peerDHT != null) {
TomP2PNode.this.peerDHT = peerDHT;
setupTimerForIPCheck();
setupTimerForStoreAddress();
setupReplyHandler(messageBroker);
try {
storeAddress();
@ -143,6 +149,44 @@ public class TomP2PNode implements ClientNode {
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
@ -306,26 +350,44 @@ public class TomP2PNode implements ClientNode {
});
}
private void setupTimerForIPCheck() {
Timer timer = new Timer();
long checkIfIPChangedPeriod = 600 * 1000;
timer.scheduleAtFixedRate(new TimerTask() {
private void setupTimerForStoreAddress() {
timerForStoreAddress = new Timer();
timerForStoreAddress.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
if (storedPeerAddress != null && peerDHT != null
&& !storedPeerAddress.equals(peerDHT.peerAddress()))
if (storedPeerAddress != null && peerDHT != null && !storedPeerAddress.equals(peerDHT.peerAddress()))
try {
storeAddress();
} catch (NetworkException e) {
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 {
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>() {
@Override
public void operationComplete(BaseFuture future) throws Exception {
@ -335,8 +397,7 @@ public class TomP2PNode implements ClientNode {
}
else {
log.error("storedPeerAddress not successful");
throw new NetworkException("Storing address was not successful. Reason: "
+ future.failedReason());
throw new NetworkException("Storing address was not successful. Reason: " + future.failedReason());
}
}
@ -353,41 +414,15 @@ public class TomP2PNode implements ClientNode {
}
}
private FuturePut saveAddress() throws IOException {
Number160 locationKey = Utils.makeSHAHash(keyPair.getPublic().getEncoded());
Data data = new Data(new TomP2PPeer(peerDHT.peerAddress()));
log.debug("storePeerAddress " + peerDHT.peerAddress().toString());
return putDomainProtectedData(locationKey, data);
}
@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);
private void removeAddress() {
try {
Number160 locationKey = Utils.makeSHAHash(keyPair.getPublic().getEncoded());
Data data = new Data(new TomP2PPeer(peerDHT.peerAddress()));
removeFromDataMap(locationKey, data).awaitUninterruptibly(2000); // give it max. 2 sec. to remove the address at shut down
} catch (IOException e) {
e.printStackTrace();
log.error("Exception at removeAddress " + e.toString());
}
}
@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 getPeerAddress(PublicKey messagePublicKey, GetPeerAddressListener getPeerAddressListener);
void findPeerAddress(PublicKey messagePublicKey, GetPeerAddressListener getPeerAddressListener);
}

View File

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

View File

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

View File

@ -34,7 +34,7 @@
<logger name="io.bitsquare.locale.BSResources" level="ERROR"/>
<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.Peer" level="WARN"/>