Compare commits

..

6 Commits

Author SHA1 Message Date
JW
eea691a5aa - implementing publishing messages 2024-03-01 02:20:11 +01:00
Jacek W
a249ac0cdd Merge pull request #62 from jwdeveloper/develop-1.5.0-messages-to-file
Develop 1.5.0 messages to file
2024-03-01 01:53:21 +01:00
JW
b82c7184b3 Removed unused projects. 2024-03-01 01:52:54 +01:00
kohlerpop1
d3004d76c1 Merge remote-tracking branch 'origin/develop-1.5.0' into develop-1.5.0/messages-to-file 2024-02-28 12:27:05 -05:00
kohlerpop1
3ae73072ff Working on collecting to files! 2024-02-28 12:24:34 -05:00
Jacek W
9c5f97157a Merge pull request #61 from jwdeveloper/develop-1.5.0-remove-old-stuff
Develop 1.5.0 remove old stuff
2024-02-28 16:45:49 +01:00
16 changed files with 307 additions and 163 deletions

View File

@@ -59,9 +59,16 @@ public interface LiveClient {
/** /**
* Use to manually invoke event * Use to manually invoke event
*/ */
void publishEvent(TikTokEvent event); void publishEvent(TikTokEvent event);
void publishMessage(String base64);
/**
* @param webcastMessageName name of TikTok protocol-buffer message
* @param payloadBase64 protocol-buffer message bytes payload
*/
void publishMessage(String webcastMessageName, String payloadBase64);
void publishMessage(String webcastMessageName, byte[] payload);
/** /**
* Get information about gifts * Get information about gifts

View File

@@ -22,6 +22,7 @@
*/ */
package io.github.jwdeveloper.tiktok; package io.github.jwdeveloper.tiktok;
import com.google.protobuf.ByteString;
import io.github.jwdeveloper.tiktok.data.events.TikTokDisconnectedEvent; import io.github.jwdeveloper.tiktok.data.events.TikTokDisconnectedEvent;
import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent; import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent;
import io.github.jwdeveloper.tiktok.data.events.TikTokReconnectingEvent; import io.github.jwdeveloper.tiktok.data.events.TikTokReconnectingEvent;
@@ -39,10 +40,12 @@ import io.github.jwdeveloper.tiktok.listener.TikTokListenersManager;
import io.github.jwdeveloper.tiktok.live.GiftsManager; import io.github.jwdeveloper.tiktok.live.GiftsManager;
import io.github.jwdeveloper.tiktok.live.LiveClient; import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.live.LiveRoomInfo; import io.github.jwdeveloper.tiktok.live.LiveRoomInfo;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import io.github.jwdeveloper.tiktok.models.ConnectionState; import io.github.jwdeveloper.tiktok.models.ConnectionState;
import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings; import io.github.jwdeveloper.tiktok.data.settings.LiveClientSettings;
import io.github.jwdeveloper.tiktok.websocket.SocketClient; import io.github.jwdeveloper.tiktok.websocket.SocketClient;
import java.util.Base64;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.logging.Logger; import java.util.logging.Logger;
@@ -56,15 +59,19 @@ public class TikTokLiveClient implements LiveClient {
private final TikTokListenersManager listenersManager; private final TikTokListenersManager listenersManager;
private final Logger logger; private final Logger logger;
private final GiftsManager giftsManager; private final GiftsManager giftsManager;
private final TikTokLiveMessageHandler messageHandler;
public TikTokLiveClient(GiftsManager giftsManager, public TikTokLiveClient(
TikTokRoomInfo tikTokLiveMeta, TikTokLiveMessageHandler messageHandler,
LiveHttpClient tiktokHttpClient, GiftsManager giftsManager,
SocketClient webSocketClient, TikTokRoomInfo tikTokLiveMeta,
TikTokLiveEventHandler tikTokEventHandler, LiveHttpClient tiktokHttpClient,
LiveClientSettings clientSettings, SocketClient webSocketClient,
TikTokListenersManager listenersManager, TikTokLiveEventHandler tikTokEventHandler,
Logger logger) { LiveClientSettings clientSettings,
TikTokListenersManager listenersManager,
Logger logger) {
this.messageHandler = messageHandler;
this.giftsManager = giftsManager; this.giftsManager = giftsManager;
this.liveRoomInfo = tikTokLiveMeta; this.liveRoomInfo = tikTokLiveMeta;
this.httpClient = tiktokHttpClient; this.httpClient = tiktokHttpClient;
@@ -184,6 +191,20 @@ public class TikTokLiveClient implements LiveClient {
tikTokEventHandler.publish(this, event); tikTokEventHandler.publish(this, event);
} }
@Override
public void publishMessage(String webcastMessageName, String payloadBase64) {
this.publishMessage(webcastMessageName, Base64.getDecoder().decode(payloadBase64));
}
@Override
public void publishMessage(String webcastMessageName, byte[] payload) {
var builder = WebcastResponse.Message.newBuilder();
builder.setMethod(webcastMessageName);
builder.setPayload(ByteString.copyFrom(payload));
var message = builder.build();
messageHandler.handleSingleMessage(this, message);
}
@Override @Override
public GiftsManager getGiftManager() { public GiftsManager getGiftManager() {
return giftsManager; return giftsManager;

View File

@@ -129,6 +129,7 @@ public class TikTokLiveClientBuilder implements LiveClientBuilder {
eventHandler); eventHandler);
return new TikTokLiveClient( return new TikTokLiveClient(
messageHandler,
giftsManager, giftsManager,
tiktokRoomInfo, tiktokRoomInfo,
liveHttpClient, liveHttpClient,

View File

@@ -40,12 +40,11 @@ public class CollectorExample {
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {
var collector = TikTokLiveCollector.use(settings -> var collector = TikTokLiveCollector.useMongo(settings ->
{ {
settings.setConnectionUrl("mongodb+srv://" + mongoUser + ":" + mongoPassword + "@" + mongoDatabase + "/?retryWrites=true&w=majority"); settings.setConnectionUrl("mongodb+srv://" + mongoUser + ":" + mongoPassword + "@" + mongoDatabase + "/?retryWrites=true&w=majority");
settings.setDatabaseName("tiktok");
}); });
collector.connectDatabase(); collector.connect();
var users = List.of("tehila_723", "dino123597", "domaxyzx", "dash4214", "obserwacje_live"); var users = List.of("tehila_723", "dino123597", "domaxyzx", "dash4214", "obserwacje_live");
Map<String, Object> additionalDataFields = Map.of("sessionTag", "ExampleTag"); Map<String, Object> additionalDataFields = Map.of("sessionTag", "ExampleTag");
@@ -71,6 +70,6 @@ public class CollectorExample {
} }
System.in.read(); System.in.read();
collector.disconnectDatabase(); collector.disconnect();
} }
} }

View File

@@ -1,7 +1,6 @@
package io.github.jwdeveloper.tiktok; package io.github.jwdeveloper.tiktok;
import io.github.jwdeveloper.tiktok.data.events.TikTokCommentEvent; import io.github.jwdeveloper.tiktok.data.events.TikTokCommentEvent;
import io.github.jwdeveloper.tiktok.data.events.TikTokSubNotifyEvent;
import io.github.jwdeveloper.tiktok.data.events.TikTokSubscribeEvent; import io.github.jwdeveloper.tiktok.data.events.TikTokSubscribeEvent;
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftComboEvent; import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftComboEvent;
import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent; import io.github.jwdeveloper.tiktok.data.events.gift.TikTokGiftEvent;
@@ -11,7 +10,9 @@ import io.github.jwdeveloper.tiktok.data.events.social.TikTokLikeEvent;
import io.github.jwdeveloper.tiktok.data.models.gifts.GiftComboStateType; import io.github.jwdeveloper.tiktok.data.models.gifts.GiftComboStateType;
import io.github.jwdeveloper.tiktok.live.LiveClient; import io.github.jwdeveloper.tiktok.live.LiveClient;
public class Events_And_Gifts_Testing_Example { public class Events_And_Gifts_Testing_Example
{
public static void main(String[] args) { public static void main(String[] args) {
LiveClient client = TikTokLive.newClient(ConnectionExample.TIKTOK_HOSTNAME) LiveClient client = TikTokLive.newClient(ConnectionExample.TIKTOK_HOSTNAME)
.configure(liveClientSettings -> .configure(liveClientSettings ->
@@ -35,6 +36,10 @@ public class Events_And_Gifts_Testing_Example {
{ {
liveClient.getLogger().info("New fake Gift: " + event.getGift()); liveClient.getLogger().info("New fake Gift: " + event.getGift());
}) })
.onLike((liveClient, event) ->
{
liveClient.getLogger().info("New fake Like event: " + event.getLikes());
})
.build(); .build();
var gifts = TikTokLive.gifts(); var gifts = TikTokLive.gifts();
@@ -57,11 +62,13 @@ public class Events_And_Gifts_Testing_Example {
client.publishEvent(fakeMessage); client.publishEvent(fakeMessage);
client.publishEvent(fakeSubscriber); client.publishEvent(fakeSubscriber);
client.publishEvent(fakeFollow); client.publishEvent(fakeFollow);
client.publishEvent(fakeLike);
client.publishEvent(fakeJoin); client.publishEvent(fakeJoin);
client.publishEvent(fakeLike);
client.publishMessage("WebcastLikeMessage", webcastLikeMessageBase64);
client.disconnect(); client.disconnect();
} }
private static final String webcastLikeMessageBase64 = "SAFSBRABGKwCUgcIAhABGKwCCv8BUAFYAbABA7gBARCflqWWo8Ha72UgzoPZhd8xQrwBGg4gkAMKCSNmZmZmZmZmZiJ/qgF6CngIhYjjgPWJv7RgGhDwnZKm8J2TjvCdk47wk4WTsgIKa3lsbGVlaGFsbPICTE1TNHdMakFCQUFBQXUyX21LNEw4WGJYa3lNaUFvZzJUTnNmVjk5N09WM2tpQ3NCTkNjYWkwcWxIcUt0Q3B0UGU1N2RLYVhxb0xWSXoICwoQcG1fbXRfbXNnX3ZpZXdlchIXezA6dXNlcn0gbGlrZWQgdGhlIExJVkVIAQoSV2ViY2FzdExpa2VNZXNzYWdlGIaWvY+RhdjvZTABwAEBEA8Y+Voq7RCyAQYImwEQjwK6AQCCAgDyAkxNUzR3TGpBQkFBQUF1Ml9tSzRMOFhiWGt5TWlBb2cyVE5zZlY5OTdPVjNraUNzQk5DY2FpMHFsSHFLdENwdFBlNTdkS2FYcW9MVkl6ggTqCLoBnwUqBggBEAEYIFoNCgASCSNCMzQ3N0VGRoABDwgEEtgEEix3ZWJjYXN0LXZhL2dyYWRlX2JhZGdlX2ljb25fbGl0ZV9sdjE1X3YyLnBuZzrpAnNzbG9jYWw6Ly93ZWJjYXN0X2x5bnh2aWV3X3BvcHVwP3VzZV9zcGFyaz0xJnVybD1odHRwcyUzQSUyRiUyRmxmMTYtZ2Vja28tc291cmNlLnRpa3Rva2Nkbi5jb20lMkZvYmolMkZieXRlLWd1cmQtc291cmNlLXNnJTJGdGlrdG9rJTJGZmUlMkZsaXZlJTJGdGlrdG9rX2xpdmVfcmV2ZW51ZV91c2VyX2xldmVsX21haW4lMkZzcmMlMkZwYWdlcyUyRnByaXZpbGVnZSUyRnBhbmVsJTJGdGVtcGxhdGUuanMmaGlkZV9zdGF0dXNfYmFyPTAmaGlkZV9uYXZfYmFyPTEmY29udGFpbmVyX2JnX2NvbG9yPTAwMDAwMDAwJmhlaWdodD05MCUyNSZiZGhtX2JpZD10aWt0b2tfbGl2ZV9yZXZlbnVlX3VzZXJfbGV2ZWxfbWFpbiZ1c2VfZm9yZXN0PTEKXWh0dHBzOi8vcDE2LXdlYmNhc3QudGlrdG9rY2RuLmNvbS93ZWJjYXN0LXZhL2dyYWRlX2JhZGdlX2ljb25fbGl0ZV9sdjE1X3YyLnBuZ350cGx2LW9iai5pbWFnZQpdaHR0cHM6Ly9wMTktd2ViY2FzdC50aWt0b2tjZG4uY29tL3dlYmNhc3QtdmEvZ3JhZGVfYmFkZ2VfaWNvbl9saXRlX2x2MTVfdjIucG5nfnRwbHYtb2JqLmltYWdlIgIxNTIAOgYaAhIAIgBiDQoAEgkjQjM0NzdFRkZ4DqIBBggBEAEYIAgEEBQYCCABUukCc3Nsb2NhbDovL3dlYmNhc3RfbHlueHZpZXdfcG9wdXA/dXNlX3NwYXJrPTEmdXJsPWh0dHBzJTNBJTJGJTJGbGYxNi1nZWNrby1zb3VyY2UudGlrdG9rY2RuLmNvbSUyRm9iaiUyRmJ5dGUtZ3VyZC1zb3VyY2Utc2clMkZ0aWt0b2slMkZmZSUyRmxpdmUlMkZ0aWt0b2tfbGl2ZV9yZXZlbnVlX3VzZXJfbGV2ZWxfbWFpbiUyRnNyYyUyRnBhZ2VzJTJGcHJpdmlsZWdlJTJGcGFuZWwlMkZ0ZW1wbGF0ZS5qcyZoaWRlX3N0YXR1c19iYXI9MCZoaWRlX25hdl9iYXI9MSZjb250YWluZXJfYmdfY29sb3I9MDAwMDAwMDAmaGVpZ2h0PTkwJTI1JmJkaG1fYmlkPXRpa3Rva19saXZlX3JldmVudWVfdXNlcl9sZXZlbF9tYWluJnVzZV9mb3Jlc3Q9MVgBYk8qAjE1CgEyEhM3MTM4MzgxNzQ3MjkyNTQyNzU2GgEwIi5tb2NrX2ZpeF93aWR0aF90cmFuc3BhcmVudF83MTM4MzgxNzQ3MjkyNTQyNzU2CIWI44D1ib+0YBoQ8J2SpvCdk47wnZOO8JOFk0r1BhJBMTAweDEwMC90b3MtdXNlYXN0OC1hdnQtMDA2OC10eDIvNjY0NmM4NjZjMzI1MWEwOTY3NjhiYjY4OTUyODVjMzEK0gFodHRwczovL3AxOS1wdS1zaWduLXVzZWFzdDgudGlrdG9rY2RuLXVzLmNvbS90b3MtdXNlYXN0OC1hdnQtMDA2OC10eDIvNjY0NmM4NjZjMzI1MWEwOTY3NjhiYjY4OTUyODVjMzF+dHBsdi10aWt0b2stc2hyaW5rOjcyOjcyLndlYnA/bGszcz1hNWQ0ODA3OCZ4LWV4cGlyZXM9MTcwOTMxMjQwMCZ4LXNpZ25hdHVyZT1VMlNEbUk3Z3R5RW9rMlBlWFdmeTNsM1F6NlElM0QKyAFodHRwczovL3AxNi1wdS1zaWduLXVzZWFzdDgudGlrdG9rY2RuLXVzLmNvbS90b3MtdXNlYXN0OC1hdnQtMDA2OC10eDIvNjY0NmM4NjZjMzI1MWEwOTY3NjhiYjY4OTUyODVjMzF+YzVfMTAweDEwMC53ZWJwP2xrM3M9YTVkNDgwNzgmeC1leHBpcmVzPTE3MDkzMTI0MDAmeC1zaWduYXR1cmU9aWNWZEVZa0FnWkYlMkZ2WU5OTSUyRlVNMzE2eG9HdyUzRArGAWh0dHBzOi8vcDE5LXB1LXNpZ24tdXNlYXN0OC50aWt0b2tjZG4tdXMuY29tL3Rvcy11c2Vhc3Q4LWF2dC0wMDY4LXR4Mi82NjQ2Yzg2NmMzMjUxYTA5Njc2OGJiNjg5NTI4NWMzMX5jNV8xMDB4MTAwLndlYnA/bGszcz1hNWQ0ODA3OCZ4LWV4cGlyZXM9MTcwOTMxMjQwMCZ4LXNpZ25hdHVyZT1PQzdBQ3htQUklMkJsYlp4RkVuWktJT1RyRExGUSUzRArGAWh0dHBzOi8vcDE2LXB1LXNpZ24tdXNlYXN0OC50aWt0b2tjZG4tdXMuY29tL3Rvcy11c2Vhc3Q4LWF2dC0wMDY4LXR4Mi82NjQ2Yzg2NmMzMjUxYTA5Njc2OGJiNjg5NTI4NWMzMX5jNV8xMDB4MTAwLmpwZWc/bGszcz1hNWQ0ODA3OCZ4LWV4cGlyZXM9MTcwOTMxMjQwMCZ4LXNpZ25hdHVyZT02YUwlMkZNZWtOeHg5NXlvVTVLOTZON0xwRUlNdyUzRLICCmt5bGxlZWhhbGxCyQEIgojG1pKb0clgErwBChBwbV9tdF9tc2dfdmlld2VyEhd7MDp1c2VyfSBsaWtlZCB0aGUgTElWRRoOCgkjZmZmZmZmZmYgkAMifwgLqgF6CngIhYjjgPWJv7RgGhDwnZKm8J2TjvCdk47wk4WTsgIKa3lsbGVlaGFsbPICTE1TNHdMakFCQUFBQXUyX21LNEw4WGJYa3lNaUFvZzJUTnNmVjk5N09WM2tpQ3NCTkNjYWkwcWxIcUt0Q3B0UGU1N2RLYVhxb0xWSXo=";
} }

View File

@@ -22,19 +22,34 @@
*/ */
package io.github.jwdeveloper.tiktok.extension.collector; package io.github.jwdeveloper.tiktok.extension.collector;
import io.github.jwdeveloper.tiktok.extension.collector.api.LiveDataCollector; import io.github.jwdeveloper.tiktok.extension.collector.api.settings.FileDataCollectorSettings;
import io.github.jwdeveloper.tiktok.extension.collector.api.data.LiveDataCollectorSettings; import io.github.jwdeveloper.tiktok.extension.collector.api.settings.mongo.MongoDataCollectorSettings;
import io.github.jwdeveloper.tiktok.extension.collector.impl.TikTokLiveDataCollector; import io.github.jwdeveloper.tiktok.extension.collector.impl.*;
import io.github.jwdeveloper.tiktok.extension.collector.impl.storages.FileStorage;
import io.github.jwdeveloper.tiktok.extension.collector.impl.storages.MongoStorage;
import java.util.function.Consumer; import java.util.function.Consumer;
/**
*
*/
public class TikTokLiveCollector public class TikTokLiveCollector
{ {
public static TikTokLiveDataCollector use(Consumer<LiveDataCollectorSettings> consumer) public static DataCollector useMongo(Consumer<MongoDataCollectorSettings> consumer) {
{ var settings = new MongoDataCollectorSettings();
var settings = new LiveDataCollectorSettings();
consumer.accept(settings); consumer.accept(settings);
return new TikTokLiveDataCollector(settings);
var storage = new MongoStorage(settings);
return new DataCollector(storage);
} }
}
public static DataCollector useFile(Consumer<FileDataCollectorSettings> consumer) {
var settings = new FileDataCollectorSettings();
consumer.accept(settings);
var storage = new FileStorage(settings);
return new DataCollector(storage);
}
}

View File

@@ -0,0 +1,11 @@
package io.github.jwdeveloper.tiktok.extension.collector.api;
import org.bson.Document;
public interface Storage {
void connect();
void disconnect();
void insert(Document document);
}

View File

@@ -1,4 +1,4 @@
package io.github.jwdeveloper.tiktok.extension.collector.api.data; package io.github.jwdeveloper.tiktok.extension.collector.api.settings;
import lombok.Data; import lombok.Data;
import org.bson.Document; import org.bson.Document;
@@ -10,4 +10,4 @@ import java.util.function.Function;
public class CollectorListenerSettings { public class CollectorListenerSettings {
private Map<String, Object> extraFields; private Map<String, Object> extraFields;
private Function<Document, Boolean> filter; private Function<Document, Boolean> filter;
} }

View File

@@ -0,0 +1,33 @@
/*
* 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.extension.collector.api.settings;
import lombok.Data;
import java.io.File;
@Data
public class FileDataCollectorSettings {
private File parentFile;
}

View File

@@ -20,36 +20,21 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
package io.github.jwdeveloper.tiktok.extension.collector.api.data; package io.github.jwdeveloper.tiktok.extension.collector.api.settings.mongo;
import lombok.Setter;
import lombok.experimental.Accessors;
@Setter
@Accessors(chain = true)
public class MongoDBConnectionStringBuilder { public class MongoDBConnectionStringBuilder {
private String username; private String username;
private String password; private String password;
private String database; private String database;
private String cluster; private String cluster;
public MongoDBConnectionStringBuilder setUsername(String username) {
this.username = username;
return this;
}
public MongoDBConnectionStringBuilder setPassword(String password) {
this.password = password;
return this;
}
public MongoDBConnectionStringBuilder setDatabase(String database) {
this.database = database;
return this;
}
public MongoDBConnectionStringBuilder setCluster(String cluster) {
this.cluster = cluster;
return this;
}
public String build() { public String build() {
return String.format("mongodb+srv://%s:%s@%s/%s?retryWrites=true&w=majority", return String.format("mongodb+srv://%s:%s@%s/%s?retryWrites=true&w=majority",
username, password, cluster, database); username, password, cluster, database);
} }
} }

View File

@@ -20,29 +20,25 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
package io.github.jwdeveloper.tiktok.extension.collector.api.data; package io.github.jwdeveloper.tiktok.extension.collector.api.settings.mongo;
import lombok.Data; import lombok.*;
import java.util.function.Consumer; import java.util.function.Consumer;
@Data @Data
public class LiveDataCollectorSettings { public class MongoDataCollectorSettings {
@Setter
private String connectionUrl; private String connectionUrl;
private String databaseName; private String databaseName = "tiktok";
private String sessionTag; private String collectionName = "data";
public void connectionBuilder(Consumer<MongoDBConnectionStringBuilder> consumer) {
public void setConnectionUrl(String connectionUrl) {
this.connectionUrl = connectionUrl;
}
public void setConnectionUrl(Consumer<MongoDBConnectionStringBuilder> consumer) {
var builder = new MongoDBConnectionStringBuilder(); var builder = new MongoDBConnectionStringBuilder();
consumer.accept(builder); consumer.accept(builder);
connectionUrl = builder.build(); connectionUrl = builder.build();
} }
} }

View File

@@ -0,0 +1,62 @@
/*
* 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.extension.collector.impl;
import io.github.jwdeveloper.tiktok.extension.collector.api.Storage;
import io.github.jwdeveloper.tiktok.extension.collector.api.settings.CollectorListenerSettings;
import org.bson.Document;
import java.util.Map;
import java.util.function.Function;
public class DataCollector {
private final Storage storage;
public DataCollector(Storage storage) {
this.storage = storage;
}
public void connect() {
storage.connect();
}
public void disconnect() {
storage.disconnect();
}
public DataCollectorListener newListener() {
return newListener(Map.of());
}
public DataCollectorListener newListener(Map<String, Object> additionalFields) {
return newListener(additionalFields, (e) -> true);
}
public DataCollectorListener newListener(Map<String, Object> additionalFields,
Function<Document, Boolean> filter) {
var settings = new CollectorListenerSettings();
settings.setExtraFields(additionalFields);
settings.setFilter(filter);
return new DataCollectorListener(storage, settings);
}
}

View File

@@ -1,6 +1,5 @@
package io.github.jwdeveloper.tiktok.extension.collector.impl; package io.github.jwdeveloper.tiktok.extension.collector.impl;
import com.mongodb.client.MongoCollection;
import io.github.jwdeveloper.tiktok.annotations.TikTokEventObserver; import io.github.jwdeveloper.tiktok.annotations.TikTokEventObserver;
import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent; import io.github.jwdeveloper.tiktok.data.events.TikTokErrorEvent;
import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent; import io.github.jwdeveloper.tiktok.data.events.common.TikTokEvent;
@@ -8,7 +7,8 @@ import io.github.jwdeveloper.tiktok.data.events.control.TikTokConnectingEvent;
import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketResponseEvent; import io.github.jwdeveloper.tiktok.data.events.websocket.TikTokWebsocketResponseEvent;
import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageException; import io.github.jwdeveloper.tiktok.exceptions.TikTokLiveMessageException;
import io.github.jwdeveloper.tiktok.extension.collector.api.LiveDataCollector; import io.github.jwdeveloper.tiktok.extension.collector.api.LiveDataCollector;
import io.github.jwdeveloper.tiktok.extension.collector.api.data.CollectorListenerSettings; import io.github.jwdeveloper.tiktok.extension.collector.api.Storage;
import io.github.jwdeveloper.tiktok.extension.collector.api.settings.CollectorListenerSettings;
import io.github.jwdeveloper.tiktok.live.LiveClient; import io.github.jwdeveloper.tiktok.live.LiveClient;
import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse; import io.github.jwdeveloper.tiktok.messages.webcast.WebcastResponse;
import io.github.jwdeveloper.tiktok.utils.JsonUtil; import io.github.jwdeveloper.tiktok.utils.JsonUtil;
@@ -19,15 +19,15 @@ import java.io.StringWriter;
import java.util.Base64; import java.util.Base64;
import java.util.UUID; import java.util.UUID;
public class TikTokLiveDataCollectorListener implements LiveDataCollector { public class DataCollectorListener implements LiveDataCollector {
private final MongoCollection<Document> collection; private final Storage storage;
private final CollectorListenerSettings settings; private final CollectorListenerSettings settings;
private String sessionId; private String sessionId;
private String userName; private String userName;
public TikTokLiveDataCollectorListener(MongoCollection<Document> collection, CollectorListenerSettings settings) { public DataCollectorListener(Storage collection, CollectorListenerSettings settings) {
this.collection = collection; this.storage = collection;
this.settings = settings; this.settings = settings;
} }
@@ -35,10 +35,7 @@ public class TikTokLiveDataCollectorListener implements LiveDataCollector {
@TikTokEventObserver @TikTokEventObserver
private void onResponse(LiveClient liveClient, TikTokWebsocketResponseEvent event) { private void onResponse(LiveClient liveClient, TikTokWebsocketResponseEvent event) {
includeResponse(liveClient, event.getResponse()); includeResponse(liveClient, event.getResponse());
event.getResponse().getMessagesList().forEach(message -> event.getResponse().getMessagesList().forEach(message -> includeMessage(liveClient, message));
{
includeMessage(liveClient, message);
});
} }
@TikTokEventObserver @TikTokEventObserver
@@ -103,7 +100,7 @@ public class TikTokLiveDataCollectorListener implements LiveDataCollector {
if (!settings.getFilter().apply(document)) { if (!settings.getFilter().apply(document)) {
return; return;
} }
collection.insertOne(document); storage.insert(document);
} }
@@ -119,4 +116,4 @@ public class TikTokLiveDataCollectorListener implements LiveDataCollector {
doc.append("content", content); doc.append("content", content);
return doc; return doc;
} }
} }

View File

@@ -1,89 +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.extension.collector.impl;
import com.mongodb.ConnectionString;
import com.mongodb.MongoClientSettings;
import com.mongodb.ServerApi;
import com.mongodb.ServerApiVersion;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Indexes;
import io.github.jwdeveloper.tiktok.extension.collector.api.data.CollectorListenerSettings;
import io.github.jwdeveloper.tiktok.extension.collector.api.data.LiveDataCollectorSettings;
import org.bson.Document;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.Function;
public class TikTokLiveDataCollector {
private final LiveDataCollectorSettings settings;
private MongoClient mongoClient;
private MongoDatabase database;
private MongoCollection<Document> collection;
public TikTokLiveDataCollector(LiveDataCollectorSettings settings) {
this.settings = settings;
}
public void connectDatabase() {
var serverApi = ServerApi.builder()
.version(ServerApiVersion.V1)
.build();
var mongoSettings = MongoClientSettings.builder()
.applyConnectionString(new ConnectionString(settings.getConnectionUrl()))
.serverApi(serverApi)
.build();
mongoClient = MongoClients.create(mongoSettings);
database = mongoClient.getDatabase(settings.getDatabaseName());
collection = database.getCollection("data");
collection.createIndex(Indexes.hashed("session"));
collection.createIndex(Indexes.hashed("dataType"));
}
public void disconnectDatabase() {
mongoClient.close();
}
public TikTokLiveDataCollectorListener newListener() {
return newListener(Map.of());
}
public TikTokLiveDataCollectorListener newListener(Map<String, Object> additionalFields) {
return newListener(additionalFields, (e)->true);
}
public TikTokLiveDataCollectorListener newListener(Map<String, Object> additionalFields,
Function<Document, Boolean> filter) {
var settings = new CollectorListenerSettings();
settings.setExtraFields(additionalFields);
settings.setFilter(filter);
return new TikTokLiveDataCollectorListener(collection, settings);
}
}

View File

@@ -0,0 +1,41 @@
package io.github.jwdeveloper.tiktok.extension.collector.impl.storages;
import io.github.jwdeveloper.tiktok.extension.collector.api.Storage;
import io.github.jwdeveloper.tiktok.extension.collector.api.settings.FileDataCollectorSettings;
import org.bson.Document;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
public class FileStorage implements Storage {
private final FileDataCollectorSettings settings;
public FileStorage(FileDataCollectorSettings fileDataCollectorSettings) {
this.settings = fileDataCollectorSettings;
}
@Override
public void connect() {
}
@Override
public void disconnect() {
}
@Override
public void insert(Document document) {
var fileName = document.get("dataType") + ":" + document.get("dataTypeName") + ".json";
try {
var file = new File(settings.getParentFile(), fileName);
file.createNewFile();
Files.writeString(file.toPath(), document.toJson(), StandardOpenOption.APPEND);
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,58 @@
package io.github.jwdeveloper.tiktok.extension.collector.impl.storages;
import com.mongodb.ConnectionString;
import com.mongodb.MongoClientSettings;
import com.mongodb.ServerApi;
import com.mongodb.ServerApiVersion;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Indexes;
import io.github.jwdeveloper.tiktok.extension.collector.api.Storage;
import io.github.jwdeveloper.tiktok.extension.collector.api.settings.mongo.MongoDataCollectorSettings;
import org.bson.Document;
public class MongoStorage implements Storage {
private MongoClient mongoClient;
private MongoDatabase database;
private MongoCollection<Document> collection;
private final MongoDataCollectorSettings settings;
public MongoStorage(MongoDataCollectorSettings settings) {
this.settings = settings;
}
@Override
public void connect() {
var serverApi = ServerApi.builder()
.version(ServerApiVersion.V1)
.build();
var mongoSettings = MongoClientSettings.builder()
.applyConnectionString(new ConnectionString(settings.getConnectionUrl()))
.serverApi(serverApi)
.build();
mongoClient = MongoClients.create(mongoSettings);
database = mongoClient.getDatabase(settings.getDatabaseName());
collection = database.getCollection(settings.getCollectionName());
collection.createIndex(Indexes.hashed("session"));
collection.createIndex(Indexes.hashed("dataType"));
}
@Override
public void disconnect() {
if (mongoClient == null) {
return;
}
mongoClient.close();
}
@Override
public void insert(Document document) {
collection.insertOne(document);
}
}