Docs: Insert JavaDocs
This commit is contained in:
@@ -3,14 +3,10 @@ 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.ChatClient;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.client.network.ClientService;
|
import ch.unibas.dmi.dbis.cs108.casono.client.network.ClientService;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui.ChatBoxController;
|
import ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui.ChatBoxController;
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Timer;
|
|
||||||
import java.util.TimerTask;
|
|
||||||
import javafx.application.Platform;
|
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* responsible for the transferring of messages from the server to the ChatModel or from the
|
* responsible for the transferring of messages from the server to the ChatModel or from the
|
||||||
* ChatViewController to the server
|
* ChatViewController to the server
|
||||||
@@ -43,6 +39,12 @@ public class ChatController {
|
|||||||
|
|
||||||
private static final long REFRESH_TIME = 1000;
|
private static final long REFRESH_TIME = 1000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor, adds TimerTask to be sent to the server regularly
|
||||||
|
*
|
||||||
|
* @param username
|
||||||
|
* @param clientService
|
||||||
|
*/
|
||||||
public ChatController(String username, ClientService clientService) {
|
public ChatController(String username, ClientService clientService) {
|
||||||
this.username = username;
|
this.username = username;
|
||||||
chatClient = new ChatClient(clientService);
|
chatClient = new ChatClient(clientService);
|
||||||
@@ -53,17 +55,19 @@ public class ChatController {
|
|||||||
new TimerTask() {
|
new TimerTask() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Platform.runLater(
|
receiveMessage();
|
||||||
() -> {
|
|
||||||
clientService.ping();
|
|
||||||
receiveMessage();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
0,
|
0,
|
||||||
REFRESH_TIME);
|
REFRESH_TIME);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to be activated, if a lobby has be chosen. It will update the UI and add a new
|
||||||
|
* ChatModel to hold the Data for the Lobby Chat
|
||||||
|
*
|
||||||
|
* @param lobbyId
|
||||||
|
*/
|
||||||
public void setLobbyChat(int lobbyId) {
|
public void setLobbyChat(int lobbyId) {
|
||||||
this.lobbyId = lobbyId;
|
this.lobbyId = lobbyId;
|
||||||
ChatModel lobbyChatModel = new ChatModel(ChatType.LOBBY, username, lobbyId, null);
|
ChatModel lobbyChatModel = new ChatModel(ChatType.LOBBY, username, lobbyId, null);
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.casono.client.chat;
|
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.ArrayList;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import javafx.beans.property.IntegerProperty;
|
|
||||||
import javafx.beans.property.SimpleIntegerProperty;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ChatModel, stores the data for a specific chat
|
* ChatModel, stores the data for a specific chat
|
||||||
@@ -28,6 +29,14 @@ public class ChatModel {
|
|||||||
|
|
||||||
public int lobbyId;
|
public int lobbyId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new ChatModel for a specific chat type.
|
||||||
|
*
|
||||||
|
* @param chattype The type of chat (e.g., GLOBAL, LOBBY, or WHISPER).
|
||||||
|
* @param username The username of the current user.
|
||||||
|
* @param lobbyId The ID of the lobby, or -1 if not applicable.
|
||||||
|
* @param target The username of the whisper recipient, or null for other chat types.
|
||||||
|
*/
|
||||||
public ChatModel(ChatType chattype, String username, int lobbyId, String target) {
|
public ChatModel(ChatType chattype, String username, int lobbyId, String target) {
|
||||||
this.messages = new ArrayList<Message>();
|
this.messages = new ArrayList<Message>();
|
||||||
this.chattype = chattype;
|
this.chattype = chattype;
|
||||||
@@ -37,34 +46,38 @@ public class ChatModel {
|
|||||||
this.target = target;
|
this.target = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of chat this model represents.
|
||||||
|
* @return The {@link ChatType}.
|
||||||
|
*/
|
||||||
public ChatType getChattype() {
|
public ChatType getChattype() {
|
||||||
return chattype;
|
return chattype;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* method, used by the ChatViewController, to access all new messages, that are stored in the
|
* Adds a new message to the history and notifies all registered listeners.
|
||||||
* ChatModel
|
* This method is synchronized to ensure thread safety when updating the message list.
|
||||||
*/
|
|
||||||
public synchronized String viewNextMessage() {
|
|
||||||
count.subtract(1);
|
|
||||||
Message msg = messages.getLast();
|
|
||||||
return String.format("[%s] %s: %s", msg.timestamp, msg.sender, msg.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a new message method used by the ChatController
|
|
||||||
*
|
*
|
||||||
* @param msg
|
* @param msg The {@link Message} to be added.
|
||||||
*/
|
*/
|
||||||
public synchronized void addMessage(Message msg) {
|
public synchronized void addMessage(Message msg) {
|
||||||
messages.add(msg);
|
messages.add(msg);
|
||||||
listeners.stream().forEach((l) -> l.accept(messages.getLast()));
|
listeners.stream().forEach((l) -> l.accept(messages.getLast()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a listener to be notified whenever a new message is added to this model.
|
||||||
|
*
|
||||||
|
* @param listener A {@link Consumer} that processes the new {@link Message}.
|
||||||
|
*/
|
||||||
public void addListener(Consumer<Message> listener) {
|
public void addListener(Consumer<Message> listener) {
|
||||||
this.listeners.add(listener);
|
this.listeners.add(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the target user for this chat, primarily used for whispers.
|
||||||
|
* @return The target username or null.
|
||||||
|
*/
|
||||||
public String getTarget() {
|
public String getTarget() {
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.casono.client.chat;
|
package ch.unibas.dmi.dbis.cs108.casono.client.chat;
|
||||||
|
|
||||||
|
/** Describing the Type of the Chat */
|
||||||
public enum ChatType {
|
public enum ChatType {
|
||||||
GLOBAL,
|
GLOBAL,
|
||||||
LOBBY,
|
LOBBY,
|
||||||
|
|||||||
@@ -3,16 +3,15 @@ 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.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.ResponseBody;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.builder.ResponseBodyBuilder;
|
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.LocalDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
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
|
* Message Object for internal handling of Chat-Messages
|
||||||
* network
|
|
||||||
*/
|
*/
|
||||||
public class Message {
|
public class Message {
|
||||||
private final ChatType type;
|
private final ChatType type;
|
||||||
@@ -23,13 +22,15 @@ public class Message {
|
|||||||
public String target = null;
|
public String target = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for creating Messages with all information given
|
* Constructs a Message with a provided timestamp. Typically used when
|
||||||
|
* reconstructing messages received from the server.
|
||||||
*
|
*
|
||||||
* @param type - Either global, local or whisper
|
* @param type The chat category (e.g., GLOBAL, LOBBY, or WHISPER).
|
||||||
* @param lobbyId - lobby id, or null, if the typChatType
|
* @param lobbyId The ID of the lobby, or -1 if not applicable.
|
||||||
* @param sender - username
|
* @param sender The username of the message creator.
|
||||||
* @param target - username of the target user, for whisper chat
|
* @param target The username of the recipient (required for whispers, otherwise null).
|
||||||
* @param message
|
* @param timestamp The formatted time string (e.g., "HH:mm").
|
||||||
|
* @param message The actual text content of the message.
|
||||||
*/
|
*/
|
||||||
public Message(
|
public Message(
|
||||||
ChatType type,
|
ChatType type,
|
||||||
@@ -47,14 +48,14 @@ public class Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for creating the Messages of the current user, using this client -> time of
|
* Constructs a new Message for the current user. Automatically generates
|
||||||
* writing is being recorded
|
* a timestamp based on the local system time ("HH:mm").
|
||||||
*
|
*
|
||||||
* @param type - Either global, local or whisper
|
* @param type The chat category (e.g., GLOBAL, LOBBY, or WHISPER).
|
||||||
* @param lobbyId - lobby id, or null, if the type is global
|
* @param lobbyId The ID of the lobby, or -1 if not applicable.
|
||||||
* @param sender - username
|
* @param sender The username of the current user.
|
||||||
* @param target - username of the target user, for whisper chat
|
* @param target The username of the recipient (for whispers).
|
||||||
* @param message
|
* @param message The actual text content to be sent.
|
||||||
*/
|
*/
|
||||||
public Message(ChatType type, int lobbyId, String sender, String target, String message) {
|
public Message(ChatType type, int lobbyId, String sender, String target, String message) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
@@ -67,18 +68,29 @@ public class Message {
|
|||||||
this.timestamp = now.format(formatter);
|
this.timestamp = now.format(formatter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the text content of the message.
|
||||||
|
*
|
||||||
|
* @return The message string.
|
||||||
|
*/
|
||||||
public String getMessage() {
|
public String getMessage() {
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of chat this message belongs to.
|
||||||
|
*
|
||||||
|
* @return The {@link ChatType}.
|
||||||
|
*/
|
||||||
public ChatType getMessageType() {
|
public ChatType getMessageType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to create the request representation of the message object, to be sent to the server
|
* Formats the message object into a string representation compatible with
|
||||||
|
* the network protocol arguments.
|
||||||
*
|
*
|
||||||
* @return - request as specified in the network protocol, as String
|
* @return A formatted string containing all message attributes for server transmission.
|
||||||
*/
|
*/
|
||||||
public String toArgsString() {
|
public String toArgsString() {
|
||||||
String gameIdString = "";
|
String gameIdString = "";
|
||||||
@@ -97,109 +109,62 @@ public class Message {
|
|||||||
this.message);
|
this.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>([^']|\\')+)'");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to create a Message Object, from the information given by the String
|
* Parses a list of network request parameters to reconstruct a Message object.
|
||||||
|
* Handles different chat types (GLOBAL, LOBBY, WHISPER) and their specific requirements.
|
||||||
*
|
*
|
||||||
* @param response - String that got sent as a response from the server
|
* @param parameters A list of {@link RequestParameter} received from the network.
|
||||||
* @return - New Message Object
|
* @return A new {@link Message} instance populated with the parsed data.
|
||||||
*/
|
*/
|
||||||
/*
|
|
||||||
public static Message toMessage(String response) {
|
|
||||||
Matcher m = msgRex.matcher(response);
|
|
||||||
if (!m.matches()) {
|
|
||||||
throw new RuntimeException("Can not parse message: '" + response + "'");
|
|
||||||
}
|
|
||||||
String typeString = m.group("type");
|
|
||||||
|
|
||||||
switch (typeString) {
|
|
||||||
case "GLOBAL":
|
|
||||||
return new Message(
|
|
||||||
ChatType.GLOBAL,
|
|
||||||
-1,
|
|
||||||
m.group("user"),
|
|
||||||
null,
|
|
||||||
m.group("time"),
|
|
||||||
m.group("text"));
|
|
||||||
|
|
||||||
case "LOBBY":
|
|
||||||
|
|
||||||
int gameId = getGameId(m.group("game"));
|
|
||||||
return new Message(
|
|
||||||
ChatType.LOBBY,
|
|
||||||
gameId,
|
|
||||||
m.group("user"),
|
|
||||||
null,
|
|
||||||
m.group("time"),
|
|
||||||
m.group("text"));
|
|
||||||
|
|
||||||
case "WHISPER":
|
|
||||||
return new Message(
|
|
||||||
ChatType.WHISPER,
|
|
||||||
m.group("user"),
|
|
||||||
m.group("target"),
|
|
||||||
m.group("time"),
|
|
||||||
m.group("text"));
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new RuntimeException("Unknown message type " + typeString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
private static int getGameId(String gameIdStr) {
|
|
||||||
int gameId = -1;
|
|
||||||
if (gameIdStr != null) {
|
|
||||||
gameId = Integer.parseInt(gameIdStr);
|
|
||||||
}
|
|
||||||
return gameId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Message toMessageReqPars(List<RequestParameter> parameters) {
|
public static Message toMessageReqPars(List<RequestParameter> parameters) {
|
||||||
String typeString = getParString(parameters, "TYPE");
|
String typeString = getParString(parameters, "TYPE");
|
||||||
ChatType type = ChatType.valueOf(typeString);
|
ChatType type = ChatType.valueOf(typeString);
|
||||||
return switch (type) {
|
return switch (type) {
|
||||||
case GLOBAL ->
|
case GLOBAL -> new Message(
|
||||||
new Message(
|
ChatType.GLOBAL,
|
||||||
ChatType.GLOBAL,
|
-1,
|
||||||
-1,
|
getParString(parameters, "USER"),
|
||||||
getParString(parameters, "USER"),
|
null,
|
||||||
null,
|
getParString(parameters, "TIME"),
|
||||||
getParString(parameters, "TIME"),
|
getParString(parameters, "TEXT"));
|
||||||
getParString(parameters, "TEXT"));
|
case LOBBY -> new Message(
|
||||||
case LOBBY ->
|
ChatType.LOBBY,
|
||||||
new Message(
|
Integer.parseInt(getParString(parameters, "GAME")),
|
||||||
ChatType.LOBBY,
|
getParString(parameters, "USER"),
|
||||||
Integer.parseInt(getParString(parameters, "GAME")),
|
null,
|
||||||
getParString(parameters, "USER"),
|
getParString(parameters, "TIME"),
|
||||||
null,
|
getParString(parameters, "TEXT"));
|
||||||
getParString(parameters, "TIME"),
|
case WHISPER -> new Message(
|
||||||
getParString(parameters, "TEXT"));
|
ChatType.WHISPER,
|
||||||
case WHISPER ->
|
Integer.parseInt(getParString(parameters, "GAME", "-1")),
|
||||||
new Message(
|
getParString(parameters, "USER"),
|
||||||
ChatType.WHISPER,
|
getParString(parameters, "TARGET"),
|
||||||
Integer.parseInt(getParString(parameters, "GAME", "-1")),
|
getParString(parameters, "TIME"),
|
||||||
getParString(parameters, "USER"),
|
getParString(parameters, "TEXT"));
|
||||||
getParString(parameters, "TARGET"),
|
|
||||||
getParString(parameters, "TIME"),
|
|
||||||
getParString(parameters, "TEXT"));
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to extract a specific parameter value by its key.
|
||||||
|
*
|
||||||
|
* @param parameters The list of parameters to search.
|
||||||
|
* @param keyString The key to look for.
|
||||||
|
* @return The value associated with the key.
|
||||||
|
* @throws RuntimeException if the key is not found.
|
||||||
|
*/
|
||||||
private static @NonNull String getParString(
|
private static @NonNull String getParString(
|
||||||
List<RequestParameter> parameters, String keyString) {
|
List<RequestParameter> parameters, String keyString) {
|
||||||
return getParString(parameters, keyString, null);
|
return getParString(parameters, keyString, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to extract a specific parameter value by its key, with a fallback default value.
|
||||||
|
*
|
||||||
|
* @param parameters The list of parameters to search.
|
||||||
|
* @param keyString The key to look for.
|
||||||
|
* @param defaultVal The value to return if the key is missing.
|
||||||
|
* @return The found value or the default value.
|
||||||
|
*/
|
||||||
private static @NonNull String getParString(
|
private static @NonNull String getParString(
|
||||||
List<RequestParameter> parameters, String keyString, String defaultVal) {
|
List<RequestParameter> parameters, String keyString, String defaultVal) {
|
||||||
Optional<String> parOption =
|
Optional<String> parOption =
|
||||||
@@ -217,6 +182,12 @@ public class Message {
|
|||||||
return parOption.get();
|
return parOption.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the message object into a network response body using the provided builder.
|
||||||
|
*
|
||||||
|
* @param builder The {@link ResponseBodyBuilder} used to construct the response.
|
||||||
|
* @return The built {@link ResponseBody} containing the message data.
|
||||||
|
*/
|
||||||
public ResponseBody toResponse(ResponseBodyBuilder builder) {
|
public ResponseBody toResponse(ResponseBodyBuilder builder) {
|
||||||
builder.param("TYPE", type.name());
|
builder.param("TYPE", type.name());
|
||||||
builder.param("GAME", lobbyId);
|
builder.param("GAME", lobbyId);
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ 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.command.parsing.RequestParameter;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.server.network.transport.RawPacket;
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.transport.RawPacket;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.server.network.transport.TcpTransport;
|
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.io.IOException;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -14,8 +17,6 @@ import java.util.concurrent.Future;
|
|||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
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
|
* The ClientService class is responsible for managing the connection to the server, sending
|
||||||
@@ -33,7 +34,7 @@ public class ClientService {
|
|||||||
private final AtomicInteger idGenerator;
|
private final AtomicInteger idGenerator;
|
||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Constructs a ClientService with the given server IP and port. It establishes
|
* Constructs a ClientService with the given server IP and port. It establishes
|
||||||
* a socket connection to the server and initializes the TcpTransport and
|
* a socket connection to the server and initializes the TcpTransport and
|
||||||
* ExecutorService for communication.
|
* ExecutorService for communication.
|
||||||
@@ -63,16 +64,25 @@ public class ClientService {
|
|||||||
"(?<key>\\w+)=(('(?<string>([^']|\\')+)')|(?<primVal>[+-]?[\\d\\w:]+))");
|
"(?<key>\\w+)=(('(?<string>([^']|\\')+)')|(?<primVal>[+-]?[\\d\\w:]+))");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends the Requests to the server and waits for the response If the response is "+OK" it
|
* Removes escape characters from a string, specifically converting escaped
|
||||||
* proceeds normal If the response "-ERROR" it throws a runtime exception
|
* single quotes (\') back to regular single quotes (').
|
||||||
*
|
*
|
||||||
* @param message
|
* @param input The escaped string to process.
|
||||||
* @return - The response as a string, if it has to be returned (+OK will not be returned)
|
* @return The unescaped string.
|
||||||
*/
|
*/
|
||||||
private static String unescape(String input) {
|
private static String unescape(String input) {
|
||||||
return input.replaceAll("\\\\'", "'");
|
return input.replaceAll("\\\\'", "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a list of raw string parameters into a list of {@link RequestParameter} objects.
|
||||||
|
* It uses a regex matcher to distinguish between quoted strings (which are unescaped)
|
||||||
|
* and primitive values.
|
||||||
|
*
|
||||||
|
* @param input A list of raw strings to be parsed.
|
||||||
|
* @return A list of parsed {@link RequestParameter} objects.
|
||||||
|
* @throws RuntimeException if a parameter does not match the expected format.
|
||||||
|
*/
|
||||||
public static List<RequestParameter> convertToRequestParameters(List<String> input) {
|
public static List<RequestParameter> convertToRequestParameters(List<String> input) {
|
||||||
return input.stream()
|
return input.stream()
|
||||||
.map((String parString) -> responseRex.matcher(parString))
|
.map((String parString) -> responseRex.matcher(parString))
|
||||||
@@ -91,6 +101,15 @@ public class ClientService {
|
|||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a command to the server and processes the multi-line response.
|
||||||
|
* It handles the protocol handshake (expecting +OK), strips leading tabs from
|
||||||
|
* response lines, and collects them until the "END" marker is reached.
|
||||||
|
*
|
||||||
|
* @param message The raw command string to be sent to the transport layer.
|
||||||
|
* @return A list of response lines received from the server (excluding protocol markers).
|
||||||
|
* @throws RuntimeException if the server responds with an error or if a communication failure occurs.
|
||||||
|
*/
|
||||||
protected List<String> processCommand(String message) {
|
protected List<String> processCommand(String message) {
|
||||||
List<String> response = new ArrayList<>();
|
List<String> response = new ArrayList<>();
|
||||||
sendRequest(
|
sendRequest(
|
||||||
|
|||||||
+31
-3
@@ -3,9 +3,6 @@ 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.ChatController;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.client.chat.ChatModel;
|
import ch.unibas.dmi.dbis.cs108.casono.client.chat.ChatModel;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.client.chat.ChatType;
|
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.FXML;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
@@ -16,6 +13,10 @@ import javafx.scene.control.TabPane;
|
|||||||
import javafx.scene.layout.Priority;
|
import javafx.scene.layout.Priority;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class ChatBoxController {
|
public class ChatBoxController {
|
||||||
|
|
||||||
private String username;
|
private String username;
|
||||||
@@ -39,6 +40,11 @@ public class ChatBoxController {
|
|||||||
this.chatController = chatController;
|
this.chatController = chatController;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the chat interface by creating the global chat model and
|
||||||
|
* adding the corresponding "GLOBAL" tab to the interface.
|
||||||
|
* It also registers the global chat in the {@link ChatController}'s model map.
|
||||||
|
*/
|
||||||
@FXML
|
@FXML
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
ChatModel globalChatModel = new ChatModel(ChatType.GLOBAL, username, -1, null);
|
ChatModel globalChatModel = new ChatModel(ChatType.GLOBAL, username, -1, null);
|
||||||
@@ -49,6 +55,13 @@ public class ChatBoxController {
|
|||||||
// TODO: Button to add new Whisper Chat
|
// TODO: Button to add new Whisper Chat
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a specific user to the list of available whisper targets.
|
||||||
|
* Creates a new menu item for the user and defines the action to open
|
||||||
|
* a private chat tab when selected.
|
||||||
|
*
|
||||||
|
* @param targetUserName The username of the person to be added to the whisper list.
|
||||||
|
*/
|
||||||
public void addWhisperUser(String targetUserName) {
|
public void addWhisperUser(String targetUserName) {
|
||||||
MenuItem menuItem = new MenuItem(targetUserName);
|
MenuItem menuItem = new MenuItem(targetUserName);
|
||||||
whisperUsers.add(menuItem);
|
whisperUsers.add(menuItem);
|
||||||
@@ -56,6 +69,12 @@ public class ChatBoxController {
|
|||||||
menuItem.setOnAction(event -> addWhisperChat(targetUserName));
|
menuItem.setOnAction(event -> addWhisperChat(targetUserName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new private (whisper) chat model for a specific target user,
|
||||||
|
* registers it within the chat system, and opens a new chat tab.
|
||||||
|
*
|
||||||
|
* @param target The username of the recipient for the private messages.
|
||||||
|
*/
|
||||||
public void addWhisperChat(String target) {
|
public void addWhisperChat(String target) {
|
||||||
ChatModel chatModel = new ChatModel(ChatType.WHISPER, username, -1, target);
|
ChatModel chatModel = new ChatModel(ChatType.WHISPER, username, -1, target);
|
||||||
chatController
|
chatController
|
||||||
@@ -64,6 +83,15 @@ public class ChatBoxController {
|
|||||||
addChatTab(target, chatModel);
|
addChatTab(target, chatModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dynamically loads a new chat tab from an FXML resource and attaches it
|
||||||
|
* to the TabPane. It initializes a {@link ChatViewController} for the tab
|
||||||
|
* and sets up a listener to display incoming messages in real-time.
|
||||||
|
*
|
||||||
|
* @param title The title to be displayed on the tab header.
|
||||||
|
* @param chatModel The {@link ChatModel} containing the data and logic for this specific chat.
|
||||||
|
* @throws RuntimeException If the FXML resource for the chat tab cannot be loaded.
|
||||||
|
*/
|
||||||
public void addChatTab(String title, ChatModel chatModel) {
|
public void addChatTab(String title, ChatModel chatModel) {
|
||||||
URL resource = getClass().getResource(ressource);
|
URL resource = getClass().getResource(ressource);
|
||||||
FXMLLoader fxmlLoader = new FXMLLoader(resource);
|
FXMLLoader fxmlLoader = new FXMLLoader(resource);
|
||||||
|
|||||||
+34
-11
@@ -3,6 +3,7 @@ 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.ChatController;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.client.chat.ChatModel;
|
import ch.unibas.dmi.dbis.cs108.casono.client.chat.ChatModel;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.client.chat.Message;
|
import ch.unibas.dmi.dbis.cs108.casono.client.chat.Message;
|
||||||
|
import javafx.application.Platform;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
@@ -43,7 +44,15 @@ public class ChatViewController implements Initializable {
|
|||||||
this.username = username;
|
this.username = username;
|
||||||
this.chatModel = chatModel;
|
this.chatModel = chatModel;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Initializes the controller after the FXML root element has been processed.
|
||||||
|
* Sets up event handlers for sending messages via the input field or button
|
||||||
|
* and ensures the ScrollPane automatically scrolls to the bottom when new
|
||||||
|
* messages are added.
|
||||||
|
*
|
||||||
|
* @param location The location used to resolve relative paths for the root object.
|
||||||
|
* @param resourceBundle The resources used to localize the root object.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void initialize(URL location, ResourceBundle resourceBundle) {
|
public void initialize(URL location, ResourceBundle resourceBundle) {
|
||||||
inputField.setOnAction(event -> sendMessage());
|
inputField.setOnAction(event -> sendMessage());
|
||||||
@@ -51,6 +60,11 @@ public class ChatViewController implements Initializable {
|
|||||||
scrollPane.vvalueProperty().bind(chat.heightProperty());
|
scrollPane.vvalueProperty().bind(chat.heightProperty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the text from the input field, creates a new {@link Message} object
|
||||||
|
* using the current model state, and passes it to the {@link ChatController}
|
||||||
|
* for network transmission. The input field is cleared after sending.
|
||||||
|
*/
|
||||||
public void sendMessage() {
|
public void sendMessage() {
|
||||||
String message = inputField.getText().trim();
|
String message = inputField.getText().trim();
|
||||||
if (!message.isEmpty()) {
|
if (!message.isEmpty()) {
|
||||||
@@ -66,16 +80,25 @@ public class ChatViewController implements Initializable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays a message in the chat interface. This method creates a new Label
|
||||||
|
* for the message text and adds it to the message container.
|
||||||
|
* It uses {@link Platform#runLater(Runnable)} to ensure the UI update
|
||||||
|
* happens on the JavaFX Application Thread.
|
||||||
|
*
|
||||||
|
* @param msg The {@link Message} object containing the content and metadata to display.
|
||||||
|
*/
|
||||||
public void showMessage(Message msg) {
|
public void showMessage(Message msg) {
|
||||||
String msgText = String.format("[%s] %s: %s", msg.timestamp, msg.sender, msg.getMessage());
|
Platform.runLater(
|
||||||
Label label = new Label(msgText);
|
() -> {
|
||||||
label.getStyleClass().add("info-text");
|
String msgText =
|
||||||
label.setWrapText(true);
|
String.format(
|
||||||
label.maxWidthProperty().bind(chat.widthProperty().subtract(CHAT_PADDING));
|
"[%s] %s: %s", msg.timestamp, msg.sender, msg.getMessage());
|
||||||
chat.getChildren().add(label);
|
Label label = new Label(msgText);
|
||||||
}
|
label.getStyleClass().add("info-text");
|
||||||
|
label.setWrapText(true);
|
||||||
public VBox getChatInterfaceVBox() {
|
label.maxWidthProperty().bind(chat.widthProperty().subtract(CHAT_PADDING));
|
||||||
return chatInterfaceVBox;
|
chat.getChildren().add(label);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+15
@@ -10,12 +10,27 @@ import java.util.Optional;
|
|||||||
public class GetMessageCountHandler extends CommandHandler<GetMessageCountRequest> {
|
public class GetMessageCountHandler extends CommandHandler<GetMessageCountRequest> {
|
||||||
private final UserRegistry userRegistry;
|
private final UserRegistry userRegistry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new GetMessageCountHandler with the necessary response dispatcher
|
||||||
|
* and user registry.
|
||||||
|
*
|
||||||
|
* @param responseDispatcher The dispatcher used to send the count or error back to the client.
|
||||||
|
* @param userRegistry The registry used to identify the user and access their message queue.
|
||||||
|
*/
|
||||||
public GetMessageCountHandler(
|
public GetMessageCountHandler(
|
||||||
ResponseDispatcher responseDispatcher, UserRegistry userRegistry) {
|
ResponseDispatcher responseDispatcher, UserRegistry userRegistry) {
|
||||||
super(responseDispatcher);
|
super(responseDispatcher);
|
||||||
this.userRegistry = userRegistry;
|
this.userRegistry = userRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes a request to retrieve the number of pending messages for a user.
|
||||||
|
* It looks up the user by their session ID; if found, it dispatches a
|
||||||
|
* {@link GetMessageCountResponse} containing the current count. Otherwise,
|
||||||
|
* it dispatches an {@link ErrorResponse}.
|
||||||
|
*
|
||||||
|
* @param request The {@link GetMessageCountRequest} containing the session details.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void execute(GetMessageCountRequest request) {
|
public void execute(GetMessageCountRequest request) {
|
||||||
Optional<User> user = userRegistry.getBySessionId(request.getSessionId());
|
Optional<User> user = userRegistry.getBySessionId(request.getSessionId());
|
||||||
|
|||||||
+8
@@ -5,6 +5,14 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.Primitive
|
|||||||
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.accessor.RequestParameterAccessor;
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.accessor.RequestParameterAccessor;
|
||||||
|
|
||||||
public class GetMessageCountParser implements CommandParser<GetMessageCountRequest> {
|
public class GetMessageCountParser implements CommandParser<GetMessageCountRequest> {
|
||||||
|
/**
|
||||||
|
* Parses a raw {@link PrimitiveRequest} into a {@link GetMessageCountRequest}.
|
||||||
|
* This method wraps the request context from the network layer into a
|
||||||
|
* structured message count request object.
|
||||||
|
*
|
||||||
|
* @param primitiveRequest The raw request containing parameters and context from the network.
|
||||||
|
* @return A new {@link GetMessageCountRequest} instance.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public GetMessageCountRequest parse(PrimitiveRequest primitiveRequest) {
|
public GetMessageCountRequest parse(PrimitiveRequest primitiveRequest) {
|
||||||
RequestParameterAccessor accessor =
|
RequestParameterAccessor accessor =
|
||||||
|
|||||||
+7
@@ -4,6 +4,13 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.Request;
|
|||||||
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.RequestContext;
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.RequestContext;
|
||||||
|
|
||||||
public class GetMessageCountRequest extends Request {
|
public class GetMessageCountRequest extends Request {
|
||||||
|
/**
|
||||||
|
* Constructs a new GetMessageCountRequest with the specified request context.
|
||||||
|
* This request is used by a client to query the number of pending messages
|
||||||
|
* currently waiting in their server-side queue.
|
||||||
|
*
|
||||||
|
* @param context The {@link RequestContext} associated with this request.
|
||||||
|
*/
|
||||||
public GetMessageCountRequest(RequestContext context) {
|
public GetMessageCountRequest(RequestContext context) {
|
||||||
super(context);
|
super(context);
|
||||||
}
|
}
|
||||||
|
|||||||
+8
@@ -5,6 +5,14 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.SuccessR
|
|||||||
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.builder.ResponseBodyBuilder;
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.builder.ResponseBodyBuilder;
|
||||||
|
|
||||||
public class GetMessageCountResponse extends SuccessResponse {
|
public class GetMessageCountResponse extends SuccessResponse {
|
||||||
|
/**
|
||||||
|
* Constructs a new GetMessageCountResponse. It creates a response body
|
||||||
|
* containing the "COUNT" parameter and associates it with the original
|
||||||
|
* request context.
|
||||||
|
*
|
||||||
|
* @param context The {@link RequestContext} of the original request.
|
||||||
|
* @param count The number of pending messages to be returned to the client.
|
||||||
|
*/
|
||||||
public GetMessageCountResponse(RequestContext context, int count) {
|
public GetMessageCountResponse(RequestContext context, int count) {
|
||||||
super(context, new ResponseBodyBuilder().param("COUNT", count).build());
|
super(context, new ResponseBodyBuilder().param("COUNT", count).build());
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-1
@@ -6,16 +6,30 @@ 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.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.ErrorResponse;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.dispatcher.ResponseDispatcher;
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.dispatcher.ResponseDispatcher;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
public class GetNextMessageHandler extends CommandHandler<GetNextMessageRequest> {
|
public class GetNextMessageHandler extends CommandHandler<GetNextMessageRequest> {
|
||||||
private final UserRegistry userRegistry;
|
private final UserRegistry userRegistry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new GetNextMessageHandler with the required dispatcher and user registry.
|
||||||
|
*
|
||||||
|
* @param responseDispatcher The dispatcher used to send responses back to clients.
|
||||||
|
* @param userRegistry The registry used to look up users by their session information.
|
||||||
|
*/
|
||||||
public GetNextMessageHandler(ResponseDispatcher responseDispatcher, UserRegistry userRegistry) {
|
public GetNextMessageHandler(ResponseDispatcher responseDispatcher, UserRegistry userRegistry) {
|
||||||
super(responseDispatcher);
|
super(responseDispatcher);
|
||||||
this.userRegistry = userRegistry;
|
this.userRegistry = userRegistry;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Executes the request to retrieve the next message for a specific user.
|
||||||
|
* It identifies the user via their session ID, dequeues the next available message,
|
||||||
|
* and dispatches a {@link GetNextMessageResponse}. If the user cannot be identified,
|
||||||
|
* an {@link ErrorResponse} is sent instead.
|
||||||
|
*
|
||||||
|
* @param request The {@link GetNextMessageRequest} containing the session and context.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void execute(GetNextMessageRequest request) {
|
public void execute(GetNextMessageRequest request) {
|
||||||
Optional<User> user = userRegistry.getBySessionId(request.getSessionId());
|
Optional<User> user = userRegistry.getBySessionId(request.getSessionId());
|
||||||
|
|||||||
+9
@@ -5,6 +5,15 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.Primitive
|
|||||||
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.accessor.RequestParameterAccessor;
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.accessor.RequestParameterAccessor;
|
||||||
|
|
||||||
public class GetNextMessageParser implements CommandParser<GetNextMessageRequest> {
|
public class GetNextMessageParser implements CommandParser<GetNextMessageRequest> {
|
||||||
|
/**
|
||||||
|
* Parses a raw {@link PrimitiveRequest} into a {@link GetNextMessageRequest}.
|
||||||
|
* This method initializes a parameter accessor (though not currently used
|
||||||
|
* for extraction) and returns a structured request object containing
|
||||||
|
* the original request context.
|
||||||
|
*
|
||||||
|
* @param primitiveRequest The raw request containing parameters and context from the network.
|
||||||
|
* @return A new {@link GetNextMessageRequest} instance.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public GetNextMessageRequest parse(PrimitiveRequest primitiveRequest) {
|
public GetNextMessageRequest parse(PrimitiveRequest primitiveRequest) {
|
||||||
RequestParameterAccessor accessor =
|
RequestParameterAccessor accessor =
|
||||||
|
|||||||
+7
@@ -4,6 +4,13 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.Request;
|
|||||||
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.RequestContext;
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.RequestContext;
|
||||||
|
|
||||||
public class GetNextMessageRequest extends Request {
|
public class GetNextMessageRequest extends Request {
|
||||||
|
/**
|
||||||
|
* Constructs a new GetNextMessageRequest with the specified request context.
|
||||||
|
* This request is typically used by a client to poll or retrieve the next
|
||||||
|
* available message from the server's queue.
|
||||||
|
*
|
||||||
|
* @param context The {@link RequestContext} associated with this request.
|
||||||
|
*/
|
||||||
public GetNextMessageRequest(RequestContext context) {
|
public GetNextMessageRequest(RequestContext context) {
|
||||||
super(context);
|
super(context);
|
||||||
}
|
}
|
||||||
|
|||||||
+8
@@ -6,6 +6,14 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.SuccessR
|
|||||||
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.ResponseBody;
|
||||||
|
|
||||||
public class GetNextMessageResponse extends SuccessResponse {
|
public class GetNextMessageResponse extends SuccessResponse {
|
||||||
|
/**
|
||||||
|
* Constructs a new GetNextMessageResponse. It converts the provided {@link Message}
|
||||||
|
* into a network-compatible response body and associates it with the original
|
||||||
|
* request context.
|
||||||
|
*
|
||||||
|
* @param context The {@link RequestContext} of the request being answered.
|
||||||
|
* @param msg The {@link Message} to be sent back to the client.
|
||||||
|
*/
|
||||||
public GetNextMessageResponse(RequestContext context, Message msg) {
|
public GetNextMessageResponse(RequestContext context, Message msg) {
|
||||||
super(context, msg.toResponse(ResponseBody.builder()));
|
super(context, msg.toResponse(ResponseBody.builder()));
|
||||||
}
|
}
|
||||||
|
|||||||
+19
@@ -9,11 +9,24 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.dispatch
|
|||||||
public class SendMessageHandler extends CommandHandler<SendMessageRequest> {
|
public class SendMessageHandler extends CommandHandler<SendMessageRequest> {
|
||||||
private final UserRegistry userRegistry;
|
private final UserRegistry userRegistry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new SendMessageHandler with the required dispatcher and user registry.
|
||||||
|
*
|
||||||
|
* @param responseDispatcher The dispatcher used to send responses back to clients.
|
||||||
|
* @param userRegistry The registry containing all currently connected users.
|
||||||
|
*/
|
||||||
public SendMessageHandler(ResponseDispatcher responseDispatcher, UserRegistry userRegistry) {
|
public SendMessageHandler(ResponseDispatcher responseDispatcher, UserRegistry userRegistry) {
|
||||||
super(responseDispatcher);
|
super(responseDispatcher);
|
||||||
this.userRegistry = userRegistry;
|
this.userRegistry = userRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes a message send request. This method extracts the message from the request,
|
||||||
|
* broadcasts it to all connected users, and dispatches a success response (OK)
|
||||||
|
* back to the sender.
|
||||||
|
*
|
||||||
|
* @param request The {@link SendMessageRequest} containing the message and context.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void execute(SendMessageRequest request) {
|
public void execute(SendMessageRequest request) {
|
||||||
Message message = request.getMessage();
|
Message message = request.getMessage();
|
||||||
@@ -22,6 +35,12 @@ public class SendMessageHandler extends CommandHandler<SendMessageRequest> {
|
|||||||
responseDispatcher.dispatch(response);
|
responseDispatcher.dispatch(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Distributes a message to every user currently registered in the system.
|
||||||
|
* Each user's message queue is updated with the new message.
|
||||||
|
*
|
||||||
|
* @param message The {@link Message} object to be broadcast.
|
||||||
|
*/
|
||||||
public void broadcast(Message message) {
|
public void broadcast(Message message) {
|
||||||
userRegistry.getAllUsers().forEach(user -> user.enqueueMessage(message));
|
userRegistry.getAllUsers().forEach(user -> user.enqueueMessage(message));
|
||||||
}
|
}
|
||||||
|
|||||||
+9
@@ -5,6 +5,15 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.command.parsing.CommandPar
|
|||||||
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.PrimitiveRequest;
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.PrimitiveRequest;
|
||||||
|
|
||||||
public class SendMessageParser implements CommandParser<SendMessageRequest> {
|
public class SendMessageParser implements CommandParser<SendMessageRequest> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a raw {@link PrimitiveRequest} into a specific {@link SendMessageRequest}.
|
||||||
|
* This method extracts the message details from the request parameters and
|
||||||
|
* wraps them along with the request context into a structured request object.
|
||||||
|
*
|
||||||
|
* @param primitiveRequest The raw request containing parameters and context from the network.
|
||||||
|
* @return A structured {@link SendMessageRequest} containing the parsed {@link Message}.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public SendMessageRequest parse(PrimitiveRequest primitiveRequest) {
|
public SendMessageRequest parse(PrimitiveRequest primitiveRequest) {
|
||||||
Message msg = Message.toMessageReqPars(primitiveRequest.parameters());
|
Message msg = Message.toMessageReqPars(primitiveRequest.parameters());
|
||||||
|
|||||||
+11
@@ -8,11 +8,22 @@ public class SendMessageRequest extends Request {
|
|||||||
|
|
||||||
private final Message msg;
|
private final Message msg;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new SendMessageRequest with the given context and message.
|
||||||
|
*
|
||||||
|
* @param context The {@link RequestContext} associated with this request.
|
||||||
|
* @param msg The {@link Message} object to be processed.
|
||||||
|
*/
|
||||||
public SendMessageRequest(RequestContext context, Message msg) {
|
public SendMessageRequest(RequestContext context, Message msg) {
|
||||||
super(context);
|
super(context);
|
||||||
this.msg = msg;
|
this.msg = msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the message contained within this request.
|
||||||
|
*
|
||||||
|
* @return The {@link Message} instance.
|
||||||
|
*/
|
||||||
public Message getMessage() {
|
public Message getMessage() {
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user