From 5b11da7477eaf392d943e3ec5b05c1e205bf8df3 Mon Sep 17 00:00:00 2001 From: LatvianModder Date: Tue, 13 Aug 2024 17:37:04 +0300 Subject: [PATCH] Updated web server to use my own library --- build.gradle | 11 +- gradle.properties | 2 +- .../mods/kubejs/BuiltinKubeJSPlugin.java | 6 +- .../client/BuiltinKubeJSClientPlugin.java | 6 +- .../mods/kubejs/plugin/KubeJSPlugin.java | 6 +- .../latvian/mods/kubejs/script/ConsoleJS.java | 35 ++--- .../mods/kubejs/script/ConsoleLine.java | 8 +- .../mods/kubejs/script/ScriptManager.java | 21 ++- .../latvian/mods/kubejs/web/CompiledPath.java | 93 ------------ .../latvian/mods/kubejs/web/HTTPServer.java | 141 ------------------ .../latvian/mods/kubejs/web/JsonContent.java | 49 ++++++ ...JSHTTPContext.java => KJSHTTPRequest.java} | 4 +- .../latvian/mods/kubejs/web/KJSWSSession.java | 22 +++ .../mods/kubejs/web/KubeJSLocalWebServer.java | 62 ++++---- .../mods/kubejs/web/WebServerRegistry.java | 55 ------- .../mods/kubejs/web/http/HTTPContext.java | 76 ---------- .../mods/kubejs/web/http/HTTPHandler.java | 5 - .../mods/kubejs/web/http/HTTPMethod.java | 20 --- .../mods/kubejs/web/http/HTTPResponse.java | 16 -- .../web/http/HTTPResponseWithHeader.java | 11 -- .../kubejs/web/http/SimpleHTTPResponse.java | 45 ------ .../kubejs/web/local/ConsoleWSSession.java | 4 +- .../mods/kubejs/web/local/KubeJSWeb.java | 129 +++++++++------- .../web/local/client/ImageGenerator.java | 48 +++--- .../web/local/client/KubeJSClientWeb.java | 44 +++--- .../latvian/mods/kubejs/web/ws/WSHandler.java | 55 ------- .../latvian/mods/kubejs/web/ws/WSSession.java | 8 - .../mods/kubejs/web/ws/WSSessionFactory.java | 6 - 28 files changed, 279 insertions(+), 709 deletions(-) delete mode 100644 src/main/java/dev/latvian/mods/kubejs/web/CompiledPath.java delete mode 100644 src/main/java/dev/latvian/mods/kubejs/web/HTTPServer.java create mode 100644 src/main/java/dev/latvian/mods/kubejs/web/JsonContent.java rename src/main/java/dev/latvian/mods/kubejs/web/{KJSHTTPContext.java => KJSHTTPRequest.java} (94%) create mode 100644 src/main/java/dev/latvian/mods/kubejs/web/KJSWSSession.java delete mode 100644 src/main/java/dev/latvian/mods/kubejs/web/WebServerRegistry.java delete mode 100644 src/main/java/dev/latvian/mods/kubejs/web/http/HTTPContext.java delete mode 100644 src/main/java/dev/latvian/mods/kubejs/web/http/HTTPHandler.java delete mode 100644 src/main/java/dev/latvian/mods/kubejs/web/http/HTTPMethod.java delete mode 100644 src/main/java/dev/latvian/mods/kubejs/web/http/HTTPResponse.java delete mode 100644 src/main/java/dev/latvian/mods/kubejs/web/http/HTTPResponseWithHeader.java delete mode 100644 src/main/java/dev/latvian/mods/kubejs/web/http/SimpleHTTPResponse.java delete mode 100644 src/main/java/dev/latvian/mods/kubejs/web/ws/WSHandler.java delete mode 100644 src/main/java/dev/latvian/mods/kubejs/web/ws/WSSession.java delete mode 100644 src/main/java/dev/latvian/mods/kubejs/web/ws/WSSessionFactory.java diff --git a/build.gradle b/build.gradle index aa22424f5..54f0b893b 100644 --- a/build.gradle +++ b/build.gradle @@ -88,6 +88,7 @@ repositories { url "https://maven.latvian.dev/releases" content { includeGroup "dev.latvian.mods" + includeGroup "dev.latvian.apps" } } @@ -125,16 +126,14 @@ dependencies { compileOnly("me.shedaniel:RoughlyEnoughItems-neoforge:$rei_version") compileOnly("dev.emi:emi-neoforge:$emi_version:api") - /* - jarJar(implementation 'org.java-websocket:Java-WebSocket') { + jarJar(implementation 'dev.latvian.apps:tiny-java-server') { version { - strictly '[1.5,)' - prefer "$java_websocket_version" + strictly '[1.0,)' + prefer "$tiny_server_version" } } - additionalRuntimeClasspath("org.java-websocket:Java-WebSocket:$java_websocket_version") - */ + additionalRuntimeClasspath("dev.latvian.apps:tiny-java-server:$tiny_server_version") } processResources { diff --git a/gradle.properties b/gradle.properties index 35cef2774..d270d6fd6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,7 +15,7 @@ mod_version=2100.7.0 neoforge_version=21.0.163 parchment_version=2024.07.28 rhino_version=2100.2.5-build.46 -java_websocket_version=1.5.7 +tiny_server_version=1.0.0-build.1 architectury_version=13.0.6 rei_version=16.0.744 diff --git a/src/main/java/dev/latvian/mods/kubejs/BuiltinKubeJSPlugin.java b/src/main/java/dev/latvian/mods/kubejs/BuiltinKubeJSPlugin.java index d98ef2424..e4bbd392c 100644 --- a/src/main/java/dev/latvian/mods/kubejs/BuiltinKubeJSPlugin.java +++ b/src/main/java/dev/latvian/mods/kubejs/BuiltinKubeJSPlugin.java @@ -4,6 +4,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; +import dev.latvian.apps.tinyserver.ServerRegistry; import dev.latvian.mods.kubejs.bindings.AABBWrapper; import dev.latvian.mods.kubejs.bindings.BlockWrapper; import dev.latvian.mods.kubejs.bindings.ColorWrapper; @@ -152,8 +153,7 @@ import dev.latvian.mods.kubejs.util.Tristate; import dev.latvian.mods.kubejs.util.UtilsJS; import dev.latvian.mods.kubejs.util.registrypredicate.RegistryPredicate; -import dev.latvian.mods.kubejs.web.KJSHTTPContext; -import dev.latvian.mods.kubejs.web.WebServerRegistry; +import dev.latvian.mods.kubejs.web.KJSHTTPRequest; import dev.latvian.mods.kubejs.web.local.KubeJSWeb; import dev.latvian.mods.rhino.type.RecordTypeInfo; import dev.latvian.mods.rhino.type.TypeInfo; @@ -721,7 +721,7 @@ public void registerDataComponentTypeDescriptions(DataComponentTypeInfoRegistry } @Override - public void registerLocalWebServer(WebServerRegistry registry) { + public void registerLocalWebServer(ServerRegistry registry) { KubeJSWeb.register(registry); } } diff --git a/src/main/java/dev/latvian/mods/kubejs/client/BuiltinKubeJSClientPlugin.java b/src/main/java/dev/latvian/mods/kubejs/client/BuiltinKubeJSClientPlugin.java index b5defad91..e1b71d4f6 100644 --- a/src/main/java/dev/latvian/mods/kubejs/client/BuiltinKubeJSClientPlugin.java +++ b/src/main/java/dev/latvian/mods/kubejs/client/BuiltinKubeJSClientPlugin.java @@ -1,5 +1,6 @@ package dev.latvian.mods.kubejs.client; +import dev.latvian.apps.tinyserver.ServerRegistry; import dev.latvian.mods.kubejs.KubeJS; import dev.latvian.mods.kubejs.bindings.event.ClientEvents; import dev.latvian.mods.kubejs.event.EventGroupRegistry; @@ -7,8 +8,7 @@ import dev.latvian.mods.kubejs.script.BindingRegistry; import dev.latvian.mods.kubejs.script.PlatformWrapper; import dev.latvian.mods.kubejs.util.ScheduledEvents; -import dev.latvian.mods.kubejs.web.KJSHTTPContext; -import dev.latvian.mods.kubejs.web.WebServerRegistry; +import dev.latvian.mods.kubejs.web.KJSHTTPRequest; import dev.latvian.mods.kubejs.web.local.client.KubeJSClientWeb; import net.minecraft.client.Minecraft; import net.neoforged.fml.ModList; @@ -34,7 +34,7 @@ public void registerBindings(BindingRegistry bindings) { } @Override - public void registerLocalWebServer(WebServerRegistry registry) { + public void registerLocalWebServer(ServerRegistry registry) { KubeJSClientWeb.register(registry); } diff --git a/src/main/java/dev/latvian/mods/kubejs/plugin/KubeJSPlugin.java b/src/main/java/dev/latvian/mods/kubejs/plugin/KubeJSPlugin.java index 74402093b..c674f416d 100644 --- a/src/main/java/dev/latvian/mods/kubejs/plugin/KubeJSPlugin.java +++ b/src/main/java/dev/latvian/mods/kubejs/plugin/KubeJSPlugin.java @@ -1,6 +1,7 @@ package dev.latvian.mods.kubejs.plugin; import com.google.gson.JsonElement; +import dev.latvian.apps.tinyserver.ServerRegistry; import dev.latvian.mods.kubejs.block.entity.BlockEntityAttachmentType; import dev.latvian.mods.kubejs.client.LangKubeEvent; import dev.latvian.mods.kubejs.core.RecipeManagerKJS; @@ -24,8 +25,7 @@ import dev.latvian.mods.kubejs.script.TypeWrapperRegistry; import dev.latvian.mods.kubejs.server.DataExport; import dev.latvian.mods.kubejs.util.AttachedData; -import dev.latvian.mods.kubejs.web.KJSHTTPContext; -import dev.latvian.mods.kubejs.web.WebServerRegistry; +import dev.latvian.mods.kubejs.web.KJSHTTPRequest; import dev.latvian.mods.rhino.Context; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; @@ -95,7 +95,7 @@ default void registerRecipeViewerEntryTypes(Consumer regi default void registerDataComponentTypeDescriptions(DataComponentTypeInfoRegistry registry) { } - default void registerLocalWebServer(WebServerRegistry registry) { + default void registerLocalWebServer(ServerRegistry registry) { } default void attachServerData(AttachedData event) { diff --git a/src/main/java/dev/latvian/mods/kubejs/script/ConsoleJS.java b/src/main/java/dev/latvian/mods/kubejs/script/ConsoleJS.java index 6b1a56259..815636b9b 100644 --- a/src/main/java/dev/latvian/mods/kubejs/script/ConsoleJS.java +++ b/src/main/java/dev/latvian/mods/kubejs/script/ConsoleJS.java @@ -1,6 +1,7 @@ package dev.latvian.mods.kubejs.script; -import com.google.gson.JsonArray; +import dev.latvian.apps.tinyserver.http.response.HTTPResponse; +import dev.latvian.apps.tinyserver.ws.WSHandler; import dev.latvian.mods.kubejs.DevProperties; import dev.latvian.mods.kubejs.bindings.TextIcons; import dev.latvian.mods.kubejs.error.KubeRuntimeException; @@ -11,10 +12,10 @@ import dev.latvian.mods.kubejs.util.TimeJS; import dev.latvian.mods.kubejs.util.UtilsJS; import dev.latvian.mods.kubejs.util.WrappedJS; -import dev.latvian.mods.kubejs.web.KJSHTTPContext; -import dev.latvian.mods.kubejs.web.http.HTTPResponse; -import dev.latvian.mods.kubejs.web.http.SimpleHTTPResponse; -import dev.latvian.mods.kubejs.web.ws.WSHandler; +import dev.latvian.mods.kubejs.web.JsonContent; +import dev.latvian.mods.kubejs.web.KJSHTTPRequest; +import dev.latvian.mods.kubejs.web.KJSWSSession; +import dev.latvian.mods.kubejs.web.local.KubeJSWeb; import dev.latvian.mods.rhino.Context; import dev.latvian.mods.rhino.ContextFactory; import dev.latvian.mods.rhino.EcmaError; @@ -78,7 +79,7 @@ public static ConsoleJS getCurrent(@Nullable Context cx) { private final List writeQueue; private final Calendar calendar; public WeakReference contextFactory; - public WSHandler wsBroadcaster; + public WSHandler wsBroadcaster; public ConsoleJS(ScriptType m, Logger log) { this.scriptType = m; @@ -247,7 +248,7 @@ private ConsoleLine log(LogType type, SourceLine sourceLine, @Nullable Throwable writeToFile(type, line.timestamp, line.getText()); if (wsBroadcaster != null) { - wsBroadcaster.broadcast(type.id, line::toJson); + KubeJSWeb.broadcastEvent(wsBroadcaster, type.id, line); } } @@ -605,27 +606,19 @@ public int compareTo(VarFunc o) { } } - public HTTPResponse getErrorsResponse(KJSHTTPContext ctx) { - return SimpleHTTPResponse.lazyJson(() -> { - var json = new JsonArray(); - + public HTTPResponse getErrorsResponse(KJSHTTPRequest ctx) { + return HTTPResponse.ok().content(JsonContent.array(json -> { for (var error : errors) { json.add(error.toJson()); } - - return json; - }); + })); } - public HTTPResponse getWarningsResponse(KJSHTTPContext ctx) { - return SimpleHTTPResponse.lazyJson(() -> { - var json = new JsonArray(); - + public HTTPResponse getWarningsResponse(KJSHTTPRequest ctx) { + return HTTPResponse.ok().content(JsonContent.array(json -> { for (var error : warnings) { json.add(error.toJson()); } - - return json; - }); + })); } } diff --git a/src/main/java/dev/latvian/mods/kubejs/script/ConsoleLine.java b/src/main/java/dev/latvian/mods/kubejs/script/ConsoleLine.java index ef12f1937..fc75249fb 100644 --- a/src/main/java/dev/latvian/mods/kubejs/script/ConsoleLine.java +++ b/src/main/java/dev/latvian/mods/kubejs/script/ConsoleLine.java @@ -12,8 +12,9 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; +import java.util.function.Supplier; -public class ConsoleLine { +public class ConsoleLine implements Supplier { public static final ConsoleLine[] EMPTY_ARRAY = new ConsoleLine[0]; public static final StreamCodec STREAM_CODEC = new StreamCodec<>() { @@ -174,4 +175,9 @@ public JsonObject toJson() { return json; } + + @Override + public JsonElement get() { + return toJson(); + } } diff --git a/src/main/java/dev/latvian/mods/kubejs/script/ScriptManager.java b/src/main/java/dev/latvian/mods/kubejs/script/ScriptManager.java index e61346ba5..cbede3449 100644 --- a/src/main/java/dev/latvian/mods/kubejs/script/ScriptManager.java +++ b/src/main/java/dev/latvian/mods/kubejs/script/ScriptManager.java @@ -197,14 +197,19 @@ private void load() { scriptType.fileWatcherThread.start(); } - var broadcast = new JsonObject(); - broadcast.addProperty("type", scriptType.name); - broadcast.addProperty("total", t); - broadcast.addProperty("successful", i); - broadcast.addProperty("errors", scriptType.console.errors.size()); - broadcast.addProperty("warnings", scriptType.console.warnings.size()); - broadcast.addProperty("time", ms); - KubeJSWeb.UPDATES.broadcast("scripts_reloaded", broadcast); + int t1 = t; + int i1 = i; + + KubeJSWeb.broadcastUpdate("scripts_reloaded", () -> { + var broadcast = new JsonObject(); + broadcast.addProperty("type", scriptType.name); + broadcast.addProperty("total", t1); + broadcast.addProperty("successful", i1); + broadcast.addProperty("errors", scriptType.console.errors.size()); + broadcast.addProperty("warnings", scriptType.console.warnings.size()); + broadcast.addProperty("time", ms); + return broadcast; + }); } public void loadAdditional() { diff --git a/src/main/java/dev/latvian/mods/kubejs/web/CompiledPath.java b/src/main/java/dev/latvian/mods/kubejs/web/CompiledPath.java deleted file mode 100644 index 66d2b8897..000000000 --- a/src/main/java/dev/latvian/mods/kubejs/web/CompiledPath.java +++ /dev/null @@ -1,93 +0,0 @@ -package dev.latvian.mods.kubejs.web; - -import org.jetbrains.annotations.Nullable; - -public record CompiledPath(Part[] parts, int variables, boolean wildcard) { - public static final CompiledPath EMPTY = new CompiledPath(new Part[0], 0, false); - - public record Part(String name, boolean variable) { - public boolean matches(String string) { - return variable || name.equals(string); - } - } - - public static CompiledPath compile(String string) { - var ostring = string; - - while (string.startsWith("/")) { - string = string.substring(1); - } - - while (string.endsWith("/")) { - string = string.substring(0, string.length() - 1); - } - - if (string.isEmpty()) { - return EMPTY; - } - - var partsStr = string.split("/"); - var parts = new Part[partsStr.length]; - boolean wildcard = false; - int variables = 0; - - for (int i = 0; i < partsStr.length; i++) { - var s = partsStr[i]; - - if (wildcard) { - throw new IllegalArgumentException(" argument must be the last part of the path '" + ostring + "'"); - } - - if (s.startsWith("{") && s.endsWith("}")) { - parts[i] = new Part(s.substring(1, s.length() - 1), true); - variables++; - } else if (s.startsWith("<") && s.endsWith(">")) { - parts[i] = new Part(s.substring(1, s.length() - 1), true); - variables++; - wildcard = true; - } else { - parts[i] = new Part(s, false); - } - } - - return new CompiledPath(parts, variables, wildcard); - } - - @Nullable - public String[] matches(String[] path) { - if (wildcard) { - if (path.length >= parts.length) { - for (int i = 0; i < parts.length; i++) { - if (!parts[i].matches(path[i])) { - return null; - } - } - - if (path.length == parts.length) { - return path; - } else { - var joinedPath = new String[parts.length]; - System.arraycopy(path, 0, joinedPath, 0, parts.length); - - for (int i = parts.length; i < path.length; i++) { - joinedPath[parts.length - 1] += "/" + path[i]; - } - - return joinedPath; - } - } - } else { - if (path.length == parts.length) { - for (int i = 0; i < parts.length; i++) { - if (!parts[i].matches(path[i])) { - return null; - } - } - - return path; - } - } - - return null; - } -} diff --git a/src/main/java/dev/latvian/mods/kubejs/web/HTTPServer.java b/src/main/java/dev/latvian/mods/kubejs/web/HTTPServer.java deleted file mode 100644 index 475064423..000000000 --- a/src/main/java/dev/latvian/mods/kubejs/web/HTTPServer.java +++ /dev/null @@ -1,141 +0,0 @@ -package dev.latvian.mods.kubejs.web; - -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; -import com.sun.net.httpserver.HttpServer; -import dev.latvian.mods.kubejs.util.Lazy; -import dev.latvian.mods.kubejs.web.http.HTTPContext; -import dev.latvian.mods.kubejs.web.http.HTTPHandler; -import dev.latvian.mods.kubejs.web.http.HTTPMethod; -import dev.latvian.mods.kubejs.web.http.HTTPResponse; -import org.jetbrains.annotations.Nullable; - -import java.io.IOException; -import java.io.InputStream; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.EnumMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Executor; -import java.util.function.Supplier; - -public class HTTPServer implements HttpHandler { - public record PathHandler(HTTPMethod method, CompiledPath path, HTTPHandler handler) { - } - - private final Supplier contextFactory; - private final Map>> handlers; - private HttpServer server; - private PathHandler homepageHandler; - - public HTTPServer(Supplier contextFactory) { - this.contextFactory = contextFactory; - this.handlers = new EnumMap<>(HTTPMethod.class); - } - - public void setHomepageHandler(HTTPHandler handler) { - homepageHandler = new PathHandler<>(HTTPMethod.GET, CompiledPath.EMPTY, handler); - } - - public boolean start(InetAddress address, int port, @Nullable Executor executor) { - int portOffset = 0; - - while (true) { - try { - server = HttpServer.create(new InetSocketAddress(address, port + portOffset), 0); - break; - } catch (IOException ex) { - portOffset++; - - if (portOffset >= 10) { - return false; - } - } - } - - server.createContext("/", this); - server.setExecutor(executor); - server.start(); - return true; - } - - public InetSocketAddress getAddress() { - return server.getAddress(); - } - - public void addHandler(HTTPMethod method, String path, HTTPHandler handler) { - var compiledPath = CompiledPath.compile(path); - handlers.computeIfAbsent(method, k -> new ArrayList<>()).add(new PathHandler<>(method, compiledPath, handler)); - } - - @Override - public void handle(HttpExchange exchange) throws IOException { - try { - var method = HTTPMethod.fromString(exchange.getRequestMethod()); - var path = exchange.getRequestURI().getPath(); - - while (path.startsWith("/")) { - path = path.substring(1); - } - - while (path.endsWith("/")) { - path = path.substring(0, path.length() - 1); - } - - if (path.isBlank()) { - if (method == HTTPMethod.GET) { - if (homepageHandler != null) { - var ctx = contextFactory.get(); - ctx.init(homepageHandler.path, exchange); - homepageHandler.handler().handle(ctx).respond(exchange); - } else { - HTTPResponse.OK.respond(exchange); - } - } else { - exchange.sendResponseHeaders(404, -1L); - } - - return; - } - - var pathParts = path.split("/"); - - for (var handler : handlers.getOrDefault(method, List.of())) { - var p = handler.path().matches(pathParts); - - if (p != null) { - var ctx = contextFactory.get(); - ctx.setPath(p); - ctx.setBody(streamLazy(exchange.getRequestBody())); - ctx.init(handler.path, exchange); - handler.handler().handle(ctx).respond(exchange); - return; - } - } - - exchange.sendResponseHeaders(404, -1L); - } catch (Exception ex) { - ex.printStackTrace(); - exchange.sendResponseHeaders(500, -1L); - } - } - - private static Lazy streamLazy(InputStream stream) { - return Lazy.of(() -> { - try { - return new String(stream.readAllBytes(), StandardCharsets.UTF_8); - } catch (Exception ex) { - return ""; - } - }); - } - - public void stopNow() { - if (server != null) { - server.stop(0); - } - } -} diff --git a/src/main/java/dev/latvian/mods/kubejs/web/JsonContent.java b/src/main/java/dev/latvian/mods/kubejs/web/JsonContent.java new file mode 100644 index 000000000..c474c54f4 --- /dev/null +++ b/src/main/java/dev/latvian/mods/kubejs/web/JsonContent.java @@ -0,0 +1,49 @@ +package dev.latvian.mods.kubejs.web; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import dev.latvian.apps.tinyserver.content.ResponseContent; +import dev.latvian.mods.kubejs.util.Lazy; + +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.util.function.Consumer; +import java.util.function.Supplier; + +public record JsonContent(Lazy json) implements ResponseContent { + public static JsonContent any(Supplier json) { + return new JsonContent(Lazy.of(() -> json.get().toString().getBytes(StandardCharsets.UTF_8))); + } + + public static JsonContent object(Consumer json) { + return new JsonContent(Lazy.of(() -> { + var t = new JsonObject(); + json.accept(t); + return t.toString().getBytes(StandardCharsets.UTF_8); + })); + } + + public static JsonContent array(Consumer json) { + return new JsonContent(Lazy.of(() -> { + var t = new JsonArray(); + json.accept(t); + return t.toString().getBytes(StandardCharsets.UTF_8); + })); + } + + @Override + public long length() { + return json.get().length; + } + + @Override + public String type() { + return "application/json; charset=utf-8"; + } + + @Override + public void write(OutputStream out) throws Exception { + out.write(json.get()); + } +} diff --git a/src/main/java/dev/latvian/mods/kubejs/web/KJSHTTPContext.java b/src/main/java/dev/latvian/mods/kubejs/web/KJSHTTPRequest.java similarity index 94% rename from src/main/java/dev/latvian/mods/kubejs/web/KJSHTTPContext.java rename to src/main/java/dev/latvian/mods/kubejs/web/KJSHTTPRequest.java index dcaee7821..ee3a05398 100644 --- a/src/main/java/dev/latvian/mods/kubejs/web/KJSHTTPContext.java +++ b/src/main/java/dev/latvian/mods/kubejs/web/KJSHTTPRequest.java @@ -3,9 +3,9 @@ import com.mojang.brigadier.StringReader; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.serialization.DynamicOps; +import dev.latvian.apps.tinyserver.http.HTTPRequest; import dev.latvian.mods.kubejs.util.Cast; import dev.latvian.mods.kubejs.util.RegistryAccessContainer; -import dev.latvian.mods.kubejs.web.http.HTTPContext; import net.minecraft.client.Minecraft; import net.minecraft.core.component.DataComponentPatch; import net.minecraft.core.registries.BuiltInRegistries; @@ -16,7 +16,7 @@ import java.util.concurrent.CompletableFuture; import java.util.function.Supplier; -public class KJSHTTPContext extends HTTPContext { +public class KJSHTTPRequest extends HTTPRequest { public RegistryAccessContainer registries() { return RegistryAccessContainer.current; } diff --git a/src/main/java/dev/latvian/mods/kubejs/web/KJSWSSession.java b/src/main/java/dev/latvian/mods/kubejs/web/KJSWSSession.java new file mode 100644 index 000000000..12e21a72b --- /dev/null +++ b/src/main/java/dev/latvian/mods/kubejs/web/KJSWSSession.java @@ -0,0 +1,22 @@ +package dev.latvian.mods.kubejs.web; + +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; +import dev.latvian.apps.tinyserver.ws.WSSession; +import dev.latvian.mods.kubejs.util.JsonUtils; + +public class KJSWSSession extends WSSession { + @Override + public void onTextMessage(String message) { + if (message.startsWith("{") && message.endsWith("}")) { + var json = JsonUtils.fromString(message).getAsJsonObject(); + + if (json.has("event")) { + onEvent(json.get("event").getAsString(), json.has("payload") ? json.get("payload") : JsonNull.INSTANCE); + } + } + } + + public void onEvent(String event, JsonElement payload) { + } +} diff --git a/src/main/java/dev/latvian/mods/kubejs/web/KubeJSLocalWebServer.java b/src/main/java/dev/latvian/mods/kubejs/web/KubeJSLocalWebServer.java index 1a6768111..7d158997e 100644 --- a/src/main/java/dev/latvian/mods/kubejs/web/KubeJSLocalWebServer.java +++ b/src/main/java/dev/latvian/mods/kubejs/web/KubeJSLocalWebServer.java @@ -1,24 +1,24 @@ package dev.latvian.mods.kubejs.web; +import dev.latvian.apps.tinyserver.HTTPServer; +import dev.latvian.apps.tinyserver.ServerRegistry; +import dev.latvian.apps.tinyserver.error.BindFailedException; +import dev.latvian.apps.tinyserver.http.HTTPHandler; +import dev.latvian.apps.tinyserver.http.HTTPMethod; +import dev.latvian.apps.tinyserver.http.response.HTTPResponse; +import dev.latvian.apps.tinyserver.ws.WSHandler; +import dev.latvian.apps.tinyserver.ws.WSSession; +import dev.latvian.apps.tinyserver.ws.WSSessionFactory; import dev.latvian.mods.kubejs.KubeJS; import dev.latvian.mods.kubejs.plugin.KubeJSPlugin; import dev.latvian.mods.kubejs.plugin.KubeJSPlugins; -import dev.latvian.mods.kubejs.web.http.HTTPContext; -import dev.latvian.mods.kubejs.web.http.HTTPHandler; -import dev.latvian.mods.kubejs.web.http.HTTPMethod; -import dev.latvian.mods.kubejs.web.http.HTTPResponse; -import dev.latvian.mods.kubejs.web.http.SimpleHTTPResponse; -import dev.latvian.mods.kubejs.web.ws.WSHandler; -import dev.latvian.mods.kubejs.web.ws.WSSessionFactory; import dev.latvian.mods.rhino.util.HideFromJS; import net.neoforged.fml.ModList; import org.jetbrains.annotations.Nullable; -import java.net.Inet4Address; import java.util.ArrayList; -import java.util.concurrent.Executors; -public record KubeJSLocalWebServer(HTTPServer http) implements WebServerRegistry { +public record KubeJSLocalWebServer(HTTPServer server) implements ServerRegistry { private static KubeJSLocalWebServer instance; @Nullable @@ -30,22 +30,22 @@ public static KubeJSLocalWebServer instance() { public static void start() { if (instance == null) { try { - var address = Inet4Address.getByName(WebServerProperties.get().publicAddress.isEmpty() ? "127.0.0.1" : "0.0.0.0"); - - var http = new HTTPServer<>(KJSHTTPContext::new); + var server = new HTTPServer<>(KJSHTTPRequest::new); // var ws = new WSServer(address, ClientProperties.get().localServerWsPort); - var s = new KubeJSLocalWebServer(http); + var s = new KubeJSLocalWebServer(server); KubeJSPlugins.forEachPlugin(s, KubeJSPlugin::registerLocalWebServer); - http.setHomepageHandler(KubeJSLocalWebServer::homepage); - - if (http.start(address, WebServerProperties.get().port, Executors.newVirtualThreadPerTaskExecutor())) { - // ws.start(); - Runtime.getRuntime().addShutdownHook(new Thread(s::stopNow, "KubeJS Web Server Shutdown Hook")); - KubeJS.LOGGER.info("Started the local web server at http://localhost:" + http.getAddress().getPort()); - instance = s; - } else { - KubeJS.LOGGER.warn("Failed to start the local web server - all ports occupied"); - } + server.get("/", KubeJSLocalWebServer::homepage); + + server.setDaemon(true); + server.setServerName("KubeJS " + KubeJS.VERSION); + server.setAddress(WebServerProperties.get().publicAddress.isEmpty() ? "127.0.0.1" : "0.0.0.0"); + server.setPort(WebServerProperties.get().port); + server.setMaxPortShift(10); + + KubeJS.LOGGER.info("Started the local web server at http://localhost:" + server.start()); + instance = s; + } catch (BindFailedException ex) { + KubeJS.LOGGER.warn("Failed to start the local web server - all ports occupied"); } catch (Exception ex) { KubeJS.LOGGER.warn("Failed to start the local web server - error"); ex.printStackTrace(); @@ -54,16 +54,16 @@ public static void start() { } @Override - public void http(HTTPMethod method, String path, HTTPHandler handler) { - http.addHandler(method, path, handler); + public void http(HTTPMethod httpMethod, String s, HTTPHandler httpHandler) { + server.http(httpMethod, s, httpHandler); } @Override - public WSHandler ws(String path, WSSessionFactory factory) { - return WSHandler.EMPTY; + public > WSHandler ws(String s, WSSessionFactory wsSessionFactory) { + return server.ws(s, wsSessionFactory); } - private static HTTPResponse homepage(HTTPContext ctx) { + private static HTTPResponse homepage(KJSHTTPRequest ctx) { var list = new ArrayList(); list.add("KubeJS Local Web Server [" + KubeJS.PROXY.getWebServerWindowTitle() + "]"); list.add(""); @@ -81,11 +81,11 @@ private static HTTPResponse homepage(HTTPContext ctx) { list.add("- " + mod.getModInfo().getDisplayName() + " (" + mod.getModId() + " - " + mod.getModInfo().getVersion() + ")"); } - return SimpleHTTPResponse.text(200, list); + return HTTPResponse.ok().text(list); } public void stopNow() { - http.stopNow(); + server.stop(); KubeJS.LOGGER.info("Stopped the local web server"); } } diff --git a/src/main/java/dev/latvian/mods/kubejs/web/WebServerRegistry.java b/src/main/java/dev/latvian/mods/kubejs/web/WebServerRegistry.java deleted file mode 100644 index 73f0fdb96..000000000 --- a/src/main/java/dev/latvian/mods/kubejs/web/WebServerRegistry.java +++ /dev/null @@ -1,55 +0,0 @@ -package dev.latvian.mods.kubejs.web; - -import dev.latvian.mods.kubejs.web.http.HTTPContext; -import dev.latvian.mods.kubejs.web.http.HTTPHandler; -import dev.latvian.mods.kubejs.web.http.HTTPMethod; -import dev.latvian.mods.kubejs.web.http.HTTPResponse; -import dev.latvian.mods.kubejs.web.ws.WSHandler; -import dev.latvian.mods.kubejs.web.ws.WSSession; -import dev.latvian.mods.kubejs.web.ws.WSSessionFactory; - -import java.util.function.Consumer; - -public interface WebServerRegistry { - void http(HTTPMethod method, String path, HTTPHandler handler); - - WSHandler ws(String path, WSSessionFactory factory); - - default WSHandler ws(String path) { - return ws(path, WSSession::new); - } - - default void get(String path, HTTPHandler handler) { - http(HTTPMethod.GET, path, handler); - } - - default void post(String path, HTTPHandler handler) { - http(HTTPMethod.POST, path, handler); - } - - default void acceptPostTask(String path, Runnable task) { - post(path, ctx -> { - task.run(); - return HTTPResponse.NO_CONTENT; - }); - } - - default void acceptPostString(String path, Consumer consumer) { - post(path, ctx -> { - consumer.accept(ctx.body()); - return HTTPResponse.NO_CONTENT; - }); - } - - default void put(String path, HTTPHandler handler) { - http(HTTPMethod.PUT, path, handler); - } - - default void patch(String path, HTTPHandler handler) { - http(HTTPMethod.PATCH, path, handler); - } - - default void delete(String path, HTTPHandler handler) { - http(HTTPMethod.DELETE, path, handler); - } -} diff --git a/src/main/java/dev/latvian/mods/kubejs/web/http/HTTPContext.java b/src/main/java/dev/latvian/mods/kubejs/web/http/HTTPContext.java deleted file mode 100644 index 9d82a4003..000000000 --- a/src/main/java/dev/latvian/mods/kubejs/web/http/HTTPContext.java +++ /dev/null @@ -1,76 +0,0 @@ -package dev.latvian.mods.kubejs.web.http; - -import com.sun.net.httpserver.HttpExchange; -import dev.latvian.mods.kubejs.web.CompiledPath; - -import java.util.HashMap; -import java.util.Map; -import java.util.function.Supplier; - -public class HTTPContext { - public static final Supplier NO_BODY = () -> ""; - - private String[] path = new String[0]; - private Map variables = Map.of(); - private Map query = Map.of(); - private final Map headers = Map.of(); - private Supplier body = NO_BODY; - - public void setPath(String[] path) { - this.path = path; - } - - public void setBody(Supplier body) { - this.body = body; - } - - public void init(CompiledPath compiledPath, HttpExchange exchange) { - if (compiledPath.variables() > 0) { - this.variables = new HashMap<>(compiledPath.variables()); - - for (var i = 0; i < compiledPath.parts().length; i++) { - var part = compiledPath.parts()[i]; - - if (part.variable()) { - variables.put(part.name(), path[i]); - } - } - } - - var queryStr = exchange.getRequestURI().getQuery(); - - if (queryStr != null) { - this.query = new HashMap<>(2); - - for (String param : queryStr.split("&")) { - var entry = param.split("=", 2); - - if (entry.length > 1) { - query.put(entry[0], entry[1]); - } else { - query.put(entry[0], ""); - } - } - } - } - - public Map variables() { - return variables; - } - - public Map query() { - return query; - } - - public String header(String name) { - return ""; - } - - public String[] path() { - return path; - } - - public String body() { - return body.get(); - } -} diff --git a/src/main/java/dev/latvian/mods/kubejs/web/http/HTTPHandler.java b/src/main/java/dev/latvian/mods/kubejs/web/http/HTTPHandler.java deleted file mode 100644 index db59e1a66..000000000 --- a/src/main/java/dev/latvian/mods/kubejs/web/http/HTTPHandler.java +++ /dev/null @@ -1,5 +0,0 @@ -package dev.latvian.mods.kubejs.web.http; - -public interface HTTPHandler { - HTTPResponse handle(CTX ctx) throws Exception; -} diff --git a/src/main/java/dev/latvian/mods/kubejs/web/http/HTTPMethod.java b/src/main/java/dev/latvian/mods/kubejs/web/http/HTTPMethod.java deleted file mode 100644 index 6fec57abc..000000000 --- a/src/main/java/dev/latvian/mods/kubejs/web/http/HTTPMethod.java +++ /dev/null @@ -1,20 +0,0 @@ -package dev.latvian.mods.kubejs.web.http; - -public enum HTTPMethod { - GET, - POST, - PUT, - PATCH, - DELETE; - - public static HTTPMethod fromString(String method) { - return switch (method) { - case "get", "GET" -> GET; - case "post", "POST" -> POST; - case "put", "PUT" -> PUT; - case "patch", "PATCH" -> PATCH; - case "delete", "DELETE" -> DELETE; - default -> throw new IllegalArgumentException("Invalid HTTP method: " + method); - }; - } -} diff --git a/src/main/java/dev/latvian/mods/kubejs/web/http/HTTPResponse.java b/src/main/java/dev/latvian/mods/kubejs/web/http/HTTPResponse.java deleted file mode 100644 index efdd11cbe..000000000 --- a/src/main/java/dev/latvian/mods/kubejs/web/http/HTTPResponse.java +++ /dev/null @@ -1,16 +0,0 @@ -package dev.latvian.mods.kubejs.web.http; - -import com.sun.net.httpserver.HttpExchange; - -public interface HTTPResponse { - HTTPResponse OK = SimpleHTTPResponse.text(200, "OK"); - HTTPResponse NO_CONTENT = new SimpleHTTPResponse(204, null, ""); - HTTPResponse WIP = SimpleHTTPResponse.text(404, "WIP"); - HTTPResponse NOT_FOUND = SimpleHTTPResponse.text(404, "Not Found"); - - void respond(HttpExchange exchange) throws Exception; - - default HTTPResponse withHeader(String header, String value) { - return new HTTPResponseWithHeader(this, header, value); - } -} diff --git a/src/main/java/dev/latvian/mods/kubejs/web/http/HTTPResponseWithHeader.java b/src/main/java/dev/latvian/mods/kubejs/web/http/HTTPResponseWithHeader.java deleted file mode 100644 index 6f099433b..000000000 --- a/src/main/java/dev/latvian/mods/kubejs/web/http/HTTPResponseWithHeader.java +++ /dev/null @@ -1,11 +0,0 @@ -package dev.latvian.mods.kubejs.web.http; - -import com.sun.net.httpserver.HttpExchange; - -public record HTTPResponseWithHeader(HTTPResponse original, String header, String value) implements HTTPResponse { - @Override - public void respond(HttpExchange exchange) throws Exception { - exchange.getResponseHeaders().set(header, value); - original.respond(exchange); - } -} diff --git a/src/main/java/dev/latvian/mods/kubejs/web/http/SimpleHTTPResponse.java b/src/main/java/dev/latvian/mods/kubejs/web/http/SimpleHTTPResponse.java deleted file mode 100644 index 18d871951..000000000 --- a/src/main/java/dev/latvian/mods/kubejs/web/http/SimpleHTTPResponse.java +++ /dev/null @@ -1,45 +0,0 @@ -package dev.latvian.mods.kubejs.web.http; - -import com.google.gson.JsonElement; -import com.sun.net.httpserver.HttpExchange; -import dev.latvian.mods.kubejs.util.JsonUtils; -import org.jetbrains.annotations.Nullable; - -import java.nio.charset.StandardCharsets; -import java.util.function.Supplier; - -public record SimpleHTTPResponse(int status, @Nullable byte[] body, String contentType) implements HTTPResponse { - public static SimpleHTTPResponse text(int status, String body) { - return new SimpleHTTPResponse(status, body.getBytes(StandardCharsets.UTF_8), "text/plain; charset=utf-8"); - } - - public static SimpleHTTPResponse text(int status, Iterable lines) { - return text(status, String.join("\n", lines)); - } - - public static SimpleHTTPResponse json(int status, JsonElement json) { - return new SimpleHTTPResponse(status, JsonUtils.GSON.toJson(json).getBytes(StandardCharsets.UTF_8), "application/json; charset=utf-8"); - } - - public static SimpleHTTPResponse lazyJson(Supplier json) { - return json(200, json.get()); - } - - @Override - public void respond(HttpExchange exchange) throws Exception { - var bytes = body(); - var contentType = contentType(); - - if (!contentType.isEmpty()) { - exchange.getResponseHeaders().set("Content-Type", contentType); - } - - exchange.sendResponseHeaders(status(), bytes == null ? -1L : bytes.length); - - if (bytes != null) { - try (var os = exchange.getResponseBody()) { - os.write(bytes); - } - } - } -} diff --git a/src/main/java/dev/latvian/mods/kubejs/web/local/ConsoleWSSession.java b/src/main/java/dev/latvian/mods/kubejs/web/local/ConsoleWSSession.java index 43e5168e8..ed50c34b7 100644 --- a/src/main/java/dev/latvian/mods/kubejs/web/local/ConsoleWSSession.java +++ b/src/main/java/dev/latvian/mods/kubejs/web/local/ConsoleWSSession.java @@ -2,9 +2,9 @@ import com.google.gson.JsonElement; import dev.latvian.mods.kubejs.script.ConsoleJS; -import dev.latvian.mods.kubejs.web.ws.WSSession; +import dev.latvian.mods.kubejs.web.KJSWSSession; -public class ConsoleWSSession extends WSSession { +public class ConsoleWSSession extends KJSWSSession { public final ConsoleJS console; public ConsoleWSSession(ConsoleJS console) { diff --git a/src/main/java/dev/latvian/mods/kubejs/web/local/KubeJSWeb.java b/src/main/java/dev/latvian/mods/kubejs/web/local/KubeJSWeb.java index 80907b0e9..f12d45558 100644 --- a/src/main/java/dev/latvian/mods/kubejs/web/local/KubeJSWeb.java +++ b/src/main/java/dev/latvian/mods/kubejs/web/local/KubeJSWeb.java @@ -1,24 +1,48 @@ package dev.latvian.mods.kubejs.web.local; -import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import dev.latvian.apps.tinyserver.ServerRegistry; +import dev.latvian.apps.tinyserver.http.response.HTTPResponse; +import dev.latvian.apps.tinyserver.http.response.HTTPStatus; +import dev.latvian.apps.tinyserver.ws.WSHandler; import dev.latvian.mods.kubejs.KubeJS; import dev.latvian.mods.kubejs.script.ScriptType; -import dev.latvian.mods.kubejs.web.KJSHTTPContext; -import dev.latvian.mods.kubejs.web.WebServerRegistry; -import dev.latvian.mods.kubejs.web.http.HTTPResponse; -import dev.latvian.mods.kubejs.web.http.SimpleHTTPResponse; -import dev.latvian.mods.kubejs.web.ws.WSHandler; +import dev.latvian.mods.kubejs.util.RegExpKJS; +import dev.latvian.mods.kubejs.web.JsonContent; +import dev.latvian.mods.kubejs.web.KJSHTTPRequest; +import dev.latvian.mods.kubejs.web.KJSWSSession; import net.minecraft.client.Minecraft; import net.minecraft.core.Holder; import net.minecraft.resources.ResourceKey; import net.minecraft.tags.TagKey; import java.util.Optional; +import java.util.function.Supplier; public class KubeJSWeb { - public static WSHandler UPDATES = WSHandler.EMPTY; + public static WSHandler UPDATES = WSHandler.empty(); - public static void addScriptTypeEndpoints(WebServerRegistry registry, ScriptType s) { + public static void broadcastEvent(WSHandler ws, String event, Supplier payload) { + ws.broadcastText(() -> { + var json = new JsonObject(); + json.addProperty("event", event); + + var p = payload == null ? null : payload.get(); + + if (p != null && !p.isJsonNull()) { + json.add("payload", p); + } + + return json.toString(); + }); + } + + public static void broadcastUpdate(String event, Supplier payload) { + broadcastEvent(UPDATES, event, payload); + } + + public static void addScriptTypeEndpoints(ServerRegistry registry, ScriptType s) { var path = "api/console/" + s.name; s.console.wsBroadcaster = registry.ws(path + "/stream", () -> new ConsoleWSSession(s.console)); @@ -30,8 +54,8 @@ public static void addScriptTypeEndpoints(WebServerRegistry regi registry.get(path + "/warnings", s.console::getWarningsResponse); } - public static void register(WebServerRegistry registry) { - UPDATES = registry.ws("updates"); + public static void register(ServerRegistry registry) { + UPDATES = registry.ws("updates", KJSWSSession::new); addScriptTypeEndpoints(registry, ScriptType.STARTUP); addScriptTypeEndpoints(registry, ScriptType.SERVER); @@ -41,6 +65,7 @@ public static void register(WebServerRegistry registry) { registry.get("api/registries", KubeJSWeb::getRegistriesResponse); // List of all registries registry.get("api/registries/{namespace}/{path}/keys", KubeJSWeb::getRegistryKeysResponse); // List of all IDs in registry + registry.get("api/registries/{namespace}/{path}/match/{regex}", KubeJSWeb::getRegistryMatchResponse); // List of RegEx matched IDs in registry registry.get("api/tags/{namespace}/{path}", KubeJSWeb::getTagsResponse); // List of all tags in registry registry.get("api/tags/{namespace}/{path}/values/{tag-namespace}/{tag-path}", KubeJSWeb::getTagValuesResponse); // List of all values in a tag @@ -55,99 +80,103 @@ private static void reloadInternalServer() { } } - private static HTTPResponse getRegistriesResponse(KJSHTTPContext ctx) { - return SimpleHTTPResponse.lazyJson(() -> { - var json = new JsonArray(); - + private static HTTPResponse getRegistriesResponse(KJSHTTPRequest ctx) { + return HTTPResponse.ok().content(JsonContent.array(json -> { for (var registry : ctx.registries().access().registries().toList()) { json.add(registry.key().location().toString()); } - - return json; - }); + })); } - private static HTTPResponse getRegistryKeysResponse(KJSHTTPContext ctx) { + private static HTTPResponse getRegistryKeysResponse(KJSHTTPRequest ctx) { var registry = ctx.registries().access().registry(ResourceKey.createRegistryKey(ctx.id())); if (registry.isEmpty()) { - return HTTPResponse.NOT_FOUND; + return HTTPStatus.NOT_FOUND; } - return SimpleHTTPResponse.lazyJson(() -> { - var json = new JsonArray(); - + return HTTPResponse.ok().content(JsonContent.array(json -> { for (var key : registry.get().keySet()) { json.add(key.toString()); } - - return json; - }); + })); } - private static HTTPResponse getTagsResponse(KJSHTTPContext ctx) { + private static HTTPResponse getRegistryMatchResponse(KJSHTTPRequest ctx) { var registry = ctx.registries().access().registry(ResourceKey.createRegistryKey(ctx.id())); if (registry.isEmpty()) { - return HTTPResponse.NOT_FOUND; + return HTTPStatus.NOT_FOUND; } - return SimpleHTTPResponse.lazyJson(() -> { - var json = new JsonArray(); + var regex = RegExpKJS.ofString(ctx.variables().get("regex")); + + if (regex == null) { + return HTTPStatus.BAD_REQUEST; + } + return HTTPResponse.ok().content(JsonContent.array(json -> { + for (var key : registry.get().keySet()) { + var k = key.toString(); + + if (regex.matcher(k).find()) { + json.add(k); + } + } + })); + } + + private static HTTPResponse getTagsResponse(KJSHTTPRequest ctx) { + var registry = ctx.registries().access().registry(ResourceKey.createRegistryKey(ctx.id())); + + if (registry.isEmpty()) { + return HTTPStatus.NOT_FOUND; + } + + return HTTPResponse.ok().content(JsonContent.array(json -> { for (var tag : registry.get().getTagNames().map(TagKey::location).toList()) { json.add(tag.toString()); } - - return json; - }); + })); } - private static HTTPResponse getTagValuesResponse(KJSHTTPContext ctx) { + private static HTTPResponse getTagValuesResponse(KJSHTTPRequest ctx) { var registry = ctx.registries().access().registry(ResourceKey.createRegistryKey(ctx.id())); if (registry.isEmpty()) { - return HTTPResponse.NOT_FOUND; + return HTTPStatus.NOT_FOUND; } var tagKey = registry.get().getTag(TagKey.create(registry.get().key(), ctx.id("tag-namespace", "tag-path"))); if (tagKey.isEmpty()) { - return HTTPResponse.NOT_FOUND; + return HTTPStatus.NOT_FOUND; } - return SimpleHTTPResponse.lazyJson(() -> { - var json = new JsonArray(); - + return HTTPResponse.ok().content(JsonContent.array(json -> { for (var key : tagKey.get().stream().map(Holder::unwrapKey).filter(Optional::isPresent).map(Optional::get).map(ResourceKey::location).toList()) { json.add(key.toString()); } - - return json; - }); + })); } - private static HTTPResponse getTagKeysResponse(KJSHTTPContext ctx) { + private static HTTPResponse getTagKeysResponse(KJSHTTPRequest ctx) { var registry = ctx.registries().access().registry(ResourceKey.createRegistryKey(ctx.id())); if (registry.isEmpty()) { - return HTTPResponse.NOT_FOUND; + return HTTPStatus.NOT_FOUND; } var value = registry.get().getHolder(ctx.id("value-namespace", "value-path")); if (value.isEmpty()) { - return HTTPResponse.NOT_FOUND; + return HTTPStatus.NOT_FOUND; } - return SimpleHTTPResponse.lazyJson(() -> { - var json = new JsonArray(); - + return HTTPResponse.ok().content(JsonContent.array(json -> { for (var key : value.get().tags().map(TagKey::location).toList()) { json.add(key.toString()); } - - return json; - }); + })); } } diff --git a/src/main/java/dev/latvian/mods/kubejs/web/local/client/ImageGenerator.java b/src/main/java/dev/latvian/mods/kubejs/web/local/client/ImageGenerator.java index b150af6e5..98bc5f685 100644 --- a/src/main/java/dev/latvian/mods/kubejs/web/local/client/ImageGenerator.java +++ b/src/main/java/dev/latvian/mods/kubejs/web/local/client/ImageGenerator.java @@ -8,13 +8,13 @@ import com.mojang.blaze3d.vertex.Tesselator; import com.mojang.blaze3d.vertex.VertexFormat; import com.mojang.blaze3d.vertex.VertexSorting; +import dev.latvian.apps.tinyserver.http.response.HTTPResponse; +import dev.latvian.apps.tinyserver.http.response.HTTPStatus; import dev.latvian.mods.kubejs.KubeJSPaths; import dev.latvian.mods.kubejs.bindings.BlockWrapper; import dev.latvian.mods.kubejs.bindings.UUIDWrapper; import dev.latvian.mods.kubejs.component.DataComponentWrapper; -import dev.latvian.mods.kubejs.web.KJSHTTPContext; -import dev.latvian.mods.kubejs.web.http.HTTPResponse; -import dev.latvian.mods.kubejs.web.http.SimpleHTTPResponse; +import dev.latvian.mods.kubejs.web.KJSHTTPRequest; import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import net.minecraft.client.Minecraft; @@ -31,7 +31,6 @@ import net.neoforged.neoforge.fluids.FluidType; import org.joml.Matrix4f; -import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.UUID; @@ -43,11 +42,11 @@ private record RenderImage(Minecraft mc, GuiGraphics graphics, int size) { public static final Int2ObjectMap FB_CACHE = new Int2ObjectArrayMap<>(); - private static HTTPResponse renderCanvas(KJSHTTPContext ctx, int canvasSize, StringBuilder cacheId, Consumer render) { + private static HTTPResponse renderCanvas(KJSHTTPRequest ctx, int canvasSize, StringBuilder cacheId, Consumer render) { int size = Integer.parseInt(ctx.variables().get("size")); if (size < 1 || size > 1024) { - return SimpleHTTPResponse.text(400, "Invalid size, must be [1, 1024]"); + return HTTPStatus.BAD_REQUEST.text("Invalid size, must be [1, 1024]"); } if (!cacheId.isEmpty()) { @@ -55,21 +54,18 @@ private static HTTPResponse renderCanvas(KJSHTTPContext ctx, int canvasSize, Str } if (cacheId.isEmpty() && ctx.header("Accept").equals("text/plain")) { - return SimpleHTTPResponse.NOT_FOUND; + return HTTPStatus.NOT_FOUND; } var cacheUUID = cacheId.isEmpty() ? null : UUIDWrapper.toString(UUID.nameUUIDFromBytes(cacheId.toString().getBytes(StandardCharsets.UTF_8))); var cachePath = cacheUUID == null ? null : KubeJSPaths.dir(KubeJSPaths.LOCAL_WEB_IMG_CACHE.resolve(cacheUUID.substring(0, 2))).resolve(cacheUUID + ".png"); if (cachePath != null && Files.exists(cachePath)) { - try { - if (ctx.header("Accept").equals("text/plain")) { - return SimpleHTTPResponse.text(200, cacheUUID); - } - - return new SimpleHTTPResponse(200, Files.readAllBytes(cachePath), "image/png").withHeader("X-KubeJS-Cache-Key", cacheUUID); - } catch (IOException ignore) { + if (ctx.header("Accept").equals("text/plain")) { + return HTTPResponse.ok().text(cacheUUID); } + + return HTTPResponse.ok().content(cachePath).header("X-KubeJS-Cache-Key", cacheUUID); } var bytes = ctx.supplyInRenderThread(() -> { @@ -125,21 +121,21 @@ private static HTTPResponse renderCanvas(KJSHTTPContext ctx, int canvasSize, Str if (ctx.header("Accept").equals("text/plain")) { if (cachePath == null) { - return SimpleHTTPResponse.NOT_FOUND; + return HTTPStatus.NOT_FOUND; } - return SimpleHTTPResponse.text(200, cacheUUID); + return HTTPResponse.ok().text(cacheUUID); } - return new SimpleHTTPResponse(200, bytes, "image/png").withHeader("X-KubeJS-Cache-Key", cacheUUID); + return HTTPResponse.ok().content(bytes, "image/png").header("X-KubeJS-Cache-Key", cacheUUID); } - public static HTTPResponse item(KJSHTTPContext ctx) throws Exception { + public static HTTPResponse item(KJSHTTPRequest ctx) throws Exception { var stack = BuiltInRegistries.ITEM.get(ctx.id()).getDefaultInstance(); stack.applyComponents(ctx.queryAsPatch(ctx.registries().nbt())); if (stack.isEmpty()) { - return HTTPResponse.NOT_FOUND; + return HTTPStatus.NOT_FOUND; } var sb = new StringBuilder(); @@ -152,11 +148,11 @@ public static HTTPResponse item(KJSHTTPContext ctx) throws Exception { }); } - public static HTTPResponse block(KJSHTTPContext ctx) throws Exception { + public static HTTPResponse block(KJSHTTPRequest ctx) throws Exception { var state = BlockWrapper.withProperties(BuiltInRegistries.BLOCK.get(ctx.id()).defaultBlockState(), ctx.query()); if (state.isEmpty()) { - return HTTPResponse.NOT_FOUND; + return HTTPStatus.NOT_FOUND; } var sb = new StringBuilder(); @@ -172,12 +168,12 @@ public static HTTPResponse block(KJSHTTPContext ctx) throws Exception { }); } - public static HTTPResponse fluid(KJSHTTPContext ctx) throws Exception { + public static HTTPResponse fluid(KJSHTTPRequest ctx) throws Exception { var stack = new FluidStack(BuiltInRegistries.FLUID.get(ctx.id()), FluidType.BUCKET_VOLUME); stack.applyComponents(ctx.queryAsPatch(ctx.registries().nbt())); if (stack.isEmpty()) { - return HTTPResponse.NOT_FOUND; + return HTTPStatus.NOT_FOUND; } var fluidInfo = IClientFluidTypeExtensions.of(stack.getFluid()); @@ -206,7 +202,7 @@ public static HTTPResponse fluid(KJSHTTPContext ctx) throws Exception { }); } - public static HTTPResponse itemTag(KJSHTTPContext ctx) throws Exception { + public static HTTPResponse itemTag(KJSHTTPRequest ctx) throws Exception { var tagKey = ItemTags.create(ctx.id()); return renderCanvas(ctx, 16, new StringBuilder(), render -> { @@ -215,7 +211,7 @@ public static HTTPResponse itemTag(KJSHTTPContext ctx) throws Exception { }); } - public static HTTPResponse blockTag(KJSHTTPContext ctx) throws Exception { + public static HTTPResponse blockTag(KJSHTTPRequest ctx) throws Exception { var tagKey = BlockTags.create(ctx.id()); return renderCanvas(ctx, 16, new StringBuilder(), render -> { @@ -224,7 +220,7 @@ public static HTTPResponse blockTag(KJSHTTPContext ctx) throws Exception { }); } - public static HTTPResponse fluidTag(KJSHTTPContext ctx) throws Exception { + public static HTTPResponse fluidTag(KJSHTTPRequest ctx) throws Exception { var tagKey = FluidTags.create(ctx.id()); return renderCanvas(ctx, 16, new StringBuilder(), render -> { diff --git a/src/main/java/dev/latvian/mods/kubejs/web/local/client/KubeJSClientWeb.java b/src/main/java/dev/latvian/mods/kubejs/web/local/client/KubeJSClientWeb.java index 4fe9eca9a..c8823fd07 100644 --- a/src/main/java/dev/latvian/mods/kubejs/web/local/client/KubeJSClientWeb.java +++ b/src/main/java/dev/latvian/mods/kubejs/web/local/client/KubeJSClientWeb.java @@ -1,23 +1,23 @@ package dev.latvian.mods.kubejs.web.local.client; -import com.google.gson.JsonArray; +import dev.latvian.apps.tinyserver.ServerRegistry; +import dev.latvian.apps.tinyserver.http.response.HTTPResponse; +import dev.latvian.apps.tinyserver.http.response.HTTPStatus; import dev.latvian.mods.kubejs.KubeJS; import dev.latvian.mods.kubejs.script.ScriptType; -import dev.latvian.mods.kubejs.web.KJSHTTPContext; -import dev.latvian.mods.kubejs.web.WebServerRegistry; -import dev.latvian.mods.kubejs.web.http.HTTPResponse; -import dev.latvian.mods.kubejs.web.http.SimpleHTTPResponse; +import dev.latvian.mods.kubejs.web.JsonContent; +import dev.latvian.mods.kubejs.web.KJSHTTPRequest; import dev.latvian.mods.kubejs.web.local.KubeJSWeb; import net.minecraft.client.Minecraft; public class KubeJSClientWeb { - public static void register(WebServerRegistry registry) { + public static void register(ServerRegistry registry) { KubeJSWeb.addScriptTypeEndpoints(registry, ScriptType.CLIENT); registry.acceptPostTask("api/reload/client", KubeJS.getClientScriptManager()::reload); - registry.get("assets", KubeJSClientWeb::getAssets); - registry.get("assets/{namespace}/", KubeJSClientWeb::getAsset); + registry.get("assets/list/", KubeJSClientWeb::getAssetList); + registry.get("assets/get/{namespace}/", KubeJSClientWeb::getAssetContent); registry.get("img/{size}/item/{namespace}/{path}", ImageGenerator::item); registry.get("img/{size}/block/{namespace}/{path}", ImageGenerator::block); @@ -27,35 +27,37 @@ public static void register(WebServerRegistry registry) { registry.get("img/{size}/fluid-tag/{namespace}/{path}", ImageGenerator::fluidTag); } - private static HTTPResponse getAssets(KJSHTTPContext ctx) { - return SimpleHTTPResponse.lazyJson(() -> { - var json = new JsonArray(); + private static HTTPResponse getAssetList(KJSHTTPRequest ctx) { + var prefix = ctx.variables().get("prefix"); - for (var id : Minecraft.getInstance().getResourceManager().listPacks().toList()) { + if (prefix.isEmpty()) { + return HTTPStatus.BAD_REQUEST; + } + + return HTTPResponse.ok().content(JsonContent.array(json -> { + for (var id : Minecraft.getInstance().getResourceManager().listResources(prefix, id -> true).keySet()) { json.add(id.toString()); } - - return json; - }); + })); } - private static HTTPResponse getAsset(KJSHTTPContext ctx) throws Exception { + private static HTTPResponse getAssetContent(KJSHTTPRequest ctx) throws Exception { var id = ctx.id(); var asset = Minecraft.getInstance().getResourceManager().getResource(id); if (asset.isEmpty()) { - return HTTPResponse.NOT_FOUND; + return HTTPStatus.NOT_FOUND; } try (var in = asset.get().open()) { if (id.getPath().endsWith(".png")) { - return new SimpleHTTPResponse(200, in.readAllBytes(), "image/png"); + return HTTPResponse.ok().content(in.readAllBytes(), "image/png"); } else if (id.getPath().endsWith(".json") || id.getPath().endsWith(".mcmeta")) { - return new SimpleHTTPResponse(200, in.readAllBytes(), "application/json; charset=utf-8"); + return HTTPResponse.ok().content(in.readAllBytes(), "application/json; charset=utf-8"); } else if (id.getPath().endsWith(".ogg")) { - return new SimpleHTTPResponse(200, in.readAllBytes(), "audio/ogg"); + return HTTPResponse.ok().content(in.readAllBytes(), "audio/ogg"); } else { - return new SimpleHTTPResponse(200, in.readAllBytes(), "text/plain"); + return HTTPResponse.ok().content(in.readAllBytes(), "text/plain"); } } } diff --git a/src/main/java/dev/latvian/mods/kubejs/web/ws/WSHandler.java b/src/main/java/dev/latvian/mods/kubejs/web/ws/WSHandler.java deleted file mode 100644 index 2d162e901..000000000 --- a/src/main/java/dev/latvian/mods/kubejs/web/ws/WSHandler.java +++ /dev/null @@ -1,55 +0,0 @@ -package dev.latvian.mods.kubejs.web.ws; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; -import org.jetbrains.annotations.Nullable; - -import java.util.function.Supplier; - -public interface WSHandler { - WSHandler EMPTY = new WSHandler() { - @Override - public void broadcast(String message) { - } - - @Override - public void broadcast(byte[] bytes) { - } - - @Override - public void broadcast(String event, Supplier payload) { - } - - @Override - public void broadcast(String event, String payload) { - } - - @Override - public void broadcast(String event, @Nullable JsonElement payload) { - } - }; - - void broadcast(String message); - - void broadcast(byte[] bytes); - - default void broadcast(String event, Supplier payload) { - broadcast(event, payload.get()); - } - - default void broadcast(String event, String payload) { - broadcast(event, new JsonPrimitive(payload)); - } - - default void broadcast(String event, @Nullable JsonElement payload) { - var json = new JsonObject(); - json.addProperty("event", event); - - if (payload != null && !payload.isJsonNull()) { - json.add("payload", payload); - } - - broadcast(json.toString()); - } -} diff --git a/src/main/java/dev/latvian/mods/kubejs/web/ws/WSSession.java b/src/main/java/dev/latvian/mods/kubejs/web/ws/WSSession.java deleted file mode 100644 index 51b613b0b..000000000 --- a/src/main/java/dev/latvian/mods/kubejs/web/ws/WSSession.java +++ /dev/null @@ -1,8 +0,0 @@ -package dev.latvian.mods.kubejs.web.ws; - -import com.google.gson.JsonElement; - -public class WSSession { - public void onEvent(String event, JsonElement payload) { - } -} diff --git a/src/main/java/dev/latvian/mods/kubejs/web/ws/WSSessionFactory.java b/src/main/java/dev/latvian/mods/kubejs/web/ws/WSSessionFactory.java deleted file mode 100644 index 4de970f30..000000000 --- a/src/main/java/dev/latvian/mods/kubejs/web/ws/WSSessionFactory.java +++ /dev/null @@ -1,6 +0,0 @@ -package dev.latvian.mods.kubejs.web.ws; - -@FunctionalInterface -public interface WSSessionFactory { - WSSession create(); -}