diff --git a/src/main/java/me/youhavetrouble/inviter/Main.java b/src/main/java/me/youhavetrouble/inviter/Main.java index 3b79653..4f5597a 100644 --- a/src/main/java/me/youhavetrouble/inviter/Main.java +++ b/src/main/java/me/youhavetrouble/inviter/Main.java @@ -98,4 +98,8 @@ public class Main { LOGGER.info("Welcome to the Inviter Application!"); } + public static Storage getStorage() { + return storage; + } + } diff --git a/src/main/java/me/youhavetrouble/inviter/http/ApiServer.java b/src/main/java/me/youhavetrouble/inviter/http/ApiServer.java index fdda9c4..52bb58a 100644 --- a/src/main/java/me/youhavetrouble/inviter/http/ApiServer.java +++ b/src/main/java/me/youhavetrouble/inviter/http/ApiServer.java @@ -2,6 +2,7 @@ package me.youhavetrouble.inviter.http; import com.sun.net.httpserver.HttpServer; import me.youhavetrouble.inviter.Main; +import me.youhavetrouble.inviter.http.endpoints.HandlerKernel; import java.io.IOException; import java.net.InetSocketAddress; @@ -14,6 +15,7 @@ public class ApiServer { public ApiServer(String hostname, int port) throws IllegalArgumentException, IOException { server = HttpServer.create(new InetSocketAddress(hostname, port), 0); server.setExecutor(Executors.newVirtualThreadPerTaskExecutor()); + server.createContext("/", new HandlerKernel()); server.start(); Main.LOGGER.info("Http API server started on {}:{}", hostname, port); } diff --git a/src/main/java/me/youhavetrouble/inviter/http/endpoints/EndpointHandler.java b/src/main/java/me/youhavetrouble/inviter/http/endpoints/EndpointHandler.java new file mode 100644 index 0000000..ed56b45 --- /dev/null +++ b/src/main/java/me/youhavetrouble/inviter/http/endpoints/EndpointHandler.java @@ -0,0 +1,15 @@ +package me.youhavetrouble.inviter.http.endpoints; + +import com.sun.net.httpserver.HttpExchange; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.util.regex.Pattern; + +public interface EndpointHandler { + + @NotNull Pattern pathPattern(); + + void handle(@NotNull HttpExchange exchange) throws IOException; + +} diff --git a/src/main/java/me/youhavetrouble/inviter/http/endpoints/GetDiscordInviteByGuildId.java b/src/main/java/me/youhavetrouble/inviter/http/endpoints/GetDiscordInviteByGuildId.java new file mode 100644 index 0000000..e01d67f --- /dev/null +++ b/src/main/java/me/youhavetrouble/inviter/http/endpoints/GetDiscordInviteByGuildId.java @@ -0,0 +1,74 @@ +package me.youhavetrouble.inviter.http.endpoints; + +import com.sun.net.httpserver.HttpExchange; +import me.youhavetrouble.inviter.DiscordInvite; +import me.youhavetrouble.inviter.Main; +import me.youhavetrouble.inviter.storage.Storage; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.util.regex.Pattern; + +public class GetDiscordInviteByGuildId implements EndpointHandler { + + private final Pattern pathPattern = Pattern.compile("^/api/v1/discord/\\d{10,18}$"); + + @NotNull + @Override + public Pattern pathPattern() { + return pathPattern; + } + + @Override + public void handle(@NotNull HttpExchange exchange) throws IOException { + if (!exchange.getRequestMethod().equals("GET")) { + exchange.sendResponseHeaders(405, -1); // Method Not Allowed + return; + } + + String path = exchange.getRequestURI().getPath(); + + String[] parts = path.split("/"); + String guildId = parts[parts.length - 1]; + long guildIdLong; + try { + guildIdLong = Long.parseLong(guildId); + } catch (NumberFormatException e) { + exchange.sendResponseHeaders(400, -1); // Bad Request + return; + } + + Storage storage = Main.getStorage(); + DiscordInvite invite = storage.getInvite(guildIdLong); + + if (invite == null) { + exchange.sendResponseHeaders(404, -1); // Not Found + return; + } + + String inviteUrl = "https://discord.gg/" + invite.code(); + + switch (exchange.getRequestHeaders().getFirst("Accept")) { + case "text/plain" -> { + exchange.getResponseHeaders().set("Content-Type", "text/plain"); + exchange.sendResponseHeaders(200, inviteUrl.length()); + exchange.getResponseBody().write(inviteUrl.getBytes()); + } + case "application/json" -> { + exchange.getResponseHeaders().set("Content-Type", "application/json"); + String jsonResponse = "{\"url\": \"" + inviteUrl + "\"}"; + exchange.sendResponseHeaders(200, jsonResponse.length()); + exchange.getResponseBody().write(jsonResponse.getBytes()); + } + default -> { + exchange.getResponseHeaders().set("Location", inviteUrl); + exchange.sendResponseHeaders(307, -1); + } + } + + + + } + + +} diff --git a/src/main/java/me/youhavetrouble/inviter/http/endpoints/HandlerKernel.java b/src/main/java/me/youhavetrouble/inviter/http/endpoints/HandlerKernel.java new file mode 100644 index 0000000..ba5fd58 --- /dev/null +++ b/src/main/java/me/youhavetrouble/inviter/http/endpoints/HandlerKernel.java @@ -0,0 +1,43 @@ +package me.youhavetrouble.inviter.http.endpoints; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import me.youhavetrouble.inviter.Main; + +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; + +public class HandlerKernel implements HttpHandler { + + private final Set handlers = new HashSet<>(); + + public HandlerKernel() { + handlers.add(new GetDiscordInviteByGuildId()); + } + + @Override + public void handle(HttpExchange exchange) throws IOException { + + String path = exchange.getRequestURI().getPath(); + if (path.endsWith("/")) path = path.substring(0, path.length() - 1); + exchange.getResponseHeaders().set("Access-Control-Allow-Origin", "*"); + exchange.getResponseHeaders().set("Access-Control-Allow-Methods", "*"); + exchange.getResponseHeaders().set("Access-Control-Allow-Headers", "Content-Type"); + + for (EndpointHandler handler : handlers) { + if (handler.pathPattern().matcher(path).matches()) { + handler.handle(exchange); + return; + } + } + + try { + exchange.sendResponseHeaders(404, -1); + exchange.getResponseBody().close(); + } catch (Exception e) { + Main.LOGGER.error("Error handling request for {}: {}", path, e.getMessage()); + } + + } +}