- New event `onSuccessResponseMapping`
  triggered when Webcast.Message was  successfully mapped to TikTokEvent

- New Project Tools-collector:
  Tool generates instance of SqlLite
  database and collect to it both to
 events and exceptions occurred while TikTokLive client was running
This commit is contained in:
Jacek Wolniewicz
2023-08-30 21:47:45 +02:00
parent 483dceadcf
commit 384cfade5a
17 changed files with 403 additions and 10 deletions

81
.gitignore vendored
View File

@@ -1,3 +1,82 @@
# Project exclude paths
/API/target/
/Client/target/
/Client/target/
*.db
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# AWS User-specific
.idea/**/aws.xml
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# SonarLint plugin
.idea/sonarlint/
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser

View File

@@ -1,8 +1,6 @@
package io.github.jwdeveloper.tiktok.events;
import io.github.jwdeveloper.tiktok.events.messages.*;
import java.util.function.Consumer;
public interface TikTokEventBuilder<T> {
@@ -89,6 +87,9 @@ public interface TikTokEventBuilder<T> {
T onUnhandledControl(TikTokEventConsumer<TikTokUnhandledControlEvent> event);
T onEvent(TikTokEventConsumer<TikTokEvent> event);
T onSuccessResponseMapping(TikTokEventConsumer<TikTokSuccessResponseMappingEvent> event);
}

View File

@@ -21,13 +21,18 @@ public class TikTokLiveMessageException extends TikTokLiveException {
this.webcastResponse = webcastResponse;
}
public void messageToBase64()
public String messageName()
{
var decoded = Base64.getEncoder().encodeToString(webcastMessage.getBinary().toByteArray());
return webcastMessage.getType();
}
public void webcastResponseToBase64()
public String messageToBase64()
{
var decoded = Base64.getEncoder().encodeToString(webcastResponse.toByteArray());
return Base64.getEncoder().encodeToString(webcastMessage.getBinary().toByteArray());
}
public String webcastResponseToBase64()
{
return Base64.getEncoder().encodeToString(webcastResponse.toByteArray());
}
}

View File

@@ -317,6 +317,12 @@ public class TikTokLiveClientBuilder implements TikTokEventBuilder<TikTokLiveCli
tikTokEventHandler.subscribe(TikTokEvent.class, event);
return this;
}
@Override
public TikTokLiveClientBuilder onSuccessResponseMapping(TikTokEventConsumer<TikTokSuccessResponseMappingEvent> event) {
tikTokEventHandler.subscribe(TikTokSuccessResponseMappingEvent.class, event);
return this;
}
}

View File

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

View File

@@ -33,8 +33,8 @@ public class TikTokMessageHandlerRegistration extends TikTokMessageHandler {
public void init() {
//ConnectionEvents events
register(WebcastControlMessage.class, TikTokRoomMessageEvent.class);
register(SystemMessage.class, this::handleWebcastControlMessage);
register(WebcastControlMessage.class, this::handleWebcastControlMessage);
register(SystemMessage.class,TikTokRoomMessageEvent.class);
//Room status events

View File

@@ -7,7 +7,7 @@ import java.io.IOException;
public class Main {
public static String TEST_TIKTOK_USER = "kitovskyyy";
public static String TEST_TIKTOK_USER = "polonezgarage";
public static void main(String[] args) throws IOException {
var client = TikTokLive.newClient(TEST_TIKTOK_USER)

View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>TikTokLiveJava</artifactId>
<groupId>io.github.jwdeveloper.tiktok</groupId>
<version>0.0.14-Release</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>Tools-EventsCollector</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.34.0</version> <!-- Use the latest version available -->
</dependency>
<dependency>
<groupId>org.jdbi</groupId>
<artifactId>jdbi3-core</artifactId>
<version>3.23.0</version>
</dependency>
<dependency>
<groupId>org.jdbi</groupId>
<artifactId>jdbi3-sqlobject</artifactId>
<version>3.23.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.32</version> <!-- Use the latest version available -->
</dependency>
<dependency>
<groupId>io.github.jwdeveloper.tiktok</groupId>
<artifactId>Client</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,65 @@
package io.github.jwdeveloper.tiktok.tools.collector;
import io.github.jwdeveloper.tiktok.TikTokLive;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageException;
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 java.sql.SQLException;
import java.util.Base64;
public class Main {
public static void main(String[] args) throws SQLException {
var tiktokUser = "mr_cios";
var db = new TikTokDatabase("test");
db.init();
TikTokLive.newClient(tiktokUser)
.onWebcastResponseDebug((liveClient, event) ->
{
var eventName = event.getEvent().getClass().getSimpleName();
var binary = Base64.getEncoder().encodeToString(event.getMessage().getBinary().toByteArray());
var model = TikTokMessageModel.builder()
.type("message")
.hostName(tiktokUser)
.eventName(eventName)
.eventContent(binary)
.build();
db.insertMessage(model);
System.out.println("EVENT: " + eventName);
})
.onError((liveClient, event) ->
{
var exception = event.getException();
var exceptionContent = ExceptionInfoModel.getStackTraceAsString(exception);
var builder = TikTokErrorModel.builder();
if (exception instanceof TikTokLiveMessageException ex) {
builder.hostName(tiktokUser)
.errorName(ex.messageName())
.errorType("error-message")
.exceptionContent(exceptionContent)
.message(ex.messageToBase64())
.response(ex.webcastResponseToBase64());
} else {
builder.hostName(tiktokUser)
.errorName(exception.getClass().getSimpleName())
.errorType("error-system")
.exceptionContent(exceptionContent)
.message("")
.response("");
}
var error = builder.build();
db.insertError(error);
System.out.println("ERROR: "+error.getErrorName());
exception.printStackTrace();
})
.buildAndRun();
}
}

View File

@@ -0,0 +1,29 @@
package io.github.jwdeveloper.tiktok.tools.collector.db;
public class SqlConsts
{
public static String CREATE_MESSAGES_TABLE = """
CREATE TABLE IF NOT EXISTS TikTokMessageModel (
id INTEGER PRIMARY KEY AUTOINCREMENT,
hostName TEXT,
type TEXT,
eventName TEXT,
eventContent TEXT,
createdAt TEXT
);
""";
public static String CREATE_ERROR_TABLE = """
CREATE TABLE IF NOT EXISTS TikTokErrorModel (
id INT AUTO_INCREMENT PRIMARY KEY,
hostName VARCHAR(255),
errorName VARCHAR(255),
errorType VARCHAR(255),
exceptionContent TEXT,
message TEXT,
response TEXT,
createdAt DATETIME
);
""";
}

View File

@@ -0,0 +1,50 @@
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.core.Jdbi;
import org.jdbi.v3.sqlobject.SqlObjectPlugin;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class TikTokDatabase
{
private final String database;
private TikTokMessageModelDAO messagesTable;
private TikTokErrorModelDAO errorTable;
public TikTokDatabase(String database) {
this.database =database;
}
public void init() throws SQLException {
var jdbcUrl ="jdbc:sqlite:"+database+".db";
var connection = DriverManager.getConnection(jdbcUrl);
Jdbi jdbi = Jdbi.create(jdbcUrl)
.installPlugin(new SqlObjectPlugin());
jdbi.useHandle(handle -> {
handle.execute(SqlConsts.CREATE_MESSAGES_TABLE);
handle.execute(SqlConsts.CREATE_ERROR_TABLE);
});
messagesTable = jdbi.onDemand(TikTokMessageModelDAO.class);
errorTable = jdbi.onDemand(TikTokErrorModelDAO.class);
}
public void insertMessage(TikTokMessageModel message)
{
var dateFormat = new SimpleDateFormat("dd:MM:yyyy HH:mm:ss.SSS");
message.setCreatedAt(dateFormat.format(new Date()));
messagesTable.insertTikTokMessage(message);
}
public void insertError(TikTokErrorModel message)
{
var dateFormat = new SimpleDateFormat("dd:MM:yyyy HH:mm:ss.SSS");
message.setCreatedAt(dateFormat.format(new Date()));
errorTable.insertTikTokMessage(message);
}
}

View File

@@ -0,0 +1,13 @@
package io.github.jwdeveloper.tiktok.tools.collector.db;
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokErrorModel;
import org.jdbi.v3.sqlobject.customizer.BindBean;
import org.jdbi.v3.sqlobject.statement.SqlUpdate;
public interface TikTokErrorModelDAO
{
@SqlUpdate("INSERT INTO TikTokErrorModel (hostName, errorName, errorType, exceptionContent, message, response, createdAt) " +
"VALUES (:hostName, :errorName, :errorType, :exceptionContent, :message, :response, :createdAt)")
void insertTikTokMessage(@BindBean TikTokErrorModel message);
}

View File

@@ -0,0 +1,12 @@
package io.github.jwdeveloper.tiktok.tools.collector.db;
import io.github.jwdeveloper.tiktok.tools.collector.tables.TikTokMessageModel;
import org.jdbi.v3.sqlobject.customizer.BindBean;
import org.jdbi.v3.sqlobject.statement.SqlUpdate;
public interface TikTokMessageModelDAO
{
@SqlUpdate("INSERT INTO TikTokMessageModel (hostName, eventName,type, eventContent, createdAt) " +
"VALUES (:hostName, :eventName, :type, :eventContent, :createdAt)")
void insertTikTokMessage(@BindBean TikTokMessageModel message);
}

View File

@@ -0,0 +1,31 @@
package io.github.jwdeveloper.tiktok.tools.collector.tables;
import java.io.PrintWriter;
import java.io.StringWriter;
public class ExceptionInfoModel
{
private String message;
private String stackTrace;
public ExceptionInfoModel(Throwable throwable) {
this.message = throwable.getMessage();
this.stackTrace = getStackTraceAsString(throwable);
}
public static String getStackTraceAsString(Throwable throwable) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
throwable.printStackTrace(pw);
return sw.toString();
}
// Getters for message and stackTrace
public String getMessage() {
return message;
}
public String getStackTrace() {
return stackTrace;
}
}

View File

@@ -0,0 +1,25 @@
package io.github.jwdeveloper.tiktok.tools.collector.tables;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class TikTokErrorModel
{
private Integer id;
private String hostName;
private String errorName;
private String errorType;
private String exceptionContent;
private String message;
private String response;
private String createdAt;
}

View File

@@ -0,0 +1,24 @@
package io.github.jwdeveloper.tiktok.tools.collector.tables;
import lombok.Builder;
import lombok.Data;
import java.util.Date;
@Data
@Builder
public class TikTokMessageModel
{
private Integer id;
private String hostName;
private String eventName;
private String type;
private String eventContent;
private String createdAt;
}

View File

@@ -13,6 +13,7 @@
<module>Client</module>
<module>Tools</module>
<module>TestApplication</module>
<module>Tools-EventsCollector</module>
</modules>
<properties>