- TikTokHttpResponseEvent
  - Fixed User attributes in CommentEvent
  - Redesign .onMapper method
This commit is contained in:
JW
2023-12-19 04:01:06 +01:00
parent d6c0d50ac3
commit 3eed982d6b
95 changed files with 3200 additions and 1653 deletions

View File

@@ -0,0 +1,65 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.tools;
import io.github.jwdeveloper.tiktok.tools.collector.client.TikTokDataCollectorBuilder;
import io.github.jwdeveloper.tiktok.tools.collector.api.DataCollectorBuilder;
import io.github.jwdeveloper.tiktok.tools.tester.TikTokDataTesterBuilder;
import io.github.jwdeveloper.tiktok.tools.tester.api.DataTesterBuilder;
public class TikTokLiveTools
{
/**
*
* @param databaseName dataCollector use sql-lite database to store message
* if database not exits it creates new one
* @return
*/
public static DataCollectorBuilder createCollector(String databaseName)
{
return new TikTokDataCollectorBuilder(databaseName);
}
/**
*
* @param databaseName dataTester will read messages for database
* before using dataTester, use dataCollector to create database
* if database not exits exception will be thrown
* @return
*/
public static DataTesterBuilder createTester(String databaseName)
{
return new TikTokDataTesterBuilder(databaseName);
}
/**
*
* Returns browser application that collects and display Events, Messages, WebcastResponses
* in online web editor so it's easier to read and analyze data structures
* @return
*/
public static void createWebViewer()
{
}
}

View File

@@ -1,93 +0,0 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.tools.collector;
import io.github.jwdeveloper.tiktok.TikTokLive;
import io.github.jwdeveloper.tiktok.TikTokLiveClient;
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
import io.github.jwdeveloper.tiktok.data.models.Picture;
import io.github.jwdeveloper.tiktok.data.models.gifts.Gift;
import io.github.jwdeveloper.tiktok.data.models.users.User;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastGiftMessage;
import io.github.jwdeveloper.tiktok.tools.collector.client.TikTokMessageCollectorClient;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.logging.Level;
public class RunCollector {
//https://protobuf-decoder.netlify.app/
//https://streamdps.com/tiktok-widgets/gifts/
//WebcastLinkMicBattleItemCard does streamer win battle?
public static void main(String[] args) throws SQLException, IOException {
TikTokMessageCollectorClient.create("giftsCollector")
//.addUser("crece.sara")
//.addUser("moniczkka")
.addUser("valeria.viral")
// .addUser("cbcgod")
// .addUser("psychotropnazywo")
// .addUser("accordionistka")
//.addEventFilter(WebcastGiftMessage.class)
.addOnBuilder(liveClientBuilder ->
{
liveClientBuilder.onGiftCombo((liveClient, event) ->
{
liveClient.getLogger().setLevel(Level.OFF);
var gifts = liveClient.getGiftManager().getGifts();
var sb = new StringBuilder();
sb.append("GIFT COMBO User: " + event.getUser().getProfileName()+" ");
sb.append("Name: " + event.getGift().getName() + " ");
sb.append("Combo: " + event.getCombo() + " ");
sb.append("COST: " + event.getGift().getDiamondCost() + " ");
sb.append("STATE: " + event.getComboState() + " ");
System.out.println(sb.toString());
});
liveClientBuilder.onGift((liveClient, event) ->
{
liveClient.getLogger().setLevel(Level.OFF);
var gifts = liveClient.getGiftManager().getGifts();
var sb = new StringBuilder();
sb.append("GIFT User: " + event.getUser().getProfileName()+" ");
sb.append("Name: " + event.getGift().getName() + " ");
sb.append("COST: " + event.getGift().getDiamondCost() + " ");
sb.append("Combo: " + event.getCombo() + " ");
System.out.println(sb.toString());
});
})
.buildAndRun();
System.in.read();
}
}

View File

@@ -20,18 +20,14 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.tools.collector.tables;
package io.github.jwdeveloper.tiktok.tools.collector.api;
import lombok.Data;
public interface DataCollector {
@Data
public class TikTokResponseModel
{
private Integer id;
void connect();
private String hostName;
private String response;
void disconnect();
private String createdAt;
void disconnect(boolean keepDatabase);
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.tools.collector.api;
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
import io.github.jwdeveloper.tiktok.tools.db.TikTokDatabase;
import java.util.function.Consumer;
public interface DataCollectorBuilder extends DataFilters<DataCollectorBuilder> {
DataCollectorBuilder setOutputPath(String path);
DataCollectorBuilder setSessionTag(String sessionTimestamp);
DataCollectorBuilder setDatabase(TikTokDatabase database);
DataCollectorBuilder configureLiveClient(Consumer<LiveClientBuilder> consumer);
DataCollectorBuilder addUser(String user);
DataCollector buildAndRun();
DataCollector build();
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.tools.collector.api;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
public interface DataFilters<T> {
T addMessageFilter(Class<? extends com.google.protobuf.GeneratedMessageV3> message);
T addMessageFilter(String message);
T addEventFilter(Class<? extends TikTokEvent> event);
T addEventFilter(String event);
}

View File

@@ -20,24 +20,22 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.tools.collector.db;
package io.github.jwdeveloper.tiktok.tools.collector.api;
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokMessageModel;
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokResponseModel;
import org.jdbi.v3.sqlobject.config.RegisterBeanMapper;
import org.jdbi.v3.sqlobject.customizer.BindBean;
import org.jdbi.v3.sqlobject.statement.SqlQuery;
import org.jdbi.v3.sqlobject.statement.SqlUpdate;
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
import lombok.Data;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
@RegisterBeanMapper(TikTokResponseModel.class)
public interface TikTokResponseModelDAO
{
@SqlUpdate("INSERT INTO TikTokResponseModel (hostName, response, createdAt) " +
"VALUES (:hostName, :response, :createdAt)")
void insert(@BindBean TikTokResponseModel message);
@SqlQuery("SELECT * FROM TikTokResponseModel")
List<TikTokResponseModel> select();
@Data
public class TikTokDataCollectorModel {
private List<String> users;
private String outputPath;
private String outputName;
private Set<String> eventsFilter;
private Set<String> messagesFilter;
private String sessionTag ="";
private Consumer<LiveClientBuilder> onConfigureLiveClient;
}

View File

@@ -37,14 +37,14 @@ import java.time.LocalDateTime;
import java.util.*;
import java.util.logging.Logger;
public class MessageCollector {
public class MessagesManager {
@Getter
Map<String, Queue<MessageData>> messages;
String outputName;
int limit = 20;
public MessageCollector(String outputName) {
public MessagesManager(String outputName) {
this.messages = new TreeMap<>();
this.outputName = outputName;
load();

View File

@@ -22,104 +22,16 @@
*/
package io.github.jwdeveloper.tiktok.tools.collector.client;
import io.github.jwdeveloper.tiktok.TikTokLive;
import io.github.jwdeveloper.tiktok.TikTokLiveClientBuilder;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageException;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
import io.github.jwdeveloper.tiktok.tools.collector.db.TikTokDatabase;
import io.github.jwdeveloper.tiktok.tools.collector.tables.ExceptionInfoModel;
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokErrorModel;
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokMessageModel;
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokResponseModel;
import java.util.Base64;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import io.github.jwdeveloper.tiktok.tools.db.TikTokDatabase;
public class TikTokClientFactory {
private final MessageCollector messageCollector;
private final MessagesManager messageCollector;
private final TikTokDatabase tikTokDatabase;
public TikTokClientFactory(MessageCollector messageCollector, TikTokDatabase tikTokDatabase) {
public TikTokClientFactory(MessagesManager messageCollector, TikTokDatabase tikTokDatabase) {
this.messageCollector = messageCollector;
this.tikTokDatabase = tikTokDatabase;
}
public CompletableFuture<LiveClient> runClientAsync(String tiktokUser, List<Class<?>> filters, Consumer<LiveClientBuilder> onBuilder) {
var builder = TikTokLive.newClient(tiktokUser);
var msgFilter = filters.stream().map(Class::getSimpleName).toList();
onBuilder.accept(builder);
return builder.onConnected((liveClient, event) ->
{
liveClient.getLogger().info("CONNECTED TO " + liveClient.getRoomInfo().getHostName());
})
.onWebsocketResponse((liveClient, event) ->
{
var response = Base64.getEncoder().encodeToString(event.getResponse().toByteArray());
var responseModel = new TikTokResponseModel();
responseModel.setResponse(response);
responseModel.setHostName(liveClient.getRoomInfo().getHostName());
tikTokDatabase.insertResponse(responseModel);
liveClient.getLogger().info("Response");
for (var message : event.getResponse().getMessagesList())
{
if(msgFilter.size() > 0 && !msgFilter.contains(message.getMethod()))
{
continue;
}
messageCollector.addMessage(liveClient.getLogger(), liveClient.getRoomInfo().getHostName(), message);
}
})
.onWebsocketMessage((liveClient, event) ->
{
var eventName = event.getEvent().getClass().getSimpleName();
/*
if (msgFilter.size() != 0 && !msgFilter.contains(event.getEvent().getClass())) {
return;
}*/
var messageBinary = Base64.getEncoder().encodeToString(event.getMessage().toByteArray());
var model = new TikTokMessageModel();
model.setType("messsage");
model.setHostName(tiktokUser);
model.setEventName(eventName);
model.setMessage(messageBinary);
// tikTokDatabase.insertMessage(model);
// liveClient.getLogger().info("EVENT: [" + tiktokUser + "] " + eventName);
})
.onError((liveClient, event) ->
{
event.getException().printStackTrace();
var exception = event.getException();
var exceptionContent = ExceptionInfoModel.getStackTraceAsString(exception);
var errorModel = new TikTokErrorModel();
if (exception instanceof TikTokLiveMessageException ex) {
errorModel.setHostName(tiktokUser);
errorModel.setErrorName(ex.messageMethod());
errorModel.setErrorType("error-message");
errorModel.setExceptionContent(exceptionContent);
errorModel.setMessage(ex.messageToBase64());
errorModel.setResponse(ex.webcastResponseToBase64());
} else {
errorModel.setHostName(tiktokUser);
errorModel.setErrorName(exception.getClass().getSimpleName());
errorModel.setErrorType("error-system");
errorModel.setExceptionContent(exceptionContent);
errorModel.setMessage("");
errorModel.setResponse("");
}
tikTokDatabase.insertError(errorModel);
liveClient.getLogger().info("ERROR: " + errorModel.getErrorName());
exception.printStackTrace();
})
.buildAndConnectAsync();
}
}

View File

@@ -0,0 +1,223 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.tools.collector.client;
import io.github.jwdeveloper.tiktok.TikTokLive;
import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.data.events.http.TikTokHttpResponseEvent;
import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketMessageEvent;
import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketResponseEvent;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageException;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import io.github.jwdeveloper.tiktok.tools.collector.api.DataCollector;
import io.github.jwdeveloper.tiktok.tools.collector.api.TikTokDataCollectorModel;
import io.github.jwdeveloper.tiktok.tools.db.TikTokDatabase;
import io.github.jwdeveloper.tiktok.tools.db.tables.ExceptionInfoModel;
import io.github.jwdeveloper.tiktok.tools.db.tables.TikTokDataTable;
import io.github.jwdeveloper.tiktok.tools.db.tables.TikTokErrorModel;
import io.github.jwdeveloper.tiktok.utils.JsonUtil;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
public class TikTokDataCollector implements DataCollector {
private final TikTokDataCollectorModel dataCollectorModel;
private final TikTokDatabase tikTokDatabase;
private final List<LiveClient> tiktokClients;
public TikTokDataCollector(TikTokDataCollectorModel dataCollectorModel, TikTokDatabase tikTokDatabase) {
this.dataCollectorModel = dataCollectorModel;
this.tikTokDatabase = tikTokDatabase;
this.tiktokClients = new ArrayList<>();
}
public void connect() {
try {
if (!tikTokDatabase.isConnected()) {
tikTokDatabase.connect();
}
for (var user : dataCollectorModel.getUsers()) {
var client = createLiveClient(user);
tiktokClients.add(client);
client.connectAsync();
}
} catch (Exception e) {
throw new RuntimeException("Unable to start tiktok connector", e);
}
}
public void disconnect() {
disconnect(false);
}
@Override
public void disconnect(boolean keepDatabase) {
try {
for (var client : tiktokClients) {
client.disconnect();
}
if (!keepDatabase) {
tikTokDatabase.close();
}
} catch (Exception e) {
throw new RuntimeException("Unable to stop tiktok connector", e);
}
}
public LiveClient createLiveClient(String tiktokUser) {
var builder = TikTokLive.newClient(tiktokUser);
builder.onConnected((liveClient, event) ->
{
liveClient.getLogger().info("Connected to " + liveClient.getRoomInfo().getHostName());
})
.onDisconnected((liveClient, event) ->
{
liveClient.getLogger().info("Disconnected " + liveClient.getRoomInfo().getHostName());
})
.onWebsocketResponse(this::handleResponseAndMessages)
.onWebsocketMessage(this::handleMappedEvent)
.onHttpResponse((liveClient, event) ->
{
var data = createHttpResponseData(event, tiktokUser);
tikTokDatabase.insertData(data);
})
.onError(this::handleError);
dataCollectorModel.getOnConfigureLiveClient().accept(builder);
return builder.build();
}
private void handleResponseAndMessages(LiveClient client, TikTokWebsocketResponseEvent event) {
var responseData = createResponseData(event.getResponse(), client.getRoomInfo().getHostName());
tikTokDatabase.insertData(responseData);
var filter = dataCollectorModel.getMessagesFilter();
for (var message : event.getResponse().getMessagesList()) {
if (filter.isEmpty()) {
var data = createMessageData(message, client.getRoomInfo().getHostName());
tikTokDatabase.insertData(data);
continue;
}
if (!filter.contains(message.getMethod())) {
continue;
}
var data = createMessageData(message, client.getRoomInfo().getHostName());
tikTokDatabase.insertData(data);
}
}
private void handleMappedEvent(LiveClient client, TikTokWebsocketMessageEvent messageEvent) {
var event = messageEvent.getEvent();
var eventName = event.getClass().getSimpleName();
var filter = dataCollectorModel.getEventsFilter();
if (filter.isEmpty()) {
var data = createEventData(event, client.getRoomInfo().getHostName());
tikTokDatabase.insertData(data);
return;
}
if (!filter.contains(eventName)) {
return;
}
var data = createEventData(event, client.getRoomInfo().getHostName());
tikTokDatabase.insertData(data);
}
private void handleError(LiveClient client, TikTokErrorEvent event) {
var exception = event.getException();
var userName = client.getRoomInfo().getHostName();
var exceptionContent = ExceptionInfoModel.getStackTraceAsString(exception);
var errorModel = new TikTokErrorModel();
if (exception instanceof TikTokLiveMessageException ex) {
errorModel.setHostName(userName);
errorModel.setErrorName(ex.messageMethod());
errorModel.setErrorType("error-message");
errorModel.setExceptionContent(exceptionContent);
errorModel.setMessage(ex.messageToBase64());
errorModel.setResponse(ex.webcastResponseToBase64());
} else {
errorModel.setHostName(userName);
errorModel.setErrorName(exception.getClass().getSimpleName());
errorModel.setErrorType("error-system");
errorModel.setExceptionContent(exceptionContent);
errorModel.setMessage("");
errorModel.setResponse("");
}
tikTokDatabase.insertError(errorModel);
client.getLogger().info("ERROR: " + errorModel.getErrorName());
exception.printStackTrace();
}
private TikTokDataTable createHttpResponseData(TikTokHttpResponseEvent response, String tiktokUser) {
var base64 = JsonUtil.toJson(response);
var data = new TikTokDataTable();
data.setSessionTag(dataCollectorModel.getSessionTag());
data.setTiktokUser(tiktokUser);
data.setDataType("response");
data.setDataTypeName("Http");
data.setContent(base64);
return data;
}
private TikTokDataTable createResponseData(WebcastResponse response, String tiktokUser) {
var base64 = Base64.getEncoder().encodeToString(response.toByteArray());
var data = new TikTokDataTable();
data.setSessionTag(dataCollectorModel.getSessionTag());
data.setTiktokUser(tiktokUser);
data.setDataType("response");
data.setDataTypeName("WebcastResponse");
data.setContent(base64);
return data;
}
private TikTokDataTable createMessageData(WebcastResponse.Message message, String tiktokUser) {
var base64 = Base64.getEncoder().encodeToString(message.getPayload().toByteArray());
var data = new TikTokDataTable();
data.setSessionTag(dataCollectorModel.getSessionTag());
data.setTiktokUser(tiktokUser);
data.setDataType("message");
data.setDataTypeName(message.getMethod());
data.setContent(base64);
return data;
}
private TikTokDataTable createEventData(TikTokEvent event, String tiktokUser) {
var base64 = JsonUtil.toJson(event);
var data = new TikTokDataTable();
data.setSessionTag(dataCollectorModel.getSessionTag());
data.setTiktokUser(tiktokUser);
data.setDataType("event");
data.setDataTypeName(event.getClass().getSimpleName());
data.setContent(base64);
return data;
}
}

View File

@@ -0,0 +1,138 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.tools.collector.client;
import com.google.protobuf.GeneratedMessageV3;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
import io.github.jwdeveloper.tiktok.tools.collector.api.DataCollectorBuilder;
import io.github.jwdeveloper.tiktok.tools.collector.api.DataCollector;
import io.github.jwdeveloper.tiktok.tools.collector.api.TikTokDataCollectorModel;
import io.github.jwdeveloper.tiktok.tools.db.TikTokDatabase;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.UUID;
import java.util.function.Consumer;
public class TikTokDataCollectorBuilder implements DataCollectorBuilder {
TikTokDataCollectorModel dataModel;
TikTokDatabase database;
public TikTokDataCollectorBuilder(String outputName) {
dataModel = new TikTokDataCollectorModel();
dataModel.setOutputName(outputName);
dataModel.setUsers(new ArrayList<>());
dataModel.setEventsFilter(new HashSet<>());
dataModel.setMessagesFilter(new HashSet<>());
dataModel.setOutputPath("...");
dataModel.setOnConfigureLiveClient((e) -> {
});
}
@Override
public DataCollectorBuilder addUser(String user) {
dataModel.getUsers().add(user);
return this;
}
@Override
public TikTokDataCollectorBuilder addMessageFilter(Class<? extends GeneratedMessageV3> message) {
dataModel.getMessagesFilter().add(message.getSimpleName());
return this;
}
@Override
public TikTokDataCollectorBuilder addMessageFilter(String message) {
dataModel.getMessagesFilter().add(message);
return this;
}
@Override
public TikTokDataCollectorBuilder addEventFilter(Class<? extends TikTokEvent> event) {
dataModel.getEventsFilter().add(event.getSimpleName());
return this;
}
@Override
public TikTokDataCollectorBuilder addEventFilter(String event) {
dataModel.getEventsFilter().add(event);
return this;
}
@Override
public DataCollectorBuilder setOutputPath(String path) {
dataModel.setOutputPath(path);
return this;
}
@Override
public DataCollectorBuilder setSessionTag(String sessionTimestamp) {
dataModel.setSessionTag(sessionTimestamp);
return this;
}
@Override
public DataCollectorBuilder setDatabase(TikTokDatabase database)
{
this.database =database;
return this;
}
@Override
public DataCollectorBuilder configureLiveClient(Consumer<LiveClientBuilder> consumer) {
dataModel.setOnConfigureLiveClient(consumer);
return this;
}
@Override
public DataCollector buildAndRun() {
var collector = build();
collector.connect();
return collector;
}
@Override
public DataCollector build() {
if (dataModel.getSessionTag().isEmpty()) {
dataModel.setSessionTag(UUID.randomUUID().toString());
}
if(database == null)
{
database = new TikTokDatabase(dataModel.getOutputName());
}
var dataCollector = new TikTokDataCollector(dataModel, database);
return dataCollector;
}
}

View File

@@ -1,99 +0,0 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.tools.collector.client;
import io.github.jwdeveloper.tiktok.TikTokLiveClientBuilder;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
import io.github.jwdeveloper.tiktok.tools.collector.db.TikTokDatabase;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class TikTokMessagessCollectorBuilder {
List<String> users;
String outputFileName;
List<Class<?>> filters;
Consumer<LiveClientBuilder> onBuilder;
List<LiveClient> tiktokclients;
MessageCollector messageCollector;
public TikTokMessagessCollectorBuilder(String outputName) {
users = new ArrayList<>();
outputFileName = outputName;
filters = new ArrayList<>();
onBuilder = (e) -> {
};
tiktokclients = new ArrayList<>();
messageCollector = new MessageCollector(outputName);
}
public TikTokMessagessCollectorBuilder(MessageCollector messageCollector, String outputFileName) {
this(outputFileName);
this.messageCollector = messageCollector;
}
public TikTokMessagessCollectorBuilder setOutputName(String name) {
outputFileName = name;
return this;
}
public TikTokMessagessCollectorBuilder addOnBuilder(Consumer<LiveClientBuilder> consumer) {
onBuilder = consumer;
return this;
}
public TikTokMessagessCollectorBuilder addUser(String user) {
users.add(user);
return this;
}
public TikTokMessagessCollectorBuilder addEventFilter(Class<?> event) {
filters.add(event);
return this;
}
public MessageCollector buildAndRun() throws SQLException {
var db = new TikTokDatabase(outputFileName);
db.init();
var factory = new TikTokClientFactory(messageCollector, db);
for (var user : users) {
var client = factory.runClientAsync(user,filters, onBuilder);
client.thenAccept(liveClient ->
{
tiktokclients.add(liveClient);
});
}
return messageCollector;
}
public void stop() {
for (var client : tiktokclients) {
client.disconnect();
}
}
}

View File

@@ -1,92 +0,0 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.tools.collector.db;
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokErrorModel;
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokMessageModel;
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokResponseModel;
import org.jdbi.v3.core.Jdbi;
import org.jdbi.v3.sqlobject.SqlObjectPlugin;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
public class TikTokDatabase {
private final String database;
private TikTokMessageModelDAO messagesTable;
private TikTokErrorModelDAO errorTable;
private TikTokResponseModelDAO responseTable;
public TikTokDatabase(String database) {
this.database = database;
}
public void init() throws SQLException {
var jdbcUrl = "jdbc:sqlite:" + database + ".db";
DriverManager.getConnection(jdbcUrl);
var jdbi = Jdbi.create(jdbcUrl)
.installPlugin(new SqlObjectPlugin());
jdbi.useHandle(handle -> {
handle.execute(SqlConsts.CREATE_MESSAGES_TABLE);
handle.execute(SqlConsts.CREATE_ERROR_TABLE);
handle.execute(SqlConsts.CREATE_RESPONSE_MODEL);
});
messagesTable = jdbi.onDemand(TikTokMessageModelDAO.class);
errorTable = jdbi.onDemand(TikTokErrorModelDAO.class);
responseTable = jdbi.onDemand(TikTokResponseModelDAO.class);
}
public void insertMessage(TikTokMessageModel message) {
message.setCreatedAt(getTime());
messagesTable.insertTikTokMessage(message);
}
public void insertError(TikTokErrorModel message) {
message.setCreatedAt(getTime());
errorTable.insertTikTokMessage(message);
}
public void insertResponse(TikTokResponseModel message) {
message.setCreatedAt(getTime());
responseTable.insert(message);
}
public List<TikTokErrorModel> selectErrors() {
return errorTable.selectErrors();
}
public List<TikTokMessageModel> selectMessages() {
return messagesTable.select();
}
public List<TikTokResponseModel> selectResponces() {
return responseTable.select();
}
private String getTime() {
return new SimpleDateFormat("dd:MM:yyyy HH:mm:ss.SSS").format(new Date());
}
}

View File

@@ -1,43 +0,0 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.tools.collector.db;
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokErrorModel;
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokMessageModel;
import org.jdbi.v3.sqlobject.config.RegisterBeanMapper;
import org.jdbi.v3.sqlobject.customizer.BindBean;
import org.jdbi.v3.sqlobject.statement.SqlQuery;
import org.jdbi.v3.sqlobject.statement.SqlUpdate;
import java.util.List;
@RegisterBeanMapper(TikTokMessageModel.class)
public interface TikTokMessageModelDAO
{
@SqlUpdate("INSERT INTO TikTokMessageModel (hostName, eventName,type, eventContent, createdAt) " +
"VALUES (:hostName, :eventName, :type, :eventContent, :createdAt)")
void insertTikTokMessage(@BindBean TikTokMessageModel message);
@SqlQuery("SELECT * FROM TikTokMessageModel")
List<TikTokMessageModel> select();
}

View File

@@ -20,17 +20,19 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.tools.collector.db;
package io.github.jwdeveloper.tiktok.tools.db;
public class SqlConsts
{
public static String CREATE_MESSAGES_TABLE = """
CREATE TABLE IF NOT EXISTS TikTokMessageModel (
public static String CREATE_DATA_TABLE = """
CREATE TABLE IF NOT EXISTS TikTokData (
id INTEGER PRIMARY KEY AUTOINCREMENT,
hostName TEXT,
type TEXT,
eventName TEXT,
eventContent TEXT,
sessionTag TEXT,
tiktokUser TEXT,
dataType TEXT,
dataTypeName TEXT,
content TEXT,
createdAt TEXT
);
""";

View File

@@ -0,0 +1,77 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.tools.db;
import io.github.jwdeveloper.tiktok.tools.db.tables.TikTokDataTable;
import org.jdbi.v3.sqlobject.config.RegisterBeanMapper;
import org.jdbi.v3.sqlobject.customizer.Bind;
import org.jdbi.v3.sqlobject.customizer.BindBean;
import org.jdbi.v3.sqlobject.statement.SqlQuery;
import org.jdbi.v3.sqlobject.statement.SqlUpdate;
import java.util.List;
import java.util.Map;
@RegisterBeanMapper(TikTokDataTable.class)
public interface TikTokDataTableDAO {
String query = """
INSERT INTO TikTokData (sessionTag, tiktokUser, dataType, dataTypeName, content, createdAt) VALUES (:sessionTag, :tiktokUser, :dataType, :dataTypeName, :content, :createdAt)
""";
@SqlUpdate(query)
void insertData(@BindBean TikTokDataTable data);
@SqlQuery("SELECT * FROM TikTokData WHERE sessionTag = :sessionTag")
List<TikTokDataTable> selectBySession(@Bind("sessionTag") String sessionTag);
@SqlQuery("SELECT * FROM TikTokData WHERE dataType = :dataType AND sessionTag = :sessionTag AND tiktokUser = :tiktokUser")
List<TikTokDataTable> selectSessionData(@Bind("dataType") String dataType,
@Bind("sessionTag") String sessionTag,
@Bind("tiktokUser") String user);
@SqlQuery("SELECT * FROM TikTokData WHERE sessionTag = :sessionTag AND tiktokUser = :tiktokUser AND dataType = \"response\"")
List<TikTokDataTable> selectResponces(@Bind("sessionTag") String sessionTag, @Bind("tiktokUser") String user);
@SqlQuery("SELECT * FROM TikTokData WHERE sessionTag = :sessionTag AND tiktokUser = :tiktokUser AND dataType = \"event\"")
List<TikTokDataTable> selectBySessionEvents(@Bind("sessionTag") String sessionTag, @Bind("tiktokUser") String userName);
@SqlQuery("SELECT * FROM TikTokData WHERE sessionTag = :sessionTag AND tiktokUser = :tiktokUser AND dataType = \"message\"")
List<TikTokDataTable> selectBySessionMessages(@Bind("sessionTag") String sessionTag, @Bind("tiktokUser") String userName);
@SqlQuery("SELECT tiktokUser FROM TikTokData GROUP BY tiktokUser")
List<String> getUsers();
@SqlQuery("SELECT sessionTag FROM TikTokData WHERE tiktokUser = :tiktokUser GROUP BY sessionTag")
List<String> getSessionTagByUser(@Bind("tiktokUser") String tiktokUser);
String groupByDataTypeNameQuery = """
SELECT dataTypeName, COUNT(*) as count
FROM TikTokData
WHERE dataType = 'message' AND sessionTag = :sessionTag AND tiktokUser = :userName
GROUP BY dataTypeName
""";
}

View File

@@ -0,0 +1,138 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.tools.db;
import io.github.jwdeveloper.tiktok.tools.db.tables.TikTokDataTable;
import io.github.jwdeveloper.tiktok.tools.db.tables.TikTokErrorModel;
import lombok.Getter;
import org.jdbi.v3.core.Jdbi;
import org.jdbi.v3.sqlobject.SqlObjectPlugin;
import org.sqlite.SQLiteConfig;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class TikTokDatabase {
private final String database;
private TikTokErrorModelDAO errorTable;
@Getter
private TikTokDataTableDAO dataTableDAO;
private Connection connection;
public TikTokDatabase(String database) {
this.database = database;
}
public boolean isConnected()
{
return connection != null;
}
public void connect() throws SQLException {
var jdbcUrl = "jdbc:sqlite:" + database + ".db";
var config = new SQLiteConfig();
config.setEncoding(SQLiteConfig.Encoding.UTF8);
connection = DriverManager.getConnection(jdbcUrl, config.toProperties());
var jdbi = Jdbi.create(jdbcUrl).installPlugin(new SqlObjectPlugin());
jdbi.useHandle(handle -> {
handle.execute(SqlConsts.CREATE_DATA_TABLE);
handle.execute(SqlConsts.CREATE_ERROR_TABLE);
});
dataTableDAO = jdbi.onDemand(TikTokDataTableDAO.class);
errorTable = jdbi.onDemand(TikTokErrorModelDAO.class);
}
public void close() throws SQLException {
connection.close();
}
public void insertData(TikTokDataTable tikTokDataTable) {
tikTokDataTable.setCreatedAt(getTime());
dataTableDAO.insertData(tikTokDataTable);
}
public List<TikTokDataTable> getSessionResponces(String sessionTag, String userName) {
return dataTableDAO.selectResponces(sessionTag, userName);
}
public List<String> getDataNames(String dataType, String sessionTag, String userName) {
try {
var sb = new StringBuilder();
sb.append("""
SELECT dataTypeName, COUNT(*) as count
FROM TikTokData
""");
sb.append(" WHERE dataType = \""+dataType+"\" ");
sb.append(" AND tiktokUser = \"" + userName + "\" ");
sb.append(" AND sessionTag = \"" + sessionTag + "\" ");
sb.append("GROUP BY dataTypeName");
var statement = connection.prepareStatement(sb.toString());
var resultSet = statement.executeQuery();
List<String> dataTypeCounts = new ArrayList<>();
while (resultSet.next()) {
var dataTypeName = resultSet.getString("dataTypeName");
dataTypeCounts.add(dataTypeName);
}
resultSet.close();
statement.close();
return dataTypeCounts;
} catch (Exception e) {
e.printStackTrace();
return List.of("error");
}
}
public List<TikTokDataTable> getSessionMessages(String sessionTag, String userName, int count) {
return dataTableDAO.selectBySessionMessages(sessionTag, userName);
}
public void insertError(TikTokErrorModel message) {
message.setCreatedAt(getTime());
errorTable.insertTikTokMessage(message);
}
public List<TikTokErrorModel> selectErrors() {
return errorTable.selectErrors();
}
private String getTime() {
return new SimpleDateFormat("dd:MM:yyyy HH:mm:ss.SSS").format(new Date());
}
}

View File

@@ -20,9 +20,9 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.tools.collector.db;
package io.github.jwdeveloper.tiktok.tools.db;
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokErrorModel;
import io.github.jwdeveloper.tiktok.tools.db.tables.TikTokErrorModel;
import org.jdbi.v3.sqlobject.config.RegisterBeanMapper;
import org.jdbi.v3.sqlobject.customizer.BindBean;

View File

@@ -20,7 +20,7 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.tools.collector.tables;
package io.github.jwdeveloper.tiktok.tools.db.tables;
import java.io.PrintWriter;
import java.io.StringWriter;

View File

@@ -20,23 +20,24 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.tools.collector.tables;
package io.github.jwdeveloper.tiktok.tools.db.tables;
import lombok.Data;
@Data
public class TikTokMessageModel
public class TikTokDataTable
{
private Integer id;
private String hostName;
private String sessionTag;
private String eventName;
private String tiktokUser;
private String type;
private String dataType;
private String message;
private String dataTypeName;
private String content;
private String createdAt;
}

View File

@@ -20,7 +20,7 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.tools.collector.tables;
package io.github.jwdeveloper.tiktok.tools.db.tables;
import lombok.Data;

View File

@@ -1,77 +0,0 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.tools.tester;
import com.google.protobuf.ByteString;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import io.github.jwdeveloper.tiktok.mockClient.TikTokClientMock;
import io.github.jwdeveloper.tiktok.tools.collector.db.TikTokDatabase;
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokResponseModel;
import io.github.jwdeveloper.tiktok.tools.util.MessageUtil;
import io.github.jwdeveloper.tiktok.utils.ConsoleColors;
import io.github.jwdeveloper.tiktok.utils.JsonUtil;
import java.util.logging.ConsoleHandler;
import java.util.logging.Formatter;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
public class RunDbTester {
public static void main(String[] args) throws Exception {
var db = new TikTokDatabase("test");
db.init();
var responses = db.selectResponces().stream().map(TikTokResponseModel::getResponse).toList();
var client = TikTokClientMock
.create()
.addResponses(responses)
.onWebsocketUnhandledMessage((liveClient, event) ->
{
var sb = new StringBuilder();
sb.append("Unhandled Message! " );
sb.append(event.getData().getMethod());
sb.append(MessageUtil.getContent(event.getData()));
liveClient.getLogger().info(sb.toString());
})
.onWebsocketMessage((liveClient, event) ->
{
var sb = new StringBuilder();
sb.append(event.getEvent().getClass().getSimpleName());
sb.append(event.getEvent().toJson());
liveClient.getLogger().fine(sb.toString());
})
.build();
client.connect();
}
}

View File

@@ -23,8 +23,8 @@
package io.github.jwdeveloper.tiktok.tools.tester;
import com.google.gson.JsonParser;
import io.github.jwdeveloper.tiktok.mockClient.TikTokClientMock;
import io.github.jwdeveloper.tiktok.mockClient.mocks.LiveClientMock;
import io.github.jwdeveloper.tiktok.tools.tester.mockClient.TikTokLiveMock;
import io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks.LiveClientMock;
import io.github.jwdeveloper.tiktok.tools.util.MessageUtil;
import java.io.FileReader;
@@ -37,7 +37,7 @@ public class RunJsonTester {
public static void main(String[] args) throws IOException {
var messages = getMessages();
var client =(LiveClientMock) TikTokClientMock.create()
var client =(LiveClientMock) TikTokLiveMock.create()
.onWebsocketUnhandledMessage((liveClient, event) ->
{
var sb = new StringBuilder();

View File

@@ -0,0 +1,90 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.tools.tester;
import io.github.jwdeveloper.tiktok.tools.db.TikTokDatabase;
import io.github.jwdeveloper.tiktok.tools.db.tables.TikTokDataTable;
import io.github.jwdeveloper.tiktok.tools.tester.api.DataTester;
import io.github.jwdeveloper.tiktok.tools.tester.api.DataTesterModel;
import io.github.jwdeveloper.tiktok.tools.tester.mockClient.TikTokLiveMock;
import io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks.LiveClientMock;
import java.util.LinkedList;
import java.util.Queue;
public class TikTokDataTester implements DataTester {
private DataTesterModel model;
private LiveClientMock client;
private Queue<TikTokDataTable> data;
private TikTokDatabase database;
public TikTokDataTester(DataTesterModel model) {
this.model = model;
}
@Override
public void connect() {
try {
database = new TikTokDatabase(model.getDatabaseName());
database.connect();
var mockBuilder = TikTokLiveMock.create();
model.getBuilderConsumer().accept(mockBuilder);
client = mockBuilder.build();
var respocnes = database.getSessionResponces(model.getSessionTag(), model.getUser());
data = new LinkedList<>(respocnes);
client.connect();
while (!data.isEmpty()) {
nextResponse();
}
} catch (Exception e) {
throw new RuntimeException("Error while running tester", e);
}
}
@Override
public void nextResponse() {
try {
var responce = data.poll();
client.publishResponse(responce.getContent());
Thread.sleep(1);
} catch (Exception e) {
throw new RuntimeException("Unable to run response!");
}
}
@Override
public void disconnect() {
try {
client.disconnect();
database.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.tools.tester;
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
import io.github.jwdeveloper.tiktok.tools.tester.api.DataTester;
import io.github.jwdeveloper.tiktok.tools.tester.api.DataTesterBuilder;
import io.github.jwdeveloper.tiktok.tools.tester.api.DataTesterModel;
import java.util.function.Consumer;
public class TikTokDataTesterBuilder implements DataTesterBuilder {
private final DataTesterModel model;
public TikTokDataTesterBuilder(String databaseName) {
this.model = new DataTesterModel();
this.model.setDatabaseName(databaseName);
}
@Override
public DataTesterBuilder setSessionTag(String sessionTag) {
model.setSessionTag(sessionTag);
return this;
}
@Override
public DataTesterBuilder setUser(String user) {
model.setUser(user);
return this;
}
@Override
public DataTesterBuilder configureLiveClient(Consumer<LiveClientBuilder> builderConsumer) {
model.setBuilderConsumer(builderConsumer);
return this;
}
@Override
public DataTester build() {
return new TikTokDataTester(model);
}
@Override
public DataTester buildAndRun()
{
var tester = build();
tester.connect();
return tester;
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.tools.tester.api;
public interface DataTester
{
void connect();
void nextResponse();
void disconnect();
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.tools.tester.api;
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
import java.util.function.Consumer;
public interface DataTesterBuilder {
DataTesterBuilder setSessionTag(String sessionTag);
DataTesterBuilder setUser(String user);
DataTesterBuilder configureLiveClient(Consumer<LiveClientBuilder> builderConsumer);
DataTester build();
DataTester buildAndRun();
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.tools.tester.api;
import io.github.jwdeveloper.tiktok.live.builder.LiveClientBuilder;
import lombok.Data;
import java.util.function.Consumer;
@Data
public class DataTesterModel {
String databaseName;
String sessionTag;
String user;
Consumer<LiveClientBuilder> builderConsumer = (a) -> {
};
}

View File

@@ -20,17 +20,17 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.tools.collector.client;
package io.github.jwdeveloper.tiktok.tools.tester.mockClient;
public class TikTokMessageCollectorClient
public class TikTokLiveMock
{
public static TikTokMessagessCollectorBuilder create(String outputName)
public static TikTokMockBuilder create(String host)
{
return new TikTokMessagessCollectorBuilder(outputName);
return new TikTokMockBuilder(host);
}
public static TikTokMessagessCollectorBuilder create(MessageCollector messageCollector, String outputName)
public static TikTokMockBuilder create()
{
return new TikTokMessagessCollectorBuilder(messageCollector,outputName);
return create("MockHostName");
}
}

View File

@@ -0,0 +1,119 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.tools.tester.mockClient;
import io.github.jwdeveloper.tiktok.TikTokLiveClientBuilder;
import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandler;
import io.github.jwdeveloper.tiktok.http.TikTokCookieJar;
import io.github.jwdeveloper.tiktok.http.TikTokHttpClient;
import io.github.jwdeveloper.tiktok.http.TikTokHttpRequestFactory;
import io.github.jwdeveloper.tiktok.listener.TikTokListenersManager;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks.ApiServiceMock;
import io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks.LiveClientMock;
import io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks.WebsocketClientMock;
import java.util.Base64;
import java.util.List;
import java.util.Stack;
public class TikTokMockBuilder extends TikTokLiveClientBuilder {
Stack<WebcastResponse> responses;
public TikTokMockBuilder(String userName) {
super(userName);
responses = new Stack<>();
}
public TikTokMockBuilder addResponse(String value) {
var bytes = Base64.getDecoder().decode(value);
return addResponse(bytes);
}
public TikTokMockBuilder addResponses(List<String> values) {
for (var value : values) {
try {
addResponse(value);
} catch (Exception e) {
throw new TikTokLiveException(value, e);
}
}
return this;
}
public TikTokMockBuilder addResponse(byte[] bytes) {
try {
var response = WebcastResponse.parseFrom(bytes);
return addResponse(response);
} catch (Exception e) {
throw new RuntimeException("Unable to parse response from bytes", e);
}
}
public TikTokMockBuilder addResponse(WebcastResponse message) {
responses.push(message);
return this;
}
@Override
public LiveClientMock build() {
validate();
var cookie = new TikTokCookieJar();
var tiktokRoomInfo = new TikTokRoomInfo();
tiktokRoomInfo.setHostName(clientSettings.getHostName());
var listenerManager = new TikTokListenersManager(listeners, tikTokEventHandler);
var giftManager = new TikTokGiftManager(logger);
var requestFactory = new TikTokHttpRequestFactory(cookie, new TikTokEventObserver());
var apiClient = new TikTokHttpClient(cookie, requestFactory);
var apiService = new ApiServiceMock(apiClient, logger, clientSettings);
var mapper = createMapper(giftManager, tiktokRoomInfo);
var handler = new TikTokMessageHandler(tikTokEventHandler, mapper);
var webSocketClient = new WebsocketClientMock(logger, responses, handler);
return new LiveClientMock(tiktokRoomInfo,
apiService,
webSocketClient,
giftManager,
tikTokEventHandler,
clientSettings,
listenerManager,
logger);
}
@Override
public LiveClientMock buildAndConnect() {
var client = build();
client.connect();
return client;
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks;
import io.github.jwdeveloper.tiktok.ClientSettings;
import io.github.jwdeveloper.tiktok.http.TikTokApiService;
import io.github.jwdeveloper.tiktok.http.TikTokHttpClient;
import io.github.jwdeveloper.tiktok.live.LiveRoomMeta;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import java.util.logging.Logger;
public class ApiServiceMock extends TikTokApiService {
public ApiServiceMock(TikTokHttpClient apiClient, Logger logger, ClientSettings clientSettings) {
super(apiClient, logger, clientSettings);
}
@Override
public void updateSessionId() {
}
@Override
public LiveRoomMeta fetchRoomInfo()
{
var meta = new LiveRoomMeta();
meta.setStatus(LiveRoomMeta.LiveRoomStatus.HostOnline);
return meta;
}
@Override
public WebcastResponse fetchClientData() {
return WebcastResponse.newBuilder().build();
}
@Override
public String fetchRoomId(String userName) {
return "mock-room-id";
}
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks;
import io.github.jwdeveloper.tiktok.ClientSettings;
import io.github.jwdeveloper.tiktok.TikTokLiveClient;
import io.github.jwdeveloper.tiktok.TikTokRoomInfo;
import io.github.jwdeveloper.tiktok.gifts.TikTokGiftManager;
import io.github.jwdeveloper.tiktok.handlers.TikTokEventObserver;
import io.github.jwdeveloper.tiktok.http.TikTokApiService;
import io.github.jwdeveloper.tiktok.listener.TikTokListenersManager;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import java.util.logging.Logger;
public class LiveClientMock extends TikTokLiveClient {
private final WebsocketClientMock websocketClientMock;
public LiveClientMock(TikTokRoomInfo tikTokLiveMeta,
TikTokApiService tikTokApiService,
WebsocketClientMock webSocketClient,
TikTokGiftManager tikTokGiftManager,
TikTokEventObserver tikTokEventHandler,
ClientSettings clientSettings,
TikTokListenersManager listenersManager,
Logger logger) {
super(tikTokLiveMeta,
tikTokApiService,
webSocketClient,
tikTokGiftManager,
tikTokEventHandler,
clientSettings,
listenersManager,
logger);
this.websocketClientMock = webSocketClient;
websocketClientMock.setClient(this);
}
public void publishMessage(String type, String base64) {
websocketClientMock.addMessage(type, base64);
}
public void publishMessage(Class<?> clazz, String base64) {
websocketClientMock.addMessage(clazz.getSimpleName(), base64);
}
public void publishResponse(String value) {
websocketClientMock.addResponse(value);
}
public void publishResponse(byte[] bytes) {
websocketClientMock.addResponse(bytes);
}
public void publishResponse(WebcastResponse message) {
websocketClientMock.addResponse(message);
}
}

View File

@@ -0,0 +1,121 @@
/*
* Copyright (c) 2023-2023 jwdeveloper jacekwoln@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.jwdeveloper.tiktok.tools.tester.mockClient.mocks;
import com.google.protobuf.ByteString;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveException;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageException;
import io.github.jwdeveloper.tiktok.handlers.TikTokMessageHandler;
import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import io.github.jwdeveloper.tiktok.websocket.SocketClient;
import lombok.Value;
import java.util.Base64;
import java.util.Stack;
import java.util.logging.Logger;
public class WebsocketClientMock implements SocketClient {
Logger logger;
Stack<WebcastResponse> responses;
Stack<MsgStruct> messages;
TikTokMessageHandler messageHandler;
LiveClient client;
Thread thread;
private boolean isRunning;
public void setClient(LiveClientMock liveClientMock) {
this.client = liveClientMock;
}
@Value
public static class MsgStruct {
String messageType;
byte[] messageValue;
}
public WebsocketClientMock(Logger logger, Stack<WebcastResponse> responses, TikTokMessageHandler messageHandler) {
this.logger = logger;
this.responses = responses;
this.messageHandler = messageHandler;
messages = new Stack<>();
}
public WebsocketClientMock addMessage(String type, String value) {
var bytes = Base64.getDecoder().decode(value);
messages.push(new MsgStruct(type, bytes));
return this;
}
public WebsocketClientMock addResponse(String value) {
var bytes = Base64.getDecoder().decode(value);
return addResponse(bytes);
}
public WebsocketClientMock addResponse(byte[] bytes) {
try {
var response = WebcastResponse.parseFrom(bytes);
return addResponse(response);
} catch (Exception e) {
throw new RuntimeException("Unable to parse response from bytes", e);
}
}
public WebsocketClientMock addResponse(WebcastResponse message) {
responses.push(message);
return this;
}
@Override
public void start(WebcastResponse webcastResponse, LiveClient tikTokLiveClient) {
logger.info("Running message: " + responses.size());
thread = new Thread(() ->
{
while (isRunning)
{
while (!responses.isEmpty()) {
var response = responses.pop();
messageHandler.handle(client, response);
}
}
});
isRunning = true;
thread.start();
}
@Override
public void stop() {
isRunning = false;
thread.interrupt();
}
}

View File

@@ -42,16 +42,16 @@ public class MessageUtil {
}
}
public static String getContent(String methodName, byte[] bytes) {
public static String getContent(String messageName, byte[] bytes) {
try {
var inputClazz = Class.forName("io.github.jwdeveloper.tiktok.messages.webcast." + methodName);
var inputClazz = Class.forName("io.github.jwdeveloper.tiktok.messages.webcast." + messageName);
var parseMethod = inputClazz.getDeclaredMethod("parseFrom", byte[].class);
var deserialized = parseMethod.invoke(null, bytes);
return JsonUtil.messageToJson(deserialized);
} catch (Exception ex) {
var sb = new StringBuilder();
sb.append("Can not find protocolbuffer file message representation for " + methodName);
sb.append("Can not find protocol-buffer file message representation for " + messageName);
sb.append("\n");
var structure = ProtocolUtils.getProtocolBufferStructure(bytes);
var json =structure.toJson();

File diff suppressed because one or more lines are too long