Add footer with status info

This commit is contained in:
Manfred Karrer 2015-04-16 17:53:03 +02:00
parent 33a539ca52
commit 24d29eaa83
15 changed files with 380 additions and 207 deletions

View file

@ -13,24 +13,6 @@
<build> <build>
<resources>
<resource>
<filtering>false</filtering>
<directory>${basedir}/src/main/java</directory>
<includes>
<include>**/*.fxml</include>
<include>**/*.css</include>
</includes>
</resource>
<resource>
<filtering>false</filtering>
<directory>${basedir}/src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>

View file

@ -66,6 +66,10 @@ import java.util.stream.Collectors;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ReadOnlyDoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -87,8 +91,7 @@ public class WalletService {
private final List<TxConfidenceListener> txConfidenceListeners = new CopyOnWriteArrayList<>(); private final List<TxConfidenceListener> txConfidenceListeners = new CopyOnWriteArrayList<>();
private final List<BalanceListener> balanceListeners = new CopyOnWriteArrayList<>(); private final List<BalanceListener> balanceListeners = new CopyOnWriteArrayList<>();
private final ObservableDownloadListener downloadListener = new ObservableDownloadListener(); private final DownloadListener downloadListener = new DownloadListener();
private final Observable<Double> downloadProgress = downloadListener.getObservable();
private final WalletEventListener walletEventListener = new BitsquareWalletEventListener(); private final WalletEventListener walletEventListener = new BitsquareWalletEventListener();
private RegTestHost regTestHost; private RegTestHost regTestHost;
@ -209,7 +212,6 @@ public class WalletService {
walletAppKit.startAsync(); walletAppKit.startAsync();
return status.timeout(30, TimeUnit.SECONDS); return status.timeout(30, TimeUnit.SECONDS);
//return status.mergeWith(downloadProgress).timeout(30, TimeUnit.SECONDS);
} }
private void initWallet() { private void initWallet() {
@ -227,8 +229,8 @@ public class WalletService {
walletAppKit.stopAsync(); walletAppKit.stopAsync();
} }
public Observable<Double> getDownloadProgress() { public ReadOnlyDoubleProperty downloadPercentageProperty() {
return downloadProgress; return downloadListener.percentageProperty();
} }
public Wallet getWallet() { public Wallet getWallet() {
@ -536,24 +538,23 @@ public class WalletService {
// Inner classes // Inner classes
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
private static class ObservableDownloadListener extends DownloadProgressTracker { private static class DownloadListener extends DownloadProgressTracker {
private final DoubleProperty percentage = new SimpleDoubleProperty(-1);
private final Subject<Double, Double> subject = BehaviorSubject.create(0d);
@Override @Override
protected void progress(double percentage, int blocksLeft, Date date) { protected void progress(double percentage, int blocksLeft, Date date) {
super.progress(percentage, blocksLeft, date); super.progress(percentage, blocksLeft, date);
subject.onNext(percentage); Threading.USER_THREAD.execute(() -> this.percentage.set(percentage / 100d));
} }
@Override @Override
protected void doneDownload() { protected void doneDownload() {
super.doneDownload(); super.doneDownload();
subject.onCompleted(); Threading.USER_THREAD.execute(() -> this.percentage.set(1));
} }
public Observable<Double> getObservable() { public ReadOnlyDoubleProperty percentageProperty() {
return subject.asObservable(); return percentage;
} }
} }

View file

@ -1,47 +0,0 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.p2p;
public enum BootstrapState {
PEER_CREATION_FAILED,
DISCOVERY_STARTED,
DISCOVERY_DIRECT_SUCCEEDED,
DISCOVERY_MANUAL_PORT_FORWARDING_SUCCEEDED,
DISCOVERY_FAILED,
DISCOVERY_AUTO_PORT_FORWARDING_STARTED,
DISCOVERY_AUTO_PORT_FORWARDING_SUCCEEDED,
DISCOVERY_AUTO_PORT_FORWARDING_FAILED,
RELAY_STARTED,
RELAY_SUCCEEDED,
RELAY_FAILED,
BOOT_STRAP_SUCCEEDED,
BOOT_STRAP_FAILED;
private String message;
BootstrapState() {
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}

View file

@ -17,16 +17,18 @@
package io.bitsquare.p2p; package io.bitsquare.p2p;
import io.bitsquare.p2p.tomp2p.BootstrappedPeerBuilder;
import java.security.KeyPair; import java.security.KeyPair;
import rx.Observable; import rx.Observable;
public interface ClientNode { public interface ClientNode {
ConnectionType getConnectionType(); BootstrappedPeerBuilder.ConnectionType getConnectionType();
Node getAddress(); Node getAddress();
Node getBootstrapNodeAddress(); Node getBootstrapNodeAddress();
Observable<BootstrapState> bootstrap(KeyPair keyPair); Observable<BootstrappedPeerBuilder.State> bootstrap(KeyPair keyPair);
} }

View file

@ -1,22 +0,0 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.p2p;
public enum ConnectionType {
UNKNOWN, DIRECT, MANUAL_PORT_FORWARDING, AUTO_PORT_FORWARDING, RELAY
}

View file

@ -17,7 +17,6 @@
package io.bitsquare.p2p.tomp2p; package io.bitsquare.p2p.tomp2p;
import io.bitsquare.p2p.BootstrapState;
import io.bitsquare.p2p.Node; import io.bitsquare.p2p.Node;
import com.google.common.util.concurrent.SettableFuture; import com.google.common.util.concurrent.SettableFuture;
@ -34,6 +33,7 @@ import java.security.KeyPair;
import javax.inject.Inject; import javax.inject.Inject;
import javafx.beans.property.ObjectProperty; import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleObjectProperty;
import net.tomp2p.connection.Bindings; import net.tomp2p.connection.Bindings;
@ -76,6 +76,40 @@ public class BootstrappedPeerBuilder {
static final String NETWORK_INTERFACE_UNSPECIFIED = "<unspecified>"; static final String NETWORK_INTERFACE_UNSPECIFIED = "<unspecified>";
static final String USE_MANUAL_PORT_FORWARDING_KEY = "node.useManualPortForwarding"; static final String USE_MANUAL_PORT_FORWARDING_KEY = "node.useManualPortForwarding";
public enum ConnectionType {
UNDEFINED, DIRECT, MANUAL_PORT_FORWARDING, AUTO_PORT_FORWARDING, RELAY
}
public enum State {
UNDEFINED,
PEER_CREATION_FAILED,
DISCOVERY_STARTED,
DISCOVERY_DIRECT_SUCCEEDED,
DISCOVERY_MANUAL_PORT_FORWARDING_SUCCEEDED,
DISCOVERY_FAILED,
DISCOVERY_AUTO_PORT_FORWARDING_STARTED,
DISCOVERY_AUTO_PORT_FORWARDING_SUCCEEDED,
DISCOVERY_AUTO_PORT_FORWARDING_FAILED,
RELAY_STARTED,
RELAY_SUCCEEDED,
RELAY_FAILED,
BOOT_STRAP_SUCCEEDED,
BOOT_STRAP_FAILED;
private String message;
State() {
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
private KeyPair keyPair; private KeyPair keyPair;
private final int port; private final int port;
private final boolean useManualPortForwarding; private final boolean useManualPortForwarding;
@ -84,7 +118,8 @@ public class BootstrappedPeerBuilder {
private final SettableFuture<PeerDHT> settableFuture = SettableFuture.create(); private final SettableFuture<PeerDHT> settableFuture = SettableFuture.create();
private final ObjectProperty<BootstrapState> bootstrapState = new SimpleObjectProperty<>(); private final ObjectProperty<State> state = new SimpleObjectProperty<>(State.UNDEFINED);
private final ObjectProperty<ConnectionType> connectionType = new SimpleObjectProperty<>(ConnectionType.UNDEFINED);
private Peer peer; private Peer peer;
private PeerDHT peerDHT; private PeerDHT peerDHT;
@ -175,7 +210,7 @@ public class BootstrappedPeerBuilder {
discoverExternalAddress(); discoverExternalAddress();
} catch (IOException e) { } catch (IOException e) {
handleError(BootstrapState.PEER_CREATION_FAILED, "Cannot create a peer with port: " + handleError(State.PEER_CREATION_FAILED, "Cannot create a peer with port: " +
port + ". Exception: " + e); port + ". Exception: " + e);
} }
@ -202,7 +237,7 @@ public class BootstrappedPeerBuilder {
private void discoverExternalAddress() { private void discoverExternalAddress() {
FutureDiscover futureDiscover = peer.discover().peerAddress(getBootstrapAddress()).start(); FutureDiscover futureDiscover = peer.discover().peerAddress(getBootstrapAddress()).start();
setState(BootstrapState.DISCOVERY_STARTED, "Starting discovery..."); setState(State.DISCOVERY_STARTED);
PeerNAT peerNAT = new PeerBuilderNAT(peer).start(); PeerNAT peerNAT = new PeerBuilderNAT(peer).start();
FutureNAT futureNAT = peerNAT.startSetupPortforwarding(futureDiscover); FutureNAT futureNAT = peerNAT.startSetupPortforwarding(futureDiscover);
FutureRelayNAT futureRelayNAT = peerNAT.startRelay(new TCPRelayClientConfig(), futureDiscover, futureNAT); FutureRelayNAT futureRelayNAT = peerNAT.startRelay(new TCPRelayClientConfig(), futureDiscover, futureNAT);
@ -212,32 +247,35 @@ public class BootstrappedPeerBuilder {
public void operationComplete(BaseFuture futureRelayNAT) throws Exception { public void operationComplete(BaseFuture futureRelayNAT) throws Exception {
if (futureDiscover.isSuccess()) { if (futureDiscover.isSuccess()) {
if (useManualPortForwarding) { if (useManualPortForwarding) {
setState(BootstrapState.DISCOVERY_MANUAL_PORT_FORWARDING_SUCCEEDED, setState(State.DISCOVERY_MANUAL_PORT_FORWARDING_SUCCEEDED,
"Now visible to the Bitsquare network (with manual port forwarding)."); "NAT traversal successful with manual port forwarding.");
setConnectionType(ConnectionType.MANUAL_PORT_FORWARDING);
bootstrap(); bootstrap();
} }
else { else {
setState(BootstrapState.DISCOVERY_DIRECT_SUCCEEDED, "Now visible to the Bitsquare network."); setState(State.DISCOVERY_DIRECT_SUCCEEDED, "Visible to the network. No NAT traversal needed.");
setConnectionType(ConnectionType.DIRECT);
bootstrap(); bootstrap();
} }
} }
else { else {
setState(BootstrapState.DISCOVERY_AUTO_PORT_FORWARDING_STARTED, setState(State.DISCOVERY_AUTO_PORT_FORWARDING_STARTED);
"Configuring automatic port forwarding");
if (futureNAT.isSuccess()) { if (futureNAT.isSuccess()) {
setState(BootstrapState.DISCOVERY_AUTO_PORT_FORWARDING_SUCCEEDED, setState(State.DISCOVERY_AUTO_PORT_FORWARDING_SUCCEEDED,
"Now visible to the Bitsquare network (with automatic port forwarding)."); "NAT traversal successful with automatic port forwarding.");
setConnectionType(ConnectionType.AUTO_PORT_FORWARDING);
bootstrap(); bootstrap();
} }
else { else {
if (futureRelayNAT.isSuccess()) { if (futureRelayNAT.isSuccess()) {
// relay mode succeeded // relay mode succeeded
setState(BootstrapState.RELAY_SUCCEEDED, "Bootstrap using relay was successful."); setState(State.RELAY_SUCCEEDED, "NAT traversal not successful. Using relay mode.");
setConnectionType(ConnectionType.RELAY);
bootstrap(); bootstrap();
} }
else { else {
// All attempts failed. Give up... // All attempts failed. Give up...
handleError(BootstrapState.RELAY_FAILED, "Bootstrap using relay has failed " + handleError(State.RELAY_FAILED, "NAT traversal using relay mode failed " +
futureRelayNAT.failedReason()); futureRelayNAT.failedReason());
} }
} }
@ -246,7 +284,7 @@ public class BootstrappedPeerBuilder {
@Override @Override
public void exceptionCaught(Throwable t) throws Exception { public void exceptionCaught(Throwable t) throws Exception {
handleError(BootstrapState.RELAY_FAILED, "Exception at bootstrap: " + t.getMessage()); handleError(State.RELAY_FAILED, "Exception at bootstrap: " + t.getMessage());
} }
}); });
} }
@ -263,18 +301,18 @@ public class BootstrappedPeerBuilder {
public void operationComplete(BaseFuture future) throws Exception { public void operationComplete(BaseFuture future) throws Exception {
if (futureBootstrap.isSuccess()) { if (futureBootstrap.isSuccess()) {
log.trace("bootstrap complete"); log.trace("bootstrap complete");
setState(BootstrapState.BOOT_STRAP_SUCCEEDED, "Bootstrap using relay was successful."); setState(State.BOOT_STRAP_SUCCEEDED, "Bootstrap was successful.");
settableFuture.set(peerDHT); settableFuture.set(peerDHT);
} }
else { else {
handleError(BootstrapState.BOOT_STRAP_FAILED, "Bootstrapping failed. " + handleError(State.BOOT_STRAP_FAILED, "Bootstrap failed. " +
futureBootstrap.failedReason()); futureBootstrap.failedReason());
} }
} }
@Override @Override
public void exceptionCaught(Throwable t) throws Exception { public void exceptionCaught(Throwable t) throws Exception {
handleError(BootstrapState.BOOT_STRAP_FAILED, "Exception at bootstrap: " + t.getMessage()); handleError(State.BOOT_STRAP_FAILED, "Exception at bootstrap: " + t.getMessage());
} }
}); });
} }
@ -295,25 +333,41 @@ public class BootstrappedPeerBuilder {
return bootstrapNode; return bootstrapNode;
} }
public ObjectProperty<BootstrapState> getBootstrapState() { public ConnectionType getConnectionType() {
return bootstrapState; return connectionType.get();
} }
private void setState(BootstrapState bootstrapState, String message) { public ReadOnlyObjectProperty<ConnectionType> connectionTypeProperty() {
setState(bootstrapState, message, true); return connectionType;
} }
private void setState(BootstrapState bootstrapState, String message, boolean isSuccess) { private void setConnectionType(ConnectionType discoveryState) {
this.connectionType.set(discoveryState);
}
public ObjectProperty<State> getState() {
return state;
}
private void setState(State state) {
setState(state, "", true);
}
private void setState(State state, String message) {
setState(state, message, true);
}
private void setState(State state, String message, boolean isSuccess) {
if (isSuccess) if (isSuccess)
log.info(message); log.info(message);
else else
log.error(message); log.error(message);
bootstrapState.setMessage(message); state.setMessage(message);
this.bootstrapState.set(bootstrapState); this.state.set(state);
} }
private void handleError(BootstrapState state, String errorMessage) { private void handleError(State state, String errorMessage) {
setState(state, errorMessage, false); setState(state, errorMessage, false);
peerDHT.shutdown(); peerDHT.shutdown();
settableFuture.setException(new Exception(errorMessage)); settableFuture.setException(new Exception(errorMessage));

View file

@ -19,9 +19,7 @@ package io.bitsquare.p2p.tomp2p;
import io.bitsquare.BitsquareException; import io.bitsquare.BitsquareException;
import io.bitsquare.common.handlers.ResultHandler; import io.bitsquare.common.handlers.ResultHandler;
import io.bitsquare.p2p.BootstrapState;
import io.bitsquare.p2p.ClientNode; import io.bitsquare.p2p.ClientNode;
import io.bitsquare.p2p.ConnectionType;
import io.bitsquare.p2p.Node; import io.bitsquare.p2p.Node;
import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.FutureCallback;
@ -54,7 +52,7 @@ public class TomP2PNode implements ClientNode {
private PeerDHT peerDHT; private PeerDHT peerDHT;
private BootstrappedPeerBuilder bootstrappedPeerBuilder; private BootstrappedPeerBuilder bootstrappedPeerBuilder;
private final Subject<BootstrapState, BootstrapState> bootstrapStateSubject; private final Subject<BootstrappedPeerBuilder.State, BootstrappedPeerBuilder.State> bootstrapStateSubject;
private final List<ResultHandler> resultHandlers = new CopyOnWriteArrayList<>(); private final List<ResultHandler> resultHandlers = new CopyOnWriteArrayList<>();
@ -80,10 +78,10 @@ public class TomP2PNode implements ClientNode {
// Public methods // Public methods
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public Observable<BootstrapState> bootstrap(KeyPair keyPair) { public Observable<BootstrappedPeerBuilder.State> bootstrap(KeyPair keyPair) {
bootstrappedPeerBuilder.setKeyPair(keyPair); bootstrappedPeerBuilder.setKeyPair(keyPair);
bootstrappedPeerBuilder.getBootstrapState().addListener((ov, oldValue, newValue) -> { bootstrappedPeerBuilder.getState().addListener((ov, oldValue, newValue) -> {
log.debug("BootstrapState changed " + newValue); log.debug("BootstrapState changed " + newValue);
bootstrapStateSubject.onNext(newValue); bootstrapStateSubject.onNext(newValue);
}); });
@ -118,20 +116,8 @@ public class TomP2PNode implements ClientNode {
} }
@Override @Override
public ConnectionType getConnectionType() { public BootstrappedPeerBuilder.ConnectionType getConnectionType() {
BootstrapState bootstrapState = bootstrappedPeerBuilder.getBootstrapState().get(); return bootstrappedPeerBuilder.getConnectionType();
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 @Override

View file

@ -18,8 +18,8 @@
package io.bitsquare.msg; package io.bitsquare.msg;
import io.bitsquare.p2p.BootstrapNodes; import io.bitsquare.p2p.BootstrapNodes;
import io.bitsquare.p2p.ConnectionType;
import io.bitsquare.p2p.Node; import io.bitsquare.p2p.Node;
import io.bitsquare.p2p.tomp2p.BootstrappedPeerBuilder;
import io.bitsquare.util.Repeat; import io.bitsquare.util.Repeat;
import io.bitsquare.util.RepeatRule; import io.bitsquare.util.RepeatRule;
@ -84,11 +84,11 @@ public class TomP2PTests {
private static final Logger log = LoggerFactory.getLogger(TomP2PTests.class); private static final Logger log = LoggerFactory.getLogger(TomP2PTests.class);
// If you want to test in one specific connection mode define it directly, otherwise use UNKNOWN // If you want to test in one specific connection mode define it directly, otherwise use UNKNOWN
private static final ConnectionType FORCED_CONNECTION_TYPE = ConnectionType.RELAY; private static final BootstrappedPeerBuilder.ConnectionType FORCED_CONNECTION_TYPE = BootstrappedPeerBuilder.ConnectionType.RELAY;
// Typically you run the bootstrap node in localhost to test direct connection. // Typically you run the bootstrap node in localhost to test direct connection.
// If you have a setup where you are not behind a router you can also use a WAN bootstrap node. // If you have a setup where you are not behind a router you can also use a WAN bootstrap node.
private static final Node BOOTSTRAP_NODE = (FORCED_CONNECTION_TYPE == ConnectionType.DIRECT) ? private static final Node BOOTSTRAP_NODE = (FORCED_CONNECTION_TYPE == BootstrappedPeerBuilder.ConnectionType.DIRECT) ?
BootstrapNodes.LOCALHOST : Node.at("digitalocean1.dev.bitsquare.io", "188.226.179.109", 7367); BootstrapNodes.LOCALHOST : Node.at("digitalocean1.dev.bitsquare.io", "188.226.179.109", 7367);
private static final PeerAddress BOOTSTRAP_NODE_ADDRESS; private static final PeerAddress BOOTSTRAP_NODE_ADDRESS;
@ -111,7 +111,7 @@ public class TomP2PTests {
private PeerDHT peer2DHT; private PeerDHT peer2DHT;
private int client1Port; private int client1Port;
private int client2Port; private int client2Port;
private ConnectionType resolvedConnectionType; private BootstrappedPeerBuilder.ConnectionType resolvedConnectionType;
public @Rule RepeatRule repeatRule = new RepeatRule(); public @Rule RepeatRule repeatRule = new RepeatRule();
@Before @Before
@ -135,7 +135,7 @@ public class TomP2PTests {
@Test @Test
@Repeat(STRESS_TEST_COUNT) @Repeat(STRESS_TEST_COUNT)
public void bootstrapInUnknownMode() throws Exception { public void bootstrapInUnknownMode() throws Exception {
if (FORCED_CONNECTION_TYPE == ConnectionType.UNKNOWN) { if (FORCED_CONNECTION_TYPE == BootstrappedPeerBuilder.ConnectionType.UNDEFINED) {
peer = bootstrapInUnknownMode(client1Port); peer = bootstrapInUnknownMode(client1Port);
assertNotNull(peer); assertNotNull(peer);
} }
@ -144,7 +144,7 @@ public class TomP2PTests {
@Test @Test
@Repeat(STRESS_TEST_COUNT) @Repeat(STRESS_TEST_COUNT)
public void testBootstrapDirectConnection() throws Exception { public void testBootstrapDirectConnection() throws Exception {
if (FORCED_CONNECTION_TYPE == ConnectionType.DIRECT) { if (FORCED_CONNECTION_TYPE == BootstrappedPeerBuilder.ConnectionType.DIRECT) {
peer = bootstrapDirectConnection(client1Port); peer = bootstrapDirectConnection(client1Port);
assertNotNull(peer); assertNotNull(peer);
} }
@ -153,8 +153,8 @@ public class TomP2PTests {
@Test @Test
@Repeat(STRESS_TEST_COUNT) @Repeat(STRESS_TEST_COUNT)
public void testBootstrapWithPortForwarding() throws Exception { public void testBootstrapWithPortForwarding() throws Exception {
if (FORCED_CONNECTION_TYPE == ConnectionType.AUTO_PORT_FORWARDING || if (FORCED_CONNECTION_TYPE == BootstrappedPeerBuilder.ConnectionType.AUTO_PORT_FORWARDING ||
FORCED_CONNECTION_TYPE == ConnectionType.MANUAL_PORT_FORWARDING) { FORCED_CONNECTION_TYPE == BootstrappedPeerBuilder.ConnectionType.MANUAL_PORT_FORWARDING) {
peer = bootstrapWithPortForwarding(client2Port); peer = bootstrapWithPortForwarding(client2Port);
assertNotNull(peer); assertNotNull(peer);
} }
@ -163,7 +163,7 @@ public class TomP2PTests {
@Test @Test
@Repeat(STRESS_TEST_COUNT) @Repeat(STRESS_TEST_COUNT)
public void testBootstrapInRelayMode() throws Exception { public void testBootstrapInRelayMode() throws Exception {
if (FORCED_CONNECTION_TYPE == ConnectionType.RELAY) { if (FORCED_CONNECTION_TYPE == BootstrappedPeerBuilder.ConnectionType.RELAY) {
peer = bootstrapInRelayMode(client1Port); peer = bootstrapInRelayMode(client1Port);
assertNotNull(peer); assertNotNull(peer);
} }
@ -498,7 +498,8 @@ public class TomP2PTests {
@Test @Test
@Repeat(STRESS_TEST_COUNT) @Repeat(STRESS_TEST_COUNT)
public void testSendDirectBetweenLocalPeers() throws Exception { public void testSendDirectBetweenLocalPeers() throws Exception {
if (FORCED_CONNECTION_TYPE == ConnectionType.DIRECT || resolvedConnectionType == ConnectionType.DIRECT) { if (FORCED_CONNECTION_TYPE == BootstrappedPeerBuilder.ConnectionType.DIRECT || resolvedConnectionType == BootstrappedPeerBuilder.ConnectionType
.DIRECT) {
peer1DHT = getDHTPeer(client1Port); peer1DHT = getDHTPeer(client1Port);
peer2DHT = getDHTPeer(client2Port); peer2DHT = getDHTPeer(client2Port);
@ -594,8 +595,8 @@ public class TomP2PTests {
Number160 peerId = Number160.createHash(UUID.randomUUID().toString()); Number160 peerId = Number160.createHash(UUID.randomUUID().toString());
Peer peer = null; Peer peer = null;
try { try {
if (FORCED_CONNECTION_TYPE == ConnectionType.MANUAL_PORT_FORWARDING || if (FORCED_CONNECTION_TYPE == BootstrappedPeerBuilder.ConnectionType.MANUAL_PORT_FORWARDING ||
resolvedConnectionType == ConnectionType.MANUAL_PORT_FORWARDING) { resolvedConnectionType == BootstrappedPeerBuilder.ConnectionType.MANUAL_PORT_FORWARDING) {
peer = new PeerBuilder(peerId).bindings(getBindings()) peer = new PeerBuilder(peerId).bindings(getBindings())
.behindFirewall() .behindFirewall()
.tcpPortForwarding(clientPort) .tcpPortForwarding(clientPort)
@ -700,22 +701,22 @@ public class TomP2PTests {
} }
private Peer bootstrapInUnknownMode(int clientPort) { private Peer bootstrapInUnknownMode(int clientPort) {
resolvedConnectionType = ConnectionType.DIRECT; resolvedConnectionType = BootstrappedPeerBuilder.ConnectionType.DIRECT;
Peer peer = bootstrapDirectConnection(clientPort); Peer peer = bootstrapDirectConnection(clientPort);
if (peer != null) if (peer != null)
return peer; return peer;
resolvedConnectionType = ConnectionType.MANUAL_PORT_FORWARDING; resolvedConnectionType = BootstrappedPeerBuilder.ConnectionType.MANUAL_PORT_FORWARDING;
peer = bootstrapWithPortForwarding(clientPort); peer = bootstrapWithPortForwarding(clientPort);
if (peer != null) if (peer != null)
return peer; return peer;
resolvedConnectionType = ConnectionType.AUTO_PORT_FORWARDING; resolvedConnectionType = BootstrappedPeerBuilder.ConnectionType.AUTO_PORT_FORWARDING;
peer = bootstrapWithPortForwarding(clientPort); peer = bootstrapWithPortForwarding(clientPort);
if (peer != null) if (peer != null)
return peer; return peer;
resolvedConnectionType = ConnectionType.RELAY; resolvedConnectionType = BootstrappedPeerBuilder.ConnectionType.RELAY;
peer = bootstrapInRelayMode(clientPort); peer = bootstrapInRelayMode(clientPort);
if (peer != null) if (peer != null)
return peer; return peer;
@ -728,13 +729,13 @@ public class TomP2PTests {
private PeerDHT getDHTPeer(int clientPort) { private PeerDHT getDHTPeer(int clientPort) {
Peer peer; Peer peer;
if (FORCED_CONNECTION_TYPE == ConnectionType.DIRECT) { if (FORCED_CONNECTION_TYPE == BootstrappedPeerBuilder.ConnectionType.DIRECT) {
peer = bootstrapDirectConnection(clientPort); peer = bootstrapDirectConnection(clientPort);
} }
else if (FORCED_CONNECTION_TYPE == ConnectionType.AUTO_PORT_FORWARDING) { else if (FORCED_CONNECTION_TYPE == BootstrappedPeerBuilder.ConnectionType.AUTO_PORT_FORWARDING) {
peer = bootstrapWithPortForwarding(clientPort); peer = bootstrapWithPortForwarding(clientPort);
} }
else if (FORCED_CONNECTION_TYPE == ConnectionType.RELAY) { else if (FORCED_CONNECTION_TYPE == BootstrappedPeerBuilder.ConnectionType.RELAY) {
peer = bootstrapInRelayMode(clientPort); peer = bootstrapInRelayMode(clientPort);
} }
else { else {

View file

@ -39,13 +39,6 @@
<include>**/*.css</include> <include>**/*.css</include>
</includes> </includes>
</resource> </resource>
<resource>
<filtering>false</filtering>
<directory>${basedir}/src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources> </resources>
<plugins> <plugins>

View file

@ -91,7 +91,7 @@ public class BitsquareApp extends Application {
CachingViewLoader viewLoader = injector.getInstance(CachingViewLoader.class); CachingViewLoader viewLoader = injector.getInstance(CachingViewLoader.class);
View view = viewLoader.load(MainView.class); View view = viewLoader.load(MainView.class);
scene = new Scene((Parent) view.getRoot(), 1000, 620); scene = new Scene((Parent) view.getRoot(), 1000, 650);
scene.getStylesheets().setAll( scene.getStylesheets().setAll(
"/io/bitsquare/gui/bitsquare.css", "/io/bitsquare/gui/bitsquare.css",
"/io/bitsquare/gui/images.css"); "/io/bitsquare/gui/images.css");

View file

@ -56,6 +56,21 @@ lower gradient color on tab: dddddd
-fx-background-color: #f4f4f4; -fx-background-color: #f4f4f4;
} }
#footer-pane {
-fx-background-color: #ddd;
-fx-font-size: 12;
-fx-text-fill: #333;
}
#footer-pane-line {
-fx-background: #bbb;
}
#footer-bitcoin-network-label {
-fx-text-fill: -fx-accent;
-fx-font-size: 12;
}
#headline-label { #headline-label {
-fx-font-weight: bold; -fx-font-weight: bold;
-fx-font-size: 18; -fx-font-size: 18;

View file

@ -114,7 +114,7 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
setLeftAnchor(this, 0d); setLeftAnchor(this, 0d);
setRightAnchor(this, 0d); setRightAnchor(this, 0d);
setTopAnchor(this, 60d); setTopAnchor(this, 60d);
setBottomAnchor(this, 25d); setBottomAnchor(this, 10d);
}}; }};
AnchorPane applicationContainer = new AnchorPane(leftNavPane, rightNavPane, contentContainer) {{ AnchorPane applicationContainer = new AnchorPane(leftNavPane, rightNavPane, contentContainer) {{
@ -124,6 +124,7 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
BorderPane baseApplicationContainer = new BorderPane(applicationContainer) {{ BorderPane baseApplicationContainer = new BorderPane(applicationContainer) {{
setId("base-content-container"); setId("base-content-container");
}}; }};
baseApplicationContainer.setBottom(createFooter());
setupNotificationIcon(portfolioButtonHolder); setupNotificationIcon(portfolioButtonHolder);
@ -187,15 +188,84 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
}); });
} }
private VBox createSplashScreen() { private AnchorPane createFooter() {
VBox vBox = new VBox(); // BTC
vBox.setAlignment(Pos.CENTER); Label blockchainSyncLabel = new Label();
vBox.setSpacing(0); blockchainSyncLabel.setId("footer-pane");
vBox.setId("splash"); blockchainSyncLabel.textProperty().bind(model.blockchainSyncInfoFooter);
model.walletServiceErrorMsg.addListener((ov, oldValue, newValue) -> {
blockchainSyncLabel.setId("splash-error-state-msg");
Popups.openErrorPopup("Error", "Connecting to the bitcoin network failed. \n\nReason: " +
newValue);
});
ImageView logo = new ImageView(); ProgressBar blockchainSyncIndicator = new ProgressBar(-1);
logo.setId("image-splash-logo"); blockchainSyncIndicator.setPrefWidth(120);
blockchainSyncIndicator.setMaxHeight(10);
blockchainSyncIndicator.progressProperty().bind(model.blockchainSyncProgress);
Label bitcoinNetworkLabel = new Label();
bitcoinNetworkLabel.setId("footer-bitcoin-network-label");
bitcoinNetworkLabel.setText(model.bitcoinNetworkAsString);
model.blockchainSyncProgress.addListener((ov, oldValue, newValue) -> {
if ((double) newValue >= 1) {
blockchainSyncIndicator.setVisible(false);
blockchainSyncIndicator.setManaged(false);
blockchainSyncLabel.setVisible(false);
blockchainSyncLabel.setManaged(false);
}
});
HBox blockchainSyncBox = new HBox();
blockchainSyncBox.setSpacing(10);
blockchainSyncBox.setAlignment(Pos.CENTER);
blockchainSyncBox.getChildren().addAll(blockchainSyncLabel, blockchainSyncIndicator, bitcoinNetworkLabel);
setLeftAnchor(blockchainSyncBox, 20d);
setBottomAnchor(blockchainSyncBox, 7d);
// version
Label versionLabel = new Label();
versionLabel.setId("footer-pane");
versionLabel.setTextAlignment(TextAlignment.CENTER);
versionLabel.setAlignment(Pos.BASELINE_CENTER);
versionLabel.setText(model.version);
root.widthProperty().addListener((ov, oldValue, newValue) -> {
versionLabel.setLayoutX(((double) newValue - versionLabel.getWidth()) / 2);
});
setBottomAnchor(versionLabel, 7d);
// P2P
Label bootstrapLabel = new Label();
bootstrapLabel.setId("footer-pane");
setRightAnchor(bootstrapLabel, 60d);
setBottomAnchor(bootstrapLabel, 7d);
bootstrapLabel.textProperty().bind(model.bootstrapInfoFooter);
ImageView bootstrapIcon = new ImageView();
setRightAnchor(bootstrapIcon, 20d);
setBottomAnchor(bootstrapIcon, 9d);
bootstrapIcon.idProperty().bind(model.bootstrapIconId);
// line
Separator separator = new Separator();
separator.setId("footer-pane-line");
separator.setPrefHeight(1);
setLeftAnchor(separator, 0d);
setRightAnchor(separator, 0d);
setTopAnchor(separator, 0d);
AnchorPane footerContainer = new AnchorPane(separator, blockchainSyncBox, versionLabel, bootstrapLabel, bootstrapIcon) {{
setId("footer-pane");
setMinHeight(30);
setMaxHeight(30);
}};
return footerContainer;
}
private HBox createBitcoinInfoBox() {
Label blockchainSyncLabel = new Label(); Label blockchainSyncLabel = new Label();
blockchainSyncLabel.textProperty().bind(model.blockchainSyncInfo); blockchainSyncLabel.textProperty().bind(model.blockchainSyncInfo);
model.walletServiceErrorMsg.addListener((ov, oldValue, newValue) -> { model.walletServiceErrorMsg.addListener((ov, oldValue, newValue) -> {
@ -232,7 +302,10 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
blockchainSyncBox.setPrefHeight(50); blockchainSyncBox.setPrefHeight(50);
blockchainSyncBox.getChildren().addAll(blockchainSyncLabel, blockchainSyncIndicator, blockchainSyncBox.getChildren().addAll(blockchainSyncLabel, blockchainSyncIndicator,
blockchainSyncIcon, bitcoinNetworkLabel); blockchainSyncIcon, bitcoinNetworkLabel);
return blockchainSyncBox;
}
private HBox createP2PNetworkBox() {
Label bootstrapStateLabel = new Label(); Label bootstrapStateLabel = new Label();
bootstrapStateLabel.setWrapText(true); bootstrapStateLabel.setWrapText(true);
bootstrapStateLabel.setMaxWidth(500); bootstrapStateLabel.setMaxWidth(500);
@ -272,8 +345,10 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
bootstrapBox.setAlignment(Pos.CENTER); bootstrapBox.setAlignment(Pos.CENTER);
bootstrapBox.setPrefHeight(50); bootstrapBox.setPrefHeight(50);
bootstrapBox.getChildren().addAll(bootstrapStateLabel, bootstrapIndicator, bootstrapIcon); bootstrapBox.getChildren().addAll(bootstrapStateLabel, bootstrapIndicator, bootstrapIcon);
return bootstrapBox;
}
// software update private HBox createUpdateBox() {
Label updateInfoLabel = new Label(); Label updateInfoLabel = new Label();
updateInfoLabel.setTextAlignment(TextAlignment.RIGHT); updateInfoLabel.setTextAlignment(TextAlignment.RIGHT);
updateInfoLabel.textProperty().bind(model.updateInfo); updateInfoLabel.textProperty().bind(model.updateInfo);
@ -297,8 +372,121 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
updateBox.setAlignment(Pos.CENTER); updateBox.setAlignment(Pos.CENTER);
updateBox.setPrefHeight(20); updateBox.setPrefHeight(20);
updateBox.getChildren().addAll(updateInfoLabel, restartButton, updateIcon); updateBox.getChildren().addAll(updateInfoLabel, restartButton, updateIcon);
return updateBox;
}
vBox.getChildren().addAll(logo, blockchainSyncBox, bootstrapBox, updateBox); private VBox createSplashScreen() {
VBox vBox = new VBox();
vBox.setAlignment(Pos.CENTER);
vBox.setSpacing(0);
vBox.setId("splash");
ImageView logo = new ImageView();
logo.setId("image-splash-logo");
/*Label blockchainSyncLabel = new Label();
blockchainSyncLabel.textProperty().bind(model.blockchainSyncInfo);
model.walletServiceErrorMsg.addListener((ov, oldValue, newValue) -> {
blockchainSyncLabel.setId("splash-error-state-msg");
Popups.openErrorPopup("Error", "Connecting to the bitcoin network failed. \n\nReason: " +
newValue);
});
ProgressBar blockchainSyncIndicator = new ProgressBar(-1);
blockchainSyncIndicator.setPrefWidth(120);
blockchainSyncIndicator.progressProperty().bind(model.blockchainSyncProgress);
ImageView blockchainSyncIcon = new ImageView();
blockchainSyncIcon.setVisible(false);
blockchainSyncIcon.setManaged(false);
model.blockchainSyncIconId.addListener((ov, oldValue, newValue) -> {
blockchainSyncIcon.setId(newValue);
blockchainSyncIcon.setVisible(true);
blockchainSyncIcon.setManaged(true);
blockchainSyncIndicator.setVisible(false);
blockchainSyncIndicator.setManaged(false);
});
Label bitcoinNetworkLabel = new Label();
bitcoinNetworkLabel.setText(model.bitcoinNetworkAsString);
bitcoinNetworkLabel.setId("splash-bitcoin-network-label");
HBox blockchainSyncBox = new HBox();
blockchainSyncBox.setSpacing(10);
blockchainSyncBox.setAlignment(Pos.CENTER);
blockchainSyncBox.setPadding(new Insets(40, 0, 0, 0));
blockchainSyncBox.setPrefHeight(50);
blockchainSyncBox.getChildren().addAll(blockchainSyncLabel, blockchainSyncIndicator,
blockchainSyncIcon, bitcoinNetworkLabel);*/
/* Label bootstrapStateLabel = new Label();
bootstrapStateLabel.setWrapText(true);
bootstrapStateLabel.setMaxWidth(500);
bootstrapStateLabel.setTextAlignment(TextAlignment.CENTER);
bootstrapStateLabel.textProperty().bind(model.bootstrapInfo);
ProgressIndicator bootstrapIndicator = new ProgressIndicator();
bootstrapIndicator.setMaxSize(24, 24);
bootstrapIndicator.progressProperty().bind(model.bootstrapProgress);
model.bootstrapErrorMsg.addListener((ov, oldValue, newValue) -> {
bootstrapStateLabel.setId("splash-error-state-msg");
bootstrapIndicator.setVisible(false);
Popups.openErrorPopup("Error", "Connecting to the Bitsquare network failed. \n\nReason: " +
model.bootstrapErrorMsg.get());
});
ImageView bootstrapIcon = new ImageView();
bootstrapIcon.setVisible(false);
bootstrapIcon.setManaged(false);
model.bootstrapIconId.addListener((ov, oldValue, newValue) -> {
bootstrapIcon.setId(newValue);
bootstrapIcon.setVisible(true);
bootstrapIcon.setManaged(true);
});
model.bootstrapProgress.addListener((ov, oldValue, newValue) -> {
if ((double) newValue >= 1) {
bootstrapIndicator.setVisible(false);
bootstrapIndicator.setManaged(false);
}
});
HBox bootstrapBox = new HBox();
bootstrapBox.setSpacing(10);
bootstrapBox.setAlignment(Pos.CENTER);
bootstrapBox.setPrefHeight(50);
bootstrapBox.getChildren().addAll(bootstrapStateLabel, bootstrapIndicator, bootstrapIcon);*/
// software update
/* Label updateInfoLabel = new Label();
updateInfoLabel.setTextAlignment(TextAlignment.RIGHT);
updateInfoLabel.textProperty().bind(model.updateInfo);
Button restartButton = new Button("Restart");
restartButton.setDefaultButton(true);
restartButton.visibleProperty().bind(model.showRestartButton);
restartButton.managedProperty().bind(model.showRestartButton);
restartButton.setOnAction(e -> model.restart());
ImageView updateIcon = new ImageView();
updateIcon.setId(model.updateIconId.get());
model.updateIconId.addListener((ov, oldValue, newValue) -> {
updateIcon.setId(newValue);
updateIcon.setVisible(true);
updateIcon.setManaged(true);
});
HBox updateBox = new HBox();
updateBox.setSpacing(10);
updateBox.setAlignment(Pos.CENTER);
updateBox.setPrefHeight(20);
updateBox.getChildren().addAll(updateInfoLabel, restartButton, updateIcon);*/
vBox.getChildren().addAll(logo, createBitcoinInfoBox(), createP2PNetworkBox(), createUpdateBox());
return vBox; return vBox;
} }

View file

@ -18,6 +18,7 @@
package io.bitsquare.gui.main; package io.bitsquare.gui.main;
import io.bitsquare.app.UpdateProcess; import io.bitsquare.app.UpdateProcess;
import io.bitsquare.app.Version;
import io.bitsquare.arbitration.ArbitrationRepository; import io.bitsquare.arbitration.ArbitrationRepository;
import io.bitsquare.btc.BitcoinNetwork; import io.bitsquare.btc.BitcoinNetwork;
import io.bitsquare.btc.WalletService; import io.bitsquare.btc.WalletService;
@ -27,8 +28,8 @@ import io.bitsquare.gui.common.model.ViewModel;
import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.locale.CountryUtil; import io.bitsquare.locale.CountryUtil;
import io.bitsquare.p2p.BaseP2PService; import io.bitsquare.p2p.BaseP2PService;
import io.bitsquare.p2p.BootstrapState;
import io.bitsquare.p2p.ClientNode; import io.bitsquare.p2p.ClientNode;
import io.bitsquare.p2p.tomp2p.BootstrappedPeerBuilder;
import io.bitsquare.trade.Trade; import io.bitsquare.trade.Trade;
import io.bitsquare.trade.TradeManager; import io.bitsquare.trade.TradeManager;
import io.bitsquare.trade.offer.OpenOfferManager; import io.bitsquare.trade.offer.OpenOfferManager;
@ -61,18 +62,22 @@ class MainViewModel implements ViewModel {
// BTC network // BTC network
final StringProperty blockchainSyncInfo = new SimpleStringProperty("Initializing"); final StringProperty blockchainSyncInfo = new SimpleStringProperty("Initializing");
final StringProperty blockchainSyncInfoFooter = new SimpleStringProperty("Initializing");
final DoubleProperty blockchainSyncProgress = new SimpleDoubleProperty(-1); final DoubleProperty blockchainSyncProgress = new SimpleDoubleProperty(-1);
final StringProperty walletServiceErrorMsg = new SimpleStringProperty(); final StringProperty walletServiceErrorMsg = new SimpleStringProperty();
final StringProperty blockchainSyncIconId = new SimpleStringProperty(); final StringProperty blockchainSyncIconId = new SimpleStringProperty();
// P2P network // P2P network
final StringProperty bootstrapInfo = new SimpleStringProperty(); final StringProperty bootstrapInfo = new SimpleStringProperty("Connecting to P2P network...");
final StringProperty bootstrapInfoFooter = new SimpleStringProperty();
final DoubleProperty bootstrapProgress = new SimpleDoubleProperty(-1); final DoubleProperty bootstrapProgress = new SimpleDoubleProperty(-1);
final StringProperty bootstrapErrorMsg = new SimpleStringProperty(); final StringProperty bootstrapErrorMsg = new SimpleStringProperty();
final StringProperty bootstrapIconId = new SimpleStringProperty(); final StringProperty bootstrapIconId = new SimpleStringProperty();
// software update // software update
final StringProperty updateInfo = new SimpleStringProperty(); final StringProperty updateInfo = new SimpleStringProperty();
String version = "v." + Version.VERSION;
final BooleanProperty showRestartButton = new SimpleBooleanProperty(false); final BooleanProperty showRestartButton = new SimpleBooleanProperty(false);
final StringProperty updateIconId = new SimpleStringProperty(); final StringProperty updateIconId = new SimpleStringProperty();
@ -110,7 +115,7 @@ class MainViewModel implements ViewModel {
this.updateProcess = updateProcess; this.updateProcess = updateProcess;
this.formatter = formatter; this.formatter = formatter;
bitcoinNetworkAsString = bitcoinNetwork.toString(); bitcoinNetworkAsString = formatter.formatBitcoinNetwork(bitcoinNetwork);
updateProcess.state.addListener((observableValue, oldValue, newValue) -> applyUpdateState(newValue)); updateProcess.state.addListener((observableValue, oldValue, newValue) -> applyUpdateState(newValue));
applyUpdateState(updateProcess.state.get()); applyUpdateState(updateProcess.state.get());
@ -131,26 +136,22 @@ class MainViewModel implements ViewModel {
public void initBackend() { public void initBackend() {
Platform.runLater(updateProcess::init); Platform.runLater(updateProcess::init);
setBitcoinNetworkSyncProgress(-1); walletService.downloadPercentageProperty().addListener((ov, oldValue, newValue) -> {
walletService.getDownloadProgress().subscribe( setBitcoinNetworkSyncProgress((double) newValue);
percentage -> Platform.runLater(() -> { });
if (percentage > 0) setBitcoinNetworkSyncProgress(walletService.downloadPercentageProperty().get());
setBitcoinNetworkSyncProgress(percentage / 100.0);
}),
error -> log.error(error.toString()),
() -> Platform.runLater(() -> setBitcoinNetworkSyncProgress(1.0)));
// Set executor for all P2PServices // Set executor for all P2PServices
BaseP2PService.setUserThread(Platform::runLater); BaseP2PService.setUserThread(Platform::runLater);
Observable<BootstrapState> bootstrapStateAsObservable = clientNode.bootstrap(keyRing.getDhtSignatureKeyPair()); Observable<BootstrappedPeerBuilder.State> bootstrapStateAsObservable = clientNode.bootstrap(keyRing.getDhtSignatureKeyPair());
bootstrapStateAsObservable.publish(); bootstrapStateAsObservable.publish();
bootstrapStateAsObservable.subscribe( bootstrapStateAsObservable.subscribe(
state -> Platform.runLater(() -> setBootstrapState(state)), state -> Platform.runLater(() -> setBootstrapState(state)),
error -> Platform.runLater(() -> { error -> Platform.runLater(() -> {
log.error(error.toString()); log.error(error.toString());
bootstrapErrorMsg.set(error.getMessage()); bootstrapErrorMsg.set(error.getMessage());
bootstrapInfo.set("Connecting to the Bitsquare network failed."); bootstrapInfo.set("Connecting to the P2P network failed.");
bootstrapProgress.set(0); bootstrapProgress.set(0);
}), }),
@ -220,7 +221,7 @@ class MainViewModel implements ViewModel {
private void applyUpdateState(UpdateProcess.State state) { private void applyUpdateState(UpdateProcess.State state) {
switch (state) { switch (state) {
case CHECK_FOR_UPDATES: case CHECK_FOR_UPDATES:
updateInfo.set("Checking for updates..."); updateInfo.set("Check for updates...");
updateIconId.set("image-update-in-progress"); updateIconId.set("image-update-in-progress");
break; break;
case UPDATE_AVAILABLE: case UPDATE_AVAILABLE:
@ -229,30 +230,33 @@ class MainViewModel implements ViewModel {
showRestartButton.set(true); showRestartButton.set(true);
break; break;
case UP_TO_DATE: case UP_TO_DATE:
updateInfo.set("Software is up to date."); updateInfo.set("Software is up to date. Version: " + Version.VERSION);
updateIconId.set("image-update-up-to-date"); updateIconId.set("image-update-up-to-date");
break; break;
case FAILURE: case FAILURE:
updateInfo.set(updateProcess.getErrorMessage()); log.error(updateProcess.getErrorMessage());
updateInfo.set("Check for updates failed. ");
updateIconId.set("image-update-failed"); updateIconId.set("image-update-failed");
break; break;
} }
} }
private void setBootstrapState(BootstrapState state) { private void setBootstrapState(BootstrappedPeerBuilder.State state) {
switch (state) { switch (state) {
case DISCOVERY_DIRECT_SUCCEEDED: case DISCOVERY_DIRECT_SUCCEEDED:
bootstrapIconId.set("image-connection-direct"); bootstrapIconId.set("image-connection-direct");
bootstrapInfoFooter.set("Direct connection");
break; break;
case DISCOVERY_MANUAL_PORT_FORWARDING_SUCCEEDED: case DISCOVERY_MANUAL_PORT_FORWARDING_SUCCEEDED:
case DISCOVERY_AUTO_PORT_FORWARDING_SUCCEEDED: case DISCOVERY_AUTO_PORT_FORWARDING_SUCCEEDED:
bootstrapIconId.set("image-connection-nat"); bootstrapIconId.set("image-connection-nat");
bootstrapInfoFooter.set("Connected with port forwarding");
break; break;
case RELAY_SUCCEEDED: case RELAY_SUCCEEDED:
bootstrapIconId.set("image-connection-relay"); bootstrapIconId.set("image-connection-relay");
bootstrapInfoFooter.set("Connected with relay node");
break; break;
default: default:
bootstrapIconId.set(null);
break; break;
} }
@ -261,15 +265,13 @@ class MainViewModel implements ViewModel {
case DISCOVERY_MANUAL_PORT_FORWARDING_SUCCEEDED: case DISCOVERY_MANUAL_PORT_FORWARDING_SUCCEEDED:
case DISCOVERY_AUTO_PORT_FORWARDING_SUCCEEDED: case DISCOVERY_AUTO_PORT_FORWARDING_SUCCEEDED:
case RELAY_SUCCEEDED: case RELAY_SUCCEEDED:
bootstrapInfo.set("Bootstrapping to P2P network: " + state.getMessage()); bootstrapInfo.set(state.getMessage());
bootstrapProgress.set(-1); bootstrapProgress.set(-1);
break; break;
case BOOT_STRAP_SUCCEEDED: case BOOT_STRAP_SUCCEEDED:
bootstrapInfo.set("Successfully connected to P2P network: " + state.getMessage());
bootstrapProgress.set(1); bootstrapProgress.set(1);
break; break;
default: default:
bootstrapInfo.set("Connecting to P2P network: " + state.getMessage());
bootstrapProgress.set(-1); bootstrapProgress.set(-1);
break; break;
} }
@ -278,6 +280,7 @@ class MainViewModel implements ViewModel {
private void setWalletServiceException(Throwable error) { private void setWalletServiceException(Throwable error) {
setBitcoinNetworkSyncProgress(0); setBitcoinNetworkSyncProgress(0);
blockchainSyncInfo.set("Connecting to the bitcoin network failed."); blockchainSyncInfo.set("Connecting to the bitcoin network failed.");
blockchainSyncInfoFooter.set("Connection failed.");
if (error instanceof TimeoutException) { if (error instanceof TimeoutException) {
walletServiceErrorMsg.set("Please check your network connection.\n\n" + walletServiceErrorMsg.set("Please check your network connection.\n\n" +
"You must allow outgoing TCP connections to port 18333 for the bitcoin testnet.\n\n" + "You must allow outgoing TCP connections to port 18333 for the bitcoin testnet.\n\n" +
@ -332,9 +335,11 @@ class MainViewModel implements ViewModel {
} }
else if (value > 0.0) { else if (value > 0.0) {
blockchainSyncInfo.set("Synchronizing blockchain: " + formatter.formatToPercent(value)); blockchainSyncInfo.set("Synchronizing blockchain: " + formatter.formatToPercent(value));
blockchainSyncInfoFooter.set("Synchronizing: " + formatter.formatToPercent(value));
} }
else { else {
blockchainSyncInfo.set("Connecting to the bitcoin network..."); blockchainSyncInfo.set("Connecting to the bitcoin network...");
blockchainSyncInfoFooter.set("Connecting...");
} }
} }

View file

@ -20,6 +20,7 @@ package io.bitsquare.gui.main.settings.network;
import io.bitsquare.btc.BitcoinNetwork; import io.bitsquare.btc.BitcoinNetwork;
import io.bitsquare.gui.common.view.FxmlView; import io.bitsquare.gui.common.view.FxmlView;
import io.bitsquare.gui.common.view.InitializableView; import io.bitsquare.gui.common.view.InitializableView;
import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.p2p.ClientNode; import io.bitsquare.p2p.ClientNode;
import javax.inject.Inject; import javax.inject.Inject;
@ -30,19 +31,19 @@ import javafx.scene.control.*;
@FxmlView @FxmlView
public class NetworkSettingsView extends InitializableView { public class NetworkSettingsView extends InitializableView {
private final String bitcoinNetworkValue; private final String bitcoinNetworkString;
private final ClientNode clientNode; private final ClientNode clientNode;
@FXML TextField bitcoinNetwork, connectionType, nodeAddress, bootstrapNodeAddress; @FXML TextField bitcoinNetwork, connectionType, nodeAddress, bootstrapNodeAddress;
@Inject @Inject
public NetworkSettingsView(BitcoinNetwork bitcoinNetwork, ClientNode clientNode) { public NetworkSettingsView(BitcoinNetwork bitcoinNetwork, ClientNode clientNode, BSFormatter formatter) {
this.bitcoinNetworkValue = bitcoinNetwork.toString(); this.bitcoinNetworkString = formatter.formatBitcoinNetwork(bitcoinNetwork);
this.clientNode = clientNode; this.clientNode = clientNode;
} }
public void initialize() { public void initialize() {
bitcoinNetwork.setText(bitcoinNetworkValue); bitcoinNetwork.setText(bitcoinNetworkString);
connectionType.setText(clientNode.getConnectionType().toString()); connectionType.setText(clientNode.getConnectionType().toString());
nodeAddress.setText(clientNode.getAddress().toString()); nodeAddress.setText(clientNode.getAddress().toString());
bootstrapNodeAddress.setText(clientNode.getBootstrapNodeAddress().toString()); bootstrapNodeAddress.setText(clientNode.getBootstrapNodeAddress().toString());

View file

@ -19,6 +19,7 @@ package io.bitsquare.gui.util;
import io.bitsquare.arbitration.ArbitrationRepository; import io.bitsquare.arbitration.ArbitrationRepository;
import io.bitsquare.arbitration.Arbitrator; import io.bitsquare.arbitration.Arbitrator;
import io.bitsquare.btc.BitcoinNetwork;
import io.bitsquare.locale.BSResources; import io.bitsquare.locale.BSResources;
import io.bitsquare.locale.Country; import io.bitsquare.locale.Country;
import io.bitsquare.locale.CurrencyUtil; import io.bitsquare.locale.CurrencyUtil;
@ -363,4 +364,17 @@ public class BSFormatter {
Date unlockDate = new Date(new Date().getTime() + missingBlocks * 10 * 60 * 1000); Date unlockDate = new Date(new Date().getTime() + missingBlocks * 10 * 60 * 1000);
return dateFormatter.format(unlockDate) + " " + timeFormatter.format(unlockDate); return dateFormatter.format(unlockDate) + " " + timeFormatter.format(unlockDate);
} }
public String formatBitcoinNetwork(BitcoinNetwork bitcoinNetwork) {
switch (bitcoinNetwork) {
case MAINNET:
return "Mainnet";
case TESTNET:
return "Testnet";
case REGTEST:
return "Regtest";
default:
return "";
}
}
} }