added HTTP hooks framework with actions for signup, report, and strike events; introduced SpawnEvent support for event broadcasting

This commit is contained in:
2025-11-15 12:50:01 +01:00
parent 448e9472db
commit 0b9dc5358d
8 changed files with 203 additions and 1 deletions

View File

@@ -2,6 +2,7 @@ package eu.mhsl.craftattack.spawn.core.api.server;
import com.google.gson.Gson;
import eu.mhsl.craftattack.spawn.core.Main;
import eu.mhsl.craftattack.spawn.core.api.server.hooks.HttpHook;
import eu.mhsl.craftattack.spawn.core.appliance.Appliance;
import org.bukkit.configuration.ConfigurationSection;
import spark.Request;
@@ -22,6 +23,11 @@ public class HttpServer {
Spark.get("/ping", (request, response) -> System.currentTimeMillis());
Spark.post("/hook/:hookId", (request, response) -> {
HttpHook.Hook hook = HttpHook.Hook.valueOf(request.params(":hookId").toUpperCase());
return hook.getHook().runAction(request.headers(hook.getHeaderAction()), request, response);
});
Main.instance().getAppliances().forEach(appliance -> appliance.httpApi(new ApiBuilder(appliance)));
}
@@ -64,7 +70,7 @@ public class HttpServer {
});
}
public String buildRoute(String path) {
private String buildRoute(String path) {
return String.format("/api/%s/%s", this.applianceName, path);
}

View File

@@ -0,0 +1,55 @@
package eu.mhsl.craftattack.spawn.core.api.server.hooks;
import eu.mhsl.craftattack.spawn.core.Main;
import eu.mhsl.craftattack.spawn.core.api.server.HttpServer;
import eu.mhsl.craftattack.spawn.core.api.server.hooks.impl.WebsiteHook;
import spark.Request;
import spark.Response;
import java.util.HashMap;
import java.util.Map;
public abstract class HttpHook {
public enum Hook {
WEBSITE("x-webhook-action", new WebsiteHook());
private final String headerAction;
private final HttpHook hook;
Hook(String headerAction, HttpHook handler) {
this.headerAction = headerAction;
this.hook = handler;
this.hook.registerHooks();
}
public HttpHook getHook() {
return this.hook;
}
public String getHeaderAction() {
return this.headerAction;
}
}
public abstract static class Action {
public abstract Object run(Request request, Response response);
}
private final Map<String, Action> actions = new HashMap<>();
protected HttpHook() {
}
protected abstract void registerHooks();
protected void addAction(String name, Action action) {
this.actions.put(name, action);
}
public Object runAction(String action, Request request, Response response) {
if(!this.actions.containsKey(action)) {
Main.logger().warning(String.format("Webhook-Action '%s' not registered, skipping!", action));
return HttpServer.nothing;
}
return this.actions.get(action).run(request, response);
}
}

View File

@@ -0,0 +1,26 @@
package eu.mhsl.craftattack.spawn.core.api.server.hooks;
import com.google.gson.Gson;
import spark.Request;
import spark.Response;
import java.util.function.Function;
public class JsonAction<TRequest, TResponse> extends HttpHook.Action {
private final Function<TRequest, TResponse> handler;
private final Class<TRequest> requestClass;
private final Gson gson = new Gson();
public JsonAction(Class<TRequest> requestClass, Function<TRequest, TResponse> handler) {
this.requestClass = requestClass;
this.handler = handler;
}
@Override
public Object run(Request request, Response response) {
TRequest req = this.gson.fromJson(request.body(), this.requestClass);
response.type("application/json");
return this.gson.toJson(this.handler.apply(req));
}
}

View File

@@ -0,0 +1,18 @@
package eu.mhsl.craftattack.spawn.core.api.server.hooks;
import spark.Request;
import spark.Response;
import java.util.function.BiFunction;
public class RawAction extends HttpHook.Action {
private final BiFunction<Request, Response, Object> handler;
public RawAction(BiFunction<Request, Response, Object> handler) {
this.handler = handler;
}
@Override
public Object run(Request request, Response response) {
return this.handler.apply(request, response);
}
}

View File

@@ -0,0 +1,43 @@
package eu.mhsl.craftattack.spawn.core.api.server.hooks.impl;
import eu.mhsl.craftattack.spawn.core.Main;
import eu.mhsl.craftattack.spawn.core.api.server.HttpServer;
import eu.mhsl.craftattack.spawn.core.api.server.hooks.HttpHook;
import eu.mhsl.craftattack.spawn.core.api.server.hooks.JsonAction;
import eu.mhsl.craftattack.spawn.core.event.ReportCreatedEvent;
import eu.mhsl.craftattack.spawn.core.event.SpawnEvent;
import eu.mhsl.craftattack.spawn.core.event.StrikeCreatedEvent;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.UUID;
public class WebsiteHook extends HttpHook {
@Override
protected void registerHooks() {
record CreatedSignup(
String firstname,
String lastname,
String birthday,
@Nullable String telephone,
String username,
String edition,
@Nullable UUID uuid
) {}
this.addAction("signup", new JsonAction<>(CreatedSignup.class, createdSignup -> {
Main.logger().info(String.format("New Website-signup from Hook: %s %s (%s)", createdSignup.firstname, createdSignup.lastname, createdSignup.username));
return HttpServer.nothing;
}));
record CreatedReport(String reporter, String reported, String reason) {}
this.addAction("report", new JsonAction<>(CreatedReport.class, createdReport -> {
SpawnEvent.call(new ReportCreatedEvent(new ReportCreatedEvent.CreatedReport(createdReport.reporter, createdReport.reported, createdReport.reason)));
return HttpServer.nothing;
}));
record CreatedStrike(UUID uuid) {}
this.addAction("strike", new JsonAction<>(CreatedStrike.class, createdStrike -> {
SpawnEvent.call(new StrikeCreatedEvent(new StrikeCreatedEvent.CreatedStrike(createdStrike.uuid)));
return HttpServer.nothing;
}));
}
}

View File

@@ -0,0 +1,15 @@
package eu.mhsl.craftattack.spawn.core.event;
public class ReportCreatedEvent extends SpawnEvent {
public record CreatedReport(String reporter, String reported, String reason) {}
private final CreatedReport report;
public ReportCreatedEvent(CreatedReport report) {
super(true);
this.report = report;
}
public CreatedReport getReport() {
return this.report;
}
}

View File

@@ -0,0 +1,22 @@
package eu.mhsl.craftattack.spawn.core.event;
import org.bukkit.Bukkit;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
public abstract class SpawnEvent extends Event {
private static final HandlerList HANDLERS = new HandlerList();
@Override
public @NotNull HandlerList getHandlers() {
return HANDLERS;
}
public static void call(SpawnEvent event) {
Bukkit.getPluginManager().callEvent(event);
}
public SpawnEvent(boolean isAsync) {
super(isAsync);
}
}

View File

@@ -0,0 +1,17 @@
package eu.mhsl.craftattack.spawn.core.event;
import java.util.UUID;
public class StrikeCreatedEvent extends SpawnEvent {
public record CreatedStrike(UUID playerToStrike) {}
private final CreatedStrike strike;
public StrikeCreatedEvent(CreatedStrike strike) {
super(true);
this.strike = strike;
}
public CreatedStrike getStrike() {
return this.strike;
}
}