-
-
Notifications
You must be signed in to change notification settings - Fork 33
Event lifetime
In this articule you will learn what happends under the hood when you are using this example code
TikTokLive.newClient("test")
.onGift((liveClient, event) ->
{
System.out.println("hello world");
}).buildAndConnect();
Initialy library runs webosocket client that listen for incoming data from tiktok. Data is coming in the binary format.
@Override
public void onMessage(ByteBuffer bytes)
{
try {
handleBinary(bytes.array());
} catch (Exception e) {
tikTokEventHandler.publish(tikTokLiveClient, new TikTokErrorEvent(e));
}
if(isNotClosing())
{
sendPing();
}
}
private void handleBinary(byte[] buffer) {
var websocketMessageOptional = getWebcastWebsocketMessage(buffer);
if (websocketMessageOptional.isEmpty()) {
return;
}
var websocketMessage = websocketMessageOptional.get();
var webResponse = getWebResponseMessage(websocketMessage.getPayload());
if(webResponse.getNeedsAck())
{
//For some reason while send ack id, server get disconnected
// sendAckId(webResponse.getFetchInterval());
}
webResponseHandler.handle(tikTokLiveClient, webResponse);
}
First step is to parse binary to WebcastPushFrame
class. This class contains most rudamenday data
such as Timestand, payload, header, sesionId
private Optional<WebcastPushFrame> getWebcastWebsocketMessage(byte[] buffer) {
try {
var websocketMessage = WebcastPushFrame.parseFrom(buffer);
if (websocketMessage.getPayload().isEmpty()) {
return Optional.empty();
}
return Optional.of(websocketMessage);
} catch (Exception e) {
throw new TikTokProtocolBufferException("Unable to parse WebcastPushFrame", buffer, e);
}
Next we are parsing WebcastPushFrame.Payload
to WebcastResponse
. WebcastResponse give use way more
data, but the most important one is WebcastResponse.getMessagesList()
. It is lists of messages "events"
that tiktok is sending to us.
private WebcastResponse getWebResponseMessage(ByteString buffer) {
try {
return WebcastResponse.parseFrom(buffer);
} catch (Exception e) {
throw new TikTokProtocolBufferException("Unable to parse WebcastResponse", buffer.toByteArray(), e);
}
}
That's it for the websocket part, we now have WebcastResponse
that is then processed in the TikTokMessageHandler
This class is responsible from manage WebcastResponse
and map events from tiktok to TikTokLiveJava events
It gets all messages from WebcastResponse
object and then map then one by one
worth to mention, before mapping TikTokWebsocketResponseEvent
is triggered, that contains WebcastResponse
object
public void handle(LiveClient client, WebcastResponse webcastResponse) {
tikTokEventHandler.publish(client, new TikTokWebsocketResponseEvent(webcastResponse));
for (var message : webcastResponse.getMessagesList()) {
try {
handleSingleMessage(client, message);
} catch (Exception e) {
var exception = new TikTokLiveMessageException(message, webcastResponse, e);
tikTokEventHandler.publish(client, new TikTokErrorEvent(exception));
}
}
}
Each message is processed by method handleSingleMessage
public void handleSingleMessage(LiveClient client, WebcastResponse.Message message) throws Exception {
var messageClassName = message.getMethod(); //getting message name, for example WebcastGiftEvent
if (!handlers.containsKey(messageClassName)) { //checking if mapping handler was registered for message name
tikTokEventHandler.publish(client, new TikTokWebsocketUnhandledMessageEvent(message)); //if there is no handler, fire TikTokWebsocketUnhandledMessageEvent
return;
}
var handler = handlers.get(messageClassName); //getitng handler
var stopwatch = new Stopwatch();
stopwatch.start();
var events = handler.handle(message.getPayload().toByteArray()); //handle mapping
var handlingTimeInMs = stopwatch.stop();
var metadata = new MessageMetaData(Duration.ofNanos(handlingTimeInMs)); //creating mapping metdataobject
for (var event : events) { //mapping handler might map TikTok message to more then one events, thats way there is a list
tikTokEventHandler.publish(client, new TikTokWebsocketMessageEvent(message, event, metadata)); // for every mapped message there is triggered TikTokWebsocketMessageEvent
tikTokEventHandler.publish(client, event); //fire actual event, for example WebcastGiftMessage, was mapped to TikTokGiftEvent
}
}
In this class all the mapping handlers are registered, here you can see some of them
public void init() {
//ConnectionEvents events
registerMapping(WebcastControlMessage.class, this::handleWebcastControlMessage);
//Room status events
registerMapping(WebcastLiveIntroMessage.class, roomInfoHandler::handleIntro);
registerMapping(WebcastRoomUserSeqMessage.class, roomInfoHandler::handleUserRanking);
registerMapping(WebcastCaptionMessage.class, TikTokCaptionEvent.class);
//User Interactions events
registerMapping(WebcastChatMessage.class, TikTokCommentEvent.class);
registerMappings(WebcastLikeMessage.class, this::handleLike);
registerMappings(WebcastGiftMessage.class, giftHandler::handleGift);
registerMapping(WebcastSocialMessage.class, socialHandler::handle);
registerMappings(WebcastMemberMessage.class, this::handleMemberMessage);
}
mapped event was send to TikTokEventObserver
class by using tikTokEventHandler.publish()
method
this is the last step
private final Map<Class<?>, Set<EventConsumer>> events;
public void publish(LiveClient tikTokLiveClient, TikTokEvent tikTokEvent) {
if (events.containsKey(TikTokEvent.class)) {
var handlers = events.get(TikTokEvent.class);
for (var handle : handlers) {
handle.onEvent(tikTokLiveClient, tikTokEvent);
}
}
if (!events.containsKey(tikTokEvent.getClass())) {
return;
}
var handlers = events.get(tikTokEvent.getClass());
for (var handler : handlers) {
handler.onEvent(tikTokLiveClient, tikTokEvent);
}
}
this method is getting class of tikTokEvent
object and is checking if there was registered some eventhandlers on this class
if so handler.onEvent(tikTokLiveClient, tikTokEvent);
handler is triggered
so as final result you will see "Hello world" message in your console, that's it