mirror of
https://github.com/jwdeveloper/TikTokLiveJava.git
synced 2026-02-27 08:49:40 -05:00
Push for proxy test!
This commit is contained in:
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package io.github.jwdeveloper.tiktok.data.dto;
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.net.*;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ProxyData
|
||||||
|
{
|
||||||
|
private final String address;
|
||||||
|
private final int port;
|
||||||
|
|
||||||
|
public static ProxyData map(String string) {
|
||||||
|
if (string == null || string.isBlank())
|
||||||
|
throw new IllegalArgumentException("Provided address cannot be null or empty!");
|
||||||
|
int portIndex = string.lastIndexOf(':');
|
||||||
|
try {
|
||||||
|
String address = string.substring(0, portIndex);
|
||||||
|
int port = Integer.parseInt(string.substring(portIndex+1));
|
||||||
|
|
||||||
|
// Port validation
|
||||||
|
if (port < 0 || port > 65535)
|
||||||
|
throw new IndexOutOfBoundsException("Port out of range: "+port);
|
||||||
|
|
||||||
|
// IP Validation
|
||||||
|
InetAddress res = InetAddress.getByName(address);
|
||||||
|
|
||||||
|
return new ProxyData(address, port);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new IllegalArgumentException("Port must be a valid integer!");
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
throw new IllegalArgumentException("Address must be valid IPv4, IPv6, or domain name!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProxyData clone() {
|
||||||
|
return new ProxyData(address, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InetSocketAddress toSocketAddress() {
|
||||||
|
return new InetSocketAddress(address, port);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -74,7 +74,7 @@ public class HttpClientSettings {
|
|||||||
* @param consumer Use to configure proxy settings for http client
|
* @param consumer Use to configure proxy settings for http client
|
||||||
*/
|
*/
|
||||||
public void configureProxy(Consumer<ProxyClientSettings> consumer) {
|
public void configureProxy(Consumer<ProxyClientSettings> consumer) {
|
||||||
proxyClientSettings.setUseProxy(true);
|
proxyClientSettings.setEnabled(true);
|
||||||
consumer.accept(proxyClientSettings);
|
consumer.accept(proxyClientSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,4 +108,4 @@ public class HttpClientSettings {
|
|||||||
|
|
||||||
return newSettings;
|
return newSettings;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -22,19 +22,100 @@
|
|||||||
*/
|
*/
|
||||||
package io.github.jwdeveloper.tiktok.data.settings;
|
package io.github.jwdeveloper.tiktok.data.settings;
|
||||||
|
|
||||||
import lombok.Getter;
|
import io.github.jwdeveloper.tiktok.data.dto.ProxyData;
|
||||||
import lombok.Setter;
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.net.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
//TODO proxy implementation
|
|
||||||
@Getter
|
@Getter
|
||||||
public class ProxyClientSettings
|
@Setter
|
||||||
|
public class ProxyClientSettings implements Iterator<ProxyData>
|
||||||
{
|
{
|
||||||
@Setter
|
private boolean enabled;
|
||||||
private boolean useProxy;
|
private Rotation rotation = Rotation.CONSECUTIVE;
|
||||||
|
private final List<ProxyData> proxyList = new ArrayList<>();
|
||||||
|
private int index = 0;
|
||||||
|
private boolean autoDiscard = true;
|
||||||
|
private Proxy.Type type = Proxy.Type.DIRECT;
|
||||||
|
private Consumer<ProxyData> onProxyUpdated = (x)->{};
|
||||||
|
|
||||||
|
|
||||||
public ProxyClientSettings clone()
|
public boolean addProxy(String addressPort) {
|
||||||
{
|
return proxyList.add(ProxyData.map(addressPort));
|
||||||
return new ProxyClientSettings();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public boolean addProxy(String address, int port) {
|
||||||
|
return addProxy(new InetSocketAddress(address, port));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean addProxy(InetSocketAddress inetAddress) {
|
||||||
|
return proxyList.add(new ProxyData(inetAddress.getHostString(), inetAddress.getPort()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addProxies(List<String> list) {
|
||||||
|
list.forEach(this::addProxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return !proxyList.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ProxyData next()
|
||||||
|
{
|
||||||
|
var nextProxy = switch (rotation)
|
||||||
|
{
|
||||||
|
case CONSECUTIVE -> {
|
||||||
|
index = (index+1) % proxyList.size();
|
||||||
|
yield proxyList.get(index).clone();
|
||||||
|
}
|
||||||
|
case RANDOM -> {
|
||||||
|
index = new Random().nextInt(proxyList.size());
|
||||||
|
yield proxyList.get(index).clone();
|
||||||
|
}
|
||||||
|
default -> {
|
||||||
|
yield proxyList.get(index).clone();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
onProxyUpdated.accept(nextProxy);
|
||||||
|
return nextProxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove() {
|
||||||
|
proxyList.remove(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIndex(int index) {
|
||||||
|
if (index == 0 && proxyList.isEmpty())
|
||||||
|
this.index = 0;
|
||||||
|
else {
|
||||||
|
if (index < 0 || index >= proxyList.size())
|
||||||
|
throw new IndexOutOfBoundsException("Index " + index + " exceeds list of size: " + proxyList.size());
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProxyClientSettings clone() {
|
||||||
|
ProxyClientSettings settings = new ProxyClientSettings();
|
||||||
|
settings.setEnabled(enabled);
|
||||||
|
settings.setRotation(rotation);
|
||||||
|
settings.setIndex(index);
|
||||||
|
settings.setType(type);
|
||||||
|
proxyList.forEach(proxyData -> settings.addProxy(proxyData.getAddress(), proxyData.getPort()));
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Rotation
|
||||||
|
{
|
||||||
|
/** Rotate addresses consecutively, from proxy 0 -> 1 -> 2 -> ...etc. */
|
||||||
|
CONSECUTIVE,
|
||||||
|
/** Rotate addresses randomly, from proxy 0 -> 69 -> 420 -> 1 -> ...etc. */
|
||||||
|
RANDOM,
|
||||||
|
/** Don't rotate addresses at all, pin to the indexed address. */
|
||||||
|
NONE
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,14 +25,9 @@ package io.github.jwdeveloper.tiktok;
|
|||||||
import com.google.protobuf.InvalidProtocolBufferException;
|
import com.google.protobuf.InvalidProtocolBufferException;
|
||||||
import io.github.jwdeveloper.tiktok.data.requests.*;
|
import io.github.jwdeveloper.tiktok.data.requests.*;
|
||||||
import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
|
import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
|
import io.github.jwdeveloper.tiktok.exceptions.*;
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokSignServerException;
|
import io.github.jwdeveloper.tiktok.http.*;
|
||||||
import io.github.jwdeveloper.tiktok.http.HttpClientFactory;
|
import io.github.jwdeveloper.tiktok.http.mappers.*;
|
||||||
import io.github.jwdeveloper.tiktok.http.LiveHttpClient;
|
|
||||||
import io.github.jwdeveloper.tiktok.http.mappers.GiftsDataMapper;
|
|
||||||
import io.github.jwdeveloper.tiktok.http.mappers.LiveDataMapper;
|
|
||||||
import io.github.jwdeveloper.tiktok.http.mappers.LiveUserDataMapper;
|
|
||||||
import io.github.jwdeveloper.tiktok.http.mappers.SignServerResponseMapper;
|
|
||||||
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
|
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
|
||||||
|
|
||||||
import java.net.http.HttpResponse;
|
import java.net.http.HttpResponse;
|
||||||
|
|||||||
@@ -26,42 +26,34 @@ import io.github.jwdeveloper.tiktok.data.settings.HttpClientSettings;
|
|||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
import java.net.CookieManager;
|
import java.net.*;
|
||||||
import java.net.URI;
|
import java.net.http.*;
|
||||||
import java.net.URLEncoder;
|
import java.nio.charset.*;
|
||||||
import java.net.http.HttpRequest;
|
import java.util.*;
|
||||||
import java.net.http.HttpResponse;
|
import java.util.regex.*;
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class HttpClient {
|
public class HttpClient {
|
||||||
private final HttpClientSettings httpClientSettings;
|
protected final HttpClientSettings httpClientSettings;
|
||||||
private final String url;
|
protected final String url;
|
||||||
|
private final Pattern pattern = Pattern.compile("charset=(.*?)(?=&|$)");
|
||||||
|
|
||||||
public <T> Optional<HttpResponse<T>> toResponse(HttpResponse.BodyHandler<T> bodyHandler) {
|
public <T> Optional<HttpResponse<T>> toResponse(HttpResponse.BodyHandler<T> bodyHandler) {
|
||||||
var client = prepareClient();
|
var client = prepareClient();
|
||||||
var request = prepareGetRequest();
|
var request = prepareGetRequest();
|
||||||
try
|
try {
|
||||||
{
|
var response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
|
||||||
var response = client.send(request, bodyHandler);
|
if (response.statusCode() != 200) {
|
||||||
if(response.statusCode() != 200)
|
|
||||||
{
|
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return Optional.of(response);
|
return Optional.of(response);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new TikTokLiveRequestException(e);
|
throw new TikTokLiveRequestException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Optional<String> toJsonResponse() {
|
public Optional<String> toJsonResponse() {
|
||||||
var optional = toResponse(HttpResponse.BodyHandlers.ofString());
|
var optional = toResponse(HttpResponse.BodyHandlers.ofString());
|
||||||
if (optional.isEmpty()) {
|
if (optional.isEmpty()) {
|
||||||
@@ -69,12 +61,24 @@ public class HttpClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var response = optional.get();
|
var response = optional.get();
|
||||||
|
|
||||||
|
|
||||||
var body = response.body();
|
var body = response.body();
|
||||||
return Optional.of(body);
|
return Optional.of(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Charset charsetFrom(HttpHeaders headers) {
|
||||||
|
String type = headers.firstValue("Content-type").orElse("text/html; charset=utf-8");
|
||||||
|
int i = type.indexOf(";");
|
||||||
|
if (i >= 0) type = type.substring(i+1);
|
||||||
|
try {
|
||||||
|
Matcher matcher = pattern.matcher(type);
|
||||||
|
if (!matcher.find())
|
||||||
|
return StandardCharsets.UTF_8;
|
||||||
|
return Charset.forName(matcher.group(1));
|
||||||
|
} catch (Throwable x) {
|
||||||
|
return StandardCharsets.UTF_8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Optional<byte[]> toBinaryResponse() {
|
public Optional<byte[]> toBinaryResponse() {
|
||||||
var optional = toResponse(HttpResponse.BodyHandlers.ofByteArray());
|
var optional = toResponse(HttpResponse.BodyHandlers.ofByteArray());
|
||||||
if (optional.isEmpty()) {
|
if (optional.isEmpty()) {
|
||||||
@@ -84,13 +88,12 @@ public class HttpClient {
|
|||||||
return Optional.of(body);
|
return Optional.of(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public URI toUrl() {
|
public URI toUrl() {
|
||||||
var stringUrl = prepareUrlWithParameters(url, httpClientSettings.getParams());
|
var stringUrl = prepareUrlWithParameters(url, httpClientSettings.getParams());
|
||||||
return URI.create(stringUrl);
|
return URI.create(stringUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
private HttpRequest prepareGetRequest() {
|
protected HttpRequest prepareGetRequest() {
|
||||||
var requestBuilder = HttpRequest.newBuilder().GET();
|
var requestBuilder = HttpRequest.newBuilder().GET();
|
||||||
requestBuilder.uri(toUrl());
|
requestBuilder.uri(toUrl());
|
||||||
requestBuilder.timeout(httpClientSettings.getTimeout());
|
requestBuilder.timeout(httpClientSettings.getTimeout());
|
||||||
@@ -100,18 +103,17 @@ public class HttpClient {
|
|||||||
return requestBuilder.build();
|
return requestBuilder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private java.net.http.HttpClient prepareClient() {
|
protected java.net.http.HttpClient prepareClient() {
|
||||||
var builder = java.net.http.HttpClient.newBuilder()
|
var builder = java.net.http.HttpClient.newBuilder()
|
||||||
.followRedirects(java.net.http.HttpClient.Redirect.NORMAL)
|
.followRedirects(java.net.http.HttpClient.Redirect.NORMAL)
|
||||||
.cookieHandler(new CookieManager())
|
.cookieHandler(new CookieManager())
|
||||||
.connectTimeout(httpClientSettings.getTimeout());
|
.connectTimeout(httpClientSettings.getTimeout());
|
||||||
|
|
||||||
|
|
||||||
httpClientSettings.getOnClientCreating().accept(builder);
|
httpClientSettings.getOnClientCreating().accept(builder);
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String prepareUrlWithParameters(String url, Map<String, Object> parameters) {
|
protected String prepareUrlWithParameters(String url, Map<String, Object> parameters) {
|
||||||
if (parameters.isEmpty()) {
|
if (parameters.isEmpty()) {
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
@@ -123,4 +125,4 @@ public class HttpClient {
|
|||||||
return encodedKey + "=" + encodedValue;
|
return encodedKey + "=" + encodedValue;
|
||||||
}).collect(Collectors.joining("&"));
|
}).collect(Collectors.joining("&"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -77,11 +77,9 @@ public class HttpClientBuilder {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public HttpClient build() {
|
public HttpClient build() {
|
||||||
|
if (httpClientSettings.getProxyClientSettings().isEnabled())
|
||||||
|
return new HttpProxyClient(httpClientSettings, url);
|
||||||
return new HttpClient(httpClientSettings, url);
|
return new HttpClient(httpClientSettings, url);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,196 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package io.github.jwdeveloper.tiktok.http;
|
||||||
|
|
||||||
|
import io.github.jwdeveloper.tiktok.data.settings.*;
|
||||||
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
|
||||||
|
|
||||||
|
import javax.net.ssl.*;
|
||||||
|
import java.net.*;
|
||||||
|
import java.net.http.*;
|
||||||
|
import java.net.http.HttpResponse.ResponseInfo;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class HttpProxyClient extends HttpClient
|
||||||
|
{
|
||||||
|
private final ProxyClientSettings proxySettings;
|
||||||
|
|
||||||
|
public HttpProxyClient(HttpClientSettings httpClientSettings, String url) {
|
||||||
|
super(httpClientSettings, url);
|
||||||
|
this.proxySettings = httpClientSettings.getProxyClientSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<HttpResponse<byte[]>> toResponse() {
|
||||||
|
return switch (proxySettings.getType()) {
|
||||||
|
case HTTP, DIRECT -> handleHttpProxyRequest();
|
||||||
|
default -> handleSocksProxyRequest();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<HttpResponse<byte[]>> handleHttpProxyRequest() {
|
||||||
|
var builder = java.net.http.HttpClient.newBuilder()
|
||||||
|
.followRedirects(java.net.http.HttpClient.Redirect.NORMAL)
|
||||||
|
.cookieHandler(new CookieManager())
|
||||||
|
.connectTimeout(httpClientSettings.getTimeout());
|
||||||
|
|
||||||
|
while (proxySettings.hasNext()) {
|
||||||
|
try {
|
||||||
|
InetSocketAddress address = proxySettings.next().toSocketAddress();
|
||||||
|
builder.proxy(ProxySelector.of(address));
|
||||||
|
|
||||||
|
httpClientSettings.getOnClientCreating().accept(builder);
|
||||||
|
var client = builder.build();
|
||||||
|
var request = prepareGetRequest();
|
||||||
|
|
||||||
|
var response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
|
||||||
|
if (response.statusCode() != 200) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return Optional.of(response);
|
||||||
|
} catch (HttpConnectTimeoutException | ConnectException e) {
|
||||||
|
if (proxySettings.isAutoDiscard())
|
||||||
|
proxySettings.remove();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new TikTokLiveRequestException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new TikTokLiveRequestException("No more proxies available!");
|
||||||
|
}
|
||||||
|
|
||||||
|
private Optional<HttpResponse<byte[]>> handleSocksProxyRequest() {
|
||||||
|
try {
|
||||||
|
SSLContext sc = SSLContext.getInstance("SSL");
|
||||||
|
sc.init(null, new TrustManager[]{ new X509TrustManager() {
|
||||||
|
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) {}
|
||||||
|
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {}
|
||||||
|
public X509Certificate[] getAcceptedIssuers() { return null; }
|
||||||
|
}}, null);
|
||||||
|
|
||||||
|
URL url = toUrl().toURL();
|
||||||
|
|
||||||
|
while (proxySettings.hasNext()) {
|
||||||
|
try {
|
||||||
|
Proxy proxy = new Proxy(Proxy.Type.SOCKS, proxySettings.next().toSocketAddress());
|
||||||
|
|
||||||
|
HttpsURLConnection socksConnection = (HttpsURLConnection) url.openConnection(proxy);
|
||||||
|
socksConnection.setSSLSocketFactory(sc.getSocketFactory());
|
||||||
|
socksConnection.setConnectTimeout(httpClientSettings.getTimeout().toMillisPart());
|
||||||
|
socksConnection.setReadTimeout(httpClientSettings.getTimeout().toMillisPart());
|
||||||
|
|
||||||
|
byte[] body = socksConnection.getInputStream().readAllBytes();
|
||||||
|
|
||||||
|
Map<String, List<String>> headers = socksConnection.getHeaderFields()
|
||||||
|
.entrySet()
|
||||||
|
.stream()
|
||||||
|
.filter(entry -> entry.getKey() != null)
|
||||||
|
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||||
|
|
||||||
|
var responseInfo = createResponseInfo(socksConnection.getResponseCode(), headers);
|
||||||
|
|
||||||
|
var response = createHttpResponse(body, toUrl(), responseInfo);
|
||||||
|
|
||||||
|
return Optional.of(response);
|
||||||
|
} catch (SocketException | SocketTimeoutException e) {
|
||||||
|
if (proxySettings.isAutoDiscard())
|
||||||
|
proxySettings.remove();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new TikTokLiveRequestException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new TikTokLiveRequestException("No more proxies available!");
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Should never be reached!
|
||||||
|
System.out.println("handleSocksProxyRequest()! If you see this message, reach us on discord!");
|
||||||
|
e.printStackTrace();
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ResponseInfo createResponseInfo(int code, Map<String, List<String>> headers) {
|
||||||
|
return new ResponseInfo() {
|
||||||
|
@Override
|
||||||
|
public int statusCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HttpHeaders headers() {
|
||||||
|
return HttpHeaders.of(headers, (s, s1) -> s != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public java.net.http.HttpClient.Version version() {
|
||||||
|
return java.net.http.HttpClient.Version.HTTP_2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private HttpResponse<byte[]> createHttpResponse(byte[] body,
|
||||||
|
URI uri,
|
||||||
|
ResponseInfo info) {
|
||||||
|
return new HttpResponse<>()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public int statusCode() {
|
||||||
|
return info.statusCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HttpRequest request() {
|
||||||
|
throw new UnsupportedOperationException("TODO");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<HttpResponse<byte[]>> previousResponse() {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HttpHeaders headers() {
|
||||||
|
return info.headers();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] body() {
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<SSLSession> sslSession() {
|
||||||
|
throw new UnsupportedOperationException("TODO");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URI uri() {
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public java.net.http.HttpClient.Version version() {
|
||||||
|
return info.version();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,14 +23,15 @@
|
|||||||
package io.github.jwdeveloper.tiktok.websocket;
|
package io.github.jwdeveloper.tiktok.websocket;
|
||||||
|
|
||||||
|
|
||||||
import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
|
import io.github.jwdeveloper.tiktok.*;
|
||||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
import io.github.jwdeveloper.tiktok.data.dto.ProxyData;
|
||||||
import io.github.jwdeveloper.tiktok.TikTokLiveEventHandler;
|
|
||||||
import io.github.jwdeveloper.tiktok.TikTokLiveMessageHandler;
|
|
||||||
import io.github.jwdeveloper.tiktok.data.requests.LiveConnectionData;
|
import io.github.jwdeveloper.tiktok.data.requests.LiveConnectionData;
|
||||||
|
import io.github.jwdeveloper.tiktok.data.settings.*;
|
||||||
|
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
||||||
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
||||||
import org.java_websocket.client.WebSocketClient;
|
import org.java_websocket.client.WebSocketClient;
|
||||||
|
|
||||||
|
import java.net.Proxy;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
public class TikTokWebSocketClient implements SocketClient {
|
public class TikTokWebSocketClient implements SocketClient {
|
||||||
@@ -52,7 +53,6 @@ public class TikTokWebSocketClient implements SocketClient {
|
|||||||
@Override
|
@Override
|
||||||
public void start(LiveConnectionData.Response connectionData, LiveClient liveClient)
|
public void start(LiveConnectionData.Response connectionData, LiveClient liveClient)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (isConnected) {
|
if (isConnected) {
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
@@ -68,8 +68,16 @@ public class TikTokWebSocketClient implements SocketClient {
|
|||||||
tikTokEventHandler,
|
tikTokEventHandler,
|
||||||
liveClient);
|
liveClient);
|
||||||
|
|
||||||
try
|
ProxyClientSettings proxyClientSettings = clientSettings.getHttpSettings().getProxyClientSettings();
|
||||||
{
|
|
||||||
|
if (proxyClientSettings.isEnabled())
|
||||||
|
connectProxy(proxyClientSettings);
|
||||||
|
else
|
||||||
|
connectDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void connectDefault() {
|
||||||
|
try {
|
||||||
webSocketClient.connect();
|
webSocketClient.connect();
|
||||||
isConnected = true;
|
isConnected = true;
|
||||||
} catch (Exception e)
|
} catch (Exception e)
|
||||||
@@ -79,9 +87,31 @@ public class TikTokWebSocketClient implements SocketClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void connectProxy(ProxyClientSettings proxySettings) {
|
||||||
|
while (proxySettings.hasNext()) {
|
||||||
|
ProxyData proxyData = proxySettings.next();
|
||||||
|
if (!tryProxyConnection(proxySettings, proxyData)) {
|
||||||
|
if (proxySettings.isAutoDiscard())
|
||||||
|
proxySettings.remove();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
isConnected = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!isConnected)
|
||||||
|
throw new TikTokLiveException("Failed to connect to the websocket");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean tryProxyConnection(ProxyClientSettings proxySettings, ProxyData proxyData) {
|
||||||
|
webSocketClient.setProxy(new Proxy(proxySettings.getType(), proxyData.toSocketAddress()));
|
||||||
|
try {
|
||||||
|
webSocketClient.connect();
|
||||||
|
return true;
|
||||||
|
} catch (Exception e)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void stop() {
|
public void stop() {
|
||||||
if (isConnected && webSocketClient != null) {
|
if (isConnected && webSocketClient != null) {
|
||||||
@@ -90,4 +120,4 @@ public class TikTokWebSocketClient implements SocketClient {
|
|||||||
webSocketClient = null;
|
webSocketClient = null;
|
||||||
isConnected = false;
|
isConnected = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package io.github.jwdeveloper.tiktok;
|
||||||
|
|
||||||
|
import java.net.*;
|
||||||
|
import java.net.http.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class ProxyExample
|
||||||
|
{
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
// TikTokLive.newClient(SimpleExample.TIKTOK_HOSTNAME)
|
||||||
|
|
||||||
|
HttpRequest request = HttpRequest.newBuilder(URI.create("https://api.proxyscrape.com/v2/?request=displayproxies&protocol=socks4,socks5&timeout=10000&country=us")).GET().build();
|
||||||
|
HttpResponse<Stream<String>> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofLines());
|
||||||
|
|
||||||
|
List<AbstractMap.SimpleEntry<String, Integer>> entries = new ArrayList<>(response.body().map(s -> {
|
||||||
|
String[] split = s.split(":");
|
||||||
|
return new AbstractMap.SimpleEntry<>(split[0], Integer.parseInt(split[1]));
|
||||||
|
}).toList());
|
||||||
|
|
||||||
|
TikTokLive.newClient("boost_grow_live_qc")
|
||||||
|
.configure(clientSettings ->
|
||||||
|
{
|
||||||
|
clientSettings.setPrintToConsole(true);
|
||||||
|
clientSettings.getHttpSettings().configureProxy(proxySettings -> {
|
||||||
|
proxySettings.setType(Proxy.Type.SOCKS);
|
||||||
|
proxySettings.setOnProxyUpdated(proxyData ->
|
||||||
|
{
|
||||||
|
System.out.println("Next proxy! "+proxyData.toString());
|
||||||
|
});
|
||||||
|
entries.forEach(entry -> proxySettings.addProxy(entry.getKey(), entry.getValue()));
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.onConnected((liveClient, event) ->
|
||||||
|
{
|
||||||
|
liveClient.getLogger().info("Hello world!");
|
||||||
|
})
|
||||||
|
.onError((liveClient, event) ->
|
||||||
|
{
|
||||||
|
event.getException().printStackTrace();
|
||||||
|
})
|
||||||
|
.buildAndConnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user