mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-19 18:03:12 +01:00
Merge branch 'master' into 08-scratch
This commit is contained in:
commit
a0f1c22d19
@ -17,9 +17,8 @@
|
||||
|
||||
package bisq.core.account.witness;
|
||||
|
||||
import bisq.network.p2p.storage.P2PDataStorage;
|
||||
import bisq.network.p2p.storage.payload.PersistableNetworkPayload;
|
||||
import bisq.network.p2p.storage.persistence.MapStoreService;
|
||||
import bisq.network.p2p.storage.persistence.HistoricalDataStoreService;
|
||||
|
||||
import bisq.common.config.Config;
|
||||
import bisq.common.persistence.PersistenceManager;
|
||||
@ -29,12 +28,10 @@ import javax.inject.Named;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class AccountAgeWitnessStorageService extends MapStoreService<AccountAgeWitnessStore, PersistableNetworkPayload> {
|
||||
public class AccountAgeWitnessStorageService extends HistoricalDataStoreService<AccountAgeWitnessStore> {
|
||||
private static final String FILE_NAME = "AccountAgeWitnessStore";
|
||||
|
||||
|
||||
@ -48,23 +45,19 @@ public class AccountAgeWitnessStorageService extends MapStoreService<AccountAgeW
|
||||
super(storageDir, persistenceManager);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// API
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
protected void initializePersistenceManager() {
|
||||
persistenceManager.initialize(store, PersistenceManager.Source.NETWORK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFileName() {
|
||||
return FILE_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<P2PDataStorage.ByteArray, PersistableNetworkPayload> getMap() {
|
||||
return store.getMap();
|
||||
protected void initializePersistenceManager() {
|
||||
persistenceManager.initialize(store, PersistenceManager.Source.NETWORK);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -26,7 +26,6 @@ import bisq.core.btc.wallet.BsqWalletService;
|
||||
import bisq.core.btc.wallet.BtcWalletService;
|
||||
import bisq.core.btc.wallet.NonBsqCoinSelector;
|
||||
import bisq.core.btc.wallet.TradeWalletService;
|
||||
import bisq.core.provider.PriceNodeHttpClient;
|
||||
import bisq.core.provider.ProvidersRepository;
|
||||
import bisq.core.provider.fee.FeeProvider;
|
||||
import bisq.core.provider.fee.FeeService;
|
||||
@ -95,8 +94,6 @@ public class BitcoinModule extends AppModule {
|
||||
bind(BtcNodes.class).in(Singleton.class);
|
||||
bind(Balances.class).in(Singleton.class);
|
||||
|
||||
bind(PriceNodeHttpClient.class).in(Singleton.class);
|
||||
|
||||
bind(ProvidersRepository.class).in(Singleton.class);
|
||||
bind(FeeProvider.class).in(Singleton.class);
|
||||
bind(PriceFeedService.class).in(Singleton.class);
|
||||
|
@ -256,6 +256,11 @@ public class MobileNotificationService {
|
||||
boolean useSound,
|
||||
Consumer<String> resultHandler,
|
||||
Consumer<Throwable> errorHandler) throws Exception {
|
||||
if (httpClient.hasPendingRequest()) {
|
||||
log.warn("We have a pending request open. We ignore that request. httpClient {}", httpClient);
|
||||
return;
|
||||
}
|
||||
|
||||
String msg;
|
||||
if (mobileModel.getOs() == null)
|
||||
throw new RuntimeException("No mobileModel OS set");
|
||||
@ -297,7 +302,7 @@ public class MobileNotificationService {
|
||||
String threadName = "sendMobileNotification-" + msgAsHex.substring(0, 5) + "...";
|
||||
ListenableFuture<String> future = executorService.submit(() -> {
|
||||
Thread.currentThread().setName(threadName);
|
||||
String result = httpClient.requestWithGET(param, "User-Agent",
|
||||
String result = httpClient.get(param, "User-Agent",
|
||||
"bisq/" + Version.VERSION + ", uid:" + httpClient.getUid());
|
||||
log.info("sendMobileNotification result: " + result);
|
||||
checkArgument(result.equals(SUCCESS), "Result was not 'success'. result=" + result);
|
||||
|
@ -17,7 +17,6 @@
|
||||
|
||||
package bisq.core.payment;
|
||||
|
||||
import bisq.core.locale.CurrencyUtil;
|
||||
import bisq.core.payment.payload.PaymentAccountPayload;
|
||||
import bisq.core.payment.payload.PaymentMethod;
|
||||
import bisq.core.payment.payload.TransferwiseAccountPayload;
|
||||
@ -28,8 +27,6 @@ import lombok.EqualsAndHashCode;
|
||||
public final class TransferwiseAccount extends PaymentAccount {
|
||||
public TransferwiseAccount() {
|
||||
super(PaymentMethod.TRANSFERWISE);
|
||||
|
||||
tradeCurrencies.addAll(CurrencyUtil.getAllTransferwiseCurrencies());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -21,12 +21,14 @@ import bisq.network.Socks5ProxyProvider;
|
||||
import bisq.network.http.HttpClientImpl;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class PriceNodeHttpClient extends HttpClientImpl {
|
||||
@Singleton
|
||||
public class FeeHttpClient extends HttpClientImpl {
|
||||
@Inject
|
||||
public PriceNodeHttpClient(@Nullable Socks5ProxyProvider socks5ProxyProvider) {
|
||||
public FeeHttpClient(@Nullable Socks5ProxyProvider socks5ProxyProvider) {
|
||||
super(socks5ProxyProvider);
|
||||
}
|
||||
}
|
34
core/src/main/java/bisq/core/provider/PriceHttpClient.java
Normal file
34
core/src/main/java/bisq/core/provider/PriceHttpClient.java
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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 bisq.core.provider;
|
||||
|
||||
import bisq.network.Socks5ProxyProvider;
|
||||
import bisq.network.http.HttpClientImpl;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@Singleton
|
||||
public class PriceHttpClient extends HttpClientImpl {
|
||||
@Inject
|
||||
public PriceHttpClient(@Nullable Socks5ProxyProvider socks5ProxyProvider) {
|
||||
super(socks5ProxyProvider);
|
||||
}
|
||||
}
|
@ -17,10 +17,12 @@
|
||||
|
||||
package bisq.core.provider.fee;
|
||||
|
||||
import bisq.core.provider.FeeHttpClient;
|
||||
import bisq.core.provider.HttpClientProvider;
|
||||
import bisq.core.provider.PriceNodeHttpClient;
|
||||
import bisq.core.provider.ProvidersRepository;
|
||||
|
||||
import bisq.network.http.HttpClient;
|
||||
|
||||
import bisq.common.app.Version;
|
||||
import bisq.common.util.Tuple2;
|
||||
|
||||
@ -40,12 +42,12 @@ import lombok.extern.slf4j.Slf4j;
|
||||
public class FeeProvider extends HttpClientProvider {
|
||||
|
||||
@Inject
|
||||
public FeeProvider(PriceNodeHttpClient httpClient, ProvidersRepository providersRepository) {
|
||||
public FeeProvider(FeeHttpClient httpClient, ProvidersRepository providersRepository) {
|
||||
super(httpClient, providersRepository.getBaseUrl(), false);
|
||||
}
|
||||
|
||||
public Tuple2<Map<String, Long>, Map<String, Long>> getFees() throws IOException {
|
||||
String json = httpClient.requestWithGET("getFees", "User-Agent", "bisq/" + Version.VERSION);
|
||||
String json = httpClient.get("getFees", "User-Agent", "bisq/" + Version.VERSION);
|
||||
|
||||
LinkedTreeMap<?, ?> linkedTreeMap = new Gson().fromJson(json, LinkedTreeMap.class);
|
||||
Map<String, Long> tsMap = new HashMap<>();
|
||||
@ -64,4 +66,8 @@ public class FeeProvider extends HttpClientProvider {
|
||||
}
|
||||
return new Tuple2<>(tsMap, map);
|
||||
}
|
||||
|
||||
public HttpClient getHttpClient() {
|
||||
return httpClient;
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ public class FeeRequest {
|
||||
public SettableFuture<Tuple2<Map<String, Long>, Map<String, Long>>> getFees(FeeProvider provider) {
|
||||
final SettableFuture<Tuple2<Map<String, Long>, Map<String, Long>>> resultFuture = SettableFuture.create();
|
||||
ListenableFuture<Tuple2<Map<String, Long>, Map<String, Long>>> future = executorService.submit(() -> {
|
||||
Thread.currentThread().setName("FeeRequest-" + provider.toString());
|
||||
Thread.currentThread().setName("FeeRequest @ " + provider.getHttpClient().getBaseUrl());
|
||||
return provider.getFees();
|
||||
});
|
||||
|
||||
|
@ -137,6 +137,11 @@ public class FeeService {
|
||||
}
|
||||
|
||||
public void requestFees(@Nullable Runnable resultHandler, @Nullable FaultHandler faultHandler) {
|
||||
if (feeProvider.getHttpClient().hasPendingRequest()) {
|
||||
log.warn("We have a pending request open. We ignore that request. httpClient {}", feeProvider.getHttpClient());
|
||||
return;
|
||||
}
|
||||
|
||||
long now = Instant.now().getEpochSecond();
|
||||
// We all requests only each 2 minutes
|
||||
if (now - lastRequest > MIN_PAUSE_BETWEEN_REQUESTS_IN_MIN * 60) {
|
||||
|
@ -21,7 +21,7 @@ import bisq.core.locale.CurrencyUtil;
|
||||
import bisq.core.locale.TradeCurrency;
|
||||
import bisq.core.monetary.Altcoin;
|
||||
import bisq.core.monetary.Price;
|
||||
import bisq.core.provider.PriceNodeHttpClient;
|
||||
import bisq.core.provider.PriceHttpClient;
|
||||
import bisq.core.provider.ProvidersRepository;
|
||||
import bisq.core.trade.statistics.TradeStatistics3;
|
||||
import bisq.core.user.Preferences;
|
||||
@ -101,7 +101,7 @@ public class PriceFeedService {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
public PriceFeedService(@SuppressWarnings("SameParameterValue") PriceNodeHttpClient httpClient,
|
||||
public PriceFeedService(PriceHttpClient httpClient,
|
||||
@SuppressWarnings("SameParameterValue") ProvidersRepository providersRepository,
|
||||
@SuppressWarnings("SameParameterValue") Preferences preferences) {
|
||||
this.httpClient = httpClient;
|
||||
@ -194,9 +194,9 @@ public class PriceFeedService {
|
||||
if (throwable instanceof PriceRequestException) {
|
||||
String baseUrlOfFaultyRequest = ((PriceRequestException) throwable).priceProviderBaseUrl;
|
||||
String baseUrlOfCurrentRequest = priceProvider.getBaseUrl();
|
||||
if (baseUrlOfFaultyRequest != null && baseUrlOfCurrentRequest.equals(baseUrlOfFaultyRequest)) {
|
||||
log.warn("We received an error: baseUrlOfCurrentRequest={}, baseUrlOfFaultyRequest={}",
|
||||
baseUrlOfCurrentRequest, baseUrlOfFaultyRequest);
|
||||
if (baseUrlOfCurrentRequest.equals(baseUrlOfFaultyRequest)) {
|
||||
log.warn("We received an error: baseUrlOfCurrentRequest={}, baseUrlOfFaultyRequest={}, error={}",
|
||||
baseUrlOfCurrentRequest, baseUrlOfFaultyRequest, throwable.toString());
|
||||
retryWithNewProvider();
|
||||
} else {
|
||||
log.debug("We received an error from an earlier request. We have started a new request already so we ignore that error. " +
|
||||
@ -204,7 +204,7 @@ public class PriceFeedService {
|
||||
baseUrlOfCurrentRequest, baseUrlOfFaultyRequest);
|
||||
}
|
||||
} else {
|
||||
log.warn("We received an error with throwable={}", throwable);
|
||||
log.warn("We received an error with throwable={}", throwable.toString());
|
||||
retryWithNewProvider();
|
||||
}
|
||||
|
||||
@ -393,6 +393,11 @@ public class PriceFeedService {
|
||||
}
|
||||
|
||||
private void requestAllPrices(PriceProvider provider, Runnable resultHandler, FaultHandler faultHandler) {
|
||||
if (httpClient.hasPendingRequest()) {
|
||||
log.warn("We have a pending request open. We ignore that request. httpClient {}", httpClient);
|
||||
return;
|
||||
}
|
||||
|
||||
priceRequest = new PriceRequest();
|
||||
SettableFuture<Tuple2<Map<String, Long>, Map<String, MarketPrice>>> future = priceRequest.requestAllPrices(provider);
|
||||
Futures.addCallback(future, new FutureCallback<>() {
|
||||
|
@ -58,7 +58,7 @@ public class PriceProvider extends HttpClientProvider {
|
||||
if (P2PService.getMyNodeAddress() != null)
|
||||
hsVersion = P2PService.getMyNodeAddress().getHostName().length() > 22 ? ", HSv3" : ", HSv2";
|
||||
|
||||
String json = httpClient.requestWithGET("getAllMarketPrices", "User-Agent", "bisq/"
|
||||
String json = httpClient.get("getAllMarketPrices", "User-Agent", "bisq/"
|
||||
+ Version.VERSION + hsVersion);
|
||||
|
||||
|
||||
|
@ -50,7 +50,7 @@ public class PriceRequest {
|
||||
String baseUrl = provider.getBaseUrl();
|
||||
SettableFuture<Tuple2<Map<String, Long>, Map<String, MarketPrice>>> resultFuture = SettableFuture.create();
|
||||
ListenableFuture<Tuple2<Map<String, Long>, Map<String, MarketPrice>>> future = executorService.submit(() -> {
|
||||
Thread.currentThread().setName("PriceRequest-" + baseUrl);
|
||||
Thread.currentThread().setName("PriceRequest @ " + baseUrl);
|
||||
return provider.getAll();
|
||||
});
|
||||
|
||||
|
@ -197,6 +197,11 @@ class XmrTxProofRequest implements AssetTxProofRequest<XmrTxProofRequest.Result>
|
||||
return;
|
||||
}
|
||||
|
||||
if (httpClient.hasPendingRequest()) {
|
||||
log.warn("We have a pending request open. We ignore that request. httpClient {}", httpClient);
|
||||
return;
|
||||
}
|
||||
|
||||
// Timeout handing is delegated to the connection timeout handling in httpClient.
|
||||
|
||||
ListenableFuture<Result> future = executorService.submit(() -> {
|
||||
@ -206,7 +211,7 @@ class XmrTxProofRequest implements AssetTxProofRequest<XmrTxProofRequest.Result>
|
||||
"&viewkey=" + model.getTxKey() +
|
||||
"&txprove=1";
|
||||
log.info("Param {} for {}", param, this);
|
||||
String json = httpClient.requestWithGET(param, "User-Agent", "bisq/" + Version.VERSION);
|
||||
String json = httpClient.get(param, "User-Agent", "bisq/" + Version.VERSION);
|
||||
try {
|
||||
String prettyJson = new GsonBuilder().setPrettyPrinting().create().toJson(new JsonParser().parse(json));
|
||||
log.info("Response json from {}\n{}", this, prettyJson);
|
||||
|
@ -3152,6 +3152,7 @@ payment.venmo.venmoUserName=Venmo username
|
||||
payment.popmoney.accountId=Email or phone no.
|
||||
payment.promptPay.promptPayId=Citizen ID/Tax ID or phone no.
|
||||
payment.supportedCurrencies=Supported currencies
|
||||
payment.supportedCurrenciesForReceiver=Currencies for receiving funds
|
||||
payment.limitations=Limitations
|
||||
payment.salt=Salt for account age verification
|
||||
payment.error.noHexSalt=The salt needs to be in HEX format.\n\
|
||||
|
@ -12,6 +12,6 @@ resDir=p2p/src/main/resources
|
||||
# Only commit new TradeStatistics3Store if you plan to add it to
|
||||
# https://github.com/bisq-network/bisq/blob/0345c795e2c227d827a1f239a323dda1250f4e69/common/src/main/java/bisq/common/app/Version.java#L40 as well.
|
||||
cp "$dbDir/TradeStatistics3Store" "$resDir/TradeStatistics3Store_${version}_BTC_MAINNET"
|
||||
cp "$dbDir/AccountAgeWitnessStore" "$resDir/AccountAgeWitnessStore_BTC_MAINNET"
|
||||
cp "$dbDir/AccountAgeWitnessStore" "$resDir/AccountAgeWitnessStore_${version}_BTC_MAINNET"
|
||||
cp "$dbDir/DaoStateStore" "$resDir/DaoStateStore_BTC_MAINNET"
|
||||
cp "$dbDir/SignedWitnessStore" "$resDir/SignedWitnessStore_BTC_MAINNET"
|
||||
|
@ -78,7 +78,7 @@ public class TransferwiseForm extends PaymentMethodForm {
|
||||
|
||||
private void addCurrenciesGrid(boolean isEditable) {
|
||||
FlowPane flowPane = FormBuilder.addTopLabelFlowPane(gridPane, ++gridRow,
|
||||
Res.get("payment.supportedCurrencies"), 20, 20).second;
|
||||
Res.get("payment.supportedCurrenciesForReceiver"), 20, 20).second;
|
||||
|
||||
if (isEditable) {
|
||||
flowPane.setId("flow-pane-checkboxes-bg");
|
||||
|
@ -26,17 +26,19 @@ public interface HttpClient {
|
||||
|
||||
void setIgnoreSocks5Proxy(boolean ignoreSocks5Proxy);
|
||||
|
||||
String requestWithGET(String param,
|
||||
@Nullable String headerKey,
|
||||
@Nullable String headerValue) throws IOException;
|
||||
String get(String param,
|
||||
@Nullable String headerKey,
|
||||
@Nullable String headerValue) throws IOException;
|
||||
|
||||
String requestWithGETNoProxy(String param,
|
||||
@Nullable String headerKey,
|
||||
@Nullable String headerValue) throws IOException;
|
||||
String post(String param,
|
||||
@Nullable String headerKey,
|
||||
@Nullable String headerValue) throws IOException;
|
||||
|
||||
String getUid();
|
||||
|
||||
String getBaseUrl();
|
||||
|
||||
boolean hasPendingRequest();
|
||||
|
||||
void shutDown();
|
||||
}
|
||||
|
@ -20,9 +20,12 @@ package bisq.network.http;
|
||||
import bisq.network.Socks5ProxyProvider;
|
||||
|
||||
import bisq.common.app.Version;
|
||||
import bisq.common.util.Utilities;
|
||||
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.client.protocol.HttpClientContext;
|
||||
import org.apache.http.config.Registry;
|
||||
import org.apache.http.config.RegistryBuilder;
|
||||
@ -49,10 +52,12 @@ import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
// TODO close connection if failing
|
||||
@ -60,14 +65,19 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||
public class HttpClientImpl implements HttpClient {
|
||||
@Nullable
|
||||
private Socks5ProxyProvider socks5ProxyProvider;
|
||||
@Getter
|
||||
private String baseUrl;
|
||||
private boolean ignoreSocks5Proxy;
|
||||
private final String uid;
|
||||
@Nullable
|
||||
private HttpURLConnection connection;
|
||||
@Nullable
|
||||
private CloseableHttpClient httpclient;
|
||||
private CloseableHttpClient closeableHttpClient;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String baseUrl;
|
||||
@Setter
|
||||
private boolean ignoreSocks5Proxy;
|
||||
@Getter
|
||||
private final String uid;
|
||||
private boolean hasPendingRequest;
|
||||
|
||||
@Inject
|
||||
public HttpClientImpl(@Nullable Socks5ProxyProvider socks5ProxyProvider) {
|
||||
@ -82,103 +92,111 @@ public class HttpClientImpl implements HttpClient {
|
||||
|
||||
@Override
|
||||
public void shutDown() {
|
||||
if (connection != null) {
|
||||
connection.disconnect();
|
||||
}
|
||||
if (httpclient != null) {
|
||||
try {
|
||||
httpclient.close();
|
||||
} catch (IOException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBaseUrl(String baseUrl) {
|
||||
this.baseUrl = baseUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIgnoreSocks5Proxy(boolean ignoreSocks5Proxy) {
|
||||
this.ignoreSocks5Proxy = ignoreSocks5Proxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String requestWithGET(String param,
|
||||
@Nullable String headerKey,
|
||||
@Nullable String headerValue) throws IOException {
|
||||
checkNotNull(baseUrl, "baseUrl must be set before calling requestWithGET");
|
||||
|
||||
Socks5Proxy socks5Proxy = null;
|
||||
if (socks5ProxyProvider != null) {
|
||||
// We use the custom socks5ProxyHttp. If not set we request socks5ProxyProvider.getSocks5ProxyBtc()
|
||||
// which delivers the btc proxy if set, otherwise the internal proxy.
|
||||
socks5Proxy = socks5ProxyProvider.getSocks5ProxyHttp();
|
||||
if (socks5Proxy == null)
|
||||
socks5Proxy = socks5ProxyProvider.getSocks5Proxy();
|
||||
}
|
||||
if (ignoreSocks5Proxy || socks5Proxy == null || baseUrl.contains("localhost")) {
|
||||
log.debug("Use clear net for HttpClient. socks5Proxy={}, ignoreSocks5Proxy={}, baseUrl={}",
|
||||
socks5Proxy, ignoreSocks5Proxy, baseUrl);
|
||||
return requestWithGETNoProxy(param, headerKey, headerValue);
|
||||
} else {
|
||||
log.debug("Use socks5Proxy for HttpClient: " + socks5Proxy);
|
||||
return doRequestWithGETProxy(param, socks5Proxy, headerKey, headerValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an HTTP Get request directly (not routed over socks5 proxy).
|
||||
*/
|
||||
@Override
|
||||
public String requestWithGETNoProxy(String param,
|
||||
@Nullable String headerKey,
|
||||
@Nullable String headerValue) throws IOException {
|
||||
log.debug("Executing HTTP request " + baseUrl + param + " proxy: none.");
|
||||
URL url = new URL(baseUrl + param);
|
||||
try {
|
||||
if (connection != null) {
|
||||
connection.getInputStream().close();
|
||||
connection.disconnect();
|
||||
}
|
||||
if (closeableHttpClient != null) {
|
||||
closeableHttpClient.close();
|
||||
}
|
||||
} catch (IOException ignore) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPendingRequest() {
|
||||
return hasPendingRequest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(String param,
|
||||
@Nullable String headerKey,
|
||||
@Nullable String headerValue) throws IOException {
|
||||
return doRequest(param, HttpMethod.GET, headerKey, headerValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String post(String param,
|
||||
@Nullable String headerKey,
|
||||
@Nullable String headerValue) throws IOException {
|
||||
return doRequest(param, HttpMethod.POST, headerKey, headerValue);
|
||||
}
|
||||
|
||||
private String doRequest(String param,
|
||||
HttpMethod httpMethod,
|
||||
@Nullable String headerKey,
|
||||
@Nullable String headerValue) throws IOException {
|
||||
checkNotNull(baseUrl, "baseUrl must be set before calling doRequest");
|
||||
checkArgument(!hasPendingRequest, "We got called on the same HttpClient again while a request is still open.");
|
||||
|
||||
hasPendingRequest = true;
|
||||
Socks5Proxy socks5Proxy = getSocks5Proxy(socks5ProxyProvider);
|
||||
if (ignoreSocks5Proxy || socks5Proxy == null || baseUrl.contains("localhost")) {
|
||||
return requestWithoutProxy(baseUrl, param, httpMethod, headerKey, headerValue);
|
||||
} else {
|
||||
return doRequestWithProxy(baseUrl, param, httpMethod, socks5Proxy, headerKey, headerValue);
|
||||
}
|
||||
}
|
||||
|
||||
private String requestWithoutProxy(String baseUrl,
|
||||
String param,
|
||||
HttpMethod httpMethod,
|
||||
@Nullable String headerKey,
|
||||
@Nullable String headerValue) throws IOException {
|
||||
long ts = System.currentTimeMillis();
|
||||
String spec = baseUrl + param;
|
||||
log.info("requestWithoutProxy: URL={}, httpMethod={}", spec, httpMethod);
|
||||
try {
|
||||
URL url = new URL(spec);
|
||||
connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setRequestMethod("GET");
|
||||
connection.setRequestMethod(httpMethod.name());
|
||||
connection.setConnectTimeout((int) TimeUnit.SECONDS.toMillis(120));
|
||||
connection.setReadTimeout((int) TimeUnit.SECONDS.toMillis(120));
|
||||
connection.setRequestProperty("User-Agent", "bisq/" + Version.VERSION);
|
||||
if (headerKey != null && headerValue != null)
|
||||
if (headerKey != null && headerValue != null) {
|
||||
connection.setRequestProperty(headerKey, headerValue);
|
||||
}
|
||||
|
||||
if (connection.getResponseCode() == 200) {
|
||||
return convertInputStreamToString(connection.getInputStream());
|
||||
String response = convertInputStreamToString(connection.getInputStream());
|
||||
log.info("Response for {} took {} ms. Data size:{}, response: {}",
|
||||
spec,
|
||||
System.currentTimeMillis() - ts,
|
||||
Utilities.readableFileSize(response.getBytes().length),
|
||||
Utilities.toTruncatedString(response));
|
||||
return response;
|
||||
} else {
|
||||
String error = convertInputStreamToString(connection.getErrorStream());
|
||||
connection.getErrorStream().close();
|
||||
throw new HttpException(error);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
final String message = "Error at requestWithGETNoProxy with URL: " + (baseUrl + param) + ". Throwable=" + t.getMessage();
|
||||
String message = "Error at requestWithoutProxy with URL: " + spec + ". Throwable=" + t.getMessage();
|
||||
log.error(message);
|
||||
throw new IOException(message);
|
||||
} finally {
|
||||
try {
|
||||
if (connection != null)
|
||||
if (connection != null) {
|
||||
connection.getInputStream().close();
|
||||
connection.disconnect();
|
||||
connection = null;
|
||||
}
|
||||
} catch (Throwable ignore) {
|
||||
}
|
||||
hasPendingRequest = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUid() {
|
||||
return uid;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make an HTTP Get request routed over socks5 proxy.
|
||||
*/
|
||||
private String doRequestWithGETProxy(String param,
|
||||
Socks5Proxy socks5Proxy,
|
||||
@Nullable String headerKey,
|
||||
@Nullable String headerValue) throws IOException {
|
||||
log.debug("requestWithGETProxy param=" + param);
|
||||
private String doRequestWithProxy(String baseUrl,
|
||||
String param,
|
||||
HttpMethod httpMethod,
|
||||
Socks5Proxy socks5Proxy,
|
||||
@Nullable String headerKey,
|
||||
@Nullable String headerValue) throws IOException {
|
||||
long ts = System.currentTimeMillis();
|
||||
String uri = baseUrl + param;
|
||||
log.info("requestWithoutProxy: uri={}, httpMethod={}", uri, httpMethod);
|
||||
// This code is adapted from:
|
||||
// http://stackoverflow.com/a/25203021/5616248
|
||||
|
||||
@ -194,7 +212,7 @@ public class HttpClientImpl implements HttpClient {
|
||||
new PoolingHttpClientConnectionManager(reg) :
|
||||
new PoolingHttpClientConnectionManager(reg, new FakeDnsResolver());
|
||||
try {
|
||||
httpclient = HttpClients.custom().setConnectionManager(cm).build();
|
||||
closeableHttpClient = HttpClients.custom().setConnectionManager(cm).build();
|
||||
InetSocketAddress socksAddress = new InetSocketAddress(socks5Proxy.getInetAddress(), socks5Proxy.getPort());
|
||||
|
||||
// remove me: Use this to test with system-wide Tor proxy, or change port for another proxy.
|
||||
@ -203,23 +221,60 @@ public class HttpClientImpl implements HttpClient {
|
||||
HttpClientContext context = HttpClientContext.create();
|
||||
context.setAttribute("socks.address", socksAddress);
|
||||
|
||||
HttpGet request = new HttpGet(baseUrl + param);
|
||||
HttpUriRequest request = getHttpUriRequest(httpMethod, uri);
|
||||
if (headerKey != null && headerValue != null)
|
||||
request.setHeader(headerKey, headerValue);
|
||||
|
||||
log.debug("Executing request " + request + " proxy: " + socksAddress);
|
||||
try (CloseableHttpResponse response = checkNotNull(httpclient).execute(request, context)) {
|
||||
return convertInputStreamToString(response.getEntity().getContent());
|
||||
try (CloseableHttpResponse httpResponse = checkNotNull(closeableHttpClient).execute(request, context)) {
|
||||
String response = convertInputStreamToString(httpResponse.getEntity().getContent());
|
||||
log.info("Response for {} took {} ms. Data size:{}, response: {}",
|
||||
uri,
|
||||
System.currentTimeMillis() - ts,
|
||||
Utilities.readableFileSize(response.getBytes().length),
|
||||
Utilities.toTruncatedString(response));
|
||||
return response;
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
throw new IOException("Error at requestWithGETProxy with URL: " + (baseUrl + param) + ". Throwable=" + t.getMessage());
|
||||
String message = "Error at doRequestWithProxy with URL: " + uri + ". Throwable=" + t.getMessage();
|
||||
log.error(message);
|
||||
throw new IOException(message);
|
||||
} finally {
|
||||
if (httpclient != null) {
|
||||
httpclient.close();
|
||||
if (closeableHttpClient != null) {
|
||||
closeableHttpClient.close();
|
||||
closeableHttpClient = null;
|
||||
}
|
||||
hasPendingRequest = false;
|
||||
}
|
||||
}
|
||||
|
||||
private HttpUriRequest getHttpUriRequest(HttpMethod httpMethod, String uri) {
|
||||
switch (httpMethod) {
|
||||
case GET:
|
||||
return new HttpGet(uri);
|
||||
case POST:
|
||||
return new HttpPost(uri);
|
||||
default:
|
||||
throw new IllegalArgumentException("HttpMethod not supported: " + httpMethod);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Socks5Proxy getSocks5Proxy(Socks5ProxyProvider socks5ProxyProvider) {
|
||||
if (socks5ProxyProvider == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// We use the custom socks5ProxyHttp.
|
||||
Socks5Proxy socks5Proxy = socks5ProxyProvider.getSocks5ProxyHttp();
|
||||
if (socks5Proxy != null) {
|
||||
return socks5Proxy;
|
||||
}
|
||||
|
||||
// If not set we request socks5ProxyProvider.getSocks5Proxy()
|
||||
// which delivers the btc proxy if set, otherwise the internal proxy.
|
||||
return socks5ProxyProvider.getSocks5Proxy();
|
||||
}
|
||||
|
||||
private String convertInputStreamToString(InputStream inputStream) throws IOException {
|
||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
@ -232,10 +287,13 @@ public class HttpClientImpl implements HttpClient {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HttpClient{" +
|
||||
"socks5ProxyProvider=" + socks5ProxyProvider +
|
||||
", baseUrl='" + baseUrl + '\'' +
|
||||
", ignoreSocks5Proxy=" + ignoreSocks5Proxy +
|
||||
'}';
|
||||
return "HttpClientImpl{" +
|
||||
"\n socks5ProxyProvider=" + socks5ProxyProvider +
|
||||
",\n baseUrl='" + baseUrl + '\'' +
|
||||
",\n ignoreSocks5Proxy=" + ignoreSocks5Proxy +
|
||||
",\n uid='" + uid + '\'' +
|
||||
",\n connection=" + connection +
|
||||
",\n httpclient=" + closeableHttpClient +
|
||||
"\n}";
|
||||
}
|
||||
}
|
||||
|
23
p2p/src/main/java/bisq/network/http/HttpMethod.java
Normal file
23
p2p/src/main/java/bisq/network/http/HttpMethod.java
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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 bisq.network.http;
|
||||
|
||||
public enum HttpMethod {
|
||||
GET,
|
||||
POST
|
||||
}
|
@ -192,10 +192,7 @@ public abstract class HistoricalDataStoreService<T extends PersistableNetworkPay
|
||||
pruneStore(persisted, version);
|
||||
completeHandler.run();
|
||||
},
|
||||
() -> {
|
||||
log.warn("Resource file with file name {} does not exits.", fileName);
|
||||
completeHandler.run();
|
||||
});
|
||||
completeHandler::run);
|
||||
}
|
||||
|
||||
private void pruneStore(PersistableNetworkPayloadStore<? extends PersistableNetworkPayload> historicalStore,
|
||||
|
Loading…
Reference in New Issue
Block a user