summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/org/luxons/sevenwonders/config/WebSocketConfig.java2
-rw-r--r--src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java28
-rw-r--r--src/main/java/org/luxons/sevenwonders/errors/ExceptionHandler.java14
-rw-r--r--src/main/java/org/luxons/sevenwonders/errors/UserInputException.java4
-rw-r--r--src/main/java/org/luxons/sevenwonders/game/Game.java3
-rw-r--r--src/main/java/org/luxons/sevenwonders/game/Lobby.java11
-rw-r--r--src/main/java/org/luxons/sevenwonders/repositories/GameRepository.java4
-rw-r--r--src/main/java/org/luxons/sevenwonders/repositories/LobbyRepository.java15
-rw-r--r--src/main/resources/static/app.js11
-rw-r--r--src/main/resources/static/test-ws.js35
-rw-r--r--src/main/resources/static/test.html16
11 files changed, 81 insertions, 62 deletions
diff --git a/src/main/java/org/luxons/sevenwonders/config/WebSocketConfig.java b/src/main/java/org/luxons/sevenwonders/config/WebSocketConfig.java
index 83629d6a..3b588894 100644
--- a/src/main/java/org/luxons/sevenwonders/config/WebSocketConfig.java
+++ b/src/main/java/org/luxons/sevenwonders/config/WebSocketConfig.java
@@ -19,7 +19,7 @@ public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
config.setUserDestinationPrefix("/user");
// prefix for all calls from clients
- config.setApplicationDestinationPrefixes("/app");
+ config.setApplicationDestinationPrefixes("/app", "/topic");
}
@Override
diff --git a/src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java b/src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java
index 22e994dd..3b98d72f 100644
--- a/src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java
+++ b/src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java
@@ -1,7 +1,7 @@
package org.luxons.sevenwonders.controllers;
import java.security.Principal;
-import java.util.List;
+import java.util.Collection;
import org.luxons.sevenwonders.actions.JoinOrCreateGameAction;
import org.luxons.sevenwonders.actions.StartGameAction;
@@ -9,7 +9,6 @@ import org.luxons.sevenwonders.errors.ApiMisuseException;
import org.luxons.sevenwonders.game.Game;
import org.luxons.sevenwonders.game.Lobby;
import org.luxons.sevenwonders.game.Player;
-import org.luxons.sevenwonders.game.api.PlayerTurnInfo;
import org.luxons.sevenwonders.repositories.GameRepository;
import org.luxons.sevenwonders.repositories.LobbyRepository;
import org.luxons.sevenwonders.session.SessionAttributes;
@@ -21,11 +20,11 @@ import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.messaging.simp.annotation.SendToUser;
+import org.springframework.messaging.simp.annotation.SubscribeMapping;
import org.springframework.stereotype.Controller;
import org.springframework.validation.annotation.Validated;
@Controller
-@MessageMapping("/lobby")
public class LobbyController {
private static final Logger logger = LoggerFactory.getLogger(LobbyController.class);
@@ -44,7 +43,13 @@ public class LobbyController {
this.gameRepository = gameRepository;
}
- @MessageMapping("/create-game")
+ @SubscribeMapping("/games") // prefix /topic not shown
+ public Collection<Lobby> listGames() {
+ logger.info("Subscribed to /games");
+ return lobbyRepository.list();
+ }
+
+ @MessageMapping("/lobby/create-game")
@SendTo("/topic/games")
public Lobby createGame(SimpMessageHeaderAccessor headerAccessor, @Validated JoinOrCreateGameAction action,
Principal principal) {
@@ -59,7 +64,7 @@ public class LobbyController {
return lobby;
}
- @MessageMapping("/join-game")
+ @MessageMapping("/lobby/join-game")
@SendToUser("/queue/join-game")
public Lobby joinGame(SimpMessageHeaderAccessor headerAccessor, @Validated JoinOrCreateGameAction action,
Principal principal) {
@@ -82,7 +87,7 @@ public class LobbyController {
}
}
- @MessageMapping("/start-game")
+ @MessageMapping("/lobby/start-game")
public void startGame(SimpMessageHeaderAccessor headerAccessor, @Validated StartGameAction action,
Principal principal) {
Lobby lobby = getOwnedLobby(headerAccessor, principal);
@@ -90,13 +95,6 @@ public class LobbyController {
gameRepository.add(game);
logger.info("Game {} successfully started", game.getId());
-
- List<PlayerTurnInfo> playerTurnInfos = game.startTurn();
- for (PlayerTurnInfo playerTurnInfo : playerTurnInfos) {
- Player player = playerTurnInfo.getTable().getPlayers().get(playerTurnInfo.getPlayerIndex());
- String userName = player.getUserName();
- template.convertAndSendToUser(userName, "/queue/game/turn", playerTurnInfo);
- }
}
private Lobby getOwnedLobby(SimpMessageHeaderAccessor headerAccessor, Principal principal) {
@@ -110,13 +108,13 @@ public class LobbyController {
return lobby;
}
- private class UserOwnsNoLobbyException extends ApiMisuseException {
+ private static class UserOwnsNoLobbyException extends ApiMisuseException {
UserOwnsNoLobbyException(String message) {
super(message);
}
}
- private class UserAlreadyInGameException extends ApiMisuseException {
+ private static class UserAlreadyInGameException extends ApiMisuseException {
UserAlreadyInGameException(String gameName, String impossibleActionDescription) {
super("Client already in game '" + gameName + "', " + impossibleActionDescription);
}
diff --git a/src/main/java/org/luxons/sevenwonders/errors/ExceptionHandler.java b/src/main/java/org/luxons/sevenwonders/errors/ExceptionHandler.java
index ca2e4062..9e26cbe3 100644
--- a/src/main/java/org/luxons/sevenwonders/errors/ExceptionHandler.java
+++ b/src/main/java/org/luxons/sevenwonders/errors/ExceptionHandler.java
@@ -7,6 +7,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
+import org.springframework.messaging.converter.MessageConversionException;
import org.springframework.messaging.handler.annotation.MessageExceptionHandler;
import org.springframework.messaging.handler.annotation.support.MethodArgumentNotValidException;
import org.springframework.messaging.simp.annotation.SendToUser;
@@ -20,7 +21,11 @@ public class ExceptionHandler {
private static final String ERROR_CODE_VALIDATION = "VALIDATION_ERROR";
- private static final String ERROR_MSG_VALIDATION = "Input invalid";
+ private static final String ERROR_CODE_CONVERSION = "MESSAGE_FORMAT_ERROR";
+
+ private static final String ERROR_MSG_VALIDATION = "Invalid input data";
+
+ private static final String ERROR_MSG_CONVERSION = "Invalid input format";
private final MessageSource messageSource;
@@ -41,6 +46,13 @@ public class ExceptionHandler {
@MessageExceptionHandler
@SendToUser("/queue/errors")
+ private UIError handleConversionError(MessageConversionException exception) {
+ logger.error("Error interpreting the message", exception);
+ return new UIError(ERROR_CODE_CONVERSION, ERROR_MSG_CONVERSION, ErrorType.VALIDATION);
+ }
+
+ @MessageExceptionHandler
+ @SendToUser("/queue/errors")
private UIError handleGenericUserError(UserInputException exception) {
logger.error("Incorrect user input: " + exception.getMessage());
String messageKey = exception.getMessageResourceKey();
diff --git a/src/main/java/org/luxons/sevenwonders/errors/UserInputException.java b/src/main/java/org/luxons/sevenwonders/errors/UserInputException.java
index a86448ae..4033a696 100644
--- a/src/main/java/org/luxons/sevenwonders/errors/UserInputException.java
+++ b/src/main/java/org/luxons/sevenwonders/errors/UserInputException.java
@@ -11,11 +11,11 @@ public class UserInputException extends RuntimeException {
this.params = params;
}
- public String getMessageResourceKey() {
+ String getMessageResourceKey() {
return messageResourceKey;
}
- public Object[] getParams() {
+ Object[] getParams() {
return params;
}
}
diff --git a/src/main/java/org/luxons/sevenwonders/game/Game.java b/src/main/java/org/luxons/sevenwonders/game/Game.java
index 6006ef47..70a5b615 100644
--- a/src/main/java/org/luxons/sevenwonders/game/Game.java
+++ b/src/main/java/org/luxons/sevenwonders/game/Game.java
@@ -131,8 +131,7 @@ public class Game {
}
private static class MissingPreparedMoveException extends RuntimeException {
-
- public MissingPreparedMoveException(int playerIndex) {
+ MissingPreparedMoveException(int playerIndex) {
super("Player " + playerIndex + " is not ready to play");
}
}
diff --git a/src/main/java/org/luxons/sevenwonders/game/Lobby.java b/src/main/java/org/luxons/sevenwonders/game/Lobby.java
index 16d4e8a3..241c5530 100644
--- a/src/main/java/org/luxons/sevenwonders/game/Lobby.java
+++ b/src/main/java/org/luxons/sevenwonders/game/Lobby.java
@@ -86,18 +86,17 @@ public class Lobby {
return owner.getUserName().equals(userName);
}
- public class GameAlreadyStartedException extends IllegalStateException {
+ private static class GameAlreadyStartedException extends IllegalStateException {
}
- public class PlayerOverflowException extends IllegalStateException {
+ private static class PlayerOverflowException extends IllegalStateException {
}
- public class PlayerUnderflowException extends IllegalStateException {
+ private static class PlayerUnderflowException extends IllegalStateException {
}
- public class PlayerNameAlreadyUsedException extends UniqueIdAlreadyUsedException {
-
- public PlayerNameAlreadyUsedException(String name) {
+ private static class PlayerNameAlreadyUsedException extends UniqueIdAlreadyUsedException {
+ PlayerNameAlreadyUsedException(String name) {
super(name);
}
}
diff --git a/src/main/java/org/luxons/sevenwonders/repositories/GameRepository.java b/src/main/java/org/luxons/sevenwonders/repositories/GameRepository.java
index 14aaf3ac..0e0f6db8 100644
--- a/src/main/java/org/luxons/sevenwonders/repositories/GameRepository.java
+++ b/src/main/java/org/luxons/sevenwonders/repositories/GameRepository.java
@@ -27,13 +27,13 @@ public class GameRepository {
return game;
}
- private class GameNotFoundException extends ApiMisuseException {
+ private static class GameNotFoundException extends ApiMisuseException {
GameNotFoundException(long id) {
super("Game " + id + " doesn't exist");
}
}
- private class GameAlreadyExistsException extends ApiMisuseException {
+ private static class GameAlreadyExistsException extends ApiMisuseException {
GameAlreadyExistsException(long id) {
super("Game " + id + " already exists");
}
diff --git a/src/main/java/org/luxons/sevenwonders/repositories/LobbyRepository.java b/src/main/java/org/luxons/sevenwonders/repositories/LobbyRepository.java
index e4f049f5..bede34af 100644
--- a/src/main/java/org/luxons/sevenwonders/repositories/LobbyRepository.java
+++ b/src/main/java/org/luxons/sevenwonders/repositories/LobbyRepository.java
@@ -1,5 +1,6 @@
package org.luxons.sevenwonders.repositories;
+import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
@@ -24,6 +25,10 @@ public class LobbyRepository {
this.gameDefinitionLoader = gameDefinitionLoader;
}
+ public Collection<Lobby> list() {
+ return lobbies.values();
+ }
+
public Lobby create(String gameName, Player owner) {
if (lobbies.containsKey(gameName)) {
throw new GameNameAlreadyUsedException(gameName);
@@ -42,16 +47,14 @@ public class LobbyRepository {
return lobby;
}
- private class LobbyNotFoundException extends RuntimeException {
-
- public LobbyNotFoundException(String name) {
+ private static class LobbyNotFoundException extends RuntimeException {
+ LobbyNotFoundException(String name) {
super("Lobby not found for game '" + name + "'");
}
}
- private class GameNameAlreadyUsedException extends UserInputException {
-
- public GameNameAlreadyUsedException(String name) {
+ private static class GameNameAlreadyUsedException extends UserInputException {
+ GameNameAlreadyUsedException(String name) {
super("Game name '" + name + "' already exists");
}
}
diff --git a/src/main/resources/static/app.js b/src/main/resources/static/app.js
index ace23fdb..2b6b160b 100644
--- a/src/main/resources/static/app.js
+++ b/src/main/resources/static/app.js
@@ -25,8 +25,15 @@ function connect() {
stompClient.subscribe('/topic/games', function (msg) {
var game = JSON.parse(msg.body);
- console.log("Received new game: " + game);
- addNewGame(game);
+ if (Array.isArray(game)) {
+ console.log("Received new games: " + game);
+ for (var i = 0; i < game.length; i++) {
+ addNewGame(game[i]);
+ }
+ } else {
+ console.log("Received new game: " + game);
+ addNewGame(game);
+ }
});
stompClient.subscribe('/user/queue/join-game', function (msg) {
diff --git a/src/main/resources/static/test-ws.js b/src/main/resources/static/test-ws.js
index 48104537..662cf811 100644
--- a/src/main/resources/static/test-ws.js
+++ b/src/main/resources/static/test-ws.js
@@ -6,31 +6,17 @@ function connect() {
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
console.log('Connected: ' + frame);
-
- for (var i = 1; i < 10; i++) {
- subscribeTest(stompClient, '/test' + i);
- subscribeTest(stompClient, '/topic/test' + i);
- subscribeTest(stompClient, '/broadcast/test' + i);
- subscribeTest(stompClient, '/queue/test' + i);
- subscribeTest(stompClient, '/user/queue/test' + i);
- subscribeTest(stompClient, '/user/queue/topic/test' + i);
- subscribeTest(stompClient, '/user/queue/broadcast/test' + i);
- }
});
}
-function sendTest(indexes) {
- for (var i = 0; i < indexes.length; i++) {
- stompClient.send("/app/test" + indexes[i], {}, "test payload " + indexes[i]);
- }
+function send(endpoint, payload) {
+ stompClient.send(endpoint, {}, payload);
}
-function subscribeTest(stompClient, endpoint) {
- var id = endpoint.replace(new RegExp('/', 'g'), '') + '-data';
- $("#test-feeds").append('<tr><td>' + endpoint + '</td><td id="' + id + '">no data received yet</td></tr>');
+function subscribeTo(endpoint) {
+ $("#test-feeds").prepend('<tr><td>' + endpoint + '</td><td>Subscribed</td></tr>');
stompClient.subscribe(endpoint, function (data) {
- console.log("Received event on " + endpoint + ": data.body=" + data.body);
- $("#" + id).html('<strong>received "' + data.body + '"</strong>');
+ $("#test-feeds").prepend('<tr><td>' + endpoint + '</td><td>Received: <pre>' + data.body + '</pre></td></tr>');
});
}
@@ -38,9 +24,14 @@ $(function () {
$("form").on('submit', function (e) {
e.preventDefault();
});
- $("#send-test").click(function () {
- var indexesToSend = $("#test-index-field").val().split(',');
- sendTest(indexesToSend);
+ $("#send-btn").click(function () {
+ var endpoint = $("#path-field").val();
+ var payload = $("#payload-field").val();
+ send(endpoint, payload);
+ });
+ $("#subscribe-btn").click(function () {
+ var endpoint = $("#subscribe-path-field").val();
+ subscribeTo(endpoint);
});
});
diff --git a/src/main/resources/static/test.html b/src/main/resources/static/test.html
index 93c5d928..e19f9eb3 100644
--- a/src/main/resources/static/test.html
+++ b/src/main/resources/static/test.html
@@ -21,9 +21,19 @@
<form class="form-inline">
<div class="form-group">
- <label for="test-index-field">Send to /app/testX, with X in </label>
- <input id="test-index-field">
- <button id="send-test" class="btn btn-default" type="submit">Send</button>
+ <label for="subscribe-path-field">Path:</label>
+ <input id="subscribe-path-field" placeholder="path">
+ <button id="subscribe-btn" class="btn btn-default" type="submit">Subscribe</button>
+ </div>
+</form>
+
+<form class="form-inline">
+ <div class="form-group">
+ <label for="path-field">Path:</label>
+ <input id="path-field" placeholder="path">
+ <label for="payload-field">Payload:</label>
+ <input id="payload-field" placeholder="JSON payload">
+ <button id="send-btn" class="btn btn-default" type="submit">Send</button>
</div>
</form>
bgstack15