Style: Apply Spotless

This commit is contained in:
Mathis Ginkel
2026-04-09 20:36:18 +02:00
parent 84e68d8b20
commit 566c9375ab
26 changed files with 275 additions and 307 deletions
@@ -3,7 +3,6 @@ package ch.unibas.dmi.dbis.cs108.casono.client;
/**
* Entry point for the Casono client application. Handles client startup and connection parameters.
*/
import ch.unibas.dmi.dbis.cs108.casono.client.ui.Launcher;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -3,15 +3,13 @@ package ch.unibas.dmi.dbis.cs108.casono.client.chat;
import ch.unibas.dmi.dbis.cs108.casono.client.network.ChatClient;
import ch.unibas.dmi.dbis.cs108.casono.client.network.ClientService;
import ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui.ChatBoxController;
import javafx.application.Platform;
import org.jspecify.annotations.Nullable;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Map;
import java.util.List;
import java.util.LinkedHashMap;
import javafx.application.Platform;
import org.jspecify.annotations.Nullable;
/**
* responsible for the transferring of messages from the server to the ChatModel or from the
@@ -31,7 +29,6 @@ public class ChatController {
private int lobbyId = -1;
private final Timer timer;
public record ChatKey(ChatType type, @Nullable String targetUser) {
public ChatKey(ChatType type) {
this(type, null);
@@ -56,7 +53,8 @@ public class ChatController {
new TimerTask() {
@Override
public void run() {
Platform.runLater(() -> {
Platform.runLater(
() -> {
clientService.ping();
receiveMessage();
});
@@ -84,21 +82,30 @@ public class ChatController {
break;
case ChatType.LOBBY:
if (msg.lobbyId == lobbyId) {
chatModelMap.computeIfAbsent(new ChatKey(ChatType.LOBBY),
(_key) -> new ChatModel(ChatType.LOBBY, username, msg.lobbyId, null)).addMessage(msg);
chatModelMap
.computeIfAbsent(
new ChatKey(ChatType.LOBBY),
(_key) ->
new ChatModel(
ChatType.LOBBY,
username,
msg.lobbyId,
null))
.addMessage(msg);
}
break;
case ChatType.WHISPER:
if (msg.target.equals(username)) {
if (chatModelMap.containsKey(new ChatKey(ChatType.WHISPER, msg.sender))) {
chatModelMap.get(new ChatKey(ChatType.WHISPER, msg.sender)).addMessage(msg);
if (chatModelMap.containsKey(
new ChatKey(ChatType.WHISPER, msg.sender))) {
chatModelMap
.get(new ChatKey(ChatType.WHISPER, msg.sender))
.addMessage(msg);
} else {
chatBoxController.addWhisperChat(msg.sender);
}
}
break;
}
}
}
@@ -106,6 +113,7 @@ public class ChatController {
/**
* method to send a message to the server
*
* @param message
*/
public void onSendToNetwork(Message message) {
@@ -1,10 +1,9 @@
package ch.unibas.dmi.dbis.cs108.casono.client.chat;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import java.util.ArrayList;
import java.util.function.Consumer;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
/**
* ChatModel, stores the data for a specific chat
@@ -19,15 +18,10 @@ public class ChatModel {
private final ChatType chattype;
/**
* The person currently using this client
*/
/** The person currently using this client */
public final String username;
/**
* The person to send the message to
* If the chat is a whisper chat
*/
/** The person to send the message to If the chat is a whisper chat */
private final String target;
private final IntegerProperty count;
@@ -67,7 +61,6 @@ public class ChatModel {
listeners.stream().forEach((l) -> l.accept(messages.getLast()));
}
public void addListener(Consumer<Message> listener) {
this.listeners.add(listener);
}
@@ -3,13 +3,12 @@ package ch.unibas.dmi.dbis.cs108.casono.client.chat;
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.parsing.RequestParameter;
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.builder.ResponseBody;
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.builder.ResponseBodyBuilder;
import org.jspecify.annotations.NonNull;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Optional;
import java.util.regex.Pattern;
import org.jspecify.annotations.NonNull;
/**
* Message Object for internal handling of Chat-Messages TODO: Should be used on both sides of the
@@ -101,10 +100,12 @@ public class Message {
/** Pattern, to analyze the response String with the given parameters */
public static Pattern msgRex =
Pattern.compile(
"TYPE=(?<type>\\w+) " + "(GAME=(?<game>\\w+) )?" +
"USER=(?<user>\\w+) " + "(TARGET=(?<target>\\w+) )?" +
"TIME=(?<time>[0-9:.]+) " + "TEXT='(?<text>([^']|\\')+)'");
"TYPE=(?<type>\\w+) "
+ "(GAME=(?<game>\\w+) )?"
+ "USER=(?<user>\\w+) "
+ "(TARGET=(?<target>\\w+) )?"
+ "TIME=(?<time>[0-9:.]+) "
+ "TEXT='(?<text>([^']|\\')+)'");
/**
* Method to create a Message Object, from the information given by the String
@@ -167,35 +168,43 @@ public class Message {
String typeString = getParString(parameters, "TYPE");
ChatType type = ChatType.valueOf(typeString);
return switch (type) {
case GLOBAL -> new Message(ChatType.GLOBAL,
case GLOBAL ->
new Message(
ChatType.GLOBAL,
-1,
getParString(parameters, "USER"),
null,
getParString(parameters, "TIME"),
getParString(parameters, "TEXT")
);
case LOBBY -> new Message(ChatType.LOBBY,
getParString(parameters, "TEXT"));
case LOBBY ->
new Message(
ChatType.LOBBY,
Integer.parseInt(getParString(parameters, "GAME")),
getParString(parameters, "USER"),
null,
getParString(parameters, "TIME"),
getParString(parameters, "TEXT")
);
case WHISPER -> new Message(ChatType.WHISPER,
getParString(parameters, "TEXT"));
case WHISPER ->
new Message(
ChatType.WHISPER,
Integer.parseInt(getParString(parameters, "GAME", "-1")),
getParString(parameters, "USER"),
getParString(parameters, "TARGET"),
getParString(parameters, "TIME"),
getParString(parameters, "TEXT")
);
getParString(parameters, "TEXT"));
};
}
private static @NonNull String getParString(List<RequestParameter> parameters, String keyString) {
private static @NonNull String getParString(
List<RequestParameter> parameters, String keyString) {
return getParString(parameters, keyString, null);
}
private static @NonNull String getParString(List<RequestParameter> parameters, String keyString, String defaultVal) {
Optional<String> parOption = parameters.stream().filter((p) -> keyString.equals(p.key()))
private static @NonNull String getParString(
List<RequestParameter> parameters, String keyString, String defaultVal) {
Optional<String> parOption =
parameters.stream()
.filter((p) -> keyString.equals(p.key()))
.findFirst()
.map(RequestParameter::value);
if (parOption.isEmpty()) {
@@ -2,16 +2,15 @@ package ch.unibas.dmi.dbis.cs108.casono.client.network;
import ch.unibas.dmi.dbis.cs108.casono.client.chat.Message;
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.parsing.RequestParameter;
import java.util.ArrayList;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.ArrayList;
import java.util.List;
/**
* The ChatClient class is responsible for sending messages to the server and
* retrieving messages from the server. It uses the ClientService to send
* commands and receive responses from the server.
* The ChatClient class is responsible for sending messages to the server and retrieving messages
* from the server. It uses the ClientService to send commands and receive responses from the
* server.
*/
public class ChatClient {
@@ -21,8 +20,8 @@ public class ChatClient {
/**
* Constructs a ChatClient with the given ClientService for communication.
*
* @param clientService The ClientService instance used to send commands and
* receive responses from the server.
* @param clientService The ClientService instance used to send commands and receive responses
* from the server.
*/
public ChatClient(ClientService clientService) {
this.clientService = clientService;
@@ -30,8 +29,8 @@ public class ChatClient {
}
/**
* Send a Message to the server by converting it to a string format and
* sending a "SEND_MESSAGE" command with the message content as arguments.
* Send a Message to the server by converting it to a string format and sending a "SEND_MESSAGE"
* command with the message content as arguments.
*
* @param message The Message object to be sent to the server.
*/
@@ -42,17 +41,18 @@ public class ChatClient {
}
/**
* Retrieve messages from the server by first sending a "GET_MESSAGE_COUNT"
* command to determine how many messages are available and then sending
* "GET_NEXT_MESSAGE" commands in a loop to retrieve each message. The
* retrieved messages are parsed into Message objects and returned as a list.
* Retrieve messages from the server by first sending a "GET_MESSAGE_COUNT" command to determine
* how many messages are available and then sending "GET_NEXT_MESSAGE" commands in a loop to
* retrieve each message. The retrieved messages are parsed into Message objects and returned as
* a list.
*
* @return A list of Message objects representing the messages retrieved from
* the server.
* @return A list of Message objects representing the messages retrieved from the server.
*/
public List<Message> getMessages() {
logger.info("Asking server for new messages");
List<RequestParameter> countStr = ClientService.convertToRequestParameters(clientService.processCommand("GET_MESSAGE_COUNT"));
List<RequestParameter> countStr =
ClientService.convertToRequestParameters(
clientService.processCommand("GET_MESSAGE_COUNT"));
RequestParameter countRes = countStr.getFirst();
if (!countRes.key().equals("COUNT")) {
logger.error("Not the right response from server");
@@ -61,7 +61,9 @@ public class ChatClient {
logger.info("Got " + count + " messages");
ArrayList<Message> messages = new ArrayList<>();
for (int i = 0; i < count; i++) {
List<RequestParameter> msgRes = ClientService.convertToRequestParameters(clientService.processCommand("GET_NEXT_MESSAGE"));
List<RequestParameter> msgRes =
ClientService.convertToRequestParameters(
clientService.processCommand("GET_NEXT_MESSAGE"));
Message msg = Message.toMessageReqPars(msgRes);
messages.add(msg);
}
@@ -3,9 +3,6 @@ package ch.unibas.dmi.dbis.cs108.casono.client.network;
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.parsing.RequestParameter;
import ch.unibas.dmi.dbis.cs108.casono.server.network.transport.RawPacket;
import ch.unibas.dmi.dbis.cs108.casono.server.network.transport.TcpTransport;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
@@ -17,13 +14,13 @@ import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* The ClientService class is responsible for managing the connection to the
* server,
* sending commands, and receiving responses. It uses a TcpTransport to
* communicate
* with the server and an ExecutorService to handle asynchronous requests.
* The ClientService class is responsible for managing the connection to the server, sending
* commands, and receiving responses. It uses a TcpTransport to communicate with the server and an
* ExecutorService to handle asynchronous requests.
*/
public class ClientService {
@@ -35,6 +32,7 @@ public class ClientService {
public static ArrayList<String> response;
private final AtomicInteger idGenerator;
private final Logger logger;
/*
* Constructs a ClientService with the given server IP and port. It establishes
* a socket connection to the server and initializes the TcpTransport and
@@ -58,10 +56,11 @@ public class ClientService {
}
executor = Executors.newSingleThreadExecutor();
}
static Pattern responseRex = Pattern.compile("(?<key>\\w+)=(('(?<string>([^']|\\')+)')|(?<primVal>[+-]?[\\d\\w:]+))");
static Pattern responseRex =
Pattern.compile(
"(?<key>\\w+)=(('(?<string>([^']|\\')+)')|(?<primVal>[+-]?[\\d\\w:]+))");
/**
* Sends the Requests to the server and waits for the response If the response is "+OK" it
@@ -73,19 +72,25 @@ public class ClientService {
private static String unescape(String input) {
return input.replaceAll("\\\\'", "'");
}
public static List<RequestParameter> convertToRequestParameters(List<String> input) {
return input.stream().map((String parString)-> responseRex.matcher(parString))
return input.stream()
.map((String parString) -> responseRex.matcher(parString))
.filter(Matcher::matches)
.map((m)->{
.map(
(m) -> {
if (!(m.group("string") == null)) {
return new RequestParameter(m.group("key"), unescape(m.group("string")));
return new RequestParameter(
m.group("key"), unescape(m.group("string")));
} else if (!(m.group("primVal") == null)) {
return new RequestParameter(m.group("key"), m.group("primVal"));
} else {
throw new RuntimeException();
}
}).toList();
})
.toList();
}
protected List<String> processCommand(String message) {
List<String> response = new ArrayList<>();
sendRequest(
@@ -113,7 +118,6 @@ public class ClientService {
}
line = line.replaceFirst("^\t", "");
response.add(line);
}
if (success != null && success) {
return;
@@ -128,13 +132,11 @@ public class ClientService {
}
/**
* Helper method to send a request to the server using the ExecutorService. It
* submits the request as a Runnable task and waits for its completion. If
* the task is interrupted or encounters an execution exception, it throws a
* RuntimeException with the appropriate cause.
* Helper method to send a request to the server using the ExecutorService. It submits the
* request as a Runnable task and waits for its completion. If the task is interrupted or
* encounters an execution exception, it throws a RuntimeException with the appropriate cause.
*
* @param request The Runnable task representing the request to be sent to the
* server.
* @param request The Runnable task representing the request to be sent to the server.
*/
private void sendRequest(Runnable request) {
Future<?> future = executor.submit(request);
@@ -148,11 +150,10 @@ public class ClientService {
}
/**
* Helper method to extract the cause of an exception and return it as a
* RuntimeException. If the cause is null, it returns the original exception as
* a RuntimeException. If the cause is already a RuntimeException, it returns
* it directly. Otherwise, it wraps the cause in a new RuntimeException and
* returns it.
* Helper method to extract the cause of an exception and return it as a RuntimeException. If
* the cause is null, it returns the original exception as a RuntimeException. If the cause is
* already a RuntimeException, it returns it directly. Otherwise, it wraps the cause in a new
* RuntimeException and returns it.
*
* @param e The exception from which to extract the cause.
* @return A RuntimeException representing the cause of the original exception.
@@ -170,10 +171,9 @@ public class ClientService {
}
/**
* Closes the socket connection to the server and shuts down the
* ExecutorService.
* It also closes the TcpTransport used for communication. If any IOException
* occurs during this process, it prints the exception to the console.
* Closes the socket connection to the server and shuts down the ExecutorService. It also closes
* the TcpTransport used for communication. If any IOException occurs during this process, it
* prints the exception to the console.
*/
public void closeSocket() {
try {
@@ -200,6 +200,4 @@ public class ClientService {
public void ping() {
processCommand("PING");
}
}
@@ -1,27 +1,26 @@
package ch.unibas.dmi.dbis.cs108.casono.client.network;
/**
* The CoreClient class provides basic functionalities for communicating with
* the
* server, such as sending a ping command to check connectivity and logging in
* with a username. It uses the ClientService to send commands and receive
* responses from the server.
* The CoreClient class provides basic functionalities for communicating with the server, such as
* sending a ping command to check connectivity and logging in with a username. It uses the
* ClientService to send commands and receive responses from the server.
*/
public class CoreClient {
private final ClientService clientService;
/**
* Constructs a CoreClient with the given ClientService for communication.
*
* @param clientservice The ClientService instance used to send commands and
* receive responses from the server.
* @param clientservice The ClientService instance used to send commands and receive responses
* from the server.
*/
public CoreClient(ClientService clientservice) {
this.clientService = clientservice;
}
/**
* Sends a "PING" command to the server to check connectivity. The server
* should respond with a "PONG" message if the connection is successful.
* Sends a "PING" command to the server to check connectivity. The server should respond with a
* "PONG" message if the connection is successful.
*/
public void ping() {
clientService.processCommand("PING");
@@ -3,14 +3,12 @@ package ch.unibas.dmi.dbis.cs108.casono.client.network;
import ch.unibas.dmi.dbis.cs108.casono.client.game.Card;
import ch.unibas.dmi.dbis.cs108.casono.client.game.GameState;
import ch.unibas.dmi.dbis.cs108.casono.client.game.Player;
import java.util.ArrayList;
import java.util.List;
/**
* The GameClient class is responsible for communicating with the server to
* retrieve the current game state. It sends a command to the server and
* parses the response into a structured GameState object.
* The GameClient class is responsible for communicating with the server to retrieve the current
* game state. It sends a command to the server and parses the response into a structured GameState
* object.
*/
public class GameClient {
@@ -19,16 +17,16 @@ public class GameClient {
/**
* Constructs a GameClient with the given ClientService for communication.
*
* @param client The ClientService instance used to send commands and receive
* responses from the server.
* @param client The ClientService instance used to send commands and receive responses from the
* server.
*/
public GameClient(ClientService client) {
this.client = client;
}
/**
* Retrieves the current game state from the server by sending a command and
* parsing the response.
* Retrieves the current game state from the server by sending a command and parsing the
* response.
*
* @return A GameState object representing the current state of the game.
*/
@@ -43,13 +41,10 @@ public class GameClient {
* @param input The raw response string from the server.
* @return A GameState object representing the current state of the game.
*/
private GameState parseGameState(String input) {
private GameState parseGameState(List<String> input) {
GameState state = new GameState();
String[] lines = input.split("\n");
Player currentPlayer = null;
Card currentCard = null;
@@ -63,46 +58,26 @@ public class GameClient {
if (line.startsWith("PHASE=")) {
state.phase = line.split("=")[1];
}
else if (line.startsWith("POT=")) {
} else if (line.startsWith("POT=")) {
state.pot = Integer.parseInt(line.split("=")[1]);
}
else if (line.startsWith("CURRENT_BET=")) {
} else if (line.startsWith("CURRENT_BET=")) {
state.currentBet = Integer.parseInt(line.split("=")[1]);
}
else if (line.startsWith("DEALER=")) {
} else if (line.startsWith("DEALER=")) {
state.dealer = Integer.parseInt(line.split("=")[1]);
}
else if (line.startsWith("ACTIVE_PLAYER=")) {
} else if (line.startsWith("ACTIVE_PLAYER=")) {
state.activePlayer = Integer.parseInt(line.split("=")[1]);
}
else if (line.startsWith("PLAYER")) {
} else if (line.startsWith("PLAYER")) {
currentPlayer = new Player();
state.players.add(currentPlayer);
}
else if (line.startsWith("NAME=") && currentPlayer != null) {
} else if (line.startsWith("NAME=") && currentPlayer != null) {
currentPlayer.name = line.split("=")[1];
}
else if (line.startsWith("CHIPS=") && currentPlayer != null) {
} else if (line.startsWith("CHIPS=") && currentPlayer != null) {
currentPlayer.chips = Integer.parseInt(line.split("=")[1]);
}
else if (line.startsWith("BET=") && currentPlayer != null) {
} else if (line.startsWith("BET=") && currentPlayer != null) {
currentPlayer.bet = Integer.parseInt(line.split("=")[1]);
}
else if (line.startsWith("STATE=") && currentPlayer != null) {
} else if (line.startsWith("STATE=") && currentPlayer != null) {
currentPlayer.state = line.split("=")[1];
}
else if (line.startsWith("CARD")) {
} else if (line.startsWith("CARD")) {
currentCard = new Card();
if (currentPlayer != null) {
@@ -110,13 +85,9 @@ public class GameClient {
} else {
state.communityCards.add(currentCard);
}
}
else if (line.startsWith("VALUE=") && currentCard != null) {
} else if (line.startsWith("VALUE=") && currentCard != null) {
currentCard.value = line.split("=")[1];
}
else if (line.startsWith("SUIT=") && currentCard != null) {
} else if (line.startsWith("SUIT=") && currentCard != null) {
currentCard.suit = line.split("=")[1];
}
}
@@ -1,10 +1,9 @@
package ch.unibas.dmi.dbis.cs108.casono.client.network;
/**
* The LobbyClient class is responsible for communicating with the server to
* manage game lobbies. It provides methods to create a lobby, join a lobby,
* and fetch the current status of a lobby by sending appropriate commands to
* the server and processing the responses.
* The LobbyClient class is responsible for communicating with the server to manage game lobbies. It
* provides methods to create a lobby, join a lobby, and fetch the current status of a lobby by
* sending appropriate commands to the server and processing the responses.
*/
public class LobbyClient {
private final ClientService client;
@@ -12,8 +11,8 @@ public class LobbyClient {
/**
* Constructs a LobbyClient with the given ClientService for communication.
*
* @param client The ClientService instance used to send commands and receive
* responses from the server.
* @param client The ClientService instance used to send commands and receive responses from the
* server.
*/
public LobbyClient(ClientService client) {
this.client = client;
@@ -23,16 +22,14 @@ public class LobbyClient {
* Fetch the current status of the lobby with the given id from the server.
*
* @param lobbyId The id of the lobby to fetch the status for.
* @return A string representing the current status of the lobby, as returned
* by the server.
* @return A string representing the current status of the lobby, as returned by the server.
*/
public String fetchLobbyStatusString(int lobbyId) {
return client.processCommand("GET_LOBBY_STATUS ID=" + lobbyId).getFirst();
}
/**
* Request the server to create a new lobby and return the id of the newly
* created lobby.
* Request the server to create a new lobby and return the id of the newly created lobby.
*
* @return The id of the newly created lobby, as returned by the server.
*/
@@ -42,11 +39,9 @@ public class LobbyClient {
}
/**
* Request the server to return the id of the lobby that the client is
* currently in.
* Request the server to return the id of the lobby that the client is currently in.
*
* @return The id of the lobby that the client is currently in, as returned by
* the server.
* @return The id of the lobby that the client is currently in, as returned by the server.
*/
public int getLobbyId() {
String response = client.processCommand("GET_LOBBY_ID").getFirst();
@@ -3,6 +3,9 @@ package ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui;
import ch.unibas.dmi.dbis.cs108.casono.client.chat.ChatController;
import ch.unibas.dmi.dbis.cs108.casono.client.chat.ChatModel;
import ch.unibas.dmi.dbis.cs108.casono.client.chat.ChatType;
import java.io.IOException;
import java.net.URL;
import java.util.List;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
@@ -10,12 +13,9 @@ import javafx.scene.control.MenuButton;
import javafx.scene.control.MenuItem;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import java.io.IOException;
import java.net.URL;
import java.util.List;
public class ChatBoxController {
private String username;
@@ -24,7 +24,7 @@ public class ChatBoxController {
@FXML private VBox chatBox;
@FXML private TabPane ChatTabPane;
@FXML private TabPane chatTabPane;
@FXML private MenuButton addWhisperChatButton;
@@ -34,7 +34,6 @@ public class ChatBoxController {
private String ressource = "/ui-structure/components/chatui/chattab.fxml";
public ChatBoxController(String username, ChatController chatController) {
this.username = username;
this.chatController = chatController;
@@ -43,37 +42,43 @@ public class ChatBoxController {
@FXML
public void initialize() {
ChatModel globalChatModel = new ChatModel(ChatType.GLOBAL, username, -1, null);
chatController.getChatModelMap().put(new ChatController.ChatKey(ChatType.GLOBAL), globalChatModel);
chatController
.getChatModelMap()
.put(new ChatController.ChatKey(ChatType.GLOBAL), globalChatModel);
addChatTab("GLOBAL", globalChatModel);
// TODO: Button to add new Whisper Chat
}
public void addWhisperUser(String targetUserName) {
MenuItem menuItem = new MenuItem(targetUserName);
whisperUsers.add(menuItem);
addWhisperChatButton.getItems().add(menuItem);
menuItem.setOnAction(event -> addWhisperChat(targetUserName));
}
public void addWhisperChat(String target) {
ChatModel chatModel = new ChatModel(ChatType.WHISPER, username, -1, target);
chatController.getChatModelMap().put(new ChatController.ChatKey(ChatType.WHISPER, target), chatModel);
chatController
.getChatModelMap()
.put(new ChatController.ChatKey(ChatType.WHISPER, target), chatModel);
addChatTab(target, chatModel);
}
public void addChatTab(String title, ChatModel chatModel) {
URL resource = getClass().getResource(ressource);
FXMLLoader fxmlLoader = new FXMLLoader(resource);
try {
ChatViewController chatViewController = new ChatViewController(this.chatController, chatModel, this.username);
ChatViewController chatViewController =
new ChatViewController(this.chatController, chatModel, this.username);
fxmlLoader.setController(chatViewController);
Node load = fxmlLoader.load();
VBox.setVgrow(load, Priority.ALWAYS);
VBox vbox = new VBox();
VBox.setVgrow(vbox, Priority.ALWAYS);
vbox.getChildren().add(load);
chatModel.addListener((msg) -> chatViewController.showMessage(msg));
Tab newChat = new Tab(title, load);
this.ChatTabPane.getTabs().add(newChat);
Tab newChat = new Tab(title, vbox);
this.chatTabPane.getTabs().add(newChat);
} catch (IOException e) {
throw new RuntimeException(e);
}
@@ -55,7 +55,13 @@ public class ChatViewController implements Initializable {
String message = inputField.getText().trim();
if (!message.isEmpty()) {
inputField.clear();
Message msg = new Message(chatModel.getChattype(), chatModel.lobbyId, username, chatModel.getTarget(), message);
Message msg =
new Message(
chatModel.getChattype(),
chatModel.lobbyId,
username,
chatModel.getTarget(),
message);
controller.onSendToNetwork(msg);
}
}
@@ -69,6 +75,7 @@ public class ChatViewController implements Initializable {
chat.getChildren().add(label);
}
public VBox getChatInterfaceVBox() {
return chatInterfaceVBox;
}
}
@@ -1,14 +1,12 @@
package ch.unibas.dmi.dbis.cs108.casono.client.ui.lobbyui;
/** Main UI application for Casono. Loads the main FXML layout and sets up the stage. */
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
/**
* JavaFX Application class for the Casono main UI.
*
@@ -3,18 +3,18 @@ package ch.unibas.dmi.dbis.cs108.casono.server;
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.check_nick.CheckUsernameHandler;
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.check_nick.CheckUsernameParser;
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.check_nick.CheckUsernameRequest;
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.login.LoginHandler;
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.login.LoginParser;
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.login.LoginRequest;
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.logout.LogoutHandler;
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.logout.LogoutParser;
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.logout.LogoutRequest;
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.get_message_count.GetMessageCountHandler;
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.get_message_count.GetMessageCountParser;
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.get_message_count.GetMessageCountRequest;
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.get_next_message.GetNextMessageHandler;
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.get_next_message.GetNextMessageParser;
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.get_next_message.GetNextMessageRequest;
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.login.LoginHandler;
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.login.LoginParser;
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.login.LoginRequest;
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.logout.LogoutHandler;
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.logout.LogoutParser;
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.logout.LogoutRequest;
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.ping.PingHandler;
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.ping.PingParser;
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.ping.PingRequest;
@@ -32,13 +32,12 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.events.EventBus;
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.dispatcher.ResponseDispatcher;
import ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.SessionDisconnectJob;
import ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.SessionManager;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.time.Duration;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/** Application class for starting the server. */
public class ServerApp {
@@ -118,22 +117,16 @@ public class ServerApp {
LogoutRequest.class, new LogoutHandler(responseDispatcher, userRegistry));
parserDispatcher.register("SEND_MESSAGE", new SendMessageParser());
commandRouter.register(
SendMessageRequest.class,
new SendMessageHandler(responseDispatcher, userRegistry)
);
SendMessageRequest.class, new SendMessageHandler(responseDispatcher, userRegistry));
parserDispatcher.register("GET_MESSAGE_COUNT", new GetMessageCountParser());
commandRouter.register(
GetMessageCountRequest.class,
new GetMessageCountHandler(responseDispatcher, userRegistry)
);
new GetMessageCountHandler(responseDispatcher, userRegistry));
parserDispatcher.register("GET_NEXT_MESSAGE", new GetNextMessageParser());
commandRouter.register(
GetNextMessageRequest.class,
new GetNextMessageHandler(responseDispatcher, userRegistry)
);
new GetNextMessageHandler(responseDispatcher, userRegistry));
}
}
@@ -5,15 +5,14 @@ import ch.unibas.dmi.dbis.cs108.casono.server.domain.user.UserRegistry;
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.execution.CommandHandler;
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.ErrorResponse;
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.dispatcher.ResponseDispatcher;
import java.util.Optional;
public class GetMessageCountHandler implements CommandHandler<GetMessageCountRequest> {
public final ResponseDispatcher responseDispatcher;
public class GetMessageCountHandler extends CommandHandler<GetMessageCountRequest> {
private final UserRegistry userRegistry;
public GetMessageCountHandler(ResponseDispatcher responseDispatcher, UserRegistry userRegistry) {
this.responseDispatcher = responseDispatcher;
public GetMessageCountHandler(
ResponseDispatcher responseDispatcher, UserRegistry userRegistry) {
super(responseDispatcher);
this.userRegistry = userRegistry;
}
@@ -22,18 +21,14 @@ public class GetMessageCountHandler implements CommandHandler<GetMessageCountReq
Optional<User> user = userRegistry.getBySessionId(request.getSessionId());
if (user.isPresent()) {
int count = user.get().getMessageCount();
GetMessageCountResponse response = new GetMessageCountResponse(
request.getContext(),
count
);
GetMessageCountResponse response =
new GetMessageCountResponse(request.getContext(), count);
responseDispatcher.dispatch(response);
} else {
ErrorResponse response = new ErrorResponse(
request.getContext(),
"",
"user could not be identified by SessionId"
ErrorResponse response =
new ErrorResponse(
request.getContext(), "", "user could not be identified by SessionId");
);
responseDispatcher.dispatch(response);
}
}
@@ -7,7 +7,8 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.accessor.
public class GetMessageCountParser implements CommandParser<GetMessageCountRequest> {
@Override
public GetMessageCountRequest parse(PrimitiveRequest primitiveRequest) {
RequestParameterAccessor accessor = new RequestParameterAccessor(primitiveRequest.parameters());
RequestParameterAccessor accessor =
new RequestParameterAccessor(primitiveRequest.parameters());
return new GetMessageCountRequest(primitiveRequest.context());
}
}
@@ -6,8 +6,6 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.builder.
public class GetMessageCountResponse extends SuccessResponse {
public GetMessageCountResponse(RequestContext context, int count) {
super(context, new ResponseBodyBuilder()
.param("COUNT", count)
.build());
super(context, new ResponseBodyBuilder().param("COUNT", count).build());
}
}
@@ -6,15 +6,13 @@ import ch.unibas.dmi.dbis.cs108.casono.server.domain.user.UserRegistry;
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.execution.CommandHandler;
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.ErrorResponse;
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.dispatcher.ResponseDispatcher;
import java.util.Optional;
public class GetNextMessageHandler implements CommandHandler<GetNextMessageRequest> {
public final ResponseDispatcher responseDispatcher;
public class GetNextMessageHandler extends CommandHandler<GetNextMessageRequest> {
private final UserRegistry userRegistry;
public GetNextMessageHandler(ResponseDispatcher responseDispatcher, UserRegistry userRegistry) {
this.responseDispatcher = responseDispatcher;
super(responseDispatcher);
this.userRegistry = userRegistry;
}
@@ -23,18 +21,14 @@ public class GetNextMessageHandler implements CommandHandler<GetNextMessageReque
Optional<User> user = userRegistry.getBySessionId(request.getSessionId());
if (user.isPresent()) {
Message msg = user.get().dequeMessage();
GetNextMessageResponse response = new GetNextMessageResponse(
request.getContext(),
msg
);
GetNextMessageResponse response = new GetNextMessageResponse(request.getContext(), msg);
responseDispatcher.dispatch(response);
} else {
ErrorResponse response = new ErrorResponse(
ErrorResponse response =
new ErrorResponse(
request.getContext(),
"NO_USER_ASSOCIATED",
"user could not be identified by SessionId"
);
"user could not be identified by SessionId");
responseDispatcher.dispatch(response);
}
}
@@ -7,7 +7,8 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.accessor.
public class GetNextMessageParser implements CommandParser<GetNextMessageRequest> {
@Override
public GetNextMessageRequest parse(PrimitiveRequest primitiveRequest) {
RequestParameterAccessor accessor = new RequestParameterAccessor(primitiveRequest.parameters());
RequestParameterAccessor accessor =
new RequestParameterAccessor(primitiveRequest.parameters());
return new GetNextMessageRequest(primitiveRequest.context());
}
}
@@ -7,7 +7,6 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.builder.
public class GetNextMessageResponse extends SuccessResponse {
public GetNextMessageResponse(RequestContext context, Message msg) {
super(context, msg.toResponse(ResponseBody.builder())
);
super(context, msg.toResponse(ResponseBody.builder()));
}
}
@@ -1,18 +1,16 @@
package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.send_message;
import ch.unibas.dmi.dbis.cs108.casono.client.chat.Message;
import ch.unibas.dmi.dbis.cs108.casono.server.domain.user.UserRegistry;
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.execution.CommandHandler;
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.OkResponse;
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.dispatcher.ResponseDispatcher;
public class SendMessageHandler implements CommandHandler<SendMessageRequest> {
public final ResponseDispatcher responseDispatcher;
public class SendMessageHandler extends CommandHandler<SendMessageRequest> {
private final UserRegistry userRegistry;
public SendMessageHandler(ResponseDispatcher responseDispatcher, UserRegistry userRegistry) {
this.responseDispatcher = responseDispatcher;
super(responseDispatcher);
this.userRegistry = userRegistry;
}
@@ -23,8 +21,8 @@ public class SendMessageHandler implements CommandHandler<SendMessageRequest> {
OkResponse response = new OkResponse(request.getContext());
responseDispatcher.dispatch(response);
}
public void broadcast(Message message) {
userRegistry.getAllUsers().forEach(user -> user.enqueueMessage(message));
}
}
@@ -1,4 +1,5 @@
package ch.unibas.dmi.dbis.cs108.casono.server.domain.message;
import ch.unibas.dmi.dbis.cs108.casono.server.domain.user.UserRegistry;
/** NOT USED * */
@@ -1,9 +1,13 @@
package ch.unibas.dmi.dbis.cs108.casono.server.domain.user;
import ch.unibas.dmi.dbis.cs108.casono.client.chat.Message;
import ch.unibas.dmi.dbis.cs108.casono.client.chat.Message;
import ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.SessionId;
import java.time.Instant;
import java.util.*;
import java.util.ArrayDeque;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
/** Represents an authenticated user on the server. */
@@ -85,9 +89,13 @@ public class User {
messages.add(message);
}
public synchronized int getMessageCount() { return messages.size(); }
public synchronized int getMessageCount() {
return messages.size();
}
public synchronized Message dequeMessage() throws NoSuchElementException { return messages.remove(); }
public synchronized Message dequeMessage() throws NoSuchElementException {
return messages.remove();
}
public synchronized List<Message> dequeueAllMessages(Message message) {
List<Message> allMessages = new ArrayDeque<>(messages).stream().toList();
@@ -17,17 +17,19 @@
maxWidth="Infinity">
<children>
<HBox>
<HBox spacing="10"
styleClass="">
<children>
<Label text="== CHAT ==" styleClass="chat-header" alignment="CENTER" maxWidth="Infinity"/>
<Region minHeight="4" styleClass="chat-separator"/>
<MenuButton fx:id="addWhisperChatButton" styleClass="gray-button" text="+" alignment="CENTER_RIGHT">
<Region HBox.hgrow="ALWAYS" />
<MenuButton fx:id="addWhisperChatButton" styleClass="yellow-button" text="WHISPER CHAT" alignment="CENTER_RIGHT">
</MenuButton>
</children>
</HBox>
<TabPane fx:id="ChatTabPane">
<TabPane fx:id="ChatTabPane"
VBox.vgrow="ALWAYS">
</TabPane>
@@ -7,14 +7,12 @@
<VBox fx:id="chatInterfaceVBox"
maxWidth="Infinity"
minHeight="500"
spacing="10"
styleClass="chat-box"
stylesheets="@chatui.css"
VBox.vgrow="ALWAYS"
xmlns="http://javafx.com/javafx/17.0.12"
xmlns:fx="http://javafx.com/fxml/1"
>
xmlns:fx="http://javafx.com/fxml/1">
<children>
<!-- Chatnachrichten werden hier hinzugefügt -->
@@ -83,7 +83,7 @@
.gray-button {
-fx-background-color: #333333;
-fx-border-color: #666666;
-fx-text-fill: #cccccc;
-fx-text-fill: #ffffff;
}
.gray-button, .yellow-button, .red-button {
@@ -1,13 +1,12 @@
package ch.unibas.dmi.dbis.cs108.casono.client.chat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import ch.unibas.dmi.dbis.cs108.casono.client.network.ClientService;
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.parsing.RequestParameter;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
public class ChatTest {
@@ -20,8 +19,6 @@ public class ChatTest {
list.add("TEXT='Hello World'");
list.add("NUMBER=-56887387394898392849");
List<RequestParameter> newList = ClientService.convertToRequestParameters(list);
RequestParameter par0 = newList.get(0);
assertEquals("COUNT", par0.key());
@@ -39,5 +36,4 @@ public class ChatTest {
assertEquals("NUMBER", par4.key());
assertEquals("-56887387394898392849", par4.value());
}
}