Add web-api module with OpenAPI integration, enable chat logs forwarding to web backend, and update dependencies across modules.
This commit is contained in:
parent
dc513ac2f0
commit
5a508fdf28
|
|
@ -3,6 +3,9 @@ plugins {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation(project(":web-api")) // Web-API
|
||||||
|
compileOnly("org.projectlombok:lombok:1.18.46")
|
||||||
|
annotationProcessor("org.projectlombok:lombok:1.18.46")
|
||||||
// Cosmos
|
// Cosmos
|
||||||
compileOnly("com.alttd.cosmos:cosmos-api:1.21.8-R0.1-SNAPSHOT") {
|
compileOnly("com.alttd.cosmos:cosmos-api:1.21.8-R0.1-SNAPSHOT") {
|
||||||
isChanging = true
|
isChanging = true
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
package com.alttd.chat.objects.chat_log;
|
package com.alttd.chat.objects.chat_log;
|
||||||
|
|
||||||
|
import com.alttd.altitudeweb.model.ChatMessageDto;
|
||||||
import com.alttd.chat.objects.BatchInsertable;
|
import com.alttd.chat.objects.BatchInsertable;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
@ -11,24 +14,21 @@ import java.sql.Timestamp;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
public class ChatLog implements BatchInsertable {
|
public class ChatLog implements BatchInsertable {
|
||||||
|
|
||||||
|
@Getter
|
||||||
private final UUID uuid;
|
private final UUID uuid;
|
||||||
|
@Getter
|
||||||
private final Instant timestamp;
|
private final Instant timestamp;
|
||||||
private final String server;
|
private final String server;
|
||||||
|
@Getter
|
||||||
private final String message;
|
private final String message;
|
||||||
|
@Getter
|
||||||
private final Component miniMessage;
|
private final Component miniMessage;
|
||||||
|
@Getter
|
||||||
private final boolean blocked;
|
private final boolean blocked;
|
||||||
|
|
||||||
protected ChatLog(UUID uuid, Instant timestamp, String server, String message, Component miniMessage, boolean blocked) {
|
|
||||||
this.uuid = uuid;
|
|
||||||
this.timestamp = timestamp;
|
|
||||||
this.server = server;
|
|
||||||
this.message = message;
|
|
||||||
this.miniMessage = miniMessage;
|
|
||||||
this.blocked = blocked;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void prepareStatement(@NotNull PreparedStatement preparedStatement) throws SQLException {
|
public void prepareStatement(@NotNull PreparedStatement preparedStatement) throws SQLException {
|
||||||
preparedStatement.setString(1, uuid.toString());
|
preparedStatement.setString(1, uuid.toString());
|
||||||
|
|
@ -41,19 +41,17 @@ public class ChatLog implements BatchInsertable {
|
||||||
preparedStatement.setInt(6, blocked ? 1 : 0);
|
preparedStatement.setInt(6, blocked ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public UUID getUuid() {
|
public ChatMessageDto toDto() {
|
||||||
return uuid;
|
ChatMessageDto chatMessageDto = new ChatMessageDto();
|
||||||
|
if (miniMessage == null) {
|
||||||
|
throw new IllegalArgumentException("MiniMessage cannot be null");
|
||||||
}
|
}
|
||||||
|
chatMessageDto.setMessage(GsonComponentSerializer.gson().serialize(miniMessage));
|
||||||
public Instant getTimestamp() {
|
chatMessageDto.setChannel(ChatMessageDto.ChannelEnum.CHAT);
|
||||||
return timestamp;
|
chatMessageDto.setServer(server);
|
||||||
}
|
chatMessageDto.setTimestamp(timestamp);
|
||||||
|
chatMessageDto.setUuid(uuid);
|
||||||
public String getMessage() {
|
chatMessageDto.setBlocked(blocked);
|
||||||
return message;
|
return chatMessageDto;
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isBlocked() {
|
|
||||||
return blocked;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import java.util.concurrent.*;
|
||||||
|
|
||||||
public class ChatLogHandler {
|
public class ChatLogHandler {
|
||||||
|
|
||||||
|
private final ChatLogWebHandler chatLogWebHandler = new ChatLogWebHandler();
|
||||||
private static ChatLogHandler instance = null;
|
private static ChatLogHandler instance = null;
|
||||||
private ScheduledExecutorService executorService = null;
|
private ScheduledExecutorService executorService = null;
|
||||||
|
|
||||||
|
|
@ -123,7 +124,9 @@ public class ChatLogHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addChatLog(UUID uuid, String server, String message, Component miniMessage, boolean blocked) {
|
public void addChatLog(UUID uuid, String server, String message, Component miniMessage, boolean blocked) {
|
||||||
addLog(new ChatLog(uuid, Instant.now(), server, message, miniMessage, blocked));
|
ChatLog chatLog = new ChatLog(uuid, Instant.now(), server, message, miniMessage, blocked);
|
||||||
|
addLog(chatLog);
|
||||||
|
chatLogWebHandler.forwardChatLogToWeb(chatLog);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompletableFuture<List<ChatLog>> retrieveChatLogs(UUID uuid, Duration duration, String server) {
|
public CompletableFuture<List<ChatLog>> retrieveChatLogs(UUID uuid, Duration duration, String server) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
package com.alttd.chat.objects.chat_log;
|
||||||
|
|
||||||
|
import com.alttd.altitudeweb.api.ChatApi;
|
||||||
|
import com.alttd.altitudeweb.invoker.ApiClient;
|
||||||
|
import com.alttd.altitudeweb.invoker.ApiException;
|
||||||
|
import com.alttd.altitudeweb.model.ChatMessageDto;
|
||||||
|
import com.alttd.chat.util.ALogger;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Queue;
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
public class ChatLogWebHandler {
|
||||||
|
|
||||||
|
private static final int MAX_QUEUE_SIZE = 100;
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(ChatLogWebHandler.class);
|
||||||
|
|
||||||
|
private final Queue<ChatLog> queue = new ConcurrentLinkedQueue<>();
|
||||||
|
private final ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||||
|
|
||||||
|
private final ChatApi chatApi;
|
||||||
|
|
||||||
|
public ChatLogWebHandler() {
|
||||||
|
ApiClient apiClient = new ApiClient();
|
||||||
|
apiClient.setBasePath("http://10.0.0.109");
|
||||||
|
|
||||||
|
chatApi = new ChatApi(apiClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
private volatile boolean sending;
|
||||||
|
|
||||||
|
public void forwardChatLogToWeb(ChatLog chatLog) {
|
||||||
|
if (queue.size() >= MAX_QUEUE_SIZE) {
|
||||||
|
queue.clear();
|
||||||
|
log.error("Chat log queue overflow, is the web backend still running?");
|
||||||
|
}
|
||||||
|
|
||||||
|
queue.add(chatLog);
|
||||||
|
triggerSend();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void triggerSend() {
|
||||||
|
if (sending) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized (this) {
|
||||||
|
if (sending || queue.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sending = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
executor.execute(this::sendBatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendBatch() {
|
||||||
|
try {
|
||||||
|
ArrayList<ChatLog> chatLogList = new ArrayList<>();
|
||||||
|
|
||||||
|
ChatLog log;
|
||||||
|
while ((log = queue.poll()) != null) {
|
||||||
|
if (log.getMiniMessage() == null) {
|
||||||
|
ALogger.warn("No mini message for message, skipping");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
chatLogList.add(log);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ChatMessageDto> batch = chatLogList.stream().map(ChatLog::toDto).toList();
|
||||||
|
|
||||||
|
if (!chatLogList.isEmpty()) {
|
||||||
|
try {
|
||||||
|
chatApi.sendChatMessages(batch);
|
||||||
|
} catch (ApiException e) {
|
||||||
|
ALogger.error("Failed to send chat messages to web backend, " +
|
||||||
|
"adding messages back to queue for another try", e
|
||||||
|
);
|
||||||
|
queue.addAll(chatLogList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
synchronized (this) {
|
||||||
|
sending = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerSend();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,6 +11,8 @@ dependencies {
|
||||||
compileOnly("com.alttd.cosmos:cosmos-api:1.21.8-R0.1-SNAPSHOT") {
|
compileOnly("com.alttd.cosmos:cosmos-api:1.21.8-R0.1-SNAPSHOT") {
|
||||||
isChanging = true
|
isChanging = true
|
||||||
}
|
}
|
||||||
|
compileOnly("org.projectlombok:lombok:1.18.46")
|
||||||
|
annotationProcessor("org.projectlombok:lombok:1.18.46")
|
||||||
compileOnly("com.gitlab.ruany:LiteBansAPI:0.6.1") // move to proxy
|
compileOnly("com.gitlab.ruany:LiteBansAPI:0.6.1") // move to proxy
|
||||||
compileOnly("org.apache.commons:commons-lang3:3.17.0") // needs an alternative, already removed from upstream api and will be removed in server
|
compileOnly("org.apache.commons:commons-lang3:3.17.0") // needs an alternative, already removed from upstream api and will be removed in server
|
||||||
compileOnly("net.luckperms:api:5.5") // Luckperms
|
compileOnly("net.luckperms:api:5.5") // Luckperms
|
||||||
|
|
|
||||||
|
|
@ -35,3 +35,5 @@ pluginManagement {
|
||||||
gradlePluginPortal()
|
gradlePluginPortal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
include("web-api")
|
||||||
|
|
@ -5,6 +5,8 @@ plugins {
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(":api")) // API
|
implementation(project(":api")) // API
|
||||||
|
compileOnly("org.projectlombok:lombok:1.18.46")
|
||||||
|
annotationProcessor("org.projectlombok:lombok:1.18.46")
|
||||||
compileOnly("com.velocitypowered:velocity-api:3.5.0-SNAPSHOT")
|
compileOnly("com.velocitypowered:velocity-api:3.5.0-SNAPSHOT")
|
||||||
annotationProcessor("com.velocitypowered:velocity-api:3.5.0-SNAPSHOT")
|
annotationProcessor("com.velocitypowered:velocity-api:3.5.0-SNAPSHOT")
|
||||||
implementation("mysql:mysql-connector-java:8.0.33") // mysql
|
implementation("mysql:mysql-connector-java:8.0.33") // mysql
|
||||||
|
|
|
||||||
69
web-api/build.gradle.kts
Normal file
69
web-api/build.gradle.kts
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
plugins {
|
||||||
|
java
|
||||||
|
id("org.openapi.generator") version "7.12.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
group = "com.alttd.chat"
|
||||||
|
version = "2.0.0-SNAPSHOT"
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation("io.swagger.core.v3:swagger-annotations:2.2.28")
|
||||||
|
|
||||||
|
implementation("com.squareup.okhttp3:okhttp:4.12.0")
|
||||||
|
implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")
|
||||||
|
|
||||||
|
implementation("com.google.code.gson:gson:2.12.1")
|
||||||
|
implementation("io.gsonfire:gson-fire:1.9.0")
|
||||||
|
|
||||||
|
implementation("javax.annotation:javax.annotation-api:1.3.2")
|
||||||
|
implementation("jakarta.annotation:jakarta.annotation-api:2.1.1")
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
main {
|
||||||
|
java {
|
||||||
|
srcDir("${projectDir}/build/generated-sources/client/src/main/java")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named<org.openapitools.generator.gradle.plugin.tasks.GenerateTask>("openApiGenerate") {
|
||||||
|
generatorName.set("java")
|
||||||
|
inputSpec.set("${projectDir}/src/main/resources/chat-api.yml")
|
||||||
|
configFile.set("${projectDir}/src/main/resources/config_backend.json")
|
||||||
|
outputDir.set("${projectDir}/build/generated-sources/client")
|
||||||
|
|
||||||
|
apiPackage.set("com.alttd.altitudeweb.api")
|
||||||
|
modelPackage.set("com.alttd.altitudeweb.model")
|
||||||
|
|
||||||
|
modelNameSuffix.set("Dto")
|
||||||
|
|
||||||
|
additionalProperties.set(
|
||||||
|
mapOf(
|
||||||
|
"dateLibrary" to "java8",
|
||||||
|
"library" to "okhttp-gson"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
typeMappings.set(mapOf("OffsetDateTime" to "Instant"))
|
||||||
|
importMappings.set(mapOf("OffsetDateTime" to "java.time.Instant"))
|
||||||
|
|
||||||
|
generateApiTests.set(false)
|
||||||
|
generateApiDocumentation.set(false)
|
||||||
|
generateModelTests.set(false)
|
||||||
|
generateModelDocumentation.set(false)
|
||||||
|
|
||||||
|
generateAliasAsModel.set(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
main {
|
||||||
|
java {
|
||||||
|
srcDir(layout.buildDirectory.dir("generated/openapi/src/main/java"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.compileJava {
|
||||||
|
dependsOn("openApiGenerate")
|
||||||
|
}
|
||||||
135
web-api/src/main/resources/chat-api.yml
Normal file
135
web-api/src/main/resources/chat-api.yml
Normal file
|
|
@ -0,0 +1,135 @@
|
||||||
|
openapi: 3.0.3
|
||||||
|
|
||||||
|
info:
|
||||||
|
title: Minecraft Network API
|
||||||
|
version: 1.0.0
|
||||||
|
|
||||||
|
servers:
|
||||||
|
- url: http://localhost:8080/api
|
||||||
|
|
||||||
|
tags:
|
||||||
|
- name: chat
|
||||||
|
description: Data for displaying Chat messages to clients
|
||||||
|
|
||||||
|
paths:
|
||||||
|
/chat/send/chat/message:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- chat
|
||||||
|
summary: Sends one or more chat messages
|
||||||
|
operationId: sendChatMessages
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/ChatMessage"
|
||||||
|
responses:
|
||||||
|
"202":
|
||||||
|
description: Accepted
|
||||||
|
|
||||||
|
/chat/send/servers/state:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- chat
|
||||||
|
summary: Update server states
|
||||||
|
operationId: updateServerStates
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/ServerState"
|
||||||
|
responses:
|
||||||
|
"202":
|
||||||
|
description: Accepted
|
||||||
|
|
||||||
|
components:
|
||||||
|
schemas:
|
||||||
|
User:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- uuid
|
||||||
|
- name
|
||||||
|
- styledName
|
||||||
|
|
||||||
|
properties:
|
||||||
|
uuid:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
styledName:
|
||||||
|
type: string
|
||||||
|
|
||||||
|
ChatMessage:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- uuid
|
||||||
|
- message
|
||||||
|
- channel
|
||||||
|
- server
|
||||||
|
- timestamp
|
||||||
|
- blocked
|
||||||
|
properties:
|
||||||
|
uuid:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
channel:
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- CHAT
|
||||||
|
- PARTY
|
||||||
|
- AC
|
||||||
|
- GAC
|
||||||
|
message:
|
||||||
|
type: string
|
||||||
|
server:
|
||||||
|
type: string
|
||||||
|
timestamp:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
blocked:
|
||||||
|
type: boolean
|
||||||
|
|
||||||
|
PrivateMessage:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- sender
|
||||||
|
- receiver
|
||||||
|
- message
|
||||||
|
- senderServer
|
||||||
|
- receiverServer
|
||||||
|
properties:
|
||||||
|
sender:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
receiver:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
message:
|
||||||
|
type: string
|
||||||
|
senderServer:
|
||||||
|
type: string
|
||||||
|
receiverServer:
|
||||||
|
type: string
|
||||||
|
|
||||||
|
Server:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
players:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/User"
|
||||||
|
|
||||||
|
ServerState:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
servers:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/Server"
|
||||||
22
web-api/src/main/resources/config_backend.json
Normal file
22
web-api/src/main/resources/config_backend.json
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"library": "okhttp-gson",
|
||||||
|
"hideGenerationTimestamp": true,
|
||||||
|
"modelPackage": "com.alttd.altitudeweb.model",
|
||||||
|
"apiPackage": "com.alttd.altitudeweb.api",
|
||||||
|
"invokerPackage": "com.alttd.altitudeweb.invoker",
|
||||||
|
"serializableModel": true,
|
||||||
|
"openApiNullable": false,
|
||||||
|
"useTags": true,
|
||||||
|
"generateApis": true,
|
||||||
|
"generateApiTests": false,
|
||||||
|
"generateApiDocumentation": false,
|
||||||
|
"generateModels": true,
|
||||||
|
"generateModelTests": false,
|
||||||
|
"generateSupportingFiles": true,
|
||||||
|
"modelNameSuffix": "Dto",
|
||||||
|
"generateTests": false,
|
||||||
|
"dateLibrary": "java8",
|
||||||
|
"enumUnknownDefaultCase": true,
|
||||||
|
"disallowAdditionalPropertiesIfNotPresent": false,
|
||||||
|
"useJakartaEe": true
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user