From b75d6da7aba96e4b70b31eb2550d77ebea23c678 Mon Sep 17 00:00:00 2001 From: JW Date: Sun, 6 Aug 2023 02:09:03 +0200 Subject: [PATCH] Establish connection with websocket --- .../github/jwdeveloper/tiktok/Constants.java | 4 +- Client/pom.xml | 15 ++++ .../tiktok/TikTokClientBuilder.java | 8 +- .../tiktok/http/TikTokCookieJar.java | 26 ++---- .../tiktok/http/TikTokHttpApiClient.java | 23 ++++- .../tiktok/http/TikTokHttpRequestFactory.java | 19 +++- .../jwdeveloper/tiktok/websocket/Client2.java | 40 +++++++++ .../websocket/TikTokWebSocketListener.java | 22 ++++- .../websocket/TikTokWebsocketClient.java | 86 +++++++++++++------ .../jwdeveloper/tiktok/TikTokLiveTest.java | 2 +- 10 files changed, 187 insertions(+), 58 deletions(-) create mode 100644 Client/src/main/java/io/github/jwdeveloper/tiktok/websocket/Client2.java diff --git a/API/src/main/java/io/github/jwdeveloper/tiktok/Constants.java b/API/src/main/java/io/github/jwdeveloper/tiktok/Constants.java index 438e305..350c13b 100644 --- a/API/src/main/java/io/github/jwdeveloper/tiktok/Constants.java +++ b/API/src/main/java/io/github/jwdeveloper/tiktok/Constants.java @@ -108,14 +108,14 @@ public class Constants { public static Map DefaultRequestHeaders() { var headers = new HashMap(); - // headers.put("Connection", "keep-alive"); + headers.put("Connection", "keep-alive"); headers.put("Cache-Control", "max-age=0"); headers.put("Accept", "text/html,application/json,application/protobuf"); headers.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36"); headers.put("Referer", "https://www.tiktok.com/"); headers.put("Origin", "https://www.tiktok.com"); headers.put("Accept-Language", "en-US,en; q=0.9"); - // headers.put("Accept-Encoding", "gzip, deflate"); + headers.put("Accept-Encoding", "gzip, deflate"); return headers; } } diff --git a/Client/pom.xml b/Client/pom.xml index baf3e61..3d302b3 100644 --- a/Client/pom.xml +++ b/Client/pom.xml @@ -92,6 +92,21 @@ test + + + org.slf4j + slf4j-simple + 2.0.7 + + + + org.slf4j + slf4j-simple + 2.0.7 + runtime + + + junit junit diff --git a/Client/src/main/java/io/github/jwdeveloper/tiktok/TikTokClientBuilder.java b/Client/src/main/java/io/github/jwdeveloper/tiktok/TikTokClientBuilder.java index fed05cf..e950231 100644 --- a/Client/src/main/java/io/github/jwdeveloper/tiktok/TikTokClientBuilder.java +++ b/Client/src/main/java/io/github/jwdeveloper/tiktok/TikTokClientBuilder.java @@ -1,6 +1,7 @@ package io.github.jwdeveloper.tiktok; import io.github.jwdeveloper.tiktok.http.TikTokApiService; +import io.github.jwdeveloper.tiktok.http.TikTokCookieJar; import io.github.jwdeveloper.tiktok.http.TikTokHttpApiClient; import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory; import io.github.jwdeveloper.tiktok.live.LiveClient; @@ -85,10 +86,11 @@ public class TikTokClientBuilder { meta.setUserName(userName); - var requestFactory = new TikTokHttpRequestFactory(); - var apiClient = new TikTokHttpApiClient(clientSettings, requestFactory); + var cookieJar = new TikTokCookieJar(); + var requestFactory = new TikTokHttpRequestFactory(cookieJar); + var apiClient = new TikTokHttpApiClient(cookieJar,clientSettings, requestFactory); var apiService = new TikTokApiService(apiClient, logger,clientParameters); - var webSocketClient = new TikTokWebsocketClient(logger,clientParameters, clientSettings); + var webSocketClient = new TikTokWebsocketClient(logger, cookieJar,clientParameters, requestFactory,clientSettings); var giftManager =new TikTokGiftManager(logger, apiService, clientSettings); return new TikTokLiveClient(meta,apiService, webSocketClient, giftManager, logger); } diff --git a/Client/src/main/java/io/github/jwdeveloper/tiktok/http/TikTokCookieJar.java b/Client/src/main/java/io/github/jwdeveloper/tiktok/http/TikTokCookieJar.java index 7762ea5..6df4576 100644 --- a/Client/src/main/java/io/github/jwdeveloper/tiktok/http/TikTokCookieJar.java +++ b/Client/src/main/java/io/github/jwdeveloper/tiktok/http/TikTokCookieJar.java @@ -5,19 +5,11 @@ import java.util.Map; import java.util.Set; public class TikTokCookieJar { - /// - /// Cookies in Jar - /// private final Map cookies; - - /// - /// Create a TikTok cookie jar instance. - /// public TikTokCookieJar() { cookies = new HashMap<>(); } - public String get(String key) { return cookies.get(key); } @@ -26,19 +18,17 @@ public class TikTokCookieJar { cookies.put(key, value); } - /// - /// Enumerates Cookies - /// public Set> GetEnumerator() { return cookies.entrySet(); } - /* /// - /// Enumerates Cookies - /// - public IEnumerator GetEnumerator() + public String parseCookies() { - foreach (var cookie in cookies) - yield return $"{cookie.Key}={cookie.Value};"; - }*/ + var sb = new StringBuilder(); + for(var entry : cookies.entrySet()) + { + sb.append(entry.getKey()).append("=").append(entry.getValue()).append(";"); + } + return sb.toString(); + } } diff --git a/Client/src/main/java/io/github/jwdeveloper/tiktok/http/TikTokHttpApiClient.java b/Client/src/main/java/io/github/jwdeveloper/tiktok/http/TikTokHttpApiClient.java index 9c72290..68d179f 100644 --- a/Client/src/main/java/io/github/jwdeveloper/tiktok/http/TikTokHttpApiClient.java +++ b/Client/src/main/java/io/github/jwdeveloper/tiktok/http/TikTokHttpApiClient.java @@ -11,17 +11,21 @@ import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; -import java.nio.charset.StandardCharsets; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.TreeMap; public class TikTokHttpApiClient { private final ClientSettings clientSettings; private final TikTokHttpRequestFactory requestFactory; + private final TikTokCookieJar tikTokCookieJar; - public TikTokHttpApiClient(ClientSettings clientSettings, TikTokHttpRequestFactory requestFactory) { + + public TikTokHttpApiClient(TikTokCookieJar tikTokCookieJar, ClientSettings clientSettings, TikTokHttpRequestFactory requestFactory) { this.clientSettings = clientSettings; this.requestFactory = requestFactory; + this.tikTokCookieJar = tikTokCookieJar; } @@ -68,6 +72,18 @@ public class TikTokHttpApiClient { .build(); var response = client.send(request, HttpResponse.BodyHandlers.ofByteArray()); + var cookies = response.headers().allValues("Set-Cookie"); + for(var cookie : cookies) + { + var split = cookie.split(";")[0].split("="); + + + var key = split[0]; + var value = split[1]; + tikTokCookieJar.set(key, value); + var i =0; + } + return response.body(); } catch (Exception e) @@ -80,7 +96,7 @@ public class TikTokHttpApiClient { private String GetSignedUrl(String url, Map parameters) { var fullUrl = HttpUtils.parseParameters(url,parameters); - var singHeaders = new HashMap(); + var singHeaders = new TreeMap(); singHeaders.put("client", "ttlive-net"); singHeaders.put("uuc", 1); singHeaders.put("url", fullUrl); @@ -95,7 +111,6 @@ public class TikTokHttpApiClient { var signedUrl = jsonObject.get("signedUrl").getAsString(); var userAgent = jsonObject.get("User-Agent").getAsString(); - //requestFactory.setHeader() requestFactory.setAgent(userAgent); return signedUrl; } catch (Exception e) { diff --git a/Client/src/main/java/io/github/jwdeveloper/tiktok/http/TikTokHttpRequestFactory.java b/Client/src/main/java/io/github/jwdeveloper/tiktok/http/TikTokHttpRequestFactory.java index 93937d2..a9440b8 100644 --- a/Client/src/main/java/io/github/jwdeveloper/tiktok/http/TikTokHttpRequestFactory.java +++ b/Client/src/main/java/io/github/jwdeveloper/tiktok/http/TikTokHttpRequestFactory.java @@ -11,6 +11,7 @@ import java.net.URLEncoder; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; +import java.net.http.WebSocket; import java.nio.charset.StandardCharsets; import java.time.Duration; import java.util.HashMap; @@ -29,9 +30,12 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest private Boolean sent; private Map defaultHeaders; - public TikTokHttpRequestFactory() { + private TikTokCookieJar tikTokCookieJar; + + public TikTokHttpRequestFactory(TikTokCookieJar tikTokCookieJar) { cookieManager = new CookieManager(); + this.tikTokCookieJar = tikTokCookieJar; defaultHeaders = Constants.DefaultRequestHeaders(); client = HttpClient.newBuilder() .cookieHandler(cookieManager) @@ -39,6 +43,11 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest .build(); } + public WebSocket.Builder openSocket() + { + return client.newWebSocketBuilder(); + } + @SneakyThrows public String Get(String url) { var uri = URI.create(url); @@ -124,8 +133,14 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest { var split = cookie.split(";")[0].split("="); var uri = request.uri(); + + + var key = split[0]; + var value = split[1]; + tikTokCookieJar.set(key, value); + var map = new HashMap>(); - map.put(split[0],List.of(split[1])); + map.put(key,List.of(value)); cookieManager.put(uri,map); } diff --git a/Client/src/main/java/io/github/jwdeveloper/tiktok/websocket/Client2.java b/Client/src/main/java/io/github/jwdeveloper/tiktok/websocket/Client2.java new file mode 100644 index 0000000..9c78309 --- /dev/null +++ b/Client/src/main/java/io/github/jwdeveloper/tiktok/websocket/Client2.java @@ -0,0 +1,40 @@ +package io.github.jwdeveloper.tiktok.websocket; + +import org.java_websocket.client.WebSocketClient; +import org.java_websocket.handshake.ServerHandshake; + +import java.net.URI; +import java.nio.ByteBuffer; +import java.util.Map; + +public class Client2 extends WebSocketClient { + public Client2(URI serverUri, Map httpHeaders) { + super(serverUri,httpHeaders); + } + + @Override + public void onOpen(ServerHandshake serverHandshake) { + + System.out.println("Open"); + } + + @Override + public void onMessage(String s) { + System.out.println("MESSAGE"); + } + + @Override + public void onMessage(ByteBuffer bytes) { + System.out.println("MESSAGE binary"); + } + + @Override + public void onClose(int i, String s, boolean b) { + System.out.println("Close"); + } + + @Override + public void onError(Exception e) { + System.out.println("Error"); + } +} diff --git a/Client/src/main/java/io/github/jwdeveloper/tiktok/websocket/TikTokWebSocketListener.java b/Client/src/main/java/io/github/jwdeveloper/tiktok/websocket/TikTokWebSocketListener.java index a78b5c2..c072f26 100644 --- a/Client/src/main/java/io/github/jwdeveloper/tiktok/websocket/TikTokWebSocketListener.java +++ b/Client/src/main/java/io/github/jwdeveloper/tiktok/websocket/TikTokWebSocketListener.java @@ -1,10 +1,11 @@ package io.github.jwdeveloper.tiktok.websocket; +import java.net.http.WebSocket; +import java.nio.ByteBuffer; import java.util.concurrent.CompletionStage; public class TikTokWebSocketListener implements java.net.http.WebSocket.Listener { - //Insert Body here @Override public void onOpen(java.net.http.WebSocket webSocket) { @@ -18,14 +19,31 @@ public class TikTokWebSocketListener implements java.net.http.WebSocket.Listene @Override public CompletionStage onText(java.net.http.WebSocket webSocket, CharSequence data, boolean last) { - System.out.println("Received message: " + data); + System.out.println("Received onText: " + data); return java.net.http.WebSocket.Listener.super.onText(webSocket, data, last); } + @Override + public CompletionStage onPing(WebSocket webSocket, ByteBuffer message) { + System.out.println("Received onPing: " ); + return java.net.http.WebSocket.Listener.super.onPing(webSocket, message); + } + + @Override + public CompletionStage onBinary(WebSocket webSocket, ByteBuffer data, boolean last) { + System.out.println("Received onBinary: " + data); + return java.net.http.WebSocket.Listener.super.onBinary(webSocket, data, last); + } @Override public CompletionStage onClose(java.net.http.WebSocket webSocket, int statusCode, String reason) { System.out.println("WebSocket closed with status code: " + statusCode + " and reason: " + reason); return java.net.http.WebSocket.Listener.super.onClose(webSocket, statusCode, reason); } + + @Override + public CompletionStage onPong(WebSocket webSocket, ByteBuffer message) { + System.out.println("Received onPong: "); + return java.net.http.WebSocket.Listener.super.onPong(webSocket,message); + } } \ No newline at end of file diff --git a/Client/src/main/java/io/github/jwdeveloper/tiktok/websocket/TikTokWebsocketClient.java b/Client/src/main/java/io/github/jwdeveloper/tiktok/websocket/TikTokWebsocketClient.java index e82a433..11ea349 100644 --- a/Client/src/main/java/io/github/jwdeveloper/tiktok/websocket/TikTokWebsocketClient.java +++ b/Client/src/main/java/io/github/jwdeveloper/tiktok/websocket/TikTokWebsocketClient.java @@ -2,46 +2,64 @@ package io.github.jwdeveloper.tiktok.websocket; import io.github.jwdeveloper.generated.WebcastResponse; import io.github.jwdeveloper.tiktok.ClientSettings; +import io.github.jwdeveloper.tiktok.Constants; import io.github.jwdeveloper.tiktok.TikTokLiveException; import io.github.jwdeveloper.tiktok.http.HttpUtils; +import io.github.jwdeveloper.tiktok.http.TikTokCookieJar; +import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory; import java.net.URI; import java.net.http.HttpClient; +import java.nio.ByteBuffer; import java.time.Duration; +import java.util.HashMap; import java.util.Map; +import java.util.TreeMap; import java.util.logging.Logger; public class TikTokWebsocketClient { private final Logger logger; private final Map clientParams; private final ClientSettings clientSettings; + private final TikTokCookieJar tikTokCookieJar; + private final TikTokHttpRequestFactory factory; - public TikTokWebsocketClient(Logger logger, Map clientParams, ClientSettings clientSettings) { + public TikTokWebsocketClient(Logger logger, + TikTokCookieJar tikTokCookieJar, + Map clientParams, + TikTokHttpRequestFactory factory, + ClientSettings clientSettings) { this.logger = logger; this.clientParams = clientParams; + this.tikTokCookieJar = tikTokCookieJar; this.clientSettings = clientSettings; + this.factory = factory; } public void start(WebcastResponse webcastResponse) { if (webcastResponse.getWsUrl().isEmpty() || webcastResponse.getWsParam().getAllFields().isEmpty()) { throw new TikTokLiveException("Could not find Room"); } - try { - for (var param : webcastResponse.getWsParam().getAllFields().entrySet()) { - var name = param.getKey().getName(); - var value = param.getValue(); - clientParams.put(name, value); - logger.info("Adding Custom Param" + param.getKey().getName() + " " + param.getValue()); - } + try { + + var params = webcastResponse.getWsParam(); + var name = params.getName(); + var value = params.getValue(); + System.out.println("KEY: " + name + " value: " + value); + + + var headers = Constants.DefaultRequestHeaders(); + + + var clone = new TreeMap<>(clientParams); + // clone.putAll(headers); + clone.put(name, value); + clone.put("compress", "gzip"); + var url = webcastResponse.getWsUrl(); - var wsUrl = HttpUtils.parseParametersEncode(url, clientParams); - logger.info("Creating Socket with URL " + wsUrl); - //socketClient = new TikTokWebSocket(TikTokHttpRequest.CookieJar, token, settings.SocketBufferSize); - //connectedSocketUrl = url; - //await socketClient.Connect(url); - + var wsUrl = HttpUtils.parseParametersEncode(url, clone); logger.info("Starting Socket-Threads"); //runningTask = Task.Run(WebSocketLoop, token); //pollingTask = Task.Run(PingLoop, token); @@ -51,28 +69,44 @@ public class TikTokWebsocketClient { } if (clientSettings.isHandleExistingMessagesOnConnect()) { try { - // HandleWebcastMessages(webcastResponse); + // HandleWebcastMessages(webcastResponse); } catch (Exception e) { throw new TikTokLiveException("Error Handling Initial Messages", e); } } } - public void startWS(String url) - { + public void startWS(String url) { try { + var cookie = tikTokCookieJar.parseCookies(); + logger.info("WssIP: " + url); + logger.info("Cookie: " + cookie); - var cookie = "tt_csrf_token=Fh92faHZ-fVnWZ8CG58Wb_kIC1hb-QzizkRM;ttwid=1%7CergNdYee4w-v_96VkhyDxkJ8NIavveA-NvCEdWF68Ik%7C1691076950%7C154533521f698b079ff5300fbd058e85e81a8ef64c41349f1d218124aa74a6db;"; - // var url = "wss://webcast16-ws-useast1a.tiktok.com/webcast/im/push/?aid=1988&app_language=en-US&app_name=tiktok_web&browser_language=en&browser_name=Mozilla&browser_online=True&browser_platform=Win32&browser_version=5.0+(Windows+NT+10.0%3b+Win64%3b+x64)+AppleWebKit%2f537.36+(KHTML%2c+like+Gecko)+Chrome%2f102.0.5005.63+Safari%2f537.36&cookie_enabled=True&cursor=1691242057374_7263829320139870326_1_1_0_0&internal_ext=fetch_time%3a1691242057374%7cstart_time%3a0%7cack_ids%3a%2c%7cflag%3a0%7cseq%3a1%7cnext_cursor%3a1691242057374_7263829320139870326_1_1_0_0%7cwss_info%3a0-1691242057374-0-0&device_platform=web&focus_state=True&from_page=user&history_len=4&is_fullscreen=False&is_page_visible=True&did_rule=3&fetch_rule=1&identity=audience&last_rtt=0&live_id=12&resp_content_type=protobuf&screen_height=1152&screen_width=2048&tz_name=Europe%2fBerlin&referer=https%2c+%2f%2fwww.tiktok.com%2f&root_referer=https%2c+%2f%2fwww.tiktok.com%2f&msToken=&version_code=180800&webcast_sdk_version=1.3.0&update_version_code=1.3.0&webcast_language=en-US&room_id=7263759223213132577&imprp=u65Ja_b3czc3iEAb4x6oLXindKyTO"; - HttpClient client = HttpClient.newHttpClient(); - var ws = client.newWebSocketBuilder() + var map = new HashMap(); + map.put("Cookie", cookie); + + //var cluent2 = new Client2(URI.create(url), map); + var builder = HttpClient.newHttpClient().newWebSocketBuilder(); + var ws = builder .subprotocols("echo-protocol") .connectTimeout(Duration.ofSeconds(15)) - .header("cookie",cookie) - .buildAsync(URI.create(url),new TikTokWebSocketListener()).get(); - } - catch (Exception e) - { + .header("Cookie", cookie) + .buildAsync(URI.create(url), new TikTokWebSocketListener()).get(); + + + + var i =0; + while (true) { + byte[] message = new byte[]{58, 2, 104, 98}; + ByteBuffer buffer = ByteBuffer.wrap(message); + while (buffer.hasRemaining()) { + ws.sendPing(buffer); + } + buffer.clear(); + Thread.sleep(10); + } + + } catch (Exception e) { e.printStackTrace(); } } diff --git a/Client/src/test/java/io/github/jwdeveloper/tiktok/TikTokLiveTest.java b/Client/src/test/java/io/github/jwdeveloper/tiktok/TikTokLiveTest.java index 69dba3e..3e5f04e 100644 --- a/Client/src/test/java/io/github/jwdeveloper/tiktok/TikTokLiveTest.java +++ b/Client/src/test/java/io/github/jwdeveloper/tiktok/TikTokLiveTest.java @@ -6,7 +6,7 @@ import java.io.IOException; public class TikTokLiveTest { - public static String TEST_USER_SUBJECT = "moniczkka"; + public static String TEST_USER_SUBJECT = "erwin_winki"; @Test