Fix Message parsing for

- LikeMessage
- MessageWebcastGiftMessage
- MessageWebcastChatMessage
This commit is contained in:
JW
2023-08-22 19:53:33 +02:00
parent a9e347b8da
commit 2391b12598
20 changed files with 203 additions and 152 deletions

View File

@@ -7,7 +7,7 @@ import io.github.jwdeveloper.tiktok.live.ConnectionState;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.live.LiveRoomInfo;
import io.github.jwdeveloper.tiktok.live.TikTokRoomInfo;
import io.github.jwdeveloper.tiktok.websocket.TikTokWebsocketClient;
import io.github.jwdeveloper.tiktok.websocket.TikTokWebSocketClient;
import java.util.logging.Logger;
@@ -15,14 +15,14 @@ public class TikTokLiveClient implements LiveClient {
private final TikTokRoomInfo meta;
private final TikTokGiftManager giftManager;
private final TikTokApiService apiClient;
private final TikTokWebsocketClient webSocketClient;
private final TikTokWebSocketClient webSocketClient;
private final TikTokEventHandler tikTokEventHandler;
private final Logger logger;
public TikTokLiveClient(TikTokRoomInfo tikTokLiveMeta,
TikTokApiService tikTokApiService,
TikTokWebsocketClient webSocketClient,
TikTokWebSocketClient webSocketClient,
TikTokGiftManager tikTokGiftManager,
TikTokEventHandler tikTokEventHandler,
Logger logger) {
@@ -57,9 +57,9 @@ public class TikTokLiveClient implements LiveClient {
public void tryConnect() {
if (meta.hasConnectionState(ConnectionState.CONNECTED))
throw new RuntimeException("Already connected");
throw new TikTokLiveException("Already connected");
if (meta.hasConnectionState(ConnectionState.CONNECTING))
throw new RuntimeException("Already connecting");
throw new TikTokLiveException("Already connecting");
logger.info("Connecting");
setState(ConnectionState.CONNECTING);

View File

@@ -11,51 +11,29 @@ import io.github.jwdeveloper.tiktok.http.TikTokHttpApiClient;
import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.live.TikTokRoomInfo;
import io.github.jwdeveloper.tiktok.websocket.TikTokWebsocketClient;
import io.github.jwdeveloper.tiktok.websocket.TikTokWebSocketClient;
import java.time.Duration;
import java.util.Map;
import java.util.function.Consumer;
import java.util.logging.Logger;
public class TikTokLiveClientBuilder implements TikTokEventBuilder<TikTokLiveClientBuilder> {
private String userName;
private final ClientSettings clientSettings;
private Map<String, Object> clientParameters;
private final Logger logger;
private final TikTokEventHandler tikTokEventHandler;
public TikTokLiveClientBuilder(String userName) {
this.tikTokEventHandler = new TikTokEventHandler();
this.userName = userName;
this.clientSettings = Constants.DefaultClientSettings();
this.clientParameters = Constants.DefaultClientParams();
this.clientSettings.setHostName(userName);
this.logger = Logger.getLogger(TikTokLive.class.getName());
}
public TikTokLiveClientBuilder clientSettings(Consumer<ClientSettings> consumer) {
public TikTokLiveClientBuilder configure(Consumer<ClientSettings> consumer) {
consumer.accept(clientSettings);
return this;
}
public TikTokLiveClientBuilder hostUserName(String userName) {
this.userName = userName;
return this;
}
public TikTokLiveClientBuilder clientParameters(Map<String, Object> clientParameters) {
this.clientParameters = clientParameters;
return this;
}
public TikTokLiveClientBuilder addClientParameters(String key, Object value) {
this.clientParameters.put(key, value);
return this;
}
private void validate() {
if (clientSettings.getTimeout() == null) {
@@ -75,16 +53,13 @@ public class TikTokLiveClientBuilder implements TikTokEventBuilder<TikTokLiveCli
}
if (userName == null || userName.equals("")) {
throw new RuntimeException("UserName can not be null");
if (clientSettings.getHostName() == null || clientSettings.getHostName() .equals("")) {
throw new RuntimeException("HostName can not be null");
}
if (clientParameters == null) {
clientParameters = Constants.DefaultClientParams();
}
clientParameters.put("app_language", clientSettings.getClientLanguage());
clientParameters.put("webcast_language", clientSettings.getClientLanguage());
var params = clientSettings.getClientParameters();
params.put("app_language", clientSettings.getClientLanguage());
params.put("webcast_language", clientSettings.getClientLanguage());
}
public LiveClient build() {
@@ -92,18 +67,17 @@ public class TikTokLiveClientBuilder implements TikTokEventBuilder<TikTokLiveCli
var meta = new TikTokRoomInfo();
meta.setUserName(userName);
meta.setUserName(clientSettings.getHostName());
var cookieJar = new TikTokCookieJar();
var requestFactory = new TikTokHttpRequestFactory(cookieJar);
var apiClient = new TikTokHttpApiClient(cookieJar, clientSettings, requestFactory);
var apiService = new TikTokApiService(apiClient, logger, clientParameters);
var apiClient = new TikTokHttpApiClient(cookieJar, requestFactory);
var apiService = new TikTokApiService(apiClient, logger, clientSettings);
var giftManager = new TikTokGiftManager(logger, apiService, clientSettings);
var webResponseHandler = new WebResponseHandler(tikTokEventHandler,giftManager);
var webSocketClient = new TikTokWebsocketClient(logger,
var webSocketClient = new TikTokWebSocketClient(logger,
cookieJar,
clientParameters,
requestFactory,
clientSettings,
webResponseHandler,

View File

@@ -69,9 +69,10 @@ public abstract class WebResponseHandlerBase {
handleSingleMessage(message);
} catch (Exception e)
{
var decoded = Base64.getEncoder().encodeToString(message.getBinary().toByteArray());
var exception = new TikTokLiveException("Error whilst Handling Message. Stopping Client. Final Message: \n"+decoded, e);
var exception = new TikTokLiveException("Error whilst Handling Message"+message.getType()+": \n"+decoded, e);
tikTokEventHandler.publish(new TikTokErrorEvent(exception));
}
}

View File

@@ -44,8 +44,8 @@ public class HttpUtils
builder.append("&");
}
final String encodedKey = URLEncoder.encode(param.getKey().toString(), StandardCharsets.UTF_8.toString());
final String encodedValue = URLEncoder.encode(param.getValue().toString(), StandardCharsets.UTF_8.toString());
final String encodedKey = URLEncoder.encode(param.getKey(), StandardCharsets.UTF_8);
final String encodedValue = URLEncoder.encode(param.getValue().toString(), StandardCharsets.UTF_8);
builder.append(encodedKey).append("=").append(encodedValue);
first = true;
}

View File

@@ -1,7 +1,9 @@
package io.github.jwdeveloper.tiktok.http;
import com.google.gson.Gson;
import io.github.jwdeveloper.tiktok.ClientSettings;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
import io.github.jwdeveloper.tiktok.live.LiveRoomMeta;
import io.github.jwdeveloper.tiktok.models.gifts.TikTokGift;
import io.github.jwdeveloper.tiktok.messages.WebcastResponse;
@@ -15,12 +17,12 @@ import java.util.regex.Pattern;
public class TikTokApiService {
private final TikTokHttpApiClient apiClient;
private final Logger logger;
private final Map<String, Object> clientParams;
private final ClientSettings clientSettings;
public TikTokApiService(TikTokHttpApiClient apiClient, Logger logger, Map<String, Object> clientParams) {
public TikTokApiService(TikTokHttpApiClient apiClient, Logger logger, ClientSettings clientSettings) {
this.apiClient = apiClient;
this.logger = logger;
this.clientParams = clientParams;
this.clientSettings = clientSettings;
}
public String fetchRoomId(String userName) {
@@ -29,7 +31,7 @@ public class TikTokApiService {
try {
html = apiClient.GetLivestreamPage(userName);
} catch (Exception e) {
throw new RuntimeException("Failed to fetch room id from WebCast, see stacktrace for more info.", e);
throw new TikTokLiveRequestException("Failed to fetch room id from WebCast, see stacktrace for more info.", e);
}
Pattern firstPattern = Pattern.compile("room_id=([0-9]*)");
@@ -51,7 +53,7 @@ public class TikTokApiService {
throw new TikTokLiveException("Unable to fetch room ID");
}
clientParams.put("room_id", id);
clientSettings.getClientParameters().put("room_id", id);
logger.info("RoomID -> "+id);
return id;
}
@@ -60,7 +62,7 @@ public class TikTokApiService {
public LiveRoomMeta fetchRoomInfo() {
logger.info("Fetch RoomInfo");
try {
var response = apiClient.GetJObjectFromWebcastAPI("room/info/", clientParams);
var response = apiClient.GetJObjectFromWebcastAPI("room/info/", clientSettings.getClientParameters());
if (!response.has("data")) {
return new LiveRoomMeta();
}
@@ -78,7 +80,7 @@ public class TikTokApiService {
logger.info("RoomInfo status -> "+info.getStatus());
return info;
} catch (Exception e) {
throw new TikTokLiveException("Failed to fetch room info from WebCast, see stacktrace for more info.", e);
throw new TikTokLiveRequestException("Failed to fetch room info from WebCast, see stacktrace for more info.", e);
}
}
@@ -86,20 +88,20 @@ public class TikTokApiService {
{
logger.info("Fetch ClientData");
try {
var response = apiClient.GetDeserializedMessage("im/fetch/", clientParams);
clientParams.put("cursor",response.getCursor());
clientParams.put("internal_ext", response.getAckIds());
var response = apiClient.GetDeserializedMessage("im/fetch/", clientSettings.getClientParameters());
clientSettings.getClientParameters().put("cursor",response.getCursor());
clientSettings.getClientParameters().put("internal_ext", response.getAckIds());
return response;
}
catch (Exception e)
{
throw new TikTokLiveException("Failed to fetch client data", e);
throw new TikTokLiveRequestException("Failed to fetch client data", e);
}
}
public Map<Integer, TikTokGift> fetchAvailableGifts() {
try {
var response = apiClient.GetJObjectFromWebcastAPI("gift/list/", clientParams);
var response = apiClient.GetJObjectFromWebcastAPI("gift/list/", clientSettings.getClientParameters());
if(!response.has("data"))
{
return new HashMap<>();
@@ -120,7 +122,7 @@ public class TikTokApiService {
}
return gifts;
} catch (Exception e) {
throw new TikTokLiveException("Failed to fetch giftTokens from WebCast, see stacktrace for more info.", e);
throw new TikTokLiveRequestException("Failed to fetch giftTokens from WebCast, see stacktrace for more info.", e);
}
}
}

View File

@@ -4,7 +4,7 @@ import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import io.github.jwdeveloper.tiktok.ClientSettings;
import io.github.jwdeveloper.tiktok.Constants;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
import io.github.jwdeveloper.tiktok.messages.WebcastResponse;
import java.net.URI;
@@ -16,27 +16,23 @@ 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(TikTokCookieJar tikTokCookieJar, ClientSettings clientSettings, TikTokHttpRequestFactory requestFactory) {
this.clientSettings = clientSettings;
public TikTokHttpApiClient(TikTokCookieJar tikTokCookieJar, TikTokHttpRequestFactory requestFactory) {
this.requestFactory = requestFactory;
this.tikTokCookieJar = tikTokCookieJar;
}
public String GetLivestreamPage(String userName) {
var url = Constants.TIKTOK_URL_WEB + "@" + userName + "/live/";
var get = getRequest(url, null, false);
var get = getRequest(url, null);
return get;
}
public JsonObject GetJObjectFromWebcastAPI(String path, Map<String, Object> parameters) {
var get = getRequest(Constants.TIKTOK_URL_WEBCAST + path, parameters, false);
var get = getRequest(Constants.TIKTOK_URL_WEBCAST + path, parameters);
var json = JsonParser.parseString(get);
var jsonObject = json.getAsJsonObject();
return jsonObject;
@@ -49,12 +45,11 @@ public class TikTokHttpApiClient {
}
catch (Exception e)
{
throw new TikTokLiveException("Unable to deserialize message: "+path,e);
throw new TikTokLiveRequestException("Unable to deserialize message: "+path,e);
}
}
private String getRequest(String url, Map<String, Object> parameters, boolean signURL) {
private String getRequest(String url, Map<String, Object> parameters) {
if (parameters == null) {
parameters = new HashMap<>();
}
@@ -86,7 +81,7 @@ public class TikTokHttpApiClient {
}
catch (Exception e)
{
throw new TikTokLiveException("unabel to send signature");
throw new TikTokLiveRequestException("Unable to send signature");
}
}
@@ -112,7 +107,7 @@ public class TikTokHttpApiClient {
requestFactory.setAgent(userAgent);
return signedUrl;
} catch (Exception e) {
throw new TikTokLiveException("Insufficent values have been supplied for signing. Likely due to an update. Post an issue on GitHub.", e);
throw new TikTokLiveRequestException("Insufficient values have been supplied for signing. Likely due to an update. Post an issue on GitHub.", e);
}
}

View File

@@ -2,10 +2,10 @@ package io.github.jwdeveloper.tiktok.http;
import io.github.jwdeveloper.tiktok.Constants;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveRequestException;
import lombok.SneakyThrows;
import java.net.CookieManager;
import java.net.ProxySelector;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
@@ -18,24 +18,16 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class TikTokHttpRequestFactory implements TikTokHttpRequest
{
private CookieManager cookieManager;
private HttpClient client;
private Duration timeout;
private ProxySelector webProxy;
public class TikTokHttpRequestFactory implements TikTokHttpRequest {
private final CookieManager cookieManager;
private final Map<String, String> defaultHeaders;
private final TikTokCookieJar tikTokCookieJar;
private final HttpClient client;
private String query;
private Boolean sent;
private Map<String, String> defaultHeaders;
private TikTokCookieJar tikTokCookieJar;
public TikTokHttpRequestFactory(TikTokCookieJar tikTokCookieJar) {
cookieManager = new CookieManager();
this.tikTokCookieJar = tikTokCookieJar;
this.cookieManager = new CookieManager();
defaultHeaders = Constants.DefaultRequestHeaders();
client = HttpClient.newBuilder()
.cookieHandler(cookieManager)
@@ -43,8 +35,7 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest
.build();
}
public WebSocket.Builder openSocket()
{
public WebSocket.Builder openSocket() {
return client.newWebSocketBuilder();
}
@@ -52,26 +43,21 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest
public String Get(String url) {
var uri = URI.create(url);
var request = HttpRequest.newBuilder().GET();
for(var header : defaultHeaders.entrySet())
{
//request.setHeader(header.getKey(),header.getValue());
}
if (query != null) {
var baseUri = uri.toString();
var requestUri = URI.create(baseUri + "?" + query);
request.uri(requestUri);
}
return GetContent(request.build());
return GetContent(request.build());
}
@SneakyThrows
public String Post(String url, HttpRequest.BodyPublisher data) {
var uri = URI.create(url);
var request = HttpRequest.newBuilder().POST(data);
for(var header : defaultHeaders.entrySet())
{
request.setHeader(header.getKey(),header.getValue());
for (var header : defaultHeaders.entrySet()) {
request.setHeader(header.getKey(), header.getValue());
}
if (query != null) {
var baseUri = uri.toString();
@@ -81,14 +67,12 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest
return GetContent(request.build());
}
public TikTokHttpRequest setHeader(String key, String value)
{
defaultHeaders.put(key,value);
public TikTokHttpRequest setHeader(String key, String value) {
defaultHeaders.put(key, value);
return this;
}
public TikTokHttpRequest setAgent( String value)
{
public TikTokHttpRequest setAgent(String value) {
defaultHeaders.put("User-Agent", value);
return this;
}
@@ -111,26 +95,18 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest
}
private String GetContent(HttpRequest request) throws Exception {
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
sent = true;
if (response.statusCode() == 404)
{
throw new RuntimeException("Request responded with 404 NOT_FOUND");
if (response.statusCode() == 404) {
throw new TikTokLiveRequestException("Request responded with 404 NOT_FOUND");
}
if(response.statusCode() != 200)
{
throw new RuntimeException("Request was unsuccessful "+response.statusCode());
if (response.statusCode() != 200) {
throw new TikTokLiveRequestException("Request was unsuccessful " + response.statusCode());
}
var cookies = response.headers().allValues("Set-Cookie");
for(var cookie : cookies)
{
for (var cookie : cookies) {
var split = cookie.split(";")[0].split("=");
var uri = request.uri();
@@ -139,9 +115,9 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest
var value = split[1];
tikTokCookieJar.set(key, value);
var map = new HashMap<String,List<String>>();
map.put(key,List.of(value));
cookieManager.put(uri,map);
var map = new HashMap<String, List<String>>();
map.put(key, List.of(value));
cookieManager.put(uri, map);
}
return response.body();

View File

@@ -13,16 +13,13 @@ import io.github.jwdeveloper.tiktok.messages.WebcastResponse;
import java.net.URI;
import java.net.http.WebSocket;
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 {
public class TikTokWebSocketClient {
private final Logger logger;
private final Map<String, Object> clientParams;
private final ClientSettings clientSettings;
private final TikTokCookieJar tikTokCookieJar;
private final TikTokHttpRequestFactory factory;
@@ -33,15 +30,13 @@ public class TikTokWebsocketClient {
private boolean isConnected;
public TikTokWebsocketClient(Logger logger,
public TikTokWebSocketClient(Logger logger,
TikTokCookieJar tikTokCookieJar,
Map<String, Object> clientParams,
TikTokHttpRequestFactory factory,
ClientSettings clientSettings,
WebResponseHandler webResponseHandler,
TikTokEventHandler tikTokEventHandler) {
this.logger = logger;
this.clientParams = clientParams;
this.tikTokCookieJar = tikTokCookieJar;
this.clientSettings = clientSettings;
this.factory = factory;
@@ -78,7 +73,7 @@ public class TikTokWebsocketClient {
var headers = Constants.DefaultRequestHeaders();
var clone = new TreeMap<>(clientParams);
var clone = new TreeMap<>(clientSettings.getClientParameters());
clone.putAll(headers);
clone.put(name, value);
var url = webcastResponse.getSocketUrl();