- Implementation on all features in `clientSettings`
  - Code optimization
  - More detail exceptions
  - Downloading gifts
This commit is contained in:
JW
2023-08-23 20:55:40 +02:00
parent 74bfe0b9e7
commit d9ef60ccad
46 changed files with 684 additions and 568 deletions

View File

@@ -1,45 +1,47 @@
package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.tiktok.events.objects.TikTokGift;
import io.github.jwdeveloper.tiktok.http.TikTokApiService;
import io.github.jwdeveloper.tiktok.live.GiftManager;
import io.github.jwdeveloper.tiktok.messages.WebcastGiftMessage;
import io.github.jwdeveloper.tiktok.models.GiftId;
import io.github.jwdeveloper.tiktok.models.gifts.TikTokGiftInfo;
import lombok.Getter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
public class TikTokGiftManager {
private Logger logger;
private ClientSettings clientSettings;
private TikTokApiService apiService;
private Map<Integer, TikTokGift> gifts;
public class TikTokGiftManager implements GiftManager {
@Getter
private Map<GiftId, TikTokGift> activeGifts;
private final Map<Integer, TikTokGiftInfo> giftsInfo;
@Getter
private final Map<GiftId, TikTokGift> activeGifts;
public TikTokGiftManager(Logger logger, TikTokApiService apiService, ClientSettings clientSettings) {
this.logger = logger;
this.clientSettings = clientSettings;
this.apiService = apiService;
this.gifts = new HashMap<>();
public TikTokGiftManager() {
giftsInfo = new HashMap<>();
activeGifts = new HashMap<>();
}
public void loadGifts() {
if (!clientSettings.isDownloadGiftInfo()) {
return;
public TikTokGift updateActiveGift(WebcastGiftMessage giftMessage) {
var giftId = new GiftId(giftMessage.getGiftId(), giftMessage.getSender().getUniqueId());
if (activeGifts.containsKey(giftId)) {
var gift = activeGifts.get(giftId);
gift.setAmount(giftMessage.getAmount());
} else {
var newGift = new TikTokGift(giftMessage);
activeGifts.put(giftId, newGift);
}
logger.info("Fetching gifts");
//TODO gifts =apiService.fetchAvailableGifts();
var gift = activeGifts.get(giftId);
if (giftMessage.getRepeatEnd()) {
gift.setStreakFinished(true);
activeGifts.remove(giftId);
}
return gift;
}
public List<TikTokGift> getGifts()
{
return gifts.values().stream().toList();
public void loadGifsInfo(Map<Integer, TikTokGiftInfo> gifts) {
this.giftsInfo.putAll(gifts);
}
}

View File

@@ -1,53 +1,70 @@
package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.tiktok.events.messages.TikTokDisconnectedEvent;
import io.github.jwdeveloper.tiktok.events.messages.TikTokErrorEvent;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveOfflineHostException;
import io.github.jwdeveloper.tiktok.handlers.TikTokEventHandler;
import io.github.jwdeveloper.tiktok.http.TikTokApiService;
import io.github.jwdeveloper.tiktok.live.ConnectionState;
import io.github.jwdeveloper.tiktok.live.GiftManager;
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 java.util.logging.Logger;
public class TikTokLiveClient implements LiveClient {
private final TikTokRoomInfo meta;
private final TikTokGiftManager giftManager;
private final TikTokRoomInfo liveRoomInfo;
private final TikTokGiftManager tikTokGiftManager;
private final TikTokApiService apiClient;
private final TikTokWebSocketClient webSocketClient;
private final TikTokEventHandler tikTokEventHandler;
private final ClientSettings clientSettings;
private final Logger logger;
public TikTokLiveClient(TikTokRoomInfo tikTokLiveMeta,
TikTokApiService tikTokApiService,
TikTokWebSocketClient webSocketClient,
TikTokGiftManager tikTokGiftManager,
TikTokEventHandler tikTokEventHandler,
ClientSettings clientSettings,
Logger logger) {
this.meta = tikTokLiveMeta;
this.giftManager = tikTokGiftManager;
this.liveRoomInfo = tikTokLiveMeta;
this.tikTokGiftManager = tikTokGiftManager;
this.apiClient = tikTokApiService;
this.webSocketClient = webSocketClient;
this.logger = logger;
this.tikTokEventHandler = tikTokEventHandler;
this.clientSettings = clientSettings;
this.logger = logger;
}
public void connect() {
try {
tryConnect();
} catch (Exception e) {
e.printStackTrace();
}
catch (TikTokLiveException e)
{
setState(ConnectionState.DISCONNECTED);
tikTokEventHandler.publish(this, new TikTokErrorEvent(e));
tikTokEventHandler.publish(this, new TikTokDisconnectedEvent());
if(e instanceof TikTokLiveOfflineHostException && clientSettings.isRetryOnConnectionFailure())
{
try {
Thread.sleep(clientSettings.getRetryConnectionTimeout().toMillis());
}
catch (Exception ignored){}
logger.info("Reconnecting");
this.connect();
}
throw e;
}
}
public void disconnect() {
if (!meta.hasConnectionState(ConnectionState.CONNECTED)) {
if (!liveRoomInfo.hasConnectionState(ConnectionState.CONNECTED)) {
return;
}
webSocketClient.stop();
@@ -55,40 +72,48 @@ public class TikTokLiveClient implements LiveClient {
}
public void tryConnect() {
if (meta.hasConnectionState(ConnectionState.CONNECTED))
if (liveRoomInfo.hasConnectionState(ConnectionState.CONNECTED))
throw new TikTokLiveException("Already connected");
if (meta.hasConnectionState(ConnectionState.CONNECTING))
if (liveRoomInfo.hasConnectionState(ConnectionState.CONNECTING))
throw new TikTokLiveException("Already connecting");
logger.info("Connecting");
setState(ConnectionState.CONNECTING);
var roomId = apiClient.fetchRoomId(meta.getUserName());
meta.setRoomId(roomId);
var roomData =apiClient.fetchRoomInfo();
if (roomData.getStatus() == 0 || roomData.getStatus() == 4)
{
throw new TikTokLiveException("LiveStream for HostID could not be found. Is the Host online?");
var roomId = apiClient.fetchRoomId(liveRoomInfo.getUserName());
liveRoomInfo.setRoomId(roomId);
var roomData = apiClient.fetchRoomInfo();
if (roomData.getStatus() == 0 || roomData.getStatus() == 4) {
throw new TikTokLiveOfflineHostException("LiveStream for HostID could not be found. Is the Host online?");
}
// giftManager.loadGifts();
if (clientSettings.isDownloadGiftInfo())
{
logger.info("Fetch Gift info");
var gifts = apiClient.fetchAvailableGifts();
tikTokGiftManager.loadGifsInfo(gifts);
}
var clientData = apiClient.fetchClientData();
webSocketClient.start(clientData);
webSocketClient.start(clientData, this);
setState(ConnectionState.CONNECTED);
}
public LiveRoomInfo getRoomInfo() {
return meta;
return liveRoomInfo;
}
@Override
public GiftManager getGiftManager() {
return tikTokGiftManager;
}
private void setState(ConnectionState connectionState) {
logger.info("TikTokLive client state: " + connectionState.name());
meta.setConnectionState(connectionState);
liveRoomInfo.setConnectionState(connectionState);
}

View File

@@ -2,19 +2,21 @@ package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.tiktok.events.TikTokEvent;
import io.github.jwdeveloper.tiktok.events.TikTokEventBuilder;
import io.github.jwdeveloper.tiktok.handlers.TikTokEventHandler;
import io.github.jwdeveloper.tiktok.events.TikTokEventConsumer;
import io.github.jwdeveloper.tiktok.events.messages.*;
import io.github.jwdeveloper.tiktok.handlers.WebResponseHandler;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.handlers.TikTokEventHandler;
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandlerRegistration;
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;
import io.github.jwdeveloper.tiktok.live.TikTokRoomInfo;
import io.github.jwdeveloper.tiktok.websocket.TikTokWebSocketClient;
import java.time.Duration;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
public class TikTokLiveClientBuilder implements TikTokEventBuilder<TikTokLiveClientBuilder> {
@@ -40,18 +42,13 @@ public class TikTokLiveClientBuilder implements TikTokEventBuilder<TikTokLiveCli
clientSettings.setTimeout(Duration.ofSeconds(Constants.DEFAULT_TIMEOUT));
}
if (clientSettings.getPollingInterval() == null) {
clientSettings.setPollingInterval(Duration.ofSeconds(Constants.DEFAULT_POLLTIME));
}
if (clientSettings.getClientLanguage() == null || clientSettings.getClientLanguage().equals("")) {
clientSettings.setClientLanguage(Constants.DefaultClientSettings().getClientLanguage());
}
if (clientSettings.getHostName() == null || clientSettings.getHostName() .equals("")) {
throw new RuntimeException("HostName can not be null");
if (clientSettings.getHostName() == null || clientSettings.getHostName().equals("")) {
throw new TikTokLiveException("HostName can not be null");
}
var params = clientSettings.getClientParameters();
@@ -59,22 +56,27 @@ public class TikTokLiveClientBuilder implements TikTokEventBuilder<TikTokLiveCli
params.put("webcast_language", clientSettings.getClientLanguage());
logger.setLevel(clientSettings.getLogLevel());
if(clientSettings.isPrintToConsole() && clientSettings.getLogLevel() == Level.OFF)
{
logger.setLevel(Level.ALL);
}
}
public LiveClient build() {
validate();
var meta = new TikTokRoomInfo();
meta.setUserName(clientSettings.getHostName());
var tiktokRoomInfo = new TikTokRoomInfo();
tiktokRoomInfo.setUserName(clientSettings.getHostName());
var cookieJar = new TikTokCookieJar();
var requestFactory = new TikTokHttpRequestFactory(cookieJar);
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 giftManager = new TikTokGiftManager();
var webResponseHandler = new TikTokMessageHandlerRegistration(tikTokEventHandler, clientSettings, logger, giftManager, tiktokRoomInfo);
var webSocketClient = new TikTokWebSocketClient(logger,
cookieJar,
requestFactory,
@@ -82,7 +84,7 @@ public class TikTokLiveClientBuilder implements TikTokEventBuilder<TikTokLiveCli
webResponseHandler,
tikTokEventHandler);
return new TikTokLiveClient(meta, apiService, webSocketClient, giftManager, tikTokEventHandler, logger);
return new TikTokLiveClient(tiktokRoomInfo, apiService, webSocketClient, giftManager, tikTokEventHandler, clientSettings, logger);
}
public LiveClient buildAndRun() {
@@ -91,214 +93,230 @@ public class TikTokLiveClientBuilder implements TikTokEventBuilder<TikTokLiveCli
return client;
}
public TikTokLiveClientBuilder onUnhandledSocial(Consumer<TikTokUnhandledSocialEvent> event) {
tikTokEventHandler.subscribe(TikTokUnhandledSocialEvent.class,event);
public TikTokLiveClientBuilder onUnhandledSocial(
TikTokEventConsumer<TikTokUnhandledSocialEvent> event) {
tikTokEventHandler.subscribe(TikTokUnhandledSocialEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkMicFanTicket(Consumer<TikTokLinkMicFanTicketEvent> event) {
tikTokEventHandler.subscribe(TikTokLinkMicFanTicketEvent.class,event);
public TikTokLiveClientBuilder onLinkMicFanTicket(
TikTokEventConsumer<TikTokLinkMicFanTicketEvent> event) {
tikTokEventHandler.subscribe(TikTokLinkMicFanTicketEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onEnvelope(Consumer<TikTokEnvelopeEvent> event) {
tikTokEventHandler.subscribe(TikTokEnvelopeEvent.class,event);
public TikTokLiveClientBuilder onEnvelope(TikTokEventConsumer<TikTokEnvelopeEvent> event) {
tikTokEventHandler.subscribe(TikTokEnvelopeEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onShopMessage(Consumer<TikTokShopMessageEvent> event) {
tikTokEventHandler.subscribe(TikTokShopMessageEvent.class,event);
public TikTokLiveClientBuilder onShopMessage(TikTokEventConsumer<TikTokShopMessageEvent> event) {
tikTokEventHandler.subscribe(TikTokShopMessageEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onDetectMessage(Consumer<TikTokDetectMessageEvent> event) {
tikTokEventHandler.subscribe(TikTokDetectMessageEvent.class,event);
public TikTokLiveClientBuilder onDetectMessage(
TikTokEventConsumer<TikTokDetectMessageEvent> event) {
tikTokEventHandler.subscribe(TikTokDetectMessageEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkLayerMessage(Consumer<TikTokLinkLayerMessageEvent> event) {
tikTokEventHandler.subscribe(TikTokLinkLayerMessageEvent.class,event);
public TikTokLiveClientBuilder onLinkLayerMessage(
TikTokEventConsumer<TikTokLinkLayerMessageEvent> event) {
tikTokEventHandler.subscribe(TikTokLinkLayerMessageEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onConnected(Consumer<TikTokConnectedEvent> event) {
tikTokEventHandler.subscribe(TikTokConnectedEvent.class,event);
public TikTokLiveClientBuilder onConnected(TikTokEventConsumer<TikTokConnectedEvent> event) {
tikTokEventHandler.subscribe(TikTokConnectedEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onCaption(Consumer<TikTokCaptionEvent> event) {
tikTokEventHandler.subscribe(TikTokCaptionEvent.class,event);
public TikTokLiveClientBuilder onCaption(TikTokEventConsumer<TikTokCaptionEvent> event) {
tikTokEventHandler.subscribe(TikTokCaptionEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onQuestion(Consumer<TikTokQuestionEvent> event) {
tikTokEventHandler.subscribe(TikTokQuestionEvent.class,event);
public TikTokLiveClientBuilder onQuestion(TikTokEventConsumer<TikTokQuestionEvent> event) {
tikTokEventHandler.subscribe(TikTokQuestionEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onRoomPinMessage(Consumer<TikTokRoomPinMessageEvent> event) {
tikTokEventHandler.subscribe(TikTokRoomPinMessageEvent.class,event);
public TikTokLiveClientBuilder onRoomPinMessage(
TikTokEventConsumer<TikTokRoomPinMessageEvent> event) {
tikTokEventHandler.subscribe(TikTokRoomPinMessageEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onRoomMessage(Consumer<TikTokRoomMessageEvent> event) {
tikTokEventHandler.subscribe(TikTokRoomMessageEvent.class,event);
public TikTokLiveClientBuilder onRoomMessage(TikTokEventConsumer<TikTokRoomMessageEvent> event) {
tikTokEventHandler.subscribe(TikTokRoomMessageEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLivePaused(Consumer<TikTokLivePausedEvent> event) {
tikTokEventHandler.subscribe(TikTokLivePausedEvent.class,event);
public TikTokLiveClientBuilder onLivePaused(TikTokEventConsumer<TikTokLivePausedEvent> event) {
tikTokEventHandler.subscribe(TikTokLivePausedEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLike(Consumer<TikTokLikeEvent> event) {
tikTokEventHandler.subscribe(TikTokLikeEvent.class,event);
public TikTokLiveClientBuilder onLike(TikTokEventConsumer<TikTokLikeEvent> event) {
tikTokEventHandler.subscribe(TikTokLikeEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkMessage(Consumer<TikTokLinkMessageEvent> event) {
tikTokEventHandler.subscribe(TikTokLinkMessageEvent.class,event);
public TikTokLiveClientBuilder onLinkMessage(TikTokEventConsumer<TikTokLinkMessageEvent> event) {
tikTokEventHandler.subscribe(TikTokLinkMessageEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onBarrageMessage(Consumer<TikTokBarrageMessageEvent> event) {
tikTokEventHandler.subscribe(TikTokBarrageMessageEvent.class,event);
public TikTokLiveClientBuilder onBarrageMessage(
TikTokEventConsumer<TikTokBarrageMessageEvent> event) {
tikTokEventHandler.subscribe(TikTokBarrageMessageEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onGiftMessage(Consumer<TikTokGiftMessageEvent> event) {
tikTokEventHandler.subscribe(TikTokGiftMessageEvent.class,event);
public TikTokLiveClientBuilder onGiftMessage(TikTokEventConsumer<TikTokGiftMessageEvent> event) {
tikTokEventHandler.subscribe(TikTokGiftMessageEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkMicArmies(Consumer<TikTokLinkMicArmiesEvent> event) {
tikTokEventHandler.subscribe(TikTokLinkMicArmiesEvent.class,event);
public TikTokLiveClientBuilder onLinkMicArmies(
TikTokEventConsumer<TikTokLinkMicArmiesEvent> event) {
tikTokEventHandler.subscribe(TikTokLinkMicArmiesEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onEmote(Consumer<TikTokEmoteEvent> event) {
tikTokEventHandler.subscribe(TikTokEmoteEvent.class,event);
public TikTokLiveClientBuilder onEmote(TikTokEventConsumer<TikTokEmoteEvent> event) {
tikTokEventHandler.subscribe(TikTokEmoteEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onUnauthorizedMember(
Consumer<TikTokUnauthorizedMemberEvent> event) {
tikTokEventHandler.subscribe(TikTokUnauthorizedMemberEvent.class,event);
TikTokEventConsumer<TikTokUnauthorizedMemberEvent> event) {
tikTokEventHandler.subscribe(TikTokUnauthorizedMemberEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onInRoomBanner(Consumer<TikTokInRoomBannerEvent> event) {
tikTokEventHandler.subscribe(TikTokInRoomBannerEvent.class,event);
public TikTokLiveClientBuilder onInRoomBanner(
TikTokEventConsumer<TikTokInRoomBannerEvent> event) {
tikTokEventHandler.subscribe(TikTokInRoomBannerEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkMicMethod(Consumer<TikTokLinkMicMethodEvent> event) {
tikTokEventHandler.subscribe(TikTokLinkMicMethodEvent.class,event);
public TikTokLiveClientBuilder onLinkMicMethod(
TikTokEventConsumer<TikTokLinkMicMethodEvent> event) {
tikTokEventHandler.subscribe(TikTokLinkMicMethodEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onSubscribe(Consumer<TikTokSubscribeEvent> event) {
tikTokEventHandler.subscribe(TikTokSubscribeEvent.class,event);
public TikTokLiveClientBuilder onSubscribe(TikTokEventConsumer<TikTokSubscribeEvent> event) {
tikTokEventHandler.subscribe(TikTokSubscribeEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onPollMessage(Consumer<TikTokPollMessageEvent> event) {
tikTokEventHandler.subscribe(TikTokPollMessageEvent.class,event);
public TikTokLiveClientBuilder onPollMessage(TikTokEventConsumer<TikTokPollMessageEvent> event) {
tikTokEventHandler.subscribe(TikTokPollMessageEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onFollow(Consumer<TikTokFollowEvent> event) {
tikTokEventHandler.subscribe(TikTokFollowEvent.class,event);
public TikTokLiveClientBuilder onFollow(TikTokEventConsumer<TikTokFollowEvent> event) {
tikTokEventHandler.subscribe(TikTokFollowEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onRoomViewerData(Consumer<TikTokRoomViewerDataEvent> event) {
tikTokEventHandler.subscribe(TikTokRoomViewerDataEvent.class,event);
public TikTokLiveClientBuilder onRoomViewerData(
TikTokEventConsumer<TikTokRoomViewerDataEvent> event) {
tikTokEventHandler.subscribe(TikTokRoomViewerDataEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onGoalUpdate(Consumer<TikTokGoalUpdateEvent> event) {
tikTokEventHandler.subscribe(TikTokGoalUpdateEvent.class,event);
public TikTokLiveClientBuilder onGoalUpdate(TikTokEventConsumer<TikTokGoalUpdateEvent> event) {
tikTokEventHandler.subscribe(TikTokGoalUpdateEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onComment(Consumer<TikTokCommentEvent> event) {
tikTokEventHandler.subscribe(TikTokCommentEvent.class,event);
public TikTokLiveClientBuilder onComment(TikTokEventConsumer<TikTokCommentEvent> event) {
tikTokEventHandler.subscribe(TikTokCommentEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onRankUpdate(Consumer<TikTokRankUpdateEvent> event) {
tikTokEventHandler.subscribe(TikTokRankUpdateEvent.class,event);
public TikTokLiveClientBuilder onRankUpdate(TikTokEventConsumer<TikTokRankUpdateEvent> event) {
tikTokEventHandler.subscribe(TikTokRankUpdateEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onIMDelete(Consumer<TikTokIMDeleteEvent> event) {
tikTokEventHandler.subscribe(TikTokIMDeleteEvent.class,event);
public TikTokLiveClientBuilder onIMDelete(TikTokEventConsumer<TikTokIMDeleteEvent> event) {
tikTokEventHandler.subscribe(TikTokIMDeleteEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLiveEnded(Consumer<TikTokLiveEndedEvent> event) {
tikTokEventHandler.subscribe(TikTokLiveEndedEvent.class,event);
public TikTokLiveClientBuilder onLiveEnded(TikTokEventConsumer<TikTokLiveEndedEvent> event) {
tikTokEventHandler.subscribe(TikTokLiveEndedEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onError(Consumer<TikTokErrorEvent> event) {
tikTokEventHandler.subscribe(TikTokErrorEvent.class,event);
public TikTokLiveClientBuilder onError(TikTokEventConsumer<TikTokErrorEvent> event) {
tikTokEventHandler.subscribe(TikTokErrorEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onUnhandled(Consumer<TikTokUnhandledEvent> event) {
tikTokEventHandler.subscribe(TikTokUnhandledEvent.class,event);
public TikTokLiveClientBuilder onUnhandled(TikTokEventConsumer<TikTokUnhandledEvent> event) {
tikTokEventHandler.subscribe(TikTokUnhandledEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onJoin(Consumer<TikTokJoinEvent> event) {
tikTokEventHandler.subscribe(TikTokJoinEvent.class,event);
public TikTokLiveClientBuilder onJoin(TikTokEventConsumer<TikTokJoinEvent> event) {
tikTokEventHandler.subscribe(TikTokJoinEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onRankText(Consumer<TikTokRankTextEvent> event) {
tikTokEventHandler.subscribe(TikTokRankTextEvent.class,event);
public TikTokLiveClientBuilder onRankText(TikTokEventConsumer<TikTokRankTextEvent> event) {
tikTokEventHandler.subscribe(TikTokRankTextEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onShare(Consumer<TikTokShareEvent> event) {
tikTokEventHandler.subscribe(TikTokShareEvent.class,event);
public TikTokLiveClientBuilder onShare(TikTokEventConsumer<TikTokShareEvent> event) {
tikTokEventHandler.subscribe(TikTokShareEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onUnhandledMember(Consumer<TikTokUnhandledMemberEvent> event) {
tikTokEventHandler.subscribe(TikTokUnhandledMemberEvent.class,event);
public TikTokLiveClientBuilder onUnhandledMember(
TikTokEventConsumer<TikTokUnhandledMemberEvent> event) {
tikTokEventHandler.subscribe(TikTokUnhandledMemberEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onSubNotify(Consumer<TikTokSubNotifyEvent> event) {
tikTokEventHandler.subscribe(TikTokSubNotifyEvent.class,event);
public TikTokLiveClientBuilder onSubNotify(TikTokEventConsumer<TikTokSubNotifyEvent> event) {
tikTokEventHandler.subscribe(TikTokSubNotifyEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onLinkMicBattle(Consumer<TikTokLinkMicBattleEvent> event) {
tikTokEventHandler.subscribe(TikTokLinkMicBattleEvent.class,event);
public TikTokLiveClientBuilder onLinkMicBattle(
TikTokEventConsumer<TikTokLinkMicBattleEvent> event) {
tikTokEventHandler.subscribe(TikTokLinkMicBattleEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onDisconnected(Consumer<TikTokDisconnectedEvent> event) {
tikTokEventHandler.subscribe(TikTokDisconnectedEvent.class,event);
public TikTokLiveClientBuilder onDisconnected(
TikTokEventConsumer<TikTokDisconnectedEvent> event) {
tikTokEventHandler.subscribe(TikTokDisconnectedEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onGiftBroadcast(Consumer<TikTokGiftBroadcastEvent> event) {
tikTokEventHandler.subscribe(TikTokGiftBroadcastEvent.class,event);
public TikTokLiveClientBuilder onGiftBroadcast(
TikTokEventConsumer<TikTokGiftBroadcastEvent> event) {
tikTokEventHandler.subscribe(TikTokGiftBroadcastEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onUnhandledControl(Consumer<TikTokUnhandledControlEvent> event) {
tikTokEventHandler.subscribe(TikTokUnhandledControlEvent.class,event);
public TikTokLiveClientBuilder onUnhandledControl(
TikTokEventConsumer<TikTokUnhandledControlEvent> event) {
tikTokEventHandler.subscribe(TikTokUnhandledControlEvent.class, event);
return this;
}
public TikTokLiveClientBuilder onEvent(Consumer<TikTokEvent> event) {
tikTokEventHandler.subscribe(TikTokEvent.class,event);
public TikTokLiveClientBuilder onEvent(TikTokEventConsumer<TikTokEvent> event) {
tikTokEventHandler.subscribe(TikTokEvent.class, event);
return this;
}
}
@@ -306,3 +324,6 @@ public class TikTokLiveClientBuilder implements TikTokEventBuilder<TikTokLiveCli

View File

@@ -0,0 +1,21 @@
package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.tiktok.live.ConnectionState;
import io.github.jwdeveloper.tiktok.live.LiveRoomInfo;
import lombok.Data;
@Data
public class TikTokRoomInfo implements LiveRoomInfo
{
private int viewersCount;
private String roomId;
private String userName;
private ConnectionState connectionState = ConnectionState.DISCONNECTED;
public boolean hasConnectionState(ConnectionState state)
{
return connectionState == state;
}
}

View File

@@ -1,40 +1,38 @@
package io.github.jwdeveloper.tiktok.handlers;
import io.github.jwdeveloper.tiktok.TikTokLiveClient;
import io.github.jwdeveloper.tiktok.events.TikTokEvent;
import io.github.jwdeveloper.tiktok.events.TikTokEventConsumer;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
public class TikTokEventHandler {
private final Map<String, Consumer> events;
public class TikTokEventHandler {
private final Map<String, TikTokEventConsumer> events;
public TikTokEventHandler()
{
public TikTokEventHandler() {
events = new HashMap<>();
}
public void publish(TikTokEvent tikTokEvent)
{
if(events.containsKey(TikTokEvent.class.getSimpleName()))
{
public void publish(TikTokLiveClient tikTokLiveClient, TikTokEvent tikTokEvent) {
if (events.containsKey(TikTokEvent.class.getSimpleName())) {
var handler = events.get(TikTokEvent.class.getSimpleName());
handler.accept(tikTokEvent);
handler.onEvent(tikTokLiveClient, tikTokEvent);
}
var name = tikTokEvent.getClass().getSimpleName();
if(!events.containsKey(name))
{
if (!events.containsKey(name)) {
return;
}
var handler = events.get(name);
handler.accept(tikTokEvent);
handler.onEvent(tikTokLiveClient, tikTokEvent);
}
public <T extends TikTokEvent> void subscribe(Class<?> clazz, Consumer<T> event)
{
events.put(clazz.getSimpleName(),event);
public <T extends TikTokEvent> void subscribe(Class<?> clazz, TikTokEventConsumer<T> event) {
events.put(clazz.getSimpleName(), event);
}
public <T extends TikTokEvent> void unsubscribe(Class<?> clazz) {
events.remove(clazz);
}
}

View File

@@ -1,12 +1,97 @@
package io.github.jwdeveloper.tiktok.handlers;
import com.google.protobuf.ByteString;
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.TikTokUnhandledEvent;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageException;
import io.github.jwdeveloper.tiktok.exceptions.TikTokMessageMappingException;
import io.github.jwdeveloper.tiktok.messages.WebcastResponse;
public interface TikTokMessageHandler<T>
{
Class<T> getHandleClazz();
import java.util.Arrays;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import java.util.logging.Logger;
TikTokEvent handle(WebcastResponse.Message message) throws Exception;
public abstract class TikTokMessageHandler {
private final Map<String, io.github.jwdeveloper.tiktok.handler.TikTokMessageHandler> handlers;
private final TikTokEventHandler tikTokEventHandler;
private final ClientSettings clientSettings;
protected final Logger logger;
public TikTokMessageHandler(TikTokEventHandler tikTokEventHandler,ClientSettings clientSettings, Logger logger) {
handlers = new HashMap<>();
this.tikTokEventHandler = tikTokEventHandler;
this.clientSettings = clientSettings;
this.logger = logger;
init();
}
public abstract void init();
public void register(Class<?> clazz, Function<WebcastResponse.Message, TikTokEvent> func) {
handlers.put(clazz.getSimpleName(), func::apply);
}
public void register(Class<?> input, Class<?> output) {
register(input, (e) -> mapMessageToEvent(input, output, e));
}
public void handle(TikTokLiveClient client, WebcastResponse webcastResponse) {
for (var message : webcastResponse.getMessagesList()) {
try
{
if(clientSettings.isPrintMessageData())
{
var type= message.getType();
var base64 = Base64.getEncoder().encodeToString(message.getBinary().toByteArray());
logger.info(type+": \n "+base64);
}
handleSingleMessage(client, message);
} catch (Exception e) {
var exception = new TikTokLiveMessageException(message, webcastResponse, e);
tikTokEventHandler.publish(client, new TikTokErrorEvent(exception));
}
}
}
private void handleSingleMessage(TikTokLiveClient client, WebcastResponse.Message message) throws Exception {
if (!handlers.containsKey(message.getType())) {
tikTokEventHandler.publish(client, new TikTokUnhandledEvent(message));
return;
}
var handler = handlers.get(message.getType());
var tiktokEvent = handler.handle(message);
tikTokEventHandler.publish(client, tiktokEvent);
}
protected TikTokEvent mapMessageToEvent(Class<?> inputClazz, Class<?> outputClass, WebcastResponse.Message message) {
try {
var parseMethod = inputClazz.getDeclaredMethod("parseFrom", ByteString.class);
var deserialized = parseMethod.invoke(null, message.getBinary());
var constructors = Arrays.stream(outputClass.getConstructors())
.filter(ea -> Arrays.stream(ea.getParameterTypes())
.toList()
.contains(inputClazz))
.findFirst();
if(constructors.isEmpty())
{
throw new TikTokMessageMappingException(inputClazz, outputClass, "Unable to find constructor with input class type");
}
var tiktokEvent = constructors.get().newInstance(deserialized);
return (TikTokEvent) tiktokEvent;
} catch (Exception ex) {
throw new TikTokMessageMappingException(inputClazz, outputClass, ex);
}
}
}

View File

@@ -1,6 +1,8 @@
package io.github.jwdeveloper.tiktok.handlers;
import io.github.jwdeveloper.tiktok.ClientSettings;
import io.github.jwdeveloper.tiktok.TikTokGiftManager;
import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
import io.github.jwdeveloper.tiktok.events.TikTokEvent;
import io.github.jwdeveloper.tiktok.events.messages.*;
import io.github.jwdeveloper.tiktok.events.objects.TikTokGift;
@@ -9,15 +11,22 @@ import io.github.jwdeveloper.tiktok.models.GiftId;
import io.github.jwdeveloper.tiktok.models.SocialTypes;
import lombok.SneakyThrows;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class WebResponseHandler extends WebResponseHandlerBase {
public class TikTokMessageHandlerRegistration extends TikTokMessageHandler {
private final TikTokGiftManager giftManager;
private final TikTokRoomInfo roomInfo;
public WebResponseHandler(TikTokEventHandler tikTokEventHandler, TikTokGiftManager giftManager) {
super(tikTokEventHandler);
public TikTokMessageHandlerRegistration(TikTokEventHandler tikTokEventHandler,
ClientSettings clientSettings,
Logger logger,
TikTokGiftManager giftManager,
TikTokRoomInfo roomInfo) {
super(tikTokEventHandler, clientSettings, logger);
this.giftManager = giftManager;
this.roomInfo = roomInfo;
}
@Override
@@ -30,7 +39,7 @@ public class WebResponseHandler extends WebResponseHandlerBase {
//Room status events
register(WebcastLiveIntroMessage.class, TikTokRoomMessageEvent.class);
register(WebcastRoomUserSeqMessage.class, TikTokRoomViewerDataEvent.class); //TODO update viewer count ViewerCount = userSeqMessage.ViewerCount;
register(WebcastRoomUserSeqMessage.class, this::handleRoomUserSeqMessage);
register(RoomMessage.class, TikTokRoomMessageEvent.class);
register(WebcastRoomMessage.class, TikTokRoomMessageEvent.class);
register(WebcastCaptionMessage.class, TikTokCaptionEvent.class);
@@ -74,9 +83,9 @@ public class WebResponseHandler extends WebResponseHandlerBase {
}
@SneakyThrows
private TikTokEvent handleWebcastControlMessage(WebcastResponse.Message msg)
{
private TikTokEvent handleWebcastControlMessage(WebcastResponse.Message msg) {
var message = WebcastControlMessage.parseFrom(msg.getBinary());
return switch (message.getAction()) {
case STREAM_PAUSED -> new TikTokLivePausedEvent();
@@ -88,29 +97,7 @@ public class WebResponseHandler extends WebResponseHandlerBase {
@SneakyThrows
private TikTokEvent handleGift(WebcastResponse.Message msg) {
var giftMessage = WebcastGiftMessage.parseFrom(msg.getBinary());
var giftId = new GiftId(giftMessage.getGiftId(), giftMessage.getSender().getUniqueId());
var activeGifts = giftManager.getActiveGifts();
if (activeGifts.containsKey(giftId)) {
// Debug.Log($"Updating Gift[{giftId.Gift}]Amount[{message.Amount}]");
var gift = activeGifts.get(giftId);
gift.setAmount(giftMessage.getAmount());
} else {
TikTokGift newGift = new TikTokGift(giftMessage);
activeGifts.put(giftId, newGift);
// Debug.Log($"New Gift[{giftId.Gift}]Amount[{message.Amount}]");
// RunEvent(OnGift, newGift);
}
if (giftMessage.getRepeatEnd()) {
//if (ShouldLog(LogLevel.Verbose))
// Debug.Log($"GiftStreak Ended: [{giftId.Gift}] Amount[{message.Amount}]")
var gift = activeGifts.get(giftId);
gift.setStreakFinished(true);
activeGifts.remove(gift);
}
// Debug.Log($"Handling GiftMessage");
giftManager.updateActiveGift(giftMessage);
return new TikTokGiftMessageEvent(giftMessage);
}
@@ -146,4 +133,11 @@ public class WebResponseHandler extends WebResponseHandlerBase {
default -> new TikTokUnhandledMemberEvent(message);
};
}
private TikTokEvent handleRoomUserSeqMessage(WebcastResponse.Message msg)
{
var event = (TikTokRoomViewerDataEvent)mapMessageToEvent(WebcastRoomUserSeqMessage.class, TikTokRoomViewerDataEvent.class, msg);
roomInfo.setViewersCount(event.getViewerCount());
return event;
}
}

View File

@@ -1,90 +0,0 @@
package io.github.jwdeveloper.tiktok.handlers;
import com.google.protobuf.ByteString;
import io.github.jwdeveloper.tiktok.events.TikTokEvent;
import io.github.jwdeveloper.tiktok.events.messages.TikTokErrorEvent;
import io.github.jwdeveloper.tiktok.events.messages.TikTokUnhandledEvent;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageParsingException;
import io.github.jwdeveloper.tiktok.messages.WebcastResponse;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
public abstract class WebResponseHandlerBase {
private final Map<String, TikTokMessageHandler> handlers;
private final TikTokEventHandler tikTokEventHandler;
public WebResponseHandlerBase(TikTokEventHandler tikTokEventHandler) {
handlers = new HashMap<>();
this.tikTokEventHandler = tikTokEventHandler;
init();
}
public abstract void init();
public void register(Class<?> input, Class<?> output) {
register(input, (e) ->
{
try {
var parseMethod = input.getDeclaredMethod("parseFrom", ByteString.class);
var deserialized = parseMethod.invoke(null, e.getBinary());
var constructors = Arrays.stream(output.getConstructors()).filter(ea -> Arrays.stream(ea.getParameterTypes()).toList().contains(input)).findFirst();
var tiktokEvent = constructors.get().newInstance(deserialized);
return (TikTokEvent)tiktokEvent;
} catch (Exception ex)
{
throw new TikTokLiveMessageParsingException("Unable to handle parsing from class: " + input.getSimpleName() + " to class " + output.getSimpleName(), ex);
}
});
}
public <T> void register(Class clazz, Function<WebcastResponse.Message, TikTokEvent> func) {
var haandler = new TikTokMessageHandler<T>() {
@Override
public Class<T> getHandleClazz() {
return clazz;
}
@Override
public TikTokEvent handle(WebcastResponse.Message message) throws Exception {
return func.apply(message);
}
};
handlers.put(haandler.getHandleClazz().getSimpleName(), haandler);
}
public void handle(WebcastResponse webcastResponse) {
for (var message : webcastResponse.getMessagesList()) {
try {
handleSingleMessage(message);
} catch (Exception e)
{
var decoded = Base64.getEncoder().encodeToString(message.getBinary().toByteArray());
var exception = new TikTokLiveException("Error whilst Handling Message"+message.getType()+": \n"+decoded, e);
tikTokEventHandler.publish(new TikTokErrorEvent(exception));
}
}
}
public void handleSingleMessage(WebcastResponse.Message message) throws Exception {
if (!handlers.containsKey(message.getType())) {
tikTokEventHandler.publish(new TikTokUnhandledEvent(message));
return;
}
var handler = handlers.get(message.getType());
var tiktokEvent = handler.handle(message);
tikTokEventHandler.publish(tiktokEvent);
}
}

View File

@@ -2,10 +2,10 @@ 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.TikTokLiveOfflineHostException;
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.models.gifts.TikTokGiftInfo;
import io.github.jwdeveloper.tiktok.messages.WebcastResponse;
import java.util.HashMap;
@@ -50,7 +50,7 @@ public class TikTokApiService {
}
if (id.isEmpty()) {
throw new TikTokLiveException("Unable to fetch room ID");
throw new TikTokLiveOfflineHostException("Unable to fetch room ID, live host could be offline or name is misspelled");
}
clientSettings.getClientParameters().put("room_id", id);
@@ -99,7 +99,7 @@ public class TikTokApiService {
}
}
public Map<Integer, TikTokGift> fetchAvailableGifts() {
public Map<Integer, TikTokGiftInfo> fetchAvailableGifts() {
try {
var response = apiClient.GetJObjectFromWebcastAPI("gift/list/", clientSettings.getClientParameters());
if(!response.has("data"))
@@ -112,11 +112,11 @@ public class TikTokApiService {
return new HashMap<>();
}
var giftsJsonList = dataJson.get("gifts").getAsJsonArray();
var gifts = new HashMap<Integer, TikTokGift>();
var gifts = new HashMap<Integer, TikTokGiftInfo>();
var gson = new Gson();
for(var jsonGift : giftsJsonList)
{
var gift = gson.fromJson(jsonGift, TikTokGift.class);
var gift = gson.fromJson(jsonGift, TikTokGiftInfo.class);
logger.info("Found Available Gift "+ gift.getName()+ " with ID "+gift.getId());
gifts.put(gift.getId(),gift);
}

View File

@@ -3,9 +3,10 @@ package io.github.jwdeveloper.tiktok.websocket;
import io.github.jwdeveloper.tiktok.ClientSettings;
import io.github.jwdeveloper.tiktok.Constants;
import io.github.jwdeveloper.tiktok.TikTokLiveClient;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.handlers.TikTokEventHandler;
import io.github.jwdeveloper.tiktok.handlers.WebResponseHandler;
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandlerRegistration;
import io.github.jwdeveloper.tiktok.http.HttpUtils;
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory;
@@ -23,18 +24,18 @@ public class TikTokWebSocketClient {
private final ClientSettings clientSettings;
private final TikTokCookieJar tikTokCookieJar;
private final TikTokHttpRequestFactory factory;
private final WebResponseHandler webResponseHandler;
private final TikTokMessageHandlerRegistration webResponseHandler;
private final TikTokEventHandler tikTokEventHandler;
private WebSocket webSocket;
private boolean isConnected;
private TikTokLiveClient tikTokLiveClient;
public TikTokWebSocketClient(Logger logger,
TikTokCookieJar tikTokCookieJar,
TikTokHttpRequestFactory factory,
ClientSettings clientSettings,
WebResponseHandler webResponseHandler,
TikTokMessageHandlerRegistration webResponseHandler,
TikTokEventHandler tikTokEventHandler) {
this.logger = logger;
this.tikTokCookieJar = tikTokCookieJar;
@@ -45,21 +46,22 @@ public class TikTokWebSocketClient {
isConnected = false;
}
public void start(WebcastResponse webcastResponse)
{
if(isConnected)
{
public void start(WebcastResponse webcastResponse, TikTokLiveClient tikTokLiveClient) {
this.tikTokLiveClient = tikTokLiveClient;
if (isConnected) {
stop();
}
if (webcastResponse.getSocketUrl().isEmpty() || webcastResponse.getSocketParamsList().isEmpty()) {
throw new TikTokLiveException("Could not find Room");
}
try {
var url =getWebSocketUrl(webcastResponse);
webSocket =startWebSocket(url);
if (clientSettings.isHandleExistingMessagesOnConnect()) {
// HandleWebcastMessages(webcastResponse);
var url = getWebSocketUrl(webcastResponse);
if (clientSettings.isHandleExistingMessagesOnConnect())
{
logger.info("Handling existing messages");
webResponseHandler.handle(tikTokLiveClient, webcastResponse);
}
webSocket = startWebSocket(url);
} catch (Exception e) {
throw new TikTokLiveException("Failed to connect to the websocket", e);
}
@@ -82,23 +84,17 @@ public class TikTokWebSocketClient {
private WebSocket startWebSocket(String url) throws Exception {
var cookie = tikTokCookieJar.parseCookies();
// System.out.println("WssIP: " + url);
// System.out.println("Cookie: " + cookie);
var map = new HashMap<String, String>();
map.put("Cookie", cookie);
return factory.openSocket()
return factory.openSocket()
.subprotocols("echo-protocol")
.connectTimeout(Duration.ofSeconds(15))
.header("Cookie", cookie)
.buildAsync(URI.create(url), new TikTokWebSocketListener(webResponseHandler, tikTokEventHandler)).get();
.buildAsync(URI.create(url), new TikTokWebSocketListener(webResponseHandler, tikTokEventHandler, tikTokLiveClient)).get();
}
public void stop() {
if(isConnected && webSocket != null)
{
if (isConnected && webSocket != null) {
webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "ok");
}
}

View File

@@ -1,12 +1,14 @@
package io.github.jwdeveloper.tiktok.websocket;
import com.google.protobuf.ByteString;
import io.github.jwdeveloper.tiktok.TikTokLiveClient;
import io.github.jwdeveloper.tiktok.events.messages.TikTokConnectedEvent;
import io.github.jwdeveloper.tiktok.events.messages.TikTokDisconnectedEvent;
import io.github.jwdeveloper.tiktok.events.messages.TikTokErrorEvent;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageParsingException;
import io.github.jwdeveloper.tiktok.exceptions.TikTokProtocolBufferException;
import io.github.jwdeveloper.tiktok.handlers.TikTokEventHandler;
import io.github.jwdeveloper.tiktok.handlers.WebResponseHandler;
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandlerRegistration;
import io.github.jwdeveloper.tiktok.messages.WebcastResponse;
import io.github.jwdeveloper.tiktok.messages.WebcastWebsocketAck;
import io.github.jwdeveloper.tiktok.messages.WebcastWebsocketMessage;
@@ -14,18 +16,23 @@ import io.github.jwdeveloper.tiktok.messages.WebcastWebsocketMessage;
import java.io.ByteArrayOutputStream;
import java.net.http.WebSocket;
import java.nio.ByteBuffer;
import java.util.Optional;
import java.util.concurrent.CompletionStage;
public class TikTokWebSocketListener implements java.net.http.WebSocket.Listener {
private final ByteArrayOutputStream accumulatedData = new ByteArrayOutputStream();
private final WebResponseHandler webResponseHandler;
private final TikTokMessageHandlerRegistration webResponseHandler;
private final TikTokEventHandler tikTokEventHandler;
private final TikTokLiveClient tikTokLiveClient;
public TikTokWebSocketListener(WebResponseHandler webResponseHandler, TikTokEventHandler tikTokEventHandler) {
public TikTokWebSocketListener(TikTokMessageHandlerRegistration webResponseHandler,
TikTokEventHandler tikTokEventHandler,
TikTokLiveClient tikTokLiveClient) {
this.webResponseHandler = webResponseHandler;
this.tikTokEventHandler = tikTokEventHandler;
this.tikTokLiveClient = tikTokLiveClient;
}
@Override
@@ -39,7 +46,7 @@ public class TikTokWebSocketListener implements java.net.http.WebSocket.Listener
accumulatedData.reset();
}
} catch (Exception e) {
tikTokEventHandler.publish(new TikTokErrorEvent(e));
tikTokEventHandler.publish(tikTokLiveClient, new TikTokErrorEvent(e));
}
webSocket.request(1);
return null;
@@ -47,38 +54,51 @@ public class TikTokWebSocketListener implements java.net.http.WebSocket.Listener
@Override
public void onOpen(java.net.http.WebSocket webSocket) {
tikTokEventHandler.publish(new TikTokConnectedEvent());
tikTokEventHandler.publish(tikTokLiveClient,new TikTokConnectedEvent());
webSocket.request(1);
}
@Override
public void onError(java.net.http.WebSocket webSocket, Throwable error) {
tikTokEventHandler.publish(new TikTokErrorEvent(error));
tikTokEventHandler.publish(tikTokLiveClient,new TikTokErrorEvent(error));
webSocket.request(1);
}
@Override
public CompletionStage<?> onClose(java.net.http.WebSocket webSocket, int statusCode, String reason) {
tikTokEventHandler.publish(new TikTokDisconnectedEvent());
tikTokEventHandler.publish(tikTokLiveClient,new TikTokDisconnectedEvent());
return java.net.http.WebSocket.Listener.super.onClose(webSocket, statusCode, reason);
}
private void handleBinary(WebSocket webSocket, byte[] buffer) {
try {
var websocketMessageOptional = getWebcastWebsocketMessage(buffer);
if (websocketMessageOptional.isEmpty()) {
return;
}
var websocketMessage = websocketMessageOptional.get();
sendAckId(webSocket, websocketMessage.getId());
var webResponse = getWebResponseMessage(websocketMessage.getBinary());
webResponseHandler.handle(tikTokLiveClient, webResponse);
}
private Optional<WebcastWebsocketMessage> getWebcastWebsocketMessage(byte[] buffer) {
try {
var websocketMessage = WebcastWebsocketMessage.parseFrom(buffer);
if (websocketMessage.getBinary().isEmpty()) {
return;
}
sendAckId(webSocket, websocketMessage.getId());
try {
var response = WebcastResponse.parseFrom(websocketMessage.getBinary());
webResponseHandler.handle(response);
} catch (Exception e) {
throw new TikTokLiveMessageParsingException("Unable to read WebcastResponse", e);
return Optional.empty();
}
return Optional.of(websocketMessage);
} catch (Exception e) {
throw new TikTokLiveMessageParsingException("Unable to read WebcastWebsocketMessage", e);
throw new TikTokProtocolBufferException("Unable to parse WebcastWebsocketMessage", buffer, e);
}
}
private WebcastResponse getWebResponseMessage(ByteString buffer) {
try {
return WebcastResponse.parseFrom(buffer);
} catch (Exception e) {
throw new TikTokProtocolBufferException("Unable to parse WebcastResponse", buffer.toByteArray(), e);
}
}

View File

@@ -1,31 +1,25 @@
package io.github.jwdeveloper.tiktok;
import com.google.protobuf.InvalidProtocolBufferException;
import io.github.jwdeveloper.tiktok.common.TikTokBaseTest;
import io.github.jwdeveloper.tiktok.events.messages.*;
import io.github.jwdeveloper.tiktok.handlers.TikTokEventHandler;
import io.github.jwdeveloper.tiktok.handlers.WebResponseHandler;
import io.github.jwdeveloper.tiktok.messages.WebcastResponse;
import io.github.jwdeveloper.tiktok.messages.WebcastSocialMessage;
import io.github.jwdeveloper.tiktok.models.SocialTypes;
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandlerRegistration;
import org.junit.Before;
import org.junit.Test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.logging.Logger;
import static org.mockito.Mockito.mock;
public class WebResponseHandlerTests extends TikTokBaseTest
{
public static WebResponseHandler sut;
public class WebResponseHandlerTests extends TikTokBaseTest {
public static TikTokMessageHandlerRegistration sut;
@Before
public void before()
{
public void before() {
var mockEventHandler = mock(TikTokEventHandler.class);
var mockGiftManager = mock(TikTokGiftManager.class);
sut = new WebResponseHandler(mockEventHandler, mockGiftManager);
var mockRoomInfo = mock(TikTokRoomInfo.class);
var mockClientSettings = mock(ClientSettings.class);
var mockLogger = mock(Logger.class);
sut = new TikTokMessageHandlerRegistration(mockEventHandler,mockClientSettings,mockLogger, mockGiftManager, mockRoomInfo);
}