From 669cd9e789c2fd3452c01c621e774ea8b1cd28b0 Mon Sep 17 00:00:00 2001 From: Zontreck Date: Sun, 11 Feb 2024 22:47:32 -0700 Subject: [PATCH] Add an http server --- .../HTTPResponseLockedException.java | 9 ++ .../playsync/server/HTTPResponseData.java | 28 +++++ .../zontreck/playsync/server/HTTPServer.java | 100 ++++++++++++++++++ .../server/events/HTTPRequestEvent.java | 38 +++++++ 4 files changed, 175 insertions(+) create mode 100644 server/src/main/java/dev/zontreck/playsync/exceptions/HTTPResponseLockedException.java create mode 100644 server/src/main/java/dev/zontreck/playsync/server/HTTPResponseData.java create mode 100644 server/src/main/java/dev/zontreck/playsync/server/HTTPServer.java create mode 100644 server/src/main/java/dev/zontreck/playsync/server/events/HTTPRequestEvent.java diff --git a/server/src/main/java/dev/zontreck/playsync/exceptions/HTTPResponseLockedException.java b/server/src/main/java/dev/zontreck/playsync/exceptions/HTTPResponseLockedException.java new file mode 100644 index 0000000..1d1ef90 --- /dev/null +++ b/server/src/main/java/dev/zontreck/playsync/exceptions/HTTPResponseLockedException.java @@ -0,0 +1,9 @@ +package dev.zontreck.playsync.exceptions; + +public class HTTPResponseLockedException extends Exception +{ + @Override + public String getMessage() { + return "The response was already set in this event. The response is now locked in"; + } +} diff --git a/server/src/main/java/dev/zontreck/playsync/server/HTTPResponseData.java b/server/src/main/java/dev/zontreck/playsync/server/HTTPResponseData.java new file mode 100644 index 0000000..f9b683f --- /dev/null +++ b/server/src/main/java/dev/zontreck/playsync/server/HTTPResponseData.java @@ -0,0 +1,28 @@ +package dev.zontreck.playsync.server; + + +import java.util.Map; + +public class HTTPResponseData { + private int responseCode; + private String body; + private Map headers; + + public HTTPResponseData(int responseCode, String body, Map headers) { + this.responseCode = responseCode; + this.body = body; + this.headers = headers; + } + + public int getResponseCode() { + return responseCode; + } + + public String getBody() { + return body; + } + + public Map getHeaders() { + return headers; + } +} \ No newline at end of file diff --git a/server/src/main/java/dev/zontreck/playsync/server/HTTPServer.java b/server/src/main/java/dev/zontreck/playsync/server/HTTPServer.java new file mode 100644 index 0000000..f9d9330 --- /dev/null +++ b/server/src/main/java/dev/zontreck/playsync/server/HTTPServer.java @@ -0,0 +1,100 @@ +package dev.zontreck.playsync.server; + +import com.sun.net.httpserver.HttpServer; +import dev.zontreck.playsync.Settings; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.HashMap; +import java.util.Map; + +public class HTTPServer +{ + private ServerSocket serverSocket; + private boolean running; + private RequestHandler requestHandler; + + public void start() { + try { + serverSocket = new ServerSocket(Settings.PORT_NUMBER); + running = true; + System.out.println("Server started on port " + Settings.PORT_NUMBER); + + while (running) { + Socket clientSocket = serverSocket.accept(); + System.out.println("Client connected: " + clientSocket); + + // Handle client request in a separate thread + new Thread(() -> handleRequest(clientSocket)).start(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void stop() { + running = false; + try { + if (serverSocket != null) + serverSocket.close(); + System.out.println("Server stopped."); + } catch (IOException e) { + e.printStackTrace(); + } + } + + + private void handleRequest(Socket clientSocket) { + try ( + BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); + PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true) + ) { + // Read request line + String requestLine = in.readLine(); + System.out.println("Request: " + requestLine); + + // Parse request line to get path + String[] parts = requestLine.split(" "); + String path = parts[1]; + + // Read headers and store them in a map + Map headers = new HashMap<>(); + String headerLine; + while ((headerLine = in.readLine()) != null && !headerLine.isEmpty()) { + String[] headerParts = headerLine.split(": ", 2); + headers.put(headerParts[0], headerParts[1]); + } + + // Read request body for POST request + StringBuilder requestBody = new StringBuilder(); + String line; + while ((line = in.readLine()) != null && !line.isEmpty()) { + requestBody.append(line).append("\n"); + } + + // Handle request and get response + HTTPResponseData response = requestHandler.handleRequest(path, requestBody.toString(), headers); + + // Send response including headers + out.println("HTTP/1.1 " + response.getResponseCode()); + for (Map.Entry entry : response.getHeaders().entrySet()) { + out.println(entry.getKey() + ": " + entry.getValue()); + } + out.println("Content-Length: " + response.getBody().length()); + out.println("Server: Harbinger/1.2"); // Use the Harbinger server signature. While Harbinger will be a separate server program, this is designed to be a part of the Harbinger software suite. + out.println(); + out.println(response.getBody()); + + // Close resources + clientSocket.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + +} diff --git a/server/src/main/java/dev/zontreck/playsync/server/events/HTTPRequestEvent.java b/server/src/main/java/dev/zontreck/playsync/server/events/HTTPRequestEvent.java new file mode 100644 index 0000000..98ec38b --- /dev/null +++ b/server/src/main/java/dev/zontreck/playsync/server/events/HTTPRequestEvent.java @@ -0,0 +1,38 @@ +package dev.zontreck.playsync.server.events; + +import dev.zontreck.ariaslib.util.Lists; +import dev.zontreck.eventsbus.Cancellable; +import dev.zontreck.eventsbus.Event; +import dev.zontreck.playsync.exceptions.HTTPResponseLockedException; +import dev.zontreck.playsync.server.HTTPResponseData; + +import java.util.Map; + +@Cancellable +public class HTTPRequestEvent extends Event +{ + public String Path; + public String Body; + public Map Headers; + private HTTPResponseData Response; + + public HTTPRequestEvent(String requestPath, String requestBody, Map requestHeaders) + { + this.Path=requestPath; + this.Body=requestBody; + this.Headers=requestHeaders; + } + + public void handle(int statusCode, String body, Map headers) throws HTTPResponseLockedException { + if(Response==null) + { + throw new HTTPResponseLockedException(); + } + Response = new HTTPResponseData(statusCode, body, headers); + } + + public HTTPResponseData getResponse() + { + return Response; + } +}