mirror of
https://github.com/jwdeveloper/TikTokLiveJava.git
synced 2026-02-28 09:19:40 -05:00
Changes:
`TikTokEventListener` new method of listening events see it at TestApplication/ListenerExample.java Bugs: - Fixed bug: Websocket was sending ping after it was closed
This commit is contained in:
@@ -23,10 +23,10 @@ public class TikTokGiftManager implements GiftManager {
|
||||
}
|
||||
|
||||
public TikTokGift updateActiveGift(WebcastGiftMessage giftMessage) {
|
||||
var giftId = new GiftId(giftMessage.getGiftId(), giftMessage.getSender().getUniqueId());
|
||||
var giftId = new GiftId(giftMessage.getGiftId(), giftMessage.getUser().getIdStr());
|
||||
if (activeGifts.containsKey(giftId)) {
|
||||
var gift = activeGifts.get(giftId);
|
||||
gift.setAmount(giftMessage.getAmount());
|
||||
gift.setAmount(giftMessage.getComboCount());
|
||||
} else {
|
||||
var newGift = new TikTokGift(giftMessage);
|
||||
activeGifts.put(giftId, newGift);
|
||||
@@ -34,7 +34,8 @@ public class TikTokGiftManager implements GiftManager {
|
||||
|
||||
var gift = activeGifts.get(giftId);
|
||||
|
||||
if (giftMessage.getRepeatEnd()) {
|
||||
if (giftMessage.getRepeatEnd() > 0)
|
||||
{
|
||||
gift.setStreakFinished(true);
|
||||
activeGifts.remove(giftId);
|
||||
}
|
||||
|
||||
@@ -4,8 +4,10 @@ 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.handlers.TikTokEventObserver;
|
||||
import io.github.jwdeveloper.tiktok.http.TikTokApiService;
|
||||
import io.github.jwdeveloper.tiktok.listener.ListenersManager;
|
||||
import io.github.jwdeveloper.tiktok.listener.TikTokListenersManager;
|
||||
import io.github.jwdeveloper.tiktok.live.ConnectionState;
|
||||
import io.github.jwdeveloper.tiktok.live.GiftManager;
|
||||
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
||||
@@ -17,25 +19,28 @@ import java.util.logging.Logger;
|
||||
public class TikTokLiveClient implements LiveClient {
|
||||
private final TikTokRoomInfo liveRoomInfo;
|
||||
private final TikTokGiftManager tikTokGiftManager;
|
||||
private final TikTokApiService apiClient;
|
||||
private final TikTokApiService apiService;
|
||||
private final TikTokWebSocketClient webSocketClient;
|
||||
private final TikTokEventHandler tikTokEventHandler;
|
||||
private final TikTokEventObserver tikTokEventHandler;
|
||||
private final ClientSettings clientSettings;
|
||||
private final TikTokListenersManager listenersManager;
|
||||
private final Logger logger;
|
||||
|
||||
public TikTokLiveClient(TikTokRoomInfo tikTokLiveMeta,
|
||||
TikTokApiService tikTokApiService,
|
||||
TikTokWebSocketClient webSocketClient,
|
||||
TikTokGiftManager tikTokGiftManager,
|
||||
TikTokEventHandler tikTokEventHandler,
|
||||
TikTokEventObserver tikTokEventHandler,
|
||||
ClientSettings clientSettings,
|
||||
TikTokListenersManager listenersManager,
|
||||
Logger logger) {
|
||||
this.liveRoomInfo = tikTokLiveMeta;
|
||||
this.tikTokGiftManager = tikTokGiftManager;
|
||||
this.apiClient = tikTokApiService;
|
||||
this.apiService = tikTokApiService;
|
||||
this.webSocketClient = webSocketClient;
|
||||
this.tikTokEventHandler = tikTokEventHandler;
|
||||
this.clientSettings = clientSettings;
|
||||
this.listenersManager = listenersManager;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@@ -71,8 +76,6 @@ public class TikTokLiveClient implements LiveClient {
|
||||
setState(ConnectionState.DISCONNECTED);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void tryConnect() {
|
||||
if (liveRoomInfo.hasConnectionState(ConnectionState.CONNECTED))
|
||||
throw new TikTokLiveException("Already connected");
|
||||
@@ -82,9 +85,9 @@ public class TikTokLiveClient implements LiveClient {
|
||||
logger.info("Connecting");
|
||||
setState(ConnectionState.CONNECTING);
|
||||
|
||||
var roomId = apiClient.fetchRoomId(liveRoomInfo.getUserName());
|
||||
var roomId = apiService.fetchRoomId(liveRoomInfo.getUserName());
|
||||
liveRoomInfo.setRoomId(roomId);
|
||||
var roomData = apiClient.fetchRoomInfo();
|
||||
var roomData = apiService.fetchRoomInfo();
|
||||
if (roomData.getStatus() == 0 || roomData.getStatus() == 4) {
|
||||
throw new TikTokLiveOfflineHostException("LiveStream for HostID could not be found. Is the Host online?");
|
||||
}
|
||||
@@ -92,10 +95,10 @@ public class TikTokLiveClient implements LiveClient {
|
||||
if (clientSettings.isDownloadGiftInfo())
|
||||
{
|
||||
logger.info("Fetch Gift info");
|
||||
var gifts = apiClient.fetchAvailableGifts();
|
||||
var gifts = apiService.fetchAvailableGifts();
|
||||
tikTokGiftManager.loadGifsInfo(gifts);
|
||||
}
|
||||
var clientData = apiClient.fetchClientData();
|
||||
var clientData = apiService.fetchClientData();
|
||||
webSocketClient.start(clientData, this);
|
||||
setState(ConnectionState.CONNECTED);
|
||||
}
|
||||
@@ -104,6 +107,11 @@ public class TikTokLiveClient implements LiveClient {
|
||||
public LiveRoomInfo getRoomInfo() {
|
||||
return liveRoomInfo;
|
||||
}
|
||||
@Override
|
||||
public ListenersManager getListenersManager()
|
||||
{
|
||||
return listenersManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GiftManager getGiftManager() {
|
||||
|
||||
@@ -5,17 +5,20 @@ import io.github.jwdeveloper.tiktok.events.TikTokEventBuilder;
|
||||
import io.github.jwdeveloper.tiktok.events.TikTokEventConsumer;
|
||||
import io.github.jwdeveloper.tiktok.events.messages.*;
|
||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
||||
import io.github.jwdeveloper.tiktok.handlers.TikTokEventHandler;
|
||||
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
|
||||
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.TikTokHttpClient;
|
||||
import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory;
|
||||
import io.github.jwdeveloper.tiktok.listener.TikTokEventListener;
|
||||
import io.github.jwdeveloper.tiktok.listener.TikTokListenersManager;
|
||||
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;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
@@ -23,19 +26,26 @@ import java.util.logging.Logger;
|
||||
public class TikTokLiveClientBuilder implements TikTokEventBuilder<TikTokLiveClientBuilder> {
|
||||
private final ClientSettings clientSettings;
|
||||
private final Logger logger;
|
||||
private final TikTokEventHandler tikTokEventHandler;
|
||||
private final TikTokEventObserver tikTokEventHandler;
|
||||
private final List<TikTokEventListener> listeners;
|
||||
|
||||
public TikTokLiveClientBuilder(String userName) {
|
||||
this.tikTokEventHandler = new TikTokEventHandler();
|
||||
this.tikTokEventHandler = new TikTokEventObserver();
|
||||
this.clientSettings = Constants.DefaultClientSettings();
|
||||
this.clientSettings.setHostName(userName);
|
||||
this.logger = Logger.getLogger(TikTokLive.class.getName());
|
||||
this.listeners = new ArrayList<>();
|
||||
}
|
||||
|
||||
public TikTokLiveClientBuilder configure(Consumer<ClientSettings> consumer) {
|
||||
consumer.accept(clientSettings);
|
||||
return this;
|
||||
}
|
||||
public TikTokLiveClientBuilder addListener(TikTokEventListener listener)
|
||||
{
|
||||
listeners.add(listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
private void validate() {
|
||||
|
||||
@@ -71,9 +81,12 @@ public class TikTokLiveClientBuilder implements TikTokEventBuilder<TikTokLiveCli
|
||||
var tiktokRoomInfo = new TikTokRoomInfo();
|
||||
tiktokRoomInfo.setUserName(clientSettings.getHostName());
|
||||
|
||||
|
||||
var listenerManager = new TikTokListenersManager(listeners, tikTokEventHandler);
|
||||
|
||||
var cookieJar = new TikTokCookieJar();
|
||||
var requestFactory = new TikTokHttpRequestFactory(cookieJar);
|
||||
var apiClient = new TikTokHttpApiClient(cookieJar, requestFactory);
|
||||
var apiClient = new TikTokHttpClient(cookieJar, requestFactory);
|
||||
var apiService = new TikTokApiService(apiClient, logger, clientSettings);
|
||||
var giftManager = new TikTokGiftManager();
|
||||
var webResponseHandler = new TikTokMessageHandlerRegistration(tikTokEventHandler, clientSettings, logger, giftManager, tiktokRoomInfo);
|
||||
@@ -83,7 +96,14 @@ public class TikTokLiveClientBuilder implements TikTokEventBuilder<TikTokLiveCli
|
||||
webResponseHandler,
|
||||
tikTokEventHandler);
|
||||
|
||||
return new TikTokLiveClient(tiktokRoomInfo, apiService, webSocketClient, giftManager, tikTokEventHandler, clientSettings, logger);
|
||||
return new TikTokLiveClient(tiktokRoomInfo,
|
||||
apiService,
|
||||
webSocketClient,
|
||||
giftManager,
|
||||
tikTokEventHandler,
|
||||
clientSettings,
|
||||
listenerManager,
|
||||
logger);
|
||||
}
|
||||
|
||||
public LiveClient buildAndRun() {
|
||||
@@ -259,8 +279,8 @@ public class TikTokLiveClientBuilder implements TikTokEventBuilder<TikTokLiveCli
|
||||
return this;
|
||||
}
|
||||
|
||||
public TikTokLiveClientBuilder onUnhandled(TikTokEventConsumer<TikTokUnhandledEvent> event) {
|
||||
tikTokEventHandler.subscribe(TikTokUnhandledEvent.class, event);
|
||||
public TikTokLiveClientBuilder onUnhandled(TikTokEventConsumer<TikTokUnhandledWebsocketMessageEvent> event) {
|
||||
tikTokEventHandler.subscribe(TikTokUnhandledWebsocketMessageEvent.class, event);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,34 +5,43 @@ import io.github.jwdeveloper.tiktok.events.TikTokEvent;
|
||||
import io.github.jwdeveloper.tiktok.events.TikTokEventConsumer;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class TikTokEventHandler {
|
||||
private final Map<String, TikTokEventConsumer> events;
|
||||
public class TikTokEventObserver {
|
||||
private final Map<String, Set<TikTokEventConsumer>> events;
|
||||
|
||||
public TikTokEventHandler() {
|
||||
public TikTokEventObserver() {
|
||||
events = new HashMap<>();
|
||||
}
|
||||
|
||||
public void publish(TikTokLiveClient tikTokLiveClient, TikTokEvent tikTokEvent) {
|
||||
if (events.containsKey(TikTokEvent.class.getSimpleName())) {
|
||||
var handler = events.get(TikTokEvent.class.getSimpleName());
|
||||
handler.onEvent(tikTokLiveClient, tikTokEvent);
|
||||
var handlers = events.get(TikTokEvent.class.getSimpleName());
|
||||
for(var handle : handlers)
|
||||
{
|
||||
handle.onEvent(tikTokLiveClient, tikTokEvent);
|
||||
}
|
||||
}
|
||||
|
||||
var name = tikTokEvent.getClass().getSimpleName();
|
||||
if (!events.containsKey(name)) {
|
||||
return;
|
||||
}
|
||||
var handler = events.get(name);
|
||||
handler.onEvent(tikTokLiveClient, tikTokEvent);
|
||||
var handlers = events.get(name);
|
||||
for(var handler : handlers)
|
||||
{
|
||||
handler.onEvent(tikTokLiveClient, tikTokEvent);
|
||||
}
|
||||
}
|
||||
|
||||
public <T extends TikTokEvent> void subscribe(Class<?> clazz, TikTokEventConsumer<T> event) {
|
||||
events.put(clazz.getSimpleName(), event);
|
||||
public <T extends TikTokEvent> void subscribe(Class<?> clazz, TikTokEventConsumer<T> event)
|
||||
{
|
||||
events.computeIfAbsent(clazz.getSimpleName(), e -> new HashSet<>()).add(event);
|
||||
}
|
||||
|
||||
public <T extends TikTokEvent> void unsubscribe(Class<?> clazz) {
|
||||
public <T extends TikTokEvent> void unsubscribeAll(Class<?> clazz) {
|
||||
events.remove(clazz);
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ 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.TikTokWebsocketMessageEvent;
|
||||
import io.github.jwdeveloper.tiktok.events.messages.TikTokUnhandledEvent;
|
||||
import io.github.jwdeveloper.tiktok.events.messages.TikTokUnhandledWebsocketMessageEvent;
|
||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageException;
|
||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokMessageMappingException;
|
||||
import io.github.jwdeveloper.tiktok.messages.WebcastResponse;
|
||||
@@ -23,11 +23,11 @@ import java.util.logging.Logger;
|
||||
public abstract class TikTokMessageHandler {
|
||||
|
||||
private final Map<String, io.github.jwdeveloper.tiktok.handler.TikTokMessageHandler> handlers;
|
||||
private final TikTokEventHandler tikTokEventHandler;
|
||||
private final TikTokEventObserver tikTokEventHandler;
|
||||
private final ClientSettings clientSettings;
|
||||
protected final Logger logger;
|
||||
|
||||
public TikTokMessageHandler(TikTokEventHandler tikTokEventHandler,ClientSettings clientSettings, Logger logger) {
|
||||
public TikTokMessageHandler(TikTokEventObserver tikTokEventHandler, ClientSettings clientSettings, Logger logger) {
|
||||
handlers = new HashMap<>();
|
||||
this.tikTokEventHandler = tikTokEventHandler;
|
||||
this.clientSettings = clientSettings;
|
||||
@@ -65,7 +65,7 @@ public abstract class TikTokMessageHandler {
|
||||
|
||||
private void handleSingleMessage(TikTokLiveClient client, WebcastResponse.Message message) throws Exception {
|
||||
if (!handlers.containsKey(message.getType())) {
|
||||
tikTokEventHandler.publish(client, new TikTokUnhandledEvent(message));
|
||||
tikTokEventHandler.publish(client, new TikTokUnhandledWebsocketMessageEvent(message));
|
||||
return;
|
||||
}
|
||||
var handler = handlers.get(message.getType());
|
||||
|
||||
@@ -5,21 +5,18 @@ 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;
|
||||
import io.github.jwdeveloper.tiktok.messages.*;
|
||||
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 TikTokMessageHandlerRegistration extends TikTokMessageHandler {
|
||||
private final TikTokGiftManager giftManager;
|
||||
private final TikTokRoomInfo roomInfo;
|
||||
|
||||
public TikTokMessageHandlerRegistration(TikTokEventHandler tikTokEventHandler,
|
||||
public TikTokMessageHandlerRegistration(TikTokEventObserver tikTokEventHandler,
|
||||
ClientSettings clientSettings,
|
||||
Logger logger,
|
||||
TikTokGiftManager giftManager,
|
||||
|
||||
@@ -2,11 +2,12 @@ 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.TikTokGiftInfo;
|
||||
import io.github.jwdeveloper.tiktok.messages.WebcastResponse;
|
||||
import io.github.jwdeveloper.tiktok.models.gifts.TikTokGiftInfo;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -15,34 +16,96 @@ import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class TikTokApiService {
|
||||
private final TikTokHttpApiClient apiClient;
|
||||
private final TikTokHttpClient tiktokHttpClient;
|
||||
private final Logger logger;
|
||||
private final ClientSettings clientSettings;
|
||||
|
||||
public TikTokApiService(TikTokHttpApiClient apiClient, Logger logger, ClientSettings clientSettings) {
|
||||
this.apiClient = apiClient;
|
||||
public TikTokApiService(TikTokHttpClient apiClient, Logger logger, ClientSettings clientSettings) {
|
||||
this.tiktokHttpClient = apiClient;
|
||||
this.logger = logger;
|
||||
this.clientSettings = clientSettings;
|
||||
}
|
||||
|
||||
/*
|
||||
if (sessionId) {
|
||||
// Update sessionId
|
||||
this.#options.sessionId = sessionId;
|
||||
}
|
||||
|
||||
if (!this.#options.sessionId) {
|
||||
throw new Error('Missing SessionId. Please provide your current SessionId to use this feature.');
|
||||
}
|
||||
|
||||
try {
|
||||
// Retrieve current room_id if not connected
|
||||
if (!this.#isConnected) {
|
||||
await this.#retrieveRoomId();
|
||||
}
|
||||
|
||||
// Add the session cookie to the CookieJar
|
||||
this.#httpClient.setSessionId(this.#options.sessionId);
|
||||
|
||||
// Submit the chat request
|
||||
let requestParams = { ...this.#clientParams, content: text };
|
||||
let response = await this.#httpClient.postFormDataToWebcastApi('room/chat/', requestParams, null);
|
||||
|
||||
// Success?
|
||||
if (response?.status_code === 0) {
|
||||
return response.data;
|
||||
}
|
||||
|
||||
// Handle errors
|
||||
switch (response?.status_code) {
|
||||
case 20003:
|
||||
throw new Error('Your SessionId has expired. Please provide a new one.');
|
||||
default:
|
||||
throw new Error(`TikTok responded with status code ${response?.status_code}: ${response?.data?.message}`);
|
||||
}
|
||||
} catch (err) {
|
||||
throw new Error(`Failed to send chat message. ${err.message}`);
|
||||
}
|
||||
*/
|
||||
|
||||
public boolean sendMessage(String message, String sessionId) {
|
||||
if (sessionId.isEmpty()) {
|
||||
throw new TikTokLiveException("Session ID must not be Empty");
|
||||
}
|
||||
var roomId = clientSettings.getClientParameters().get("room_id");
|
||||
if (roomId == null) {
|
||||
throw new TikTokLiveException("Room ID must not be Empty");
|
||||
}
|
||||
logger.info("Sending message to chat");
|
||||
try {
|
||||
var params = new HashMap<String, Object>(clientSettings.getClientParameters());
|
||||
params.put("content", message);
|
||||
params.put("channel", "tiktok_web");
|
||||
params.remove("cursor");
|
||||
tiktokHttpClient.setSessionId(sessionId);
|
||||
tiktokHttpClient.postMessageToChat(params);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
throw new TikTokLiveRequestException("Failed to fetch room id from WebCast, see stacktrace for more info.", e);
|
||||
}
|
||||
}
|
||||
|
||||
public String fetchRoomId(String userName) {
|
||||
logger.info("Fetching room ID");
|
||||
String html;
|
||||
try {
|
||||
html = apiClient.GetLivestreamPage(userName);
|
||||
html = tiktokHttpClient.getLivestreamPage(userName);
|
||||
} catch (Exception 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]*)");
|
||||
Matcher firstMatcher = firstPattern.matcher(html);
|
||||
String id = "";
|
||||
var firstPattern = Pattern.compile("room_id=([0-9]*)");
|
||||
var firstMatcher = firstPattern.matcher(html);
|
||||
var id = "";
|
||||
|
||||
if (firstMatcher.find()) {
|
||||
id = firstMatcher.group(1);
|
||||
} else {
|
||||
Pattern secondPattern = Pattern.compile("\"roomId\":\"([0-9]*)\"");
|
||||
Matcher secondMatcher = secondPattern.matcher(html);
|
||||
var secondPattern = Pattern.compile("\"roomId\":\"([0-9]*)\"");
|
||||
var secondMatcher = secondPattern.matcher(html);
|
||||
|
||||
if (secondMatcher.find()) {
|
||||
id = secondMatcher.group(1);
|
||||
@@ -54,7 +117,7 @@ public class TikTokApiService {
|
||||
}
|
||||
|
||||
clientSettings.getClientParameters().put("room_id", id);
|
||||
logger.info("RoomID -> "+id);
|
||||
logger.info("RoomID -> " + id);
|
||||
return id;
|
||||
}
|
||||
|
||||
@@ -62,7 +125,7 @@ public class TikTokApiService {
|
||||
public LiveRoomMeta fetchRoomInfo() {
|
||||
logger.info("Fetch RoomInfo");
|
||||
try {
|
||||
var response = apiClient.GetJObjectFromWebcastAPI("room/info/", clientSettings.getClientParameters());
|
||||
var response = tiktokHttpClient.getJObjectFromWebcastAPI("room/info/", clientSettings.getClientParameters());
|
||||
if (!response.has("data")) {
|
||||
return new LiveRoomMeta();
|
||||
}
|
||||
@@ -77,48 +140,42 @@ public class TikTokApiService {
|
||||
var info = new LiveRoomMeta();
|
||||
info.setStatus(status.getAsInt());
|
||||
|
||||
logger.info("RoomInfo status -> "+info.getStatus());
|
||||
logger.info("RoomInfo status -> " + info.getStatus());
|
||||
return info;
|
||||
} catch (Exception e) {
|
||||
throw new TikTokLiveRequestException("Failed to fetch room info from WebCast, see stacktrace for more info.", e);
|
||||
}
|
||||
}
|
||||
|
||||
public WebcastResponse fetchClientData()
|
||||
{
|
||||
public WebcastResponse fetchClientData() {
|
||||
logger.info("Fetch ClientData");
|
||||
try {
|
||||
var response = apiClient.GetDeserializedMessage("im/fetch/", clientSettings.getClientParameters());
|
||||
clientSettings.getClientParameters().put("cursor",response.getCursor());
|
||||
var response = tiktokHttpClient.getDeserializedMessage("im/fetch/", clientSettings.getClientParameters());
|
||||
clientSettings.getClientParameters().put("cursor", response.getCursor());
|
||||
clientSettings.getClientParameters().put("internal_ext", response.getAckIds());
|
||||
return response;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
} catch (Exception e) {
|
||||
throw new TikTokLiveRequestException("Failed to fetch client data", e);
|
||||
}
|
||||
}
|
||||
|
||||
public Map<Integer, TikTokGiftInfo> fetchAvailableGifts() {
|
||||
try {
|
||||
var response = apiClient.GetJObjectFromWebcastAPI("gift/list/", clientSettings.getClientParameters());
|
||||
if(!response.has("data"))
|
||||
{
|
||||
var response = tiktokHttpClient.getJObjectFromWebcastAPI("gift/list/", clientSettings.getClientParameters());
|
||||
if (!response.has("data")) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
var dataJson = response.getAsJsonObject("data");
|
||||
if(!dataJson.has("gifts"))
|
||||
{
|
||||
if (!dataJson.has("gifts")) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
var giftsJsonList = dataJson.get("gifts").getAsJsonArray();
|
||||
var gifts = new HashMap<Integer, TikTokGiftInfo>();
|
||||
var gson = new Gson();
|
||||
for(var jsonGift : giftsJsonList)
|
||||
{
|
||||
for (var jsonGift : giftsJsonList) {
|
||||
var gift = gson.fromJson(jsonGift, TikTokGiftInfo.class);
|
||||
logger.info("Found Available Gift "+ gift.getName()+ " with ID "+gift.getId());
|
||||
gifts.put(gift.getId(),gift);
|
||||
logger.info("Found Available Gift " + gift.getName() + " with ID " + gift.getId());
|
||||
gifts.put(gift.getId(), gift);
|
||||
}
|
||||
return gifts;
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -2,7 +2,6 @@ package io.github.jwdeveloper.tiktok.http;
|
||||
|
||||
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.TikTokLiveRequestException;
|
||||
import io.github.jwdeveloper.tiktok.messages.WebcastResponse;
|
||||
@@ -15,30 +14,44 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public class TikTokHttpApiClient {
|
||||
public class TikTokHttpClient {
|
||||
private final TikTokHttpRequestFactory requestFactory;
|
||||
private final TikTokCookieJar tikTokCookieJar;
|
||||
|
||||
public TikTokHttpApiClient(TikTokCookieJar tikTokCookieJar, TikTokHttpRequestFactory requestFactory) {
|
||||
public TikTokHttpClient(TikTokCookieJar tikTokCookieJar, TikTokHttpRequestFactory requestFactory) {
|
||||
this.requestFactory = requestFactory;
|
||||
this.tikTokCookieJar = tikTokCookieJar;
|
||||
}
|
||||
|
||||
public String GetLivestreamPage(String userName) {
|
||||
public void setSessionId(String sessionId)
|
||||
{
|
||||
tikTokCookieJar.set("sessionid", sessionId);
|
||||
tikTokCookieJar.set("sessionid_ss", sessionId);
|
||||
tikTokCookieJar.set("sid_tt", sessionId);
|
||||
}
|
||||
|
||||
|
||||
public String getLivestreamPage(String userName) {
|
||||
|
||||
var url = Constants.TIKTOK_URL_WEB + "@" + userName + "/live/";
|
||||
var get = getRequest(url, null);
|
||||
return get;
|
||||
}
|
||||
|
||||
public JsonObject GetJObjectFromWebcastAPI(String path, Map<String, Object> parameters) {
|
||||
public String postMessageToChat(Map<String,Object> parameters)
|
||||
{
|
||||
var get = postRequest(Constants.TIKTOK_URL_WEBCAST + "room/chat/", parameters);
|
||||
return get;
|
||||
}
|
||||
|
||||
public JsonObject getJObjectFromWebcastAPI(String path, Map<String, Object> parameters) {
|
||||
var get = getRequest(Constants.TIKTOK_URL_WEBCAST + path, parameters);
|
||||
var json = JsonParser.parseString(get);
|
||||
var jsonObject = json.getAsJsonObject();
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
public WebcastResponse GetDeserializedMessage(String path, Map<String, Object> parameters) {
|
||||
public WebcastResponse getDeserializedMessage(String path, Map<String, Object> parameters) {
|
||||
var bytes = getSignRequest(Constants.TIKTOK_URL_WEBCAST + path, parameters);
|
||||
try {
|
||||
return WebcastResponse.parseFrom(bytes);
|
||||
@@ -49,16 +62,25 @@ public class TikTokHttpApiClient {
|
||||
}
|
||||
}
|
||||
|
||||
private String postRequest(String url, Map<String, Object> parameters) {
|
||||
if (parameters == null) {
|
||||
parameters = new HashMap<>();
|
||||
}
|
||||
System.out.println("RomMID: "+parameters.get("room_id"));
|
||||
var request = requestFactory.setQueries(parameters);
|
||||
return request.post(url);
|
||||
}
|
||||
|
||||
private String getRequest(String url, Map<String, Object> parameters) {
|
||||
if (parameters == null) {
|
||||
parameters = new HashMap<>();
|
||||
}
|
||||
|
||||
var request = requestFactory.SetQueries(parameters);
|
||||
return request.Get(url);
|
||||
var request = requestFactory.setQueries(parameters);
|
||||
return request.get(url);
|
||||
}
|
||||
private byte[] getSignRequest(String url, Map<String, Object> parameters) {
|
||||
url = GetSignedUrl(url, parameters);
|
||||
url = getSignedUrl(url, parameters);
|
||||
try {
|
||||
var client = HttpClient.newHttpClient();
|
||||
var request = HttpRequest.newBuilder()
|
||||
@@ -86,7 +108,7 @@ public class TikTokHttpApiClient {
|
||||
}
|
||||
|
||||
|
||||
private String GetSignedUrl(String url, Map<String, Object> parameters) {
|
||||
private String getSignedUrl(String url, Map<String, Object> parameters) {
|
||||
|
||||
var fullUrl = HttpUtils.parseParameters(url,parameters);
|
||||
var singHeaders = new TreeMap<String,Object>();
|
||||
@@ -94,8 +116,8 @@ public class TikTokHttpApiClient {
|
||||
singHeaders.put("uuc", 1);
|
||||
singHeaders.put("url", fullUrl);
|
||||
|
||||
var request = requestFactory.SetQueries(singHeaders);
|
||||
var content = request.Get(Constants.TIKTOK_SIGN_API);
|
||||
var request = requestFactory.setQueries(singHeaders);
|
||||
var content = request.get(Constants.TIKTOK_SIGN_API);
|
||||
|
||||
|
||||
try {
|
||||
@@ -11,12 +11,12 @@ 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;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public class TikTokHttpRequestFactory implements TikTokHttpRequest {
|
||||
private final CookieManager cookieManager;
|
||||
@@ -34,13 +34,8 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest {
|
||||
.connectTimeout(Duration.ofSeconds(2))
|
||||
.build();
|
||||
}
|
||||
|
||||
public WebSocket.Builder openSocket() {
|
||||
return client.newWebSocketBuilder();
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public String Get(String url) {
|
||||
public String get(String url) {
|
||||
var uri = URI.create(url);
|
||||
var request = HttpRequest.newBuilder().GET();
|
||||
if (query != null) {
|
||||
@@ -49,22 +44,35 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest {
|
||||
request.uri(requestUri);
|
||||
}
|
||||
|
||||
return GetContent(request.build());
|
||||
return getContent(request.build());
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public String Post(String url, HttpRequest.BodyPublisher data) {
|
||||
public String post(String url) {
|
||||
var uri = URI.create(url);
|
||||
var request = HttpRequest.newBuilder().POST(data);
|
||||
for (var header : defaultHeaders.entrySet()) {
|
||||
var request = HttpRequest.newBuilder().POST(HttpRequest.BodyPublishers.ofString(""));
|
||||
for (var header : defaultHeaders.entrySet())
|
||||
{
|
||||
if(header.getKey().equals("Connection"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
request.setHeader(header.getKey(), header.getValue());
|
||||
}
|
||||
request.setHeader("Content-type","application/x-www-form-urlencoded; charset=UTF-8");
|
||||
request.setHeader("Cookie", tikTokCookieJar.parseCookies());
|
||||
|
||||
|
||||
if (query != null) {
|
||||
var baseUri = uri.toString();
|
||||
var requestUri = URI.create(baseUri + "?" + query);
|
||||
request.uri(requestUri);
|
||||
System.out.println(requestUri.toString());
|
||||
}
|
||||
return GetContent(request.build());
|
||||
|
||||
|
||||
|
||||
return getContent(request.build());
|
||||
}
|
||||
|
||||
public TikTokHttpRequest setHeader(String key, String value) {
|
||||
@@ -77,10 +85,11 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest {
|
||||
return this;
|
||||
}
|
||||
|
||||
public TikTokHttpRequest SetQueries(Map<String, Object> queries) {
|
||||
public TikTokHttpRequest setQueries(Map<String, Object> queries) {
|
||||
if (queries == null)
|
||||
return this;
|
||||
query = String.join("&", queries.entrySet().stream().map(x ->
|
||||
var testMap = new TreeMap<String,Object>(queries);
|
||||
query = String.join("&", testMap.entrySet().stream().map(x ->
|
||||
{
|
||||
var key = x.getKey();
|
||||
var value = "";
|
||||
@@ -95,7 +104,7 @@ public class TikTokHttpRequestFactory implements TikTokHttpRequest {
|
||||
}
|
||||
|
||||
|
||||
private String GetContent(HttpRequest request) throws Exception {
|
||||
private String getContent(HttpRequest request) throws Exception {
|
||||
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
if (response.statusCode() == 404) {
|
||||
throw new TikTokLiveRequestException("Request responded with 404 NOT_FOUND");
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package io.github.jwdeveloper.tiktok.listener;
|
||||
|
||||
import io.github.jwdeveloper.tiktok.events.TikTokEventConsumer;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Value
|
||||
public class ListenerBindingModel
|
||||
{
|
||||
|
||||
TikTokEventListener listener;
|
||||
|
||||
List<TikTokEventConsumer<?>> events;
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package io.github.jwdeveloper.tiktok.listener;
|
||||
|
||||
|
||||
import io.github.jwdeveloper.tiktok.annotations.TikTokEventHandler;
|
||||
import io.github.jwdeveloper.tiktok.events.TikTokEvent;
|
||||
import io.github.jwdeveloper.tiktok.events.TikTokEventConsumer;
|
||||
import io.github.jwdeveloper.tiktok.events.messages.TikTokWebsocketMessageEvent;
|
||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokEventListenerMethodException;
|
||||
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
|
||||
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
|
||||
import io.github.jwdeveloper.tiktok.live.LiveClient;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class TikTokListenersManager implements ListenersManager {
|
||||
private final TikTokEventObserver eventObserver;
|
||||
private final List<ListenerBindingModel> bindingModels;
|
||||
|
||||
public TikTokListenersManager(List<TikTokEventListener> listeners, TikTokEventObserver tikTokEventHandler) {
|
||||
this.eventObserver = tikTokEventHandler;
|
||||
this.bindingModels = listeners.stream().map(this::bindToEvents).toList();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<TikTokEventListener> getBindingModels() {
|
||||
return bindingModels.stream().map(ListenerBindingModel::getListener).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(TikTokEventListener listener) {
|
||||
var alreadyExists = bindingModels.stream().filter(e -> e.getListener() == listener).findAny();
|
||||
if (alreadyExists.isPresent()) {
|
||||
throw new TikTokLiveException("Listener " + listener.getClass() + " has already been registered");
|
||||
}
|
||||
var bindingModel = bindToEvents(listener);
|
||||
bindingModels.add(bindingModel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(TikTokEventListener listener) {
|
||||
var optional = bindingModels.stream().filter(e -> e.getListener() == listener).findAny();
|
||||
if (optional.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
bindingModels.remove(optional.get());
|
||||
}
|
||||
|
||||
private ListenerBindingModel bindToEvents(TikTokEventListener listener) {
|
||||
|
||||
var clazz = listener.getClass();
|
||||
var methods = Arrays.stream(clazz.getDeclaredMethods()).filter(m ->
|
||||
m.getParameterCount() == 2 &&
|
||||
m.isAnnotationPresent(TikTokEventHandler.class) &&
|
||||
m.getParameterTypes()[0].equals(LiveClient.class)).toList();
|
||||
var eventConsumer = new ArrayList<TikTokEventConsumer<?>>();
|
||||
|
||||
|
||||
for (var method : methods)
|
||||
{
|
||||
var eventClazz = method.getParameterTypes()[1];
|
||||
if(!eventClazz.isAssignableFrom(TikTokEvent.class))
|
||||
{
|
||||
throw new TikTokEventListenerMethodException("Method "+method.getName()+" 2nd parameter must instance of "+TikTokEvent.class.getName());
|
||||
}
|
||||
var tikTokEventConsumer = new TikTokEventConsumer() {
|
||||
@Override
|
||||
public void onEvent(LiveClient liveClient, TikTokEvent event) {
|
||||
try {
|
||||
method.invoke(listener, liveClient, event);
|
||||
} catch (Exception e) {
|
||||
throw new TikTokEventListenerMethodException(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
eventObserver.subscribe(eventClazz, tikTokEventConsumer);
|
||||
}
|
||||
return new ListenerBindingModel(listener, eventConsumer);
|
||||
}
|
||||
}
|
||||
@@ -5,16 +5,14 @@ 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.TikTokEventObserver;
|
||||
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;
|
||||
import io.github.jwdeveloper.tiktok.messages.WebcastResponse;
|
||||
import org.java_websocket.client.WebSocketClient;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.http.WebSocket;
|
||||
import java.util.HashMap;
|
||||
import java.util.TreeMap;
|
||||
import java.util.logging.Logger;
|
||||
@@ -24,7 +22,7 @@ public class TikTokWebSocketClient {
|
||||
private final ClientSettings clientSettings;
|
||||
private final TikTokCookieJar tikTokCookieJar;
|
||||
private final TikTokMessageHandlerRegistration webResponseHandler;
|
||||
private final TikTokEventHandler tikTokEventHandler;
|
||||
private final TikTokEventObserver tikTokEventHandler;
|
||||
private WebSocketClient webSocketClient;
|
||||
private TikTokLiveClient tikTokLiveClient;
|
||||
private TikTokWebSocketPingingTask pingingTask;
|
||||
@@ -34,7 +32,7 @@ public class TikTokWebSocketClient {
|
||||
TikTokCookieJar tikTokCookieJar,
|
||||
ClientSettings clientSettings,
|
||||
TikTokMessageHandlerRegistration webResponseHandler,
|
||||
TikTokEventHandler tikTokEventHandler) {
|
||||
TikTokEventObserver tikTokEventHandler) {
|
||||
this.logger = logger;
|
||||
this.tikTokCookieJar = tikTokCookieJar;
|
||||
this.clientSettings = clientSettings;
|
||||
@@ -97,12 +95,11 @@ public class TikTokWebSocketClient {
|
||||
tikTokLiveClient);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void stop()
|
||||
{
|
||||
if (isConnected && webSocketClient != null) {
|
||||
webSocketClient.close(1);
|
||||
if (isConnected && webSocketClient != null)
|
||||
{
|
||||
webSocketClient.closeConnection(0,"");
|
||||
}
|
||||
webSocketClient = null;
|
||||
pingingTask = null;
|
||||
|
||||
@@ -6,7 +6,7 @@ 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.TikTokProtocolBufferException;
|
||||
import io.github.jwdeveloper.tiktok.handlers.TikTokEventHandler;
|
||||
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
|
||||
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandlerRegistration;
|
||||
import io.github.jwdeveloper.tiktok.messages.WebcastResponse;
|
||||
import io.github.jwdeveloper.tiktok.messages.WebcastWebsocketAck;
|
||||
@@ -16,7 +16,6 @@ import org.java_websocket.drafts.Draft_6455;
|
||||
import org.java_websocket.handshake.ServerHandshake;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.http.WebSocket;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
@@ -24,14 +23,14 @@ import java.util.Optional;
|
||||
public class TikTokWebSocketListener extends WebSocketClient {
|
||||
|
||||
private final TikTokMessageHandlerRegistration webResponseHandler;
|
||||
private final TikTokEventHandler tikTokEventHandler;
|
||||
private final TikTokEventObserver tikTokEventHandler;
|
||||
private final TikTokLiveClient tikTokLiveClient;
|
||||
|
||||
public TikTokWebSocketListener(URI serverUri,
|
||||
Map<String, String> httpHeaders,
|
||||
int connectTimeout,
|
||||
TikTokMessageHandlerRegistration webResponseHandler,
|
||||
TikTokEventHandler tikTokEventHandler,
|
||||
TikTokEventObserver tikTokEventHandler,
|
||||
TikTokLiveClient tikTokLiveClient) {
|
||||
super(serverUri, new Draft_6455(), httpHeaders,connectTimeout);
|
||||
this.webResponseHandler = webResponseHandler;
|
||||
@@ -43,7 +42,10 @@ public class TikTokWebSocketListener extends WebSocketClient {
|
||||
@Override
|
||||
public void onOpen(ServerHandshake serverHandshake) {
|
||||
tikTokEventHandler.publish(tikTokLiveClient,new TikTokConnectedEvent());
|
||||
sendPing();
|
||||
if(isNotClosing())
|
||||
{
|
||||
sendPing();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +57,10 @@ public class TikTokWebSocketListener extends WebSocketClient {
|
||||
} catch (Exception e) {
|
||||
tikTokEventHandler.publish(tikTokLiveClient, new TikTokErrorEvent(e));
|
||||
}
|
||||
sendPing();
|
||||
if(isNotClosing())
|
||||
{
|
||||
sendPing();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -66,7 +71,10 @@ public class TikTokWebSocketListener extends WebSocketClient {
|
||||
@Override
|
||||
public void onError(Exception error) {
|
||||
tikTokEventHandler.publish(tikTokLiveClient,new TikTokErrorEvent(error));
|
||||
sendPing();
|
||||
if(isNotClosing())
|
||||
{
|
||||
sendPing();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleBinary(byte[] buffer) {
|
||||
@@ -101,6 +109,11 @@ public class TikTokWebSocketListener extends WebSocketClient {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isNotClosing()
|
||||
{
|
||||
return !isClosed() && !isClosing();
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void sendAckId(long id) {
|
||||
@@ -109,7 +122,10 @@ public class TikTokWebSocketListener extends WebSocketClient {
|
||||
.setType("ack")
|
||||
.setId(id)
|
||||
.build();
|
||||
send(serverInfo.toByteString().asReadOnlyByteBuffer());
|
||||
if(isNotClosing())
|
||||
{
|
||||
send(serverInfo.toByteString().asReadOnlyByteBuffer());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user