mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-24 07:07:43 +01:00
Merging and adapting old bridges UI code to new bisq structure
Had to merge by hand because of the many changes in the new bisq structure. Also removed the 'default bridges' concept because it's discouraged to do that. Open issues: UI screen is still WIP, and bitcoinj SOCKS proxy error which makes that we can't connect to bitcoin nodes anymore. Signed-off-by: Mike Rosseel <mike@eon-consult.be>
This commit is contained in:
parent
af39d00e6b
commit
0ec4b5edac
19 changed files with 688 additions and 491 deletions
|
@ -1257,6 +1257,7 @@ message PreferencesPayload {
|
|||
bool use_animations = 31;
|
||||
PaymentAccount selectedPayment_account_for_createOffer = 32;
|
||||
bool pay_fee_in_Btc = 33;
|
||||
repeated string bridge_addresses = 34;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -167,6 +167,11 @@ public class AppSetupWithP2P extends AppSetup {
|
|||
public void onSetupFailed(Throwable throwable) {
|
||||
log.error(throwable.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestCustomBridges(Runnable resultHandler) {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
return p2pNetworkInitialized;
|
||||
|
|
|
@ -112,6 +112,11 @@ public class TradeStatisticsMigrationTool {
|
|||
@Override
|
||||
public void onSetupFailed(Throwable throwable) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestCustomBridges(Runnable resultHandler) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import io.bisq.core.btc.BaseCurrencyNetwork;
|
|||
import io.bisq.core.btc.BtcOptionKeys;
|
||||
import io.bisq.core.btc.Restrictions;
|
||||
import io.bisq.core.payment.PaymentAccount;
|
||||
import io.bisq.network.BridgeProvider;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.LongProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
|
@ -175,6 +176,7 @@ public final class Preferences implements PersistedDataHost {
|
|||
setPreferredTradeCurrency(preferredTradeCurrency);
|
||||
setFiatCurrencies(prefPayload.getFiatCurrencies());
|
||||
setCryptoCurrencies(prefPayload.getCryptoCurrencies());
|
||||
setBridgeAddresses(prefPayload.getBridgeAddresses());
|
||||
|
||||
} else {
|
||||
prefPayload = new PreferencesPayload();
|
||||
|
@ -474,6 +476,13 @@ public final class Preferences implements PersistedDataHost {
|
|||
storage.queueUpForSave(prefPayload, 1);
|
||||
}
|
||||
|
||||
public void setBridgeAddresses(List<String> bridgeAddresses) {
|
||||
prefPayload.setBridgeAddresses(bridgeAddresses);
|
||||
BridgeProvider.setBridges(bridgeAddresses);
|
||||
// We call that before shutdown so we dont want a delay here
|
||||
storage.queueUpForSave(prefPayload, 1);
|
||||
}
|
||||
|
||||
// Only used from PB but keep it explicit as maybe it get used from the client and then we want to persist
|
||||
public void setPeerTagMap(Map<String, String> peerTagMap) {
|
||||
prefPayload.setPeerTagMap(peerTagMap);
|
||||
|
@ -650,5 +659,7 @@ public final class Preferences implements PersistedDataHost {
|
|||
void setDontShowAgainMap(Map<String, Boolean> dontShowAgainMap);
|
||||
|
||||
void setPeerTagMap(Map<String, String> peerTagMap);
|
||||
|
||||
void setBridgeAddresses(List<String> bridgeAddresses);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import io.bisq.core.btc.Restrictions;
|
|||
import io.bisq.core.payment.PaymentAccount;
|
||||
import io.bisq.core.proto.CoreProtoResolver;
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
|
@ -21,6 +22,7 @@ import java.util.stream.Collectors;
|
|||
|
||||
@Slf4j
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public final class PreferencesPayload implements PersistableEnvelope {
|
||||
private String userLanguage;
|
||||
private Country userCountry;
|
||||
|
@ -64,6 +66,8 @@ public final class PreferencesPayload implements PersistableEnvelope {
|
|||
@Nullable
|
||||
private PaymentAccount selectedPaymentAccountForCreateOffer;
|
||||
private boolean payFeeInBtc = true;
|
||||
@Nullable
|
||||
private List<String> bridgeAddresses = new ArrayList<>();
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -78,74 +82,6 @@ public final class PreferencesPayload implements PersistableEnvelope {
|
|||
// PROTO BUFFER
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private PreferencesPayload(String userLanguage,
|
||||
Country userCountry,
|
||||
List<FiatCurrency> fiatCurrencies,
|
||||
List<CryptoCurrency> cryptoCurrencies,
|
||||
BlockChainExplorer blockChainExplorerMainNet,
|
||||
BlockChainExplorer blockChainExplorerTestNet,
|
||||
BlockChainExplorer bsqBlockChainExplorer,
|
||||
@Nullable String backupDirectory,
|
||||
boolean autoSelectArbitrators,
|
||||
Map<String, Boolean> dontShowAgainMap,
|
||||
boolean tacAccepted,
|
||||
boolean useTorForBitcoinJ,
|
||||
boolean showOwnOffersInOfferBook,
|
||||
@Nullable TradeCurrency preferredTradeCurrency,
|
||||
long withdrawalTxFeeInBytes,
|
||||
boolean useCustomWithdrawalTxFee,
|
||||
double maxPriceDistanceInPercent,
|
||||
@Nullable String offerBookChartScreenCurrencyCode,
|
||||
@Nullable String tradeChartsScreenCurrencyCode,
|
||||
@Nullable String buyScreenCurrencyCode,
|
||||
@Nullable String sellScreenCurrencyCode,
|
||||
int tradeStatisticsTickUnitIndex,
|
||||
boolean resyncSpvRequested,
|
||||
boolean sortMarketCurrenciesNumerically,
|
||||
boolean usePercentageBasedPrice,
|
||||
Map<String, String> peerTagMap,
|
||||
String bitcoinNodes,
|
||||
List<String> ignoreTradersList,
|
||||
String directoryChooserPath,
|
||||
long buyerSecurityDepositAsLong,
|
||||
boolean useAnimations,
|
||||
@Nullable PaymentAccount selectedPaymentAccountForCreateOffer,
|
||||
boolean payFeeInBtc) {
|
||||
this.userLanguage = userLanguage;
|
||||
this.userCountry = userCountry;
|
||||
this.fiatCurrencies = fiatCurrencies;
|
||||
this.cryptoCurrencies = cryptoCurrencies;
|
||||
this.blockChainExplorerMainNet = blockChainExplorerMainNet;
|
||||
this.blockChainExplorerTestNet = blockChainExplorerTestNet;
|
||||
this.bsqBlockChainExplorer = bsqBlockChainExplorer;
|
||||
this.backupDirectory = backupDirectory;
|
||||
this.autoSelectArbitrators = autoSelectArbitrators;
|
||||
this.dontShowAgainMap = dontShowAgainMap;
|
||||
this.tacAccepted = tacAccepted;
|
||||
this.useTorForBitcoinJ = useTorForBitcoinJ;
|
||||
this.showOwnOffersInOfferBook = showOwnOffersInOfferBook;
|
||||
this.preferredTradeCurrency = preferredTradeCurrency;
|
||||
this.withdrawalTxFeeInBytes = withdrawalTxFeeInBytes;
|
||||
this.useCustomWithdrawalTxFee = useCustomWithdrawalTxFee;
|
||||
this.maxPriceDistanceInPercent = maxPriceDistanceInPercent;
|
||||
this.offerBookChartScreenCurrencyCode = offerBookChartScreenCurrencyCode;
|
||||
this.tradeChartsScreenCurrencyCode = tradeChartsScreenCurrencyCode;
|
||||
this.buyScreenCurrencyCode = buyScreenCurrencyCode;
|
||||
this.sellScreenCurrencyCode = sellScreenCurrencyCode;
|
||||
this.tradeStatisticsTickUnitIndex = tradeStatisticsTickUnitIndex;
|
||||
this.resyncSpvRequested = resyncSpvRequested;
|
||||
this.sortMarketCurrenciesNumerically = sortMarketCurrenciesNumerically;
|
||||
this.usePercentageBasedPrice = usePercentageBasedPrice;
|
||||
this.peerTagMap = peerTagMap;
|
||||
this.bitcoinNodes = bitcoinNodes;
|
||||
this.ignoreTradersList = ignoreTradersList;
|
||||
this.directoryChooserPath = directoryChooserPath;
|
||||
this.buyerSecurityDepositAsLong = buyerSecurityDepositAsLong;
|
||||
this.useAnimations = useAnimations;
|
||||
this.selectedPaymentAccountForCreateOffer = selectedPaymentAccountForCreateOffer;
|
||||
this.payFeeInBtc = payFeeInBtc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message toProtoMessage() {
|
||||
PB.PreferencesPayload.Builder builder = PB.PreferencesPayload.newBuilder()
|
||||
|
@ -178,8 +114,8 @@ public final class PreferencesPayload implements PersistableEnvelope {
|
|||
.setDirectoryChooserPath(directoryChooserPath)
|
||||
.setBuyerSecurityDepositAsLong(buyerSecurityDepositAsLong)
|
||||
.setUseAnimations(useAnimations)
|
||||
.setPayFeeInBtc(payFeeInBtc);
|
||||
|
||||
.setPayFeeInBtc(payFeeInBtc)
|
||||
.addAllBridgeAddresses(bridgeAddresses);
|
||||
Optional.ofNullable(backupDirectory).ifPresent(builder::setBackupDirectory);
|
||||
Optional.ofNullable(preferredTradeCurrency).ifPresent(e -> builder.setPreferredTradeCurrency((PB.TradeCurrency) e.toProtoMessage()));
|
||||
Optional.ofNullable(offerBookChartScreenCurrencyCode).ifPresent(builder::setOfferBookChartScreenCurrencyCode);
|
||||
|
@ -188,7 +124,6 @@ public final class PreferencesPayload implements PersistableEnvelope {
|
|||
Optional.ofNullable(sellScreenCurrencyCode).ifPresent(builder::setSellScreenCurrencyCode);
|
||||
Optional.ofNullable(selectedPaymentAccountForCreateOffer).ifPresent(
|
||||
account -> builder.setSelectedPaymentAccountForCreateOffer(selectedPaymentAccountForCreateOffer.toProtoMessage()));
|
||||
|
||||
return PB.PersistableEnvelope.newBuilder().setPreferencesPayload(builder).build();
|
||||
}
|
||||
|
||||
|
@ -237,6 +172,7 @@ public final class PreferencesPayload implements PersistableEnvelope {
|
|||
proto.getBuyerSecurityDepositAsLong(),
|
||||
proto.getUseAnimations(),
|
||||
paymentAccount,
|
||||
proto.getPayFeeInBtc());
|
||||
proto.getPayFeeInBtc(),
|
||||
proto.getBridgeAddressesList());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,12 +72,14 @@ import io.bisq.gui.components.BalanceWithConfirmationTextField;
|
|||
import io.bisq.gui.components.TxIdTextField;
|
||||
import io.bisq.gui.main.overlays.notifications.NotificationCenter;
|
||||
import io.bisq.gui.main.overlays.popups.Popup;
|
||||
import io.bisq.gui.main.overlays.windows.AddBridgeEntriesWindow;
|
||||
import io.bisq.gui.main.overlays.windows.DisplayAlertMessageWindow;
|
||||
import io.bisq.gui.main.overlays.windows.TacWindow;
|
||||
import io.bisq.gui.main.overlays.windows.WalletPasswordWindow;
|
||||
import io.bisq.gui.main.overlays.windows.downloadupdate.DisplayUpdateDownloadWindow;
|
||||
import io.bisq.gui.util.BSFormatter;
|
||||
import io.bisq.gui.util.GUIUtil;
|
||||
import io.bisq.gui.util.Transitions;
|
||||
import io.bisq.network.crypto.DecryptedDataTuple;
|
||||
import io.bisq.network.crypto.EncryptionService;
|
||||
import io.bisq.network.p2p.BootstrapListener;
|
||||
|
@ -485,6 +487,13 @@ public class MainViewModel implements ViewModel {
|
|||
bootstrapWarning.set(Res.get("mainView.bootstrapWarning.bootstrappingToP2PFailed"));
|
||||
p2pNetworkLabelId.set("splash-error-state-msg");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestCustomBridges(Runnable resultHandler) {
|
||||
AddBridgeEntriesWindow addBridgeEntriesWindow = new AddBridgeEntriesWindow(preferences)
|
||||
.onAction(resultHandler::run);
|
||||
UserThread.execute(addBridgeEntriesWindow::show);
|
||||
}
|
||||
});
|
||||
|
||||
return p2pNetworkInitialized;
|
||||
|
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* This file is part of bisq.
|
||||
*
|
||||
* bisq 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.
|
||||
*
|
||||
* bisq 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 bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
/** This file is part of bisq.
|
||||
*
|
||||
* bisq 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.
|
||||
*
|
||||
* bisq 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 bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bisq.gui.main.overlays.windows;
|
||||
|
||||
import io.bisq.common.util.Tuple2;
|
||||
import io.bisq.common.util.Utilities;
|
||||
import io.bisq.core.alert.Alert;
|
||||
import io.bisq.core.user.Preferences;
|
||||
import io.bisq.gui.main.overlays.Overlay;
|
||||
import javafx.geometry.HPos;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.layout.Priority;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static io.bisq.gui.util.FormBuilder.addLabel;
|
||||
import static io.bisq.gui.util.FormBuilder.addLabelTextArea;
|
||||
|
||||
@Slf4j
|
||||
public class AddBridgeEntriesWindow extends Overlay<AddBridgeEntriesWindow> {
|
||||
private TextArea bridgeEntriesTextArea;
|
||||
private final Preferences preferences;
|
||||
|
||||
@Inject
|
||||
public AddBridgeEntriesWindow(Preferences preferences) {
|
||||
this.preferences = preferences;
|
||||
type = Type.Attention;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Public API
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void show() {
|
||||
if (headLine == null)
|
||||
headLine = "Add Tor bridge entries";
|
||||
|
||||
width = 900;
|
||||
createGridPane();
|
||||
addHeadLine();
|
||||
addSeparator();
|
||||
addContent();
|
||||
addCloseButton();
|
||||
applyStyles();
|
||||
display();
|
||||
}
|
||||
|
||||
protected void addCloseButton() {
|
||||
closeButton = new Button(closeButtonText == null ? "Close" : closeButtonText);
|
||||
closeButton.setOnAction(event -> doClose());
|
||||
|
||||
if (actionHandlerOptional.isPresent() || actionButtonText != null) {
|
||||
actionButton = new Button("Save and retry");
|
||||
actionButton.setDefaultButton(true);
|
||||
//TODO app wide focus
|
||||
//actionButton.requestFocus();
|
||||
actionButton.setOnAction(event -> save());
|
||||
|
||||
Button urlButton = new Button("Open Tor project web page");
|
||||
urlButton.setOnAction(event -> {
|
||||
try {
|
||||
Utilities.openURI(URI.create("https://bridges.torproject.org/bridges"));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
|
||||
Pane spacer = new Pane();
|
||||
HBox hBox = new HBox();
|
||||
hBox.setSpacing(10);
|
||||
hBox.getChildren().addAll(spacer, closeButton, urlButton, actionButton);
|
||||
HBox.setHgrow(spacer, Priority.ALWAYS);
|
||||
|
||||
GridPane.setHalignment(hBox, HPos.RIGHT);
|
||||
GridPane.setRowIndex(hBox, rowIndex);
|
||||
GridPane.setColumnSpan(hBox, 2);
|
||||
GridPane.setMargin(hBox, new Insets(buttonDistance, 0, 0, 0));
|
||||
gridPane.getChildren().add(hBox);
|
||||
} else if (!hideCloseButton) {
|
||||
closeButton.setDefaultButton(true);
|
||||
GridPane.setHalignment(closeButton, HPos.RIGHT);
|
||||
GridPane.setMargin(closeButton, new Insets(buttonDistance, 0, 0, 0));
|
||||
GridPane.setRowIndex(closeButton, rowIndex);
|
||||
GridPane.setColumnIndex(closeButton, 1);
|
||||
gridPane.getChildren().add(closeButton);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Protected
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
protected void setupKeyHandler(Scene scene) {
|
||||
if (!hideCloseButton) {
|
||||
scene.setOnKeyPressed(e -> {
|
||||
if (e.getCode() == KeyCode.ESCAPE) {
|
||||
e.consume();
|
||||
doClose();
|
||||
} else if (e.getCode() == KeyCode.ENTER) {
|
||||
e.consume();
|
||||
save();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void addContent() {
|
||||
Label label = addLabel(gridPane, ++rowIndex, "We could not connect to the Tor network.\n" +
|
||||
"If Tor is blocked at your internet provider, you can try to add Tor bridge address entries from the Tor project:\n" +
|
||||
"https://bridges.torproject.org/bridges\n\n" +
|
||||
"Add one address entry in each line.\n");
|
||||
GridPane.setColumnIndex(label, 0);
|
||||
GridPane.setColumnSpan(label, 2);
|
||||
GridPane.setHalignment(label, HPos.LEFT);
|
||||
Tuple2<Label, TextArea> labelTextAreaTuple2 = addLabelTextArea(gridPane, rowIndex, "Bridge entries:", "");
|
||||
bridgeEntriesTextArea = labelTextAreaTuple2.second;
|
||||
}
|
||||
|
||||
private void save() {
|
||||
if (!bridgeEntriesTextArea.getText().isEmpty()) {
|
||||
List<String> list = Arrays.asList(bridgeEntriesTextArea.getText().split("\\n"));
|
||||
preferences.setBridgeAddresses(list);
|
||||
actionHandlerOptional.ifPresent(Runnable::run);
|
||||
hide();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,11 +9,11 @@
|
|||
<root level="TRACE">
|
||||
<appender-ref ref="CONSOLE_APPENDER"/>
|
||||
</root>
|
||||
<!--
|
||||
|
||||
<logger name="com.neemre.btcdcli4j" level="WARN"/>
|
||||
|
||||
<logger name="com.msopentech.thali.toronionproxy.OnionProxyManagerEventHandler" level="INFO"/>
|
||||
|
||||
<logger name="org.bitcoinj.core.AbstractBlockChain" level="WARN"/>
|
||||
<logger name="org.bitcoinj.net.BlockingClient" level="WARN"/>
|
||||
<logger name="org.bitcoinj.core.PeerGroup" level="WARN"/>
|
||||
|
@ -23,10 +23,11 @@
|
|||
<logger name="org.bitcoinj.core.listeners.DownloadProgressTracker" level="WARN"/>
|
||||
<logger name="org.bitcoinj.core.PeerSocketHandler" level="WARN"/>
|
||||
<logger name="org.bitcoinj.net.NioClientManager" level="WARN"/>
|
||||
-->
|
||||
|
||||
<!-- We get too many errors logged from connection issues-->
|
||||
<!-- We get too many errors logged from connection issues
|
||||
<logger name="org.bitcoinj.net.BlockingClient" level="OFF"/>
|
||||
|
||||
-->
|
||||
<!--
|
||||
<logger name="org.bitcoinj.net.ConnectionHandler" level="WARN"/>
|
||||
|
||||
|
|
23
network/src/main/java/io/bisq/network/BridgeProvider.java
Normal file
23
network/src/main/java/io/bisq/network/BridgeProvider.java
Normal file
|
@ -0,0 +1,23 @@
|
|||
package io.bisq.network;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class exists because the TorNetworkNode in module 'network' can't access the preferences
|
||||
* in 'core' directly, so we use this provider.
|
||||
*/
|
||||
@Slf4j
|
||||
public class BridgeProvider {
|
||||
@Setter
|
||||
@Getter
|
||||
static List<String> bridges = new ArrayList<>();
|
||||
}
|
|
@ -28,4 +28,8 @@ public abstract class BootstrapListener implements P2PServiceListener {
|
|||
|
||||
@Override
|
||||
abstract public void onBootstrapComplete();
|
||||
|
||||
@Override
|
||||
public void onRequestCustomBridges(Runnable resultHandler) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -272,6 +272,12 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
|
|||
p2pServiceListeners.stream().forEach(e -> e.onSetupFailed(throwable));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestCustomBridges(Runnable resultHandler) {
|
||||
Log.traceCall();
|
||||
p2pServiceListeners.stream().forEach(e -> e.onRequestCustomBridges(resultHandler));
|
||||
}
|
||||
|
||||
// Called from networkReadyBinding
|
||||
private void onNetworkReady() {
|
||||
Log.traceCall();
|
||||
|
|
|
@ -7,4 +7,6 @@ public interface SetupListener {
|
|||
|
||||
@SuppressWarnings("unused")
|
||||
void onSetupFailed(Throwable throwable);
|
||||
|
||||
void onRequestCustomBridges(Runnable resultHandler);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import io.bisq.common.app.Log;
|
|||
import io.bisq.common.proto.network.NetworkProtoResolver;
|
||||
import io.bisq.common.storage.FileUtil;
|
||||
import io.bisq.common.util.Utilities;
|
||||
import io.bisq.network.BridgeProvider;
|
||||
import io.bisq.network.p2p.NodeAddress;
|
||||
import io.bisq.network.p2p.Utils;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
|
@ -31,7 +32,7 @@ import java.nio.file.Paths;
|
|||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
|
@ -41,6 +42,7 @@ public class TorNetworkNode extends NetworkNode {
|
|||
|
||||
private static final int MAX_RESTART_ATTEMPTS = 5;
|
||||
private static final long SHUT_DOWN_TIMEOUT_SEC = 5;
|
||||
private static final int WAIT_BEFORE_RESTART = 2000;
|
||||
|
||||
private HiddenServiceSocket hiddenServiceSocket;
|
||||
private final File torDir;
|
||||
|
@ -48,8 +50,6 @@ public class TorNetworkNode extends NetworkNode {
|
|||
private int restartCounter;
|
||||
@SuppressWarnings("FieldCanBeLocal")
|
||||
private MonadicBinding<Boolean> allShutDown;
|
||||
@Setter
|
||||
private List<String> bridgeLines = null;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -76,8 +76,7 @@ public class TorNetworkNode extends NetworkNode {
|
|||
createExecutorService();
|
||||
|
||||
// Create the tor node (takes about 6 sec.)
|
||||
//createTorNode(torDir, (nativeTor) -> createHiddenService(Utils.findFreeSystemPort(), servicePort, bridgeLines));
|
||||
createTorAndHiddenService(torDir, Utils.findFreeSystemPort(), servicePort, bridgeLines);
|
||||
createTorAndHiddenService(torDir, Utils.findFreeSystemPort(), servicePort, BridgeProvider.getBridges());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -170,8 +169,25 @@ public class TorNetworkNode extends NetworkNode {
|
|||
|
||||
private void restartTor(String errorMessage) {
|
||||
Log.traceCall();
|
||||
log.warn("Restarting Tor");
|
||||
restartCounter++;
|
||||
if (restartCounter > MAX_RESTART_ATTEMPTS) {
|
||||
if (restartCounter <= MAX_RESTART_ATTEMPTS) {
|
||||
// If we failed we try with custom bridges
|
||||
if (restartCounter == 1) {
|
||||
setupListeners.stream().forEach(e -> e.onRequestCustomBridges(() -> {
|
||||
log.warn("Tor restart after custom bridges.");
|
||||
start(null);
|
||||
}));
|
||||
log.warn("We stop tor as starting tor with the default bridges failed. We request user to add custom bridges.");
|
||||
shutDown(null);
|
||||
} else {
|
||||
shutDown(() -> UserThread.runAfter(() -> {
|
||||
log.warn("We restart tor using custom bridges.");
|
||||
log.warn("Bridges: " + BridgeProvider.getBridges());
|
||||
start(null);
|
||||
}, WAIT_BEFORE_RESTART, TimeUnit.MILLISECONDS));
|
||||
}
|
||||
} else {
|
||||
String msg = "We tried to restart Tor " + restartCounter +
|
||||
" times, but it continued to fail with error message:\n" +
|
||||
errorMessage + "\n\n" +
|
||||
|
@ -186,99 +202,21 @@ public class TorNetworkNode extends NetworkNode {
|
|||
// create tor
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
private void createTorNode(final File torDir, final Consumer<NativeTor> resultHandler) {
|
||||
Log.traceCall();
|
||||
ListenableFuture<NativeTor> future = executorService.submit(() -> {
|
||||
Utilities.setThreadName("TorNetworkNode:CreateTorNode");
|
||||
long ts = System.currentTimeMillis();
|
||||
if (torDir.mkdirs())
|
||||
log.trace("Created directory for tor at {}", torDir.getAbsolutePath());
|
||||
NativeTor nativeTor = null;
|
||||
try {
|
||||
nativeTor = new NativeTor(torDir, bridgeLines);
|
||||
} catch (TorCtlException e) {
|
||||
throw new Exception(e);
|
||||
}
|
||||
log.debug("\n\n############################################################\n" +
|
||||
"TorNode created:" +
|
||||
"\nTook " + (System.currentTimeMillis() - ts) + " ms"
|
||||
+ "\n############################################################\n");
|
||||
return nativeTor;
|
||||
});
|
||||
Futures.addCallback(future, new FutureCallback<NativeTor>() {
|
||||
public void onSuccess(NativeTor torNode) {
|
||||
Tor.setDefault(torNode);
|
||||
UserThread.execute(() -> resultHandler.accept(torNode));
|
||||
}
|
||||
|
||||
public void onFailure(@NotNull Throwable throwable) {
|
||||
UserThread.execute(() -> {
|
||||
log.error("TorNode creation failed with exception: " + throwable.getMessage());
|
||||
restartTor(throwable.getMessage());
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void createHiddenService(int localPort, int servicePort, List<String> bridgeLines) {
|
||||
Log.traceCall();
|
||||
ListenableFuture<Object> future = executorService.submit(() -> {
|
||||
Utilities.setThreadName("TorNetworkNode:CreateHiddenService");
|
||||
{
|
||||
long ts = System.currentTimeMillis();
|
||||
// TODO backup has to be taken from ./hiddenservice, not ./
|
||||
hiddenServiceSocket = new HiddenServiceSocket(localPort, "hiddenservice", servicePort);
|
||||
hiddenServiceSocket.addReadyListener(socket -> {
|
||||
Socket con;
|
||||
try {
|
||||
log.info("Hidden Service " + socket + " is ready");
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Log.traceCall("hiddenService created");
|
||||
nodeAddressProperty.set(new NodeAddress(hiddenServiceSocket.getServiceName() + ":" + hiddenServiceSocket.getHiddenServicePort()));
|
||||
startServer(socket);
|
||||
UserThread.execute(() -> setupListeners.stream().forEach(SetupListener::onHiddenServicePublished));
|
||||
} catch (final Exception e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
});
|
||||
log.info("It will take some time for the HS to be reachable (~40 seconds). You will be notified about this");
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
Futures.addCallback(future, new FutureCallback<Object>() {
|
||||
public void onSuccess(Object hiddenServiceDescriptor) {
|
||||
log.debug("HiddenServiceDescriptor created. Wait for publishing.");
|
||||
}
|
||||
|
||||
public void onFailure(@NotNull Throwable throwable) {
|
||||
UserThread.execute(() -> {
|
||||
log.error("Hidden service creation failed");
|
||||
restartTor(throwable.getMessage());
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void createTorAndHiddenService(final File torDir, int localPort, int servicePort, List<String> bridgeLines) {
|
||||
Log.traceCall();
|
||||
log.debug("Using bridges: {}", bridgeLines.stream().collect(Collectors.joining(",")));
|
||||
if(restartCounter == 0) {
|
||||
log.error("Doing fake restart to get to the bridges");
|
||||
restartTor("error message here...");
|
||||
return;
|
||||
}
|
||||
ListenableFuture<Object> future = (ListenableFuture<Object>) executorService.submit(() -> {
|
||||
try {
|
||||
Tor.setDefault(new NativeTor(torDir, bridgeLines));
|
||||
} catch (TorCtlException e) {
|
||||
log.error("Tor node creation failed", e);
|
||||
restartTor(e.getMessage());
|
||||
return;
|
||||
}
|
||||
UserThread.execute(() -> setupListeners.stream().forEach(SetupListener::onTorNodeReady));
|
||||
|
||||
|
|
|
@ -117,6 +117,10 @@ public class PeerServiceTest {
|
|||
@Override
|
||||
public void onSetupFailed(Throwable throwable) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestCustomBridges(Runnable resultHandler) {
|
||||
}
|
||||
});
|
||||
}
|
||||
Thread.sleep(30_000);
|
||||
|
@ -208,6 +212,11 @@ public class PeerServiceTest {
|
|||
@Override
|
||||
public void onSetupFailed(Throwable throwable) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestCustomBridges(Runnable resultHandler) {
|
||||
|
||||
}
|
||||
});
|
||||
P2PService p2PService1 = seedNode1.getSeedNodeP2PService();
|
||||
|
||||
|
@ -245,6 +254,11 @@ public class PeerServiceTest {
|
|||
@Override
|
||||
public void onSetupFailed(Throwable throwable) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestCustomBridges(Runnable resultHandler) {
|
||||
|
||||
}
|
||||
});
|
||||
P2PService p2PService2 = seedNode2.getSeedNodeP2PService();
|
||||
latch.await();
|
||||
|
@ -480,6 +494,10 @@ public class PeerServiceTest {
|
|||
@Override
|
||||
public void onSetupFailed(Throwable throwable) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestCustomBridges(Runnable resultHandler) {
|
||||
}
|
||||
});
|
||||
latch.await();
|
||||
Thread.sleep(sleepTime);
|
||||
|
|
|
@ -80,6 +80,11 @@ public class TestUtils {
|
|||
@Override
|
||||
public void onSetupFailed(Throwable throwable) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestCustomBridges(Runnable resultHandler) {
|
||||
|
||||
}
|
||||
});
|
||||
latch.await();
|
||||
Thread.sleep(sleepTime);
|
||||
|
|
|
@ -52,6 +52,11 @@ public class LocalhostNetworkNodeTest {
|
|||
public void onSetupFailed(Throwable throwable) {
|
||||
log.debug("onSetupFailed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestCustomBridges(Runnable resultHandler) {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
LocalhostNetworkNode node2 = new LocalhostNetworkNode(9002, TestUtils.getNetworkProtoResolver());
|
||||
|
@ -75,6 +80,11 @@ public class LocalhostNetworkNodeTest {
|
|||
public void onSetupFailed(Throwable throwable) {
|
||||
log.debug("onSetupFailed 2");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestCustomBridges(Runnable resultHandler) {
|
||||
|
||||
}
|
||||
});
|
||||
startupLatch.await();
|
||||
|
||||
|
|
|
@ -416,6 +416,11 @@ public class NetworkStressTest {
|
|||
localServicesFailed.set(true);
|
||||
localServicesLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestCustomBridges(Runnable resultHandler) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private class SeedServiceListener extends TestSetupListener implements P2PServiceListener {
|
||||
|
@ -802,6 +807,11 @@ public class NetworkStressTest {
|
|||
@Override
|
||||
public void onSetupFailed(Throwable throwable) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestCustomBridges(Runnable resultHandler) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -53,6 +53,11 @@ public class TorNetworkNodeTest {
|
|||
@Override
|
||||
public void onSetupFailed(Throwable throwable) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestCustomBridges(Runnable resultHandler) {
|
||||
|
||||
}
|
||||
});
|
||||
latch.await();
|
||||
|
||||
|
@ -75,6 +80,11 @@ public class TorNetworkNodeTest {
|
|||
@Override
|
||||
public void onSetupFailed(Throwable throwable) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestCustomBridges(Runnable resultHandler) {
|
||||
|
||||
}
|
||||
});
|
||||
latch.await();
|
||||
|
||||
|
@ -127,6 +137,11 @@ public class TorNetworkNodeTest {
|
|||
public void onSetupFailed(Throwable throwable) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestCustomBridges(Runnable resultHandler) {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
int port2 = 9002;
|
||||
|
@ -146,6 +161,11 @@ public class TorNetworkNodeTest {
|
|||
@Override
|
||||
public void onSetupFailed(Throwable throwable) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestCustomBridges(Runnable resultHandler) {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
latch.await();
|
||||
|
|
|
@ -117,6 +117,11 @@ public class PeerManagerTest {
|
|||
public void onSetupFailed(Throwable throwable) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestCustomBridges(Runnable resultHandler) {
|
||||
|
||||
}
|
||||
});
|
||||
P2PService p2PService1 = seedNode1.getSeedNodeP2PService();
|
||||
latch.await();
|
||||
|
@ -168,6 +173,11 @@ public class PeerManagerTest {
|
|||
@Override
|
||||
public void onSetupFailed(Throwable throwable) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestCustomBridges(Runnable resultHandler) {
|
||||
|
||||
}
|
||||
});
|
||||
P2PService p2PService1 = seedNode1.getSeedNodeP2PService();
|
||||
|
||||
|
@ -205,6 +215,11 @@ public class PeerManagerTest {
|
|||
@Override
|
||||
public void onSetupFailed(Throwable throwable) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestCustomBridges(Runnable resultHandler) {
|
||||
|
||||
}
|
||||
});
|
||||
P2PService p2PService2 = seedNode2.getSeedNodeP2PService();
|
||||
latch.await();
|
||||
|
@ -439,6 +454,11 @@ public class PeerManagerTest {
|
|||
@Override
|
||||
public void onSetupFailed(Throwable throwable) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestCustomBridges(Runnable resultHandler) {
|
||||
|
||||
}
|
||||
});
|
||||
latch.await();
|
||||
Thread.sleep(sleepTime);
|
||||
|
|
Loading…
Add table
Reference in a new issue