`onWebsocketMessage()` TikTokWebsocketMessageEvent new event that is
   triggered when new ProtocolBuffer message come from TikTok server.
   Should be mainly use for debuging purpose

Bugs:
 - Fixed bug: WebcastSocialMessage was always triggering `TikTokShareEvent` events such as `TikTokLikeEvent`, `TikTokFollowEvent`, `TikTokShareEvent`, `TikTokJoinEvent` was ignored

 - Fixed bug: Websocket was disconnecting when there was no incoming events for the while. Fixed by implementing background loop that pinging TikTok server every few ms.

 - Fixed bug: Disconnect method was not working
This commit is contained in:
JW
2023-09-04 12:05:13 +02:00
parent b059afd621
commit 1aff710523
18 changed files with 279 additions and 38 deletions

View File

@@ -12,6 +12,7 @@ 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;
import io.github.jwdeveloper.tiktok.utils.CancelationToken;
import io.github.jwdeveloper.tiktok.websocket.TikTokWebSocketClient;
import java.time.Duration;
@@ -319,8 +320,8 @@ public class TikTokLiveClientBuilder implements TikTokEventBuilder<TikTokLiveCli
}
@Override
public TikTokLiveClientBuilder onSuccessResponseMapping(TikTokEventConsumer<TikTokSuccessResponseMappingEvent> event) {
tikTokEventHandler.subscribe(TikTokSuccessResponseMappingEvent.class, event);
public TikTokLiveClientBuilder onWebsocketMessage(TikTokEventConsumer<TikTokWebsocketMessageEvent> event) {
tikTokEventHandler.subscribe(TikTokWebsocketMessageEvent.class, event);
return this;
}
}

View File

@@ -6,7 +6,7 @@ import io.github.jwdeveloper.tiktok.ClientSettings;
import io.github.jwdeveloper.tiktok.TikTokLiveClient;
import io.github.jwdeveloper.tiktok.events.TikTokEvent;
import io.github.jwdeveloper.tiktok.events.messages.TikTokErrorEvent;
import io.github.jwdeveloper.tiktok.events.messages.TikTokSuccessResponseMappingEvent;
import io.github.jwdeveloper.tiktok.events.messages.TikTokWebsocketMessageEvent;
import io.github.jwdeveloper.tiktok.events.messages.TikTokUnhandledEvent;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageException;
import io.github.jwdeveloper.tiktok.exceptions.TikTokMessageMappingException;
@@ -70,7 +70,7 @@ public abstract class TikTokMessageHandler {
}
var handler = handlers.get(message.getType());
var tiktokEvent = handler.handle(message);
tikTokEventHandler.publish(client, new TikTokSuccessResponseMappingEvent(tiktokEvent, message));
tikTokEventHandler.publish(client, new TikTokWebsocketMessageEvent(tiktokEvent, message));
tikTokEventHandler.publish(client, tiktokEvent);
}

View File

@@ -25,10 +25,10 @@ public class TikTokWebSocketClient {
private final TikTokCookieJar tikTokCookieJar;
private final TikTokMessageHandlerRegistration webResponseHandler;
private final TikTokEventHandler tikTokEventHandler;
private WebSocketClient webSocketClient;
private boolean isConnected;
private TikTokLiveClient tikTokLiveClient;
private TikTokWebSocketPingingTask pingingTask;
private boolean isConnected;
public TikTokWebSocketClient(Logger logger,
TikTokCookieJar tikTokCookieJar,
@@ -59,7 +59,13 @@ public class TikTokWebSocketClient {
}
webSocketClient = startWebSocket(url);
webSocketClient.connect();
} catch (Exception e) {
pingingTask = new TikTokWebSocketPingingTask();
pingingTask.run(webSocketClient);
isConnected = true;
} catch (Exception e)
{
isConnected =false;
throw new TikTokLiveException("Failed to connect to the websocket", e);
}
}
@@ -83,15 +89,23 @@ public class TikTokWebSocketClient {
var cookie = tikTokCookieJar.parseCookies();
var map = new HashMap<String, String>();
map.put("Cookie", cookie);
return new TikTokWebSocketListener(URI.create(url), map, 3000, webResponseHandler, tikTokEventHandler, tikTokLiveClient);
return new TikTokWebSocketListener(URI.create(url),
map,
3000,
webResponseHandler,
tikTokEventHandler,
tikTokLiveClient);
}
public void stop() {
public void stop()
{
if (isConnected && webSocketClient != null) {
webSocketClient.close();
webSocketClient.close(1);
}
webSocketClient = null;
pingingTask = null;
isConnected = false;
}
}

View File

@@ -101,17 +101,7 @@ public class TikTokWebSocketListener extends WebSocketClient {
}
}
private void pingTask(WebSocket webSocket) throws InterruptedException {
while (true) {
byte[] message = new byte[]{58, 2, 104, 98};
ByteBuffer buffer = ByteBuffer.wrap(message);
while (buffer.hasRemaining()) {
webSocket.sendPing(buffer);
}
buffer.clear();
Thread.sleep(10);
}
}
private void sendAckId(long id) {
var serverInfo = WebcastWebsocketAck

View File

@@ -0,0 +1,58 @@
package io.github.jwdeveloper.tiktok.websocket;
import org.java_websocket.WebSocket;
import java.util.Random;
public class TikTokWebSocketPingingTask
{
private Thread thread;
private boolean isRunning = false;
private final int MIN_TIMEOUT = 5;
private final int MAX_TIMEOUT = 100;
public void run(WebSocket webSocket)
{
var thread = new Thread(() ->
{
pingTask(webSocket);
});
isRunning =true;
thread.start();
}
public void stop()
{
if(thread != null)
{
thread.interrupt();
}
isRunning = false;
}
private void pingTask(WebSocket webSocket)
{
var random = new Random();
while (isRunning)
{
try
{
if(!webSocket.isOpen())
{
Thread.sleep(100);
continue;
}
webSocket.sendPing();
var timeout = random.nextInt(MAX_TIMEOUT)+MIN_TIMEOUT;
Thread.sleep(timeout);
}
catch (Exception e)
{
isRunning = false;
}
}
}
}

View File

@@ -40,4 +40,10 @@ public class ParseMessagesTests extends TikTokBaseTest
}
@Test
public void ShouldParseMessageWebcastMemberMessage() throws InvalidProtocolBufferException {
var bytes = getFileBytesUtf("WebcastMemberMessage.bin");
var message = WebcastMemberMessage.parseFrom(bytes);
}
}

File diff suppressed because one or more lines are too long