summaryrefslogtreecommitdiff
path: root/api
diff options
context:
space:
mode:
Diffstat (limited to 'api')
-rw-r--r--api/build.gradle8
-rw-r--r--api/src/main/java/akkamon/api/AkkamonSession.java12
-rw-r--r--api/src/main/java/akkamon/api/App.java46
-rw-r--r--api/src/main/java/akkamon/api/EventSocket.java31
-rw-r--r--api/src/main/java/akkamon/api/MessagingEngine.java117
-rw-r--r--api/src/main/java/akkamon/api/models/Event.java14
-rw-r--r--api/src/main/java/akkamon/api/models/GameState.java33
-rw-r--r--api/src/main/java/akkamon/api/models/Player.java13
-rw-r--r--api/src/main/java/akkamon/api/models/Position.java11
-rw-r--r--api/src/main/java/akkamon/api/models/User.java11
-rw-r--r--api/src/test/java/akkamon/api/EventSocketTest.java7
-rw-r--r--api/src/test/java/akkamon/api/MessagingEngineTest.java7
12 files changed, 293 insertions, 17 deletions
diff --git a/api/build.gradle b/api/build.gradle
index 3db517e..28ec919 100644
--- a/api/build.gradle
+++ b/api/build.gradle
@@ -29,16 +29,18 @@ dependencies {
// In our simple use case, the logger gets automatically configured by simply existing.
implementation 'org.slf4j:slf4j-simple:+'
+ implementation 'com.google.code.gson:gson:2.8.7'
+
// Reference the domain subproject.
- // implementation project(':domain')
+ implementation project(':domain')
// Use JUnit Jupiter API for testing.
- testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.2'
+ testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
// Also use the Mockito mocking framework to mock simple server functionality.
testImplementation "org.mockito:mockito-core:2.+"
// Use JUnit Jupiter Engine for testing.
- testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.6.2'
+ testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
}
application {
diff --git a/api/src/main/java/akkamon/api/AkkamonSession.java b/api/src/main/java/akkamon/api/AkkamonSession.java
new file mode 100644
index 0000000..217c8d8
--- /dev/null
+++ b/api/src/main/java/akkamon/api/AkkamonSession.java
@@ -0,0 +1,12 @@
+package akkamon.api;
+
+import akkamon.api.models.User;
+
+public interface AkkamonSession {
+
+ void receiveGameState(String gameState);
+
+ void disconnect(int statusCode, String message);
+
+ void setCurrentUser(User user);
+}
diff --git a/api/src/main/java/akkamon/api/App.java b/api/src/main/java/akkamon/api/App.java
index bc462d0..989562b 100644
--- a/api/src/main/java/akkamon/api/App.java
+++ b/api/src/main/java/akkamon/api/App.java
@@ -3,21 +3,18 @@ package akkamon.api;
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.eclipse.jetty.websocket.server.JettyWebSocketServlet;
import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer;
+import org.glassfish.jersey.servlet.ServletContainer;
public class App {
public static void main(String[] args) {
- Server server = new Server();
- ServerConnector connector = new ServerConnector(server);
- connector.setPort(8080);
- server.addConnector(connector);
+ Server server = startServer(8080);
+ ServletContextHandler context = createStatefulContext(server);
- // application "context" ?
- ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
- context.setContextPath("/");
- server.setHandler(context);
// websocket behaviour
// Configure specific websocket behavior
@@ -30,8 +27,13 @@ public class App {
wsContainer.addMapping("/", EventSocket.class);
});
+ // registerServlets(context);
+
try {
server.start();
+ System.out.println("Started server.");
+ System.out.println("Listening on http://localhost:8080/");
+ System.out.println("Press CTRL+C to exit.");
server.join();
}
catch (Throwable t) {
@@ -39,4 +41,32 @@ public class App {
}
}
+
+ private static ServletContextHandler createStatefulContext(Server server) {
+ ServletContextHandler context =
+ new ServletContextHandler(ServletContextHandler.SESSIONS);
+ context.setContextPath("/");
+ server.setHandler(context);
+ return context;
+ }
+
+ private static Server startServer(int port) {
+ Server server = new Server();
+ ServerConnector connector = new ServerConnector(server);
+ connector.setPort(port);
+ server.addConnector(connector);
+ return server;
+ }
+
+ private static void registerServlets(ServletContextHandler context) {
+ // Use the Jersey framework to translate the classes in the
+ // mancala.api package to server endpoints (servlets).
+ // For example, the StartMancala class will become an endpoint at
+ // http://localost:8080/mancala/api/start
+ ServletHolder serverHolder = context.addServlet(JettyWebSocketServlet.class, "/");
+ serverHolder.setInitOrder(1);
+ serverHolder.setInitParameter("jersey.config.server.provider.packages",
+ "akkamon.api");
+ }
+
}
diff --git a/api/src/main/java/akkamon/api/EventSocket.java b/api/src/main/java/akkamon/api/EventSocket.java
index 1c7bafc..5a2693e 100644
--- a/api/src/main/java/akkamon/api/EventSocket.java
+++ b/api/src/main/java/akkamon/api/EventSocket.java
@@ -1,16 +1,18 @@
package akkamon.api;
-import java.util.Locale;
+import java.io.IOException;
import java.util.concurrent.CountDownLatch;
+import akkamon.api.models.User;
import org.eclipse.jetty.websocket.api.WebSocketAdapter;
import org.eclipse.jetty.websocket.api.Session;
-import org.eclipse.jetty.websocket.api.StatusCode;
-public class EventSocket extends WebSocketAdapter {
+public class EventSocket extends WebSocketAdapter implements AkkamonSession {
private final CountDownLatch closureLatch = new CountDownLatch(1);
+ public User user;
+
@Override
public void onWebSocketConnect(Session sess)
{
@@ -23,10 +25,8 @@ public class EventSocket extends WebSocketAdapter {
{
super.onWebSocketText(message);
System.out.println("Received TEXT message: " + message);
+ MessagingEngine.getInstance().incoming(this, message);
- if (message.toLowerCase(Locale.US).contains("bye")) {
- getSession().close(StatusCode.NORMAL, "Thanks");
- }
}
@Override
@@ -49,4 +49,23 @@ public class EventSocket extends WebSocketAdapter {
System.out.println("Awaiting closure from remote");
closureLatch.await();
}
+
+ @Override
+ public void receiveGameState(String gameState) {
+ try {
+ getRemote().sendString(gameState);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void disconnect(int statusCode, String message) {
+ getSession().close(statusCode, message);
+ }
+
+ @Override
+ public void setCurrentUser(User user) {
+ this.user = user;
+ }
}
diff --git a/api/src/main/java/akkamon/api/MessagingEngine.java b/api/src/main/java/akkamon/api/MessagingEngine.java
new file mode 100644
index 0000000..a3cff1d
--- /dev/null
+++ b/api/src/main/java/akkamon/api/MessagingEngine.java
@@ -0,0 +1,117 @@
+package akkamon.api;
+
+import akkamon.api.models.*;
+import akkamon.domain.AkkamonImpl;
+import akkamon.domain.Trainer;
+import com.google.gson.Gson;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+public class MessagingEngine {
+
+ private HashMap<String, AkkamonSession> akkamonSessions = new HashMap<>();
+ private static MessagingEngine instance;
+ private Gson gson = new Gson();
+
+ public static MessagingEngine getInstance() {
+ if (instance == null) {
+ instance = new MessagingEngine();
+ return instance;
+ }
+ return instance;
+ }
+
+ public MessagingEngine() {
+ ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(2);
+ executor.scheduleAtFixedRate(new Runnable() {
+ @Override
+ public void run() {
+ emitGameState();
+ }
+ }, 0, 200, TimeUnit.MILLISECONDS);
+
+ }
+
+ void emitGameState() {
+ HashMap<String, Trainer> trainers = AkkamonImpl.getInstance().getDummyTrainersCollection();
+
+ if (akkamonSessions.size() == 1) {
+ AkkamonSession session = akkamonSessions.get("Ash");
+
+ GameState gameState = new GameState();
+ // dummy
+ gameState.setCurrentPlayer("Ash", trainers);
+
+ Event event = new Event("updatePos", gameState);
+
+ session.receiveGameState(gson.toJson(event));
+
+ } else if (akkamonSessions.size() == 2) {
+ for (String name: akkamonSessions.keySet()) {
+ AkkamonSession session = akkamonSessions.get(name);
+
+ GameState gameState = new GameState();
+ // dummy
+ gameState.setCurrentPlayer(name, trainers);
+ gameState.setRemotePlayers(trainers);
+
+ Event event = new Event("updatePos", gameState);
+
+ session.receiveGameState(gson.toJson(event));
+ }
+ }
+
+ // for (Map.Entry<User, AkkamonSession> sess: akkamonSessions.entrySet()) {
+
+ // User user = sess.getKey();
+ // AkkamonSession session = sess.getValue();
+
+ // GameState gameState = new GameState();
+ // // dummy
+ // gameState.setCurrentPlayer(user.name, trainers);
+
+ // session.receiveGameState(gson.toJson(gameState));
+ // }
+ }
+
+ void incoming(AkkamonSession session, String message) {
+ Event event = gson.fromJson(message, Event.class);
+ switch (event.type) {
+ case "login":
+ login(session, event.user);
+ break;
+ case "posUpdate":
+ updatePositions(event.gameState);
+ break;
+ }
+ }
+
+ private void updatePositions(GameState gameState) {
+ Player current = gameState.currentPlayer;
+ if (gameState.currentPlayer != null) {
+ AkkamonImpl.getInstance().updateTrainerPosition(current.name, current.position.x, current.position.y);
+ }
+ }
+
+ private void login(AkkamonSession session, User user) {
+ if (user == null) {
+ session.disconnect(401, "Give username and password");
+ }
+ System.out.println("Currrent connections: " + akkamonSessions.size());
+ if (akkamonSessions.size() == 0) {
+ akkamonSessions.put("Ash", session);
+ System.out.println("After adding ash!: " + akkamonSessions.size());
+ session.setCurrentUser(new User("Ash", ""));
+ } else if (akkamonSessions.size() == 1) {
+ akkamonSessions.put("Misty", session);
+ session.setCurrentUser(new User("Misty", ""));
+ }
+ AkkamonImpl.getInstance().newPlayerConnected(user.name, user.password);
+ System.out.println("Emitting gameState!");
+ emitGameState();
+ }
+
+}
diff --git a/api/src/main/java/akkamon/api/models/Event.java b/api/src/main/java/akkamon/api/models/Event.java
new file mode 100644
index 0000000..50fc849
--- /dev/null
+++ b/api/src/main/java/akkamon/api/models/Event.java
@@ -0,0 +1,14 @@
+package akkamon.api.models;
+
+import org.eclipse.jetty.server.Authentication;
+
+public class Event {
+ public String type;
+ public GameState gameState;
+ public User user;
+
+ public Event(String type, GameState gameState) {
+ this.type = type;
+ this.gameState = gameState;
+ }
+}
diff --git a/api/src/main/java/akkamon/api/models/GameState.java b/api/src/main/java/akkamon/api/models/GameState.java
new file mode 100644
index 0000000..b303d24
--- /dev/null
+++ b/api/src/main/java/akkamon/api/models/GameState.java
@@ -0,0 +1,33 @@
+package akkamon.api.models;
+
+import akkamon.domain.Trainer;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class GameState {
+ public Player currentPlayer;
+ public HashMap<String, Player> remotePlayers;
+
+
+ public void setCurrentPlayer(String name, HashMap<String, Trainer> trainers) {
+ Trainer trainer = trainers.get(name);
+ Position position = new Position(trainer.getX(), trainer.getY());
+ currentPlayer = new Player(name, position);
+ }
+
+ public void setRemotePlayers(HashMap<String, Trainer> trainers) {
+ for (Map.Entry<String, Trainer> trainer: trainers.entrySet()) {
+ if (trainer.getValue().getName().equals(currentPlayer.name)) {
+ continue;
+ }
+
+ String name = trainer.getKey();
+ Trainer obj = trainer.getValue();
+ remotePlayers.put(name, new Player(name, new Position(
+ obj.getX(),
+ obj.getY()
+ )));
+ }
+ }
+}
diff --git a/api/src/main/java/akkamon/api/models/Player.java b/api/src/main/java/akkamon/api/models/Player.java
new file mode 100644
index 0000000..3aebb4d
--- /dev/null
+++ b/api/src/main/java/akkamon/api/models/Player.java
@@ -0,0 +1,13 @@
+package akkamon.api.models;
+
+import java.util.HashMap;
+
+public class Player {
+ public String name;
+ public Position position;
+
+ public Player(String name, Position position) {
+ this.name = name;
+ this.position = position;
+ }
+}
diff --git a/api/src/main/java/akkamon/api/models/Position.java b/api/src/main/java/akkamon/api/models/Position.java
new file mode 100644
index 0000000..abe11dd
--- /dev/null
+++ b/api/src/main/java/akkamon/api/models/Position.java
@@ -0,0 +1,11 @@
+package akkamon.api.models;
+
+public class Position {
+ public int x;
+ public int y;
+
+ public Position(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+}
diff --git a/api/src/main/java/akkamon/api/models/User.java b/api/src/main/java/akkamon/api/models/User.java
new file mode 100644
index 0000000..5f26ea0
--- /dev/null
+++ b/api/src/main/java/akkamon/api/models/User.java
@@ -0,0 +1,11 @@
+package akkamon.api.models;
+
+public class User {
+ public String name;
+ public String password;
+
+ public User(String name, String password) {
+ this.name = name;
+ this.password = password;
+ }
+}
diff --git a/api/src/test/java/akkamon/api/EventSocketTest.java b/api/src/test/java/akkamon/api/EventSocketTest.java
new file mode 100644
index 0000000..e9a6cc0
--- /dev/null
+++ b/api/src/test/java/akkamon/api/EventSocketTest.java
@@ -0,0 +1,7 @@
+package akkamon.api;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class EventSocketTest {
+
+} \ No newline at end of file
diff --git a/api/src/test/java/akkamon/api/MessagingEngineTest.java b/api/src/test/java/akkamon/api/MessagingEngineTest.java
new file mode 100644
index 0000000..97d556c
--- /dev/null
+++ b/api/src/test/java/akkamon/api/MessagingEngineTest.java
@@ -0,0 +1,7 @@
+package akkamon.api;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class MessagingEngineTest {
+
+} \ No newline at end of file