api header support, team api integration

This commit is contained in:
Elias Müller 2025-05-30 18:34:49 +02:00
parent 8093a4a644
commit bdbb8b5824
18 changed files with 153 additions and 54 deletions

View File

@ -3,4 +3,5 @@ dependencies {
compileOnly 'io.papermc.paper:paper-api:1.21.1-R0.1-SNAPSHOT'
compileOnly 'org.geysermc.floodgate:api:2.2.2-SNAPSHOT'
implementation 'org.apache.httpcomponents:httpclient:4.5.14'
}

View File

@ -1,4 +1,4 @@
package eu.mhsl.craftattack.spawn.core.util.api;
package eu.mhsl.craftattack.spawn.common.api;
import eu.mhsl.craftattack.spawn.core.config.Configuration;
import org.apache.http.client.utils.URIBuilder;
@ -8,7 +8,7 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.util.Objects;
public class WebsiteApiUtil {
public class CraftAttackApi {
private final static ConfigurationSection apiConfig = Objects.requireNonNull(Configuration.cfg.getConfigurationSection("api"));
public final static String basePath = apiConfig.getString("baseurl");
public final static String apiSecret = apiConfig.getString("secret");

View File

@ -1,8 +1,8 @@
package eu.mhsl.craftattack.spawn.core.api.client.repositories;
package eu.mhsl.craftattack.spawn.common.api.repositories;
import eu.mhsl.craftattack.spawn.core.api.client.HttpRepository;
import eu.mhsl.craftattack.spawn.core.api.client.ReqResp;
import eu.mhsl.craftattack.spawn.core.util.api.WebsiteApiUtil;
import eu.mhsl.craftattack.spawn.common.api.CraftAttackApi;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -11,7 +11,7 @@ import java.util.UUID;
public class ReportRepository extends HttpRepository {
public ReportRepository() {
super(WebsiteApiUtil.getBaseUri(), WebsiteApiUtil::withAuthorizationSecret);
super(CraftAttackApi.getBaseUri(), new RequestModifier(CraftAttackApi::withAuthorizationSecret, null));
}
public record ReportCreationInfo(@NotNull UUID reporter, @Nullable UUID reported, String reason) {

View File

@ -2,7 +2,7 @@ package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.report;
import eu.mhsl.craftattack.spawn.core.Main;
import eu.mhsl.craftattack.spawn.core.api.client.ReqResp;
import eu.mhsl.craftattack.spawn.core.api.client.repositories.ReportRepository;
import eu.mhsl.craftattack.spawn.common.api.repositories.ReportRepository;
import eu.mhsl.craftattack.spawn.core.appliance.Appliance;
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand;
import net.kyori.adventure.text.Component;

View File

@ -1,4 +1,4 @@
package eu.mhsl.craftattack.spawn.core.util.api;
package eu.mhsl.craftattack.spawn.core.api;
public class HttpStatus {
public static final int OK = 200;

View File

@ -10,23 +10,29 @@ import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
@RepositoryLoader.Abstraction
public abstract class HttpRepository extends Repository {
private final Consumer<URIBuilder> baseUriBuilder;
public record RequestModifier(
@Nullable Consumer<URIBuilder> uri,
@Nullable Consumer<HttpRequest.Builder> header
) {}
private final List<RequestModifier> baseRequestModifier;
public HttpRepository(URI basePath) {
this(basePath, null);
this(basePath, new RequestModifier(null, null));
}
public HttpRepository(URI basePath, @Nullable Consumer<URIBuilder> baseUriBuilder) {
public HttpRepository(URI basePath, RequestModifier... baseRequestModifier) {
super(basePath);
this.baseUriBuilder = baseUriBuilder == null
? uriBuilder -> {
}
: baseUriBuilder;
this.baseRequestModifier = baseRequestModifier == null
? List.of()
: List.of(baseRequestModifier);
}
protected <TInput, TOutput> ReqResp<TOutput> post(String command, TInput data, Class<TOutput> outputType) {
@ -58,7 +64,11 @@ public abstract class HttpRepository extends Repository {
private URI getUri(String command, Consumer<URIBuilder> parameters) {
try {
URIBuilder builder = new URIBuilder(this.basePath + "/" + command);
this.baseUriBuilder.accept(builder);
this.baseRequestModifier.stream()
.map(requestModifier -> requestModifier.uri)
.filter(Objects::nonNull)
.forEach(modifier -> modifier.accept(builder));
parameters.accept(builder);
return builder.build();
} catch(URISyntaxException e) {
@ -67,14 +77,22 @@ public abstract class HttpRepository extends Repository {
}
private HttpRequest.Builder getRequestBuilder(URI endpoint) {
return HttpRequest.newBuilder()
HttpRequest.Builder builder = HttpRequest.newBuilder()
.uri(endpoint)
.header("User-Agent", Main.instance().getServer().getBukkitVersion())
.header("Content-Type", "application/json");
this.baseRequestModifier.stream()
.map(requestModifier -> requestModifier.header)
.filter(Objects::nonNull)
.forEach(modifier -> modifier.accept(builder));
return builder;
}
private <TResponse> ReqResp<TResponse> execute(HttpRequest request, Class<TResponse> clazz) {
ReqResp<String> rawResponse = this.sendHttp(request);
Main.logger().info(String.format("HTTP-Repository fired %s, response: %s", request, rawResponse));
return new ReqResp<>(rawResponse.status(), this.gson.fromJson(rawResponse.data(), clazz));
}

View File

@ -1,4 +1,16 @@
package eu.mhsl.craftattack.spawn.core.api.client;
import com.google.gson.Gson;
import java.lang.reflect.Type;
public record ReqResp<TData>(int status, TData data) {
public ReqResp<?> convertToTypeToken(Type type) {
var gson = new Gson();
return new ReqResp<>(this.status, gson.fromJson(gson.toJson(this.data), type));
}
@SuppressWarnings("unchecked")
public <T> T cast() {
return (T) this;
}
}

View File

@ -77,3 +77,7 @@ shrinkingBorder:
minimumSize: 10
shrinkPerDay: 10
shrinkTime: 03:00
varoApi:
endpoint: "https://mhsl.eu/varo/api"
auth: "Basic xxx"

View File

@ -1,4 +1,4 @@
package eu.mhsl.craftattack.spawn.core.util.api;
package eu.mhsl.craftattack.spawn.craftattack.api;
import eu.mhsl.craftattack.spawn.core.config.Configuration;
import org.bukkit.configuration.ConfigurationSection;
@ -7,7 +7,7 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.util.Objects;
public class EventApiUtil {
public class EventServerApi {
private final static ConfigurationSection apiConfig = Objects.requireNonNull(Configuration.cfg.getConfigurationSection("event"));
public final static String basePath = apiConfig.getString("api");

View File

@ -1,14 +1,14 @@
package eu.mhsl.craftattack.spawn.core.api.client.repositories;
package eu.mhsl.craftattack.spawn.craftattack.api.repositories;
import eu.mhsl.craftattack.spawn.core.api.client.HttpRepository;
import eu.mhsl.craftattack.spawn.core.api.client.ReqResp;
import eu.mhsl.craftattack.spawn.core.util.api.EventApiUtil;
import eu.mhsl.craftattack.spawn.craftattack.api.EventServerApi;
import java.util.UUID;
public class EventRepository extends HttpRepository {
public EventRepository() {
super(EventApiUtil.getBaseUri());
super(EventServerApi.getBaseUri());
}
public record CreatedRoom(UUID uuid) {

View File

@ -1,9 +1,9 @@
package eu.mhsl.craftattack.spawn.core.api.client.repositories;
package eu.mhsl.craftattack.spawn.craftattack.api.repositories;
import com.google.common.reflect.TypeToken;
import eu.mhsl.craftattack.spawn.core.api.client.HttpRepository;
import eu.mhsl.craftattack.spawn.core.api.client.ReqResp;
import eu.mhsl.craftattack.spawn.core.util.api.WebsiteApiUtil;
import eu.mhsl.craftattack.spawn.common.api.CraftAttackApi;
import java.lang.reflect.Type;
import java.util.List;
@ -12,7 +12,7 @@ import java.util.UUID;
public class FeedbackRepository extends HttpRepository {
public FeedbackRepository() {
super(WebsiteApiUtil.getBaseUri(), WebsiteApiUtil::withAuthorizationSecret);
super(CraftAttackApi.getBaseUri(), new RequestModifier(CraftAttackApi::withAuthorizationSecret, null));
}
public record Request(String event, List<UUID> users) {
@ -22,6 +22,7 @@ public class FeedbackRepository extends HttpRepository {
final Type responseType = new TypeToken<Map<UUID, String>>() {
}.getType();
ReqResp<Object> rawData = this.post("feedback", data, Object.class);
// TODO: use convertToTypeToken from ReqResp
return new ReqResp<>(rawData.status(), this.gson.fromJson(this.gson.toJson(rawData.data()), responseType));
}
}

View File

@ -1,14 +1,14 @@
package eu.mhsl.craftattack.spawn.core.api.client.repositories;
package eu.mhsl.craftattack.spawn.craftattack.api.repositories;
import eu.mhsl.craftattack.spawn.core.api.client.HttpRepository;
import eu.mhsl.craftattack.spawn.core.api.client.ReqResp;
import eu.mhsl.craftattack.spawn.core.util.api.WebsiteApiUtil;
import eu.mhsl.craftattack.spawn.common.api.CraftAttackApi;
import java.util.UUID;
public class WhitelistRepository extends HttpRepository {
public WhitelistRepository() {
super(WebsiteApiUtil.getBaseUri(), WebsiteApiUtil::withAuthorizationSecret);
super(CraftAttackApi.getBaseUri(), new RequestModifier(CraftAttackApi::withAuthorizationSecret, null));
}
public record UserData(

View File

@ -2,14 +2,14 @@ package eu.mhsl.craftattack.spawn.craftattack.appliances.metaGameplay.event;
import eu.mhsl.craftattack.spawn.core.Main;
import eu.mhsl.craftattack.spawn.core.api.client.ReqResp;
import eu.mhsl.craftattack.spawn.core.api.client.repositories.EventRepository;
import eu.mhsl.craftattack.spawn.craftattack.api.repositories.EventRepository;
import eu.mhsl.craftattack.spawn.core.api.server.HttpServer;
import eu.mhsl.craftattack.spawn.core.appliance.Appliance;
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand;
import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.customAdvancements.Advancements;
import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.customAdvancements.CustomAdvancements;
import eu.mhsl.craftattack.spawn.core.util.IteratorUtil;
import eu.mhsl.craftattack.spawn.core.util.api.HttpStatus;
import eu.mhsl.craftattack.spawn.core.api.HttpStatus;
import eu.mhsl.craftattack.spawn.core.util.entity.DisplayVillager;
import eu.mhsl.craftattack.spawn.core.util.listener.DismissInventoryOpenFromHolder;
import eu.mhsl.craftattack.spawn.core.util.listener.PlayerInteractAtEntityEventListener;

View File

@ -2,10 +2,10 @@ package eu.mhsl.craftattack.spawn.craftattack.appliances.metaGameplay.feedback;
import eu.mhsl.craftattack.spawn.core.Main;
import eu.mhsl.craftattack.spawn.core.api.client.ReqResp;
import eu.mhsl.craftattack.spawn.core.api.client.repositories.FeedbackRepository;
import eu.mhsl.craftattack.spawn.craftattack.api.repositories.FeedbackRepository;
import eu.mhsl.craftattack.spawn.core.appliance.Appliance;
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand;
import eu.mhsl.craftattack.spawn.core.util.api.HttpStatus;
import eu.mhsl.craftattack.spawn.core.api.HttpStatus;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ComponentBuilder;
import net.kyori.adventure.text.TextComponent;

View File

@ -2,10 +2,10 @@ package eu.mhsl.craftattack.spawn.craftattack.appliances.tooling.whitelist;
import eu.mhsl.craftattack.spawn.core.Main;
import eu.mhsl.craftattack.spawn.core.api.client.ReqResp;
import eu.mhsl.craftattack.spawn.core.api.client.repositories.WhitelistRepository;
import eu.mhsl.craftattack.spawn.craftattack.api.repositories.WhitelistRepository;
import eu.mhsl.craftattack.spawn.core.api.server.HttpServer;
import eu.mhsl.craftattack.spawn.core.appliance.Appliance;
import eu.mhsl.craftattack.spawn.core.util.api.HttpStatus;
import eu.mhsl.craftattack.spawn.core.api.HttpStatus;
import eu.mhsl.craftattack.spawn.core.util.server.Floodgate;
import eu.mhsl.craftattack.spawn.core.util.text.DisconnectInfo;
import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.outlawed.Outlawed;

View File

@ -0,0 +1,28 @@
package eu.mhsl.craftattack.spawn.varo.api;
import eu.mhsl.craftattack.spawn.core.config.Configuration;
import org.bukkit.configuration.ConfigurationSection;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpRequest;
import java.util.Objects;
public class VaroApi {
private final static ConfigurationSection apiConfig = Objects.requireNonNull(Configuration.cfg.getConfigurationSection("varoApi"));
public final static String basePath = apiConfig.getString("endpoint");
public final static String apiSecret = apiConfig.getString("auth");
public static URI getBaseUri() {
Objects.requireNonNull(basePath);
try {
return new URI(basePath);
} catch(URISyntaxException e) {
throw new RuntimeException(e);
}
}
public static void authorizationHeader(HttpRequest.Builder builder) {
builder.header("Authorization", apiSecret);
}
}

View File

@ -0,0 +1,36 @@
package eu.mhsl.craftattack.spawn.varo.api.repositories;
import com.google.common.reflect.TypeToken;
import eu.mhsl.craftattack.spawn.core.api.client.HttpRepository;
import eu.mhsl.craftattack.spawn.core.api.client.ReqResp;
import eu.mhsl.craftattack.spawn.varo.api.VaroApi;
import java.util.List;
import java.util.UUID;
public class TeamRepository extends HttpRepository {
public TeamRepository() {
super(VaroApi.getBaseUri(), new RequestModifier(null, VaroApi::authorizationHeader));
}
public record Team(
String name,
String color,
Object lastJoined,
Object strikeWeight,
List<User> users
) {
public record User(
UUID uuid,
boolean dead
) {}
}
public ReqResp<List<Team>> getTeams() {
var resp = this.get("team", Object.class);
System.out.println(resp.toString());
return resp
.convertToTypeToken(new TypeToken<List<Team>>() {}.getType())
.cast();
}
}

View File

@ -4,6 +4,7 @@ import eu.mhsl.craftattack.spawn.core.Main;
import eu.mhsl.craftattack.spawn.core.appliance.Appliance;
import eu.mhsl.craftattack.spawn.core.util.text.DisconnectInfo;
import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.displayName.DisplayName;
import eu.mhsl.craftattack.spawn.varo.api.repositories.TeamRepository;
import eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.joinProtection.JoinProtection;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
@ -18,19 +19,19 @@ import org.jetbrains.annotations.Nullable;
import java.util.*;
public class Teams extends Appliance implements DisplayName.Prefixed, DisplayName.Colored {
private Set<VaroTeam> teams = new HashSet<>() {{
this.add(new VaroTeam(
new HashSet<>() {{
this.add(new VaroTeam.Member(UUID.fromString("3a0a699c-7f0c-319b-839c-ccc8cac8ae63"), false));
this.add(new VaroTeam.Member(UUID.fromString("959ed433-14ea-38fe-918b-75b7d09466af"), true));
}},
"Die Admins",
"#0E0E0E"
));
}};
private List<VaroTeam> teams = List.of();
public Teams() {
this.refreshTeamList();
}
public void refreshTeamList() {
this.teams = this.queryRepository(TeamRepository.class).getTeams().data().stream()
.map(team -> new VaroTeam(
team.users().stream().map(user -> new VaroTeam.Member(user.uuid(), user.dead())).toList(),
team.name(),
team.color()
)).toList();
}
public boolean canLogin(UUID playerId) {
@ -58,16 +59,14 @@ public class Teams extends Appliance implements DisplayName.Prefixed, DisplayNam
VaroTeam team = this.getTeamFromPlayer(joinedPlayer.getUniqueId());
Bukkit.getScheduler().scheduleSyncDelayedTask(
Main.instance(),
() -> {
team.members.stream()
.filter(member -> !member.isDead)
.filter(member -> {
Player p = Bukkit.getPlayer(member.player.getUniqueId());
return p == null || !p.isOnline();
})
.findAny()
.ifPresent(member -> team.kickTeam(disconnectInfo));
},
() -> team.members.stream()
.filter(member -> !member.isDead)
.filter(member -> {
Player p = Bukkit.getPlayer(member.player.getUniqueId());
return p == null || !p.isOnline();
})
.findAny()
.ifPresent(member -> team.kickTeam(disconnectInfo)),
Ticks.TICKS_PER_SECOND * (JoinProtection.resistanceDuration / 2)
);
}