diff --git a/core/pom.xml b/core/pom.xml
index 23864e0..6a8de2f 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -17,4 +17,12 @@
17
+
+
+
+ com.google.code.gson
+ gson
+ 2.9.0
+
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index e6af771..97bfde5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -20,15 +20,6 @@
UTF-8
-
-
-
- com.google.code.gson
- gson
- 2.9.0
-
-
-
diff --git a/server/src/main/java/nl/andrewl/starship_arena/server/ClientManager.java b/server/src/main/java/nl/andrewl/starship_arena/server/ClientManager.java
new file mode 100644
index 0000000..e2b9a42
--- /dev/null
+++ b/server/src/main/java/nl/andrewl/starship_arena/server/ClientManager.java
@@ -0,0 +1,31 @@
+package nl.andrewl.starship_arena.server;
+
+import nl.andrewl.starship_arena.server.model.Arena;
+
+import java.io.IOException;
+import java.net.Socket;
+
+public class ClientManager extends Thread {
+ private final Arena arena;
+ private final Socket clientSocket;
+
+ public ClientManager(Arena arena, Socket clientSocket) {
+ this.arena = arena;
+ this.clientSocket = clientSocket;
+ }
+
+ public void shutdown() {
+ try {
+ clientSocket.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void run() {
+ while (clientSocket.isConnected() && !clientSocket.isClosed()) {
+
+ }
+ }
+}
diff --git a/server/src/main/java/nl/andrewl/starship_arena/server/StarshipArenaServer.java b/server/src/main/java/nl/andrewl/starship_arena/server/StarshipArenaServer.java
index 1779b65..eafb506 100644
--- a/server/src/main/java/nl/andrewl/starship_arena/server/StarshipArenaServer.java
+++ b/server/src/main/java/nl/andrewl/starship_arena/server/StarshipArenaServer.java
@@ -1,23 +1,90 @@
package nl.andrewl.starship_arena.server;
+import nl.andrewl.starship_arena.server.model.Arena;
import nl.andrewl.starship_arena.server.servlet.ArenasServlet;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
public class StarshipArenaServer {
+ private static final Logger logger = LoggerFactory.getLogger(StarshipArenaServer.class);
+
+ private final Map arenas = new ConcurrentHashMap<>();
+ private final ServerSocket serverSocket;
+ private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
+
public static void main(String[] args) throws Exception {
+ StarshipArenaServer server = new StarshipArenaServer();
+ server.registerArena(new Arena());
+ server.registerArena(new Arena("Andrew's Arena"));
+
Server jettyServer = new Server(8080);
Connector connector = new ServerConnector(jettyServer);
jettyServer.addConnector(connector);
ServletContextHandler servletContext = new ServletContextHandler();
servletContext.setContextPath("/");
- servletContext.addServlet(new ServletHolder(new ArenasServlet()), "/arenas");
+ servletContext.addServlet(new ServletHolder(new ArenasServlet(server)), "/arenas");
jettyServer.setHandler(servletContext);
jettyServer.start();
+ server.acceptConnections();
+ }
+
+ public StarshipArenaServer() throws IOException {
+ serverSocket = new ServerSocket();
+ serverSocket.setReuseAddress(true);
+ }
+
+ public List getArenas() {
+ List sortedArenas = new ArrayList<>(this.arenas.values());
+ sortedArenas.sort(Comparator.comparing(Arena::getCreatedAt));
+ return sortedArenas;
+ }
+
+ public void registerArena(Arena a) {
+ arenas.put(a.getId(), a);
+ }
+
+ public void acceptConnections() throws Exception {
+ serverSocket.bind(new InetSocketAddress("127.0.0.1", 8081));
+ logger.info("Now accepting TCP connections.");
+ while (!serverSocket.isClosed()) {
+ Socket clientSocket = serverSocket.accept();
+ logger.info("Client connected from {}", clientSocket.getRemoteSocketAddress());
+ executor.submit(() -> {
+ try {
+ processIncomingConnection(clientSocket);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ });
+ }
+ }
+
+ private void processIncomingConnection(Socket clientSocket) throws IOException {
+ var din = new DataInputStream(clientSocket.getInputStream());
+ UUID arenaId = new UUID(din.readLong(), din.readLong());
+ Arena arena = arenas.get(arenaId);
+ if (arena != null) {
+ var cm = new ClientManager(arenas.get(arenaId), clientSocket);
+ cm.start();
+ } else {
+ clientSocket.close();
+ }
}
}
diff --git a/server/src/main/java/nl/andrewl/starship_arena/server/model/Arena.java b/server/src/main/java/nl/andrewl/starship_arena/server/model/Arena.java
index 4a53efc..f00f160 100644
--- a/server/src/main/java/nl/andrewl/starship_arena/server/model/Arena.java
+++ b/server/src/main/java/nl/andrewl/starship_arena/server/model/Arena.java
@@ -1,4 +1,67 @@
package nl.andrewl.starship_arena.server.model;
+import nl.andrewl.starship_arena.server.ClientManager;
+
+import java.time.Instant;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+
public class Arena {
+ private final UUID id;
+ private final Instant createdAt;
+ private final String name;
+
+ private ArenaStage currentStage = ArenaStage.STAGING;
+
+ private final Map clients = new ConcurrentHashMap<>();
+
+ public Arena(String name) {
+ this.id = UUID.randomUUID();
+ this.createdAt = Instant.now();
+ this.name = name;
+ }
+
+ public Arena() {
+ this("Unnamed Arena");
+ }
+
+ public UUID getId() {
+ return id;
+ }
+
+ public Instant getCreatedAt() {
+ return createdAt;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public ArenaStage getCurrentStage() {
+ return currentStage;
+ }
+
+ public void registerClient(UUID id, ClientManager clientManager) {
+ if (clients.containsKey(id)) {
+ clientManager.shutdown();
+ } else {
+ clients.put(id, clientManager);
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o == this || o instanceof Arena a && id.equals(a.id);
+ }
+
+ @Override
+ public int hashCode() {
+ return id.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return id.toString();
+ }
}
diff --git a/server/src/main/java/nl/andrewl/starship_arena/server/model/ArenaStage.java b/server/src/main/java/nl/andrewl/starship_arena/server/model/ArenaStage.java
new file mode 100644
index 0000000..a72aab3
--- /dev/null
+++ b/server/src/main/java/nl/andrewl/starship_arena/server/model/ArenaStage.java
@@ -0,0 +1,7 @@
+package nl.andrewl.starship_arena.server.model;
+
+public enum ArenaStage {
+ STAGING,
+ BATTLE,
+ ANALYSIS
+}
diff --git a/server/src/main/java/nl/andrewl/starship_arena/server/servlet/ArenaRequest.java b/server/src/main/java/nl/andrewl/starship_arena/server/servlet/ArenaRequest.java
new file mode 100644
index 0000000..f1438b1
--- /dev/null
+++ b/server/src/main/java/nl/andrewl/starship_arena/server/servlet/ArenaRequest.java
@@ -0,0 +1,5 @@
+package nl.andrewl.starship_arena.server.servlet;
+
+public class ArenaRequest {
+ public String name;
+}
diff --git a/server/src/main/java/nl/andrewl/starship_arena/server/servlet/ArenaResponse.java b/server/src/main/java/nl/andrewl/starship_arena/server/servlet/ArenaResponse.java
new file mode 100644
index 0000000..54b2ed0
--- /dev/null
+++ b/server/src/main/java/nl/andrewl/starship_arena/server/servlet/ArenaResponse.java
@@ -0,0 +1,19 @@
+package nl.andrewl.starship_arena.server.servlet;
+
+import nl.andrewl.starship_arena.server.model.Arena;
+
+public record ArenaResponse(
+ String id,
+ String createdAt,
+ String name,
+ String currentStage
+) {
+ public ArenaResponse(Arena a) {
+ this(
+ a.getId().toString(),
+ a.getCreatedAt().toString(),
+ a.getName(),
+ a.getCurrentStage().name()
+ );
+ }
+}
diff --git a/server/src/main/java/nl/andrewl/starship_arena/server/servlet/ArenasServlet.java b/server/src/main/java/nl/andrewl/starship_arena/server/servlet/ArenasServlet.java
index 5fdb694..5eb9b49 100644
--- a/server/src/main/java/nl/andrewl/starship_arena/server/servlet/ArenasServlet.java
+++ b/server/src/main/java/nl/andrewl/starship_arena/server/servlet/ArenasServlet.java
@@ -1,16 +1,51 @@
package nl.andrewl.starship_arena.server.servlet;
-import jakarta.servlet.ServletException;
+import com.google.gson.Gson;
+import com.google.gson.JsonIOException;
+import com.google.gson.JsonSyntaxException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
+import nl.andrewl.starship_arena.server.StarshipArenaServer;
+import nl.andrewl.starship_arena.server.model.Arena;
import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.List;
public class ArenasServlet extends HttpServlet {
+ private static final Gson gson = new Gson();
+ private final StarshipArenaServer server;
+
+ public ArenasServlet(StarshipArenaServer server) {
+ this.server = server;
+ }
+
@Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- super.doGet(req, resp);
- // TODO: Return the list of available arenas.
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+ List data = server.getArenas().stream()
+ .map(ArenaResponse::new).toList();
+ resp.setStatus(HttpServletResponse.SC_OK);
+ resp.setContentType("application/json");
+ resp.setCharacterEncoding("UTF-8");
+ gson.toJson(data, resp.getWriter());
+ }
+
+ @Override
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+ if (!req.getContentType().equals("application/json")) resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Only JSON is allowed.");
+ ArenaRequest arenaRequest;
+ try {
+ arenaRequest = gson.fromJson(new InputStreamReader(req.getInputStream()), ArenaRequest.class);
+ } catch (JsonSyntaxException | JsonIOException e) {
+ resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid JSON.");
+ return;
+ }
+ Arena arena = arenaRequest.name == null ? new Arena() : new Arena(arenaRequest.name);
+ server.registerArena(arena);
+ resp.setStatus(HttpServletResponse.SC_CREATED);
+ resp.setContentType("application/json");
+ resp.setCharacterEncoding("UTF-8");
+ gson.toJson(new ArenaResponse(arena), resp.getWriter());
}
}