Compare commits

..

No commits in common. "master" and "1.0.4" have entirely different histories.

7 changed files with 69 additions and 94 deletions

View File

@ -4,7 +4,7 @@ plugins {
}
group = 'com.sparrowwallet'
version = '1.0.6'
version = '1.0.4'
def secrets = new Properties()
file("publish.properties").withInputStream {
@ -24,6 +24,7 @@ dependencies {
implementation('org.eclipse.jetty:jetty-client:9.4.54.v20240208')
implementation('io.reactivex.rxjava2:rxjava:2.2.15')
implementation('org.apache.commons:commons-lang3:3.7')
implementation('com.google.guava:guava:33.0.0-jre')
implementation('org.slf4j:slf4j-api:2.0.12')
testImplementation platform('org.junit:junit-bom:5.10.0')
testImplementation('org.junit.jupiter:junit-jupiter')

View File

@ -1,41 +0,0 @@
package com.sparrowwallet.tern.http.client;
import java.util.Optional;
public class DefaultHttpProxySupplier implements IHttpProxySupplier {
private final String host;
private final int port;
private final HttpProxy httpProxy;
public DefaultHttpProxySupplier(String host, int port) {
this.host = host;
this.port = port;
this.httpProxy = computeHttpProxy(host, port);
}
private HttpProxy computeHttpProxy(String host, int port) {
if(host == null || host.isEmpty() || port < 0) {
return null;
}
return new HttpProxy(HttpProxyProtocol.SOCKS, host, port);
}
public String getHost() {
return host;
}
public int getPort() {
return port;
}
@Override
public Optional<HttpProxy> getHttpProxy(HttpUsage httpUsage) {
return Optional.ofNullable(httpProxy);
}
@Override
public void changeIdentity() {
//not implemented
}
}

View File

@ -1,5 +1,6 @@
package com.sparrowwallet.tern.http.client;
import com.google.common.net.HostAndPort;
import io.reactivex.Observable;
import java.util.Map;
@ -16,8 +17,8 @@ public class HttpClientService extends JettyHttpClientService {
this(requestTimeout, null);
}
public HttpClientService(String host, int port) {
this(DEFAULT_REQUEST_TIMEOUT, new DefaultHttpProxySupplier(host, port));
public HttpClientService(HostAndPort torProxy) {
this(DEFAULT_REQUEST_TIMEOUT, new TorHttpProxySupplier(torProxy));
}
public HttpClientService(IHttpProxySupplier httpProxySupplier) {
@ -40,4 +41,20 @@ public class HttpClientService extends JettyHttpClientService {
IHttpClient httpClient = getHttpClient(HttpUsage.DEFAULT);
return AsyncUtil.getInstance().blockingGet(httpClient.postString(url, headers, contentType, content)).get();
}
public HostAndPort getTorProxy() {
if(getHttpProxySupplier() instanceof TorHttpProxySupplier torHttpProxySupplier) {
return torHttpProxySupplier.getTorProxy();
}
return null;
}
public void setTorProxy(HostAndPort torProxy) {
if(getHttpProxySupplier() instanceof TorHttpProxySupplier torHttpProxySupplier) {
//Ensure all http clients are shutdown first
stop();
torHttpProxySupplier._setTorProxy(torProxy);
}
}
}

View File

@ -1,10 +1,10 @@
package com.sparrowwallet.tern.http.client;
import com.google.common.util.concurrent.RateLimiter;
import com.sparrowwallet.tern.http.client.socks5.Socks5Proxy;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.ProxyConfiguration;
import org.eclipse.jetty.client.Socks4Proxy;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
@ -23,11 +23,7 @@ public class JettyHttpClientService implements IHttpClientService {
public static final long DEFAULT_TIMEOUT = 30000;
// limit changing Tor identity on network error every 4 minutes
private static final int RATE_CHANGE_IDENTITY_ON_NETWORK_ERROR = 4 * 60 * 1000;
static {
Log.getProperties().setProperty("org.eclipse.jetty.util.log.announce", "false");
}
private static final double RATE_CHANGE_IDENTITY_ON_NETWORK_ERROR = 1.0 / 240;
protected Map<HttpUsage, JettyHttpClient> httpClients; // used by Sparrow
private final IHttpProxySupplier httpProxySupplier;
@ -95,7 +91,7 @@ public class JettyHttpClientService implements IHttpClientService {
}
protected Consumer<Exception> computeOnNetworkError() {
RateLimiter rateLimiter = new RateLimiter(1, RATE_CHANGE_IDENTITY_ON_NETWORK_ERROR);
RateLimiter rateLimiter = RateLimiter.create(RATE_CHANGE_IDENTITY_ON_NETWORK_ERROR);
return e -> {
if(!rateLimiter.tryAcquire()) {
if(log.isDebugEnabled()) {

View File

@ -1,43 +0,0 @@
package com.sparrowwallet.tern.http.client;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
public class RateLimiter {
private final int maxTokens;
private final long refillIntervalMillis;
private final AtomicInteger tokens;
private long lastRefillTimestamp;
private final ReentrantLock lock = new ReentrantLock();
public RateLimiter(int maxTokens, long refillIntervalMillis) {
this.maxTokens = maxTokens;
this.refillIntervalMillis = refillIntervalMillis;
this.tokens = new AtomicInteger(maxTokens);
this.lastRefillTimestamp = System.currentTimeMillis();
}
public boolean tryAcquire() {
refill();
if (tokens.get() > 0) {
tokens.decrementAndGet();
return true;
}
return false;
}
private void refill() {
lock.lock();
try {
long now = System.currentTimeMillis();
long elapsed = now - lastRefillTimestamp;
if (elapsed > refillIntervalMillis) {
int tokensToAdd = (int) (elapsed / refillIntervalMillis);
tokens.set(Math.min(maxTokens, tokens.get() + tokensToAdd));
lastRefillTimestamp = now;
}
} finally {
lock.unlock();
}
}
}

View File

@ -0,0 +1,44 @@
package com.sparrowwallet.tern.http.client;
import com.google.common.net.HostAndPort;
import java.util.Optional;
public class TorHttpProxySupplier implements IHttpProxySupplier {
private HostAndPort torProxy;
private HttpProxy httpProxy;
public TorHttpProxySupplier(HostAndPort torProxy) {
this.torProxy = torProxy;
this.httpProxy = computeHttpProxy(torProxy);
}
private HttpProxy computeHttpProxy(HostAndPort hostAndPort) {
if (hostAndPort == null) {
return null;
}
return new HttpProxy(HttpProxyProtocol.SOCKS, hostAndPort.getHost(), hostAndPort.getPort());
}
public HostAndPort getTorProxy() {
return torProxy;
}
// shouldnt call directly but use httpClientService.setTorProxy()
public void _setTorProxy(HostAndPort hostAndPort) {
// set proxy
this.torProxy = hostAndPort;
this.httpProxy = computeHttpProxy(hostAndPort);
}
@Override
public Optional<HttpProxy> getHttpProxy(HttpUsage httpUsage) {
return Optional.ofNullable(httpProxy);
}
@Override
public void changeIdentity() {
//unimplemented
}
}

View File

@ -1,5 +1,6 @@
module com.sparrowwallet.tern {
requires java.management;
requires com.google.common;
requires io.reactivex.rxjava2;
requires com.fasterxml.jackson.databind;
requires org.eclipse.jetty.io;