Fix: Parsing of Server Responses for Client Chat
This commit is contained in:
@@ -3,6 +3,7 @@ package ch.unibas.dmi.dbis.cs108.casono.client;
|
|||||||
/**
|
/**
|
||||||
* Entry point for the Casono client application. Handles client startup and connection parameters.
|
* Entry point for the Casono client application. Handles client startup and connection parameters.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.client.ui.Launcher;
|
import ch.unibas.dmi.dbis.cs108.casono.client.ui.Launcher;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|||||||
@@ -77,13 +77,14 @@ public class ChatController {
|
|||||||
switch (msg.getMessageType()) {
|
switch (msg.getMessageType()) {
|
||||||
case ChatType.GLOBAL:
|
case ChatType.GLOBAL:
|
||||||
chatModelMap.get(new ChatKey(ChatType.GLOBAL)).addMessage(msg);
|
chatModelMap.get(new ChatKey(ChatType.GLOBAL)).addMessage(msg);
|
||||||
|
break;
|
||||||
case ChatType.LOBBY:
|
case ChatType.LOBBY:
|
||||||
if (msg.lobbyId == lobbyId) {
|
if (msg.lobbyId == lobbyId) {
|
||||||
chatModelMap.computeIfAbsent(new ChatKey(ChatType.LOBBY),
|
chatModelMap.computeIfAbsent(new ChatKey(ChatType.LOBBY),
|
||||||
(_key) -> new ChatModel(ChatType.LOBBY, username, msg.lobbyId, null)).addMessage(msg);
|
(_key) -> new ChatModel(ChatType.LOBBY, username, msg.lobbyId, null)).addMessage(msg);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case ChatType.WHISPER:
|
case ChatType.WHISPER:
|
||||||
// TODO: Check, if target person is user and if yes, iterate through all
|
|
||||||
if (msg.target.equals(username)) {
|
if (msg.target.equals(username)) {
|
||||||
if (chatModelMap.containsKey(new ChatKey(ChatType.WHISPER, msg.sender))) {
|
if (chatModelMap.containsKey(new ChatKey(ChatType.WHISPER, msg.sender))) {
|
||||||
chatModelMap.get(new ChatKey(ChatType.WHISPER, msg.sender)).addMessage(msg);
|
chatModelMap.get(new ChatKey(ChatType.WHISPER, msg.sender)).addMessage(msg);
|
||||||
@@ -93,6 +94,7 @@ public class ChatController {
|
|||||||
chatBoxController.addWhisperChat(msg.sender, value);
|
chatBoxController.addWhisperChat(msg.sender, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.casono.client.chat;
|
package ch.unibas.dmi.dbis.cs108.casono.client.chat;
|
||||||
|
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui.ChatViewController;
|
|
||||||
import javafx.beans.property.IntegerProperty;
|
import javafx.beans.property.IntegerProperty;
|
||||||
import javafx.beans.property.SimpleIntegerProperty;
|
import javafx.beans.property.SimpleIntegerProperty;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ChatModel, stores the data for a specific chat
|
* ChatModel, stores the data for a specific chat
|
||||||
@@ -13,6 +13,8 @@ import java.util.ArrayList;
|
|||||||
*/
|
*/
|
||||||
public class ChatModel {
|
public class ChatModel {
|
||||||
|
|
||||||
|
private ArrayList<Consumer<Message>> listeners = new ArrayList<>();
|
||||||
|
|
||||||
public ArrayList<Message> messages;
|
public ArrayList<Message> messages;
|
||||||
|
|
||||||
private final ChatType chattype;
|
private final ChatType chattype;
|
||||||
@@ -62,18 +64,12 @@ public class ChatModel {
|
|||||||
*/
|
*/
|
||||||
public synchronized void addMessage(Message msg) {
|
public synchronized void addMessage(Message msg) {
|
||||||
messages.add(msg);
|
messages.add(msg);
|
||||||
count.add(1);
|
listeners.stream().forEach((l)-> l.accept(messages.getLast()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void addListener(ChatViewController chatViewController) {
|
public void addListener(Consumer<Message> listener) {
|
||||||
count.addListener(
|
this.listeners.add(listener);
|
||||||
(_count, _p, n) ->
|
|
||||||
{
|
|
||||||
if(n.intValue() > 0) {
|
|
||||||
chatViewController.showMessage();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTarget() {
|
public String getTarget() {
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.casono.client.chat;
|
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.ResponseBodyBuilder;
|
||||||
import org.jspecify.annotations.NonNull;
|
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.regex.Matcher;
|
import java.util.Optional;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -80,10 +82,16 @@ public class Message {
|
|||||||
* @return - request as specified in the network protocol, as String
|
* @return - request as specified in the network protocol, as String
|
||||||
*/
|
*/
|
||||||
public String toArgsString() {
|
public String toArgsString() {
|
||||||
|
String gameIdString="";
|
||||||
|
if(lobbyId >= 0) {
|
||||||
|
gameIdString=" GAME="+lobbyId;
|
||||||
|
} else {
|
||||||
|
gameIdString=" GAME='-1'";
|
||||||
|
}
|
||||||
return String.format(
|
return String.format(
|
||||||
"TYPE=%s GAME=%d USER=%s TARGET=%s TIME=%s TEXT='%s'",
|
"TYPE=%s%s USER='%s' TARGET='%s' TIME='%s' TEXT='%s'",
|
||||||
this.type.toString(),
|
this.type.toString(),
|
||||||
this.lobbyId,
|
gameIdString,
|
||||||
this.sender,
|
this.sender,
|
||||||
this.target,
|
this.target,
|
||||||
this.timestamp,
|
this.timestamp,
|
||||||
@@ -93,16 +101,18 @@ public class Message {
|
|||||||
/** Pattern, to analyze the response String with the given parameters */
|
/** Pattern, to analyze the response String with the given parameters */
|
||||||
public static Pattern msgRex =
|
public static Pattern msgRex =
|
||||||
Pattern.compile(
|
Pattern.compile(
|
||||||
"TYPE=(?<type>\\w+) " + "GAME=(?<game>\\w+) " +
|
"TYPE=(?<type>\\w+) " + "(GAME=(?<game>\\w+) )?" +
|
||||||
"USER=(?<user>\\w+) " + "TARGET=(?<target>\\w+) " +
|
"USER=(?<user>\\w+) " + "(TARGET=(?<target>\\w+) )?" +
|
||||||
"TIME=(?<time>[0-9:.]+) " + "TEXT='(?<text>([^']|\\')+)'");
|
"TIME=(?<time>[0-9:.]+) " + "TEXT='(?<text>([^']|\\')+)'");
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to create a Message Object, from the information given by the String
|
* Method to create a Message Object, from the information given by the String
|
||||||
*
|
*
|
||||||
* @param response - String that got sent as a response from the server
|
* @param response - String that got sent as a response from the server
|
||||||
* @return - New Message Object
|
* @return - New Message Object
|
||||||
*/
|
*/
|
||||||
|
/*
|
||||||
public static Message toMessage(String response) {
|
public static Message toMessage(String response) {
|
||||||
Matcher m = msgRex.matcher(response);
|
Matcher m = msgRex.matcher(response);
|
||||||
if (!m.matches()) {
|
if (!m.matches()) {
|
||||||
@@ -114,16 +124,18 @@ public class Message {
|
|||||||
case "GLOBAL":
|
case "GLOBAL":
|
||||||
return new Message(
|
return new Message(
|
||||||
ChatType.GLOBAL,
|
ChatType.GLOBAL,
|
||||||
0,
|
-1,
|
||||||
m.group("user"),
|
m.group("user"),
|
||||||
null,
|
null,
|
||||||
m.group("time"),
|
m.group("time"),
|
||||||
m.group("text"));
|
m.group("text"));
|
||||||
|
|
||||||
case "LOBBY":
|
case "LOBBY":
|
||||||
|
|
||||||
|
int gameId = getGameId(m.group("game"));
|
||||||
return new Message(
|
return new Message(
|
||||||
ChatType.LOBBY,
|
ChatType.LOBBY,
|
||||||
Integer.parseInt(m.group("game")),
|
gameId,
|
||||||
m.group("user"),
|
m.group("user"),
|
||||||
null,
|
null,
|
||||||
m.group("time"),
|
m.group("time"),
|
||||||
@@ -132,7 +144,7 @@ public class Message {
|
|||||||
case "WHISPER":
|
case "WHISPER":
|
||||||
return new Message(
|
return new Message(
|
||||||
ChatType.WHISPER,
|
ChatType.WHISPER,
|
||||||
Integer.parseInt(m.group("game")),
|
-1,
|
||||||
m.group("user"),
|
m.group("user"),
|
||||||
m.group("target"),
|
m.group("target"),
|
||||||
m.group("time"),
|
m.group("time"),
|
||||||
@@ -142,13 +154,22 @@ public class Message {
|
|||||||
throw new RuntimeException("Unknown message type " + typeString);
|
throw new RuntimeException("Unknown message type " + typeString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
public static Message toMessage(List<RequestParameter> parameters) {
|
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) {
|
||||||
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 -> new Message(ChatType.GLOBAL,
|
case GLOBAL -> new Message(ChatType.GLOBAL,
|
||||||
0,
|
-1,
|
||||||
getParString(parameters, "USER"),
|
getParString(parameters, "USER"),
|
||||||
null,
|
null,
|
||||||
getParString(parameters, "TIME"),
|
getParString(parameters, "TIME"),
|
||||||
@@ -162,7 +183,7 @@ public class Message {
|
|||||||
getParString(parameters, "TEXT")
|
getParString(parameters, "TEXT")
|
||||||
);
|
);
|
||||||
case WHISPER -> new Message(ChatType.WHISPER,
|
case WHISPER -> new Message(ChatType.WHISPER,
|
||||||
Integer.parseInt(getParString(parameters, "GAME")),
|
Integer.parseInt(getParString(parameters, "GAME", "-1")),
|
||||||
getParString(parameters, "USER"),
|
getParString(parameters, "USER"),
|
||||||
getParString(parameters, "TARGET"),
|
getParString(parameters, "TARGET"),
|
||||||
getParString(parameters, "TIME"),
|
getParString(parameters, "TIME"),
|
||||||
@@ -171,11 +192,32 @@ public class Message {
|
|||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static @NonNull String getParString(List<RequestParameter> parameters, String keyString) {
|
private static @NonNull String getParString(List<RequestParameter> parameters, String keyString) {
|
||||||
return parameters.stream().filter((p) -> "TYPE".equals(p.key()))
|
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()))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.map(RequestParameter::value)
|
.map(RequestParameter::value);
|
||||||
.orElseThrow(() -> new RuntimeException("No " + keyString + " found"));
|
if(parOption.isEmpty()) {
|
||||||
|
if (defaultVal == null) {
|
||||||
|
throw new RuntimeException("No " + keyString + " found");
|
||||||
|
} else {
|
||||||
|
return defaultVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return parOption.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResponseBody toResponse(ResponseBodyBuilder builder) {
|
||||||
|
builder.param("TYPE", type.name());
|
||||||
|
builder.param("GAME", lobbyId);
|
||||||
|
builder.param("USER", this.sender);
|
||||||
|
if (target != null) {
|
||||||
|
builder.param("TARGET", target);
|
||||||
|
}
|
||||||
|
builder.param("TIME", this.timestamp);
|
||||||
|
builder.param("TEXT", this.message);
|
||||||
|
return builder.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.casono.client.network;
|
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.client.chat.Message;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.parsing.RequestParameter;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ChatClient class is responsible for sending messages to the server and
|
* The ChatClient class is responsible for sending messages to the server and
|
||||||
@@ -15,6 +16,7 @@ import java.util.regex.Pattern;
|
|||||||
public class ChatClient {
|
public class ChatClient {
|
||||||
|
|
||||||
private final ClientService clientService;
|
private final ClientService clientService;
|
||||||
|
private final Logger logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a ChatClient with the given ClientService for communication.
|
* Constructs a ChatClient with the given ClientService for communication.
|
||||||
@@ -24,6 +26,7 @@ public class ChatClient {
|
|||||||
*/
|
*/
|
||||||
public ChatClient(ClientService clientService) {
|
public ChatClient(ClientService clientService) {
|
||||||
this.clientService = clientService;
|
this.clientService = clientService;
|
||||||
|
this.logger = LogManager.getLogger(ChatClient.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -34,6 +37,7 @@ public class ChatClient {
|
|||||||
*/
|
*/
|
||||||
public void sendMessage(Message message) {
|
public void sendMessage(Message message) {
|
||||||
String request = "SEND_MESSAGE " + message.toArgsString();
|
String request = "SEND_MESSAGE " + message.toArgsString();
|
||||||
|
logger.info("Writing to server: " + request);
|
||||||
clientService.processCommand(request);
|
clientService.processCommand(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,24 +51,20 @@ public class ChatClient {
|
|||||||
* the server.
|
* the server.
|
||||||
*/
|
*/
|
||||||
public List<Message> getMessages() {
|
public List<Message> getMessages() {
|
||||||
String countStr = clientService.processCommand("GET_MESSAGE_COUNT");
|
logger.info("Asking server for new messages");
|
||||||
Matcher m = countRex.matcher(countStr);
|
List<RequestParameter> countStr = ClientService.convertToRequestParameters(clientService.processCommand("GET_MESSAGE_COUNT"));
|
||||||
if (!m.matches()) {
|
RequestParameter countRes = countStr.getFirst();
|
||||||
throw new RuntimeException("Can not parse response: " + countStr);
|
if (!countRes.key().equals("COUNT")) {
|
||||||
|
logger.error("Not the right response from server");
|
||||||
}
|
}
|
||||||
int count = Integer.parseInt(m.group("count"));
|
int count = Integer.parseInt(countRes.value());
|
||||||
System.out.println("Got " + count + " messages");
|
logger.info("Got " + count + " messages");
|
||||||
List<Message> messages = new ArrayList<>();
|
ArrayList<Message> messages = new ArrayList<>();
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
String message = clientService.processCommand("GET_NEXT_MESSAGE");
|
List<RequestParameter> msgRes = ClientService.convertToRequestParameters(clientService.processCommand("GET_NEXT_MESSAGE"));
|
||||||
if (message != null) {
|
Message msg = Message.toMessageReqPars(msgRes);
|
||||||
Message message1 = Message.toMessage(message);
|
messages.add(msg);
|
||||||
messages.add(message1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return messages;
|
return messages;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Pattern countRex = Pattern.compile("COUNT=(?<count>[0-9]+)");
|
|
||||||
}
|
}
|
||||||
// (?<key>\w+)='(?<string>([^']|\')+)'|(?<primVal>[\d\w]+)
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.casono.client.network;
|
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.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.LogManager;
|
||||||
@@ -8,12 +9,14 @@ 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;
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ClientService class is responsible for managing the connection to the
|
* The ClientService class is responsible for managing the connection to the
|
||||||
@@ -58,6 +61,8 @@ public class ClientService {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
* Sends the Requests to the server and waits for the response If the response is "+OK" it
|
||||||
* proceeds normal If the response "-ERROR" it throws a runtime exception
|
* proceeds normal If the response "-ERROR" it throws a runtime exception
|
||||||
@@ -65,36 +70,61 @@ public class ClientService {
|
|||||||
* @param message
|
* @param message
|
||||||
* @return - The response as a string, if it has to be returned (+OK will not be returned)
|
* @return - The response as a string, if it has to be returned (+OK will not be returned)
|
||||||
*/
|
*/
|
||||||
protected String processCommand(String message) {
|
private static String unescape(String input) {
|
||||||
AtomicReference<String> response = new AtomicReference<>();
|
return input.replaceAll("\\\\'", "'");
|
||||||
|
}
|
||||||
|
public static List<RequestParameter> convertToRequestParameters(List<String> input) {
|
||||||
|
return input.stream().map((String parString)-> responseRex.matcher(parString))
|
||||||
|
.filter(Matcher::matches)
|
||||||
|
.map((m)->{
|
||||||
|
if (!(m.group("string") == null)) {
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
protected List<String> processCommand(String message) {
|
||||||
|
List<String> response = new ArrayList<>();
|
||||||
sendRequest(
|
sendRequest(
|
||||||
() -> {
|
() -> {
|
||||||
try {
|
try {
|
||||||
writeToTransport(message);
|
writeToTransport(message);
|
||||||
String responseText = null;
|
String responseText = null;
|
||||||
do {
|
|
||||||
responseText = clienttcptransport.read().payload();
|
responseText = clienttcptransport.read().payload();
|
||||||
logger.info("Raw message '" + responseText + "'");
|
logger.info("Raw message '" + responseText + "'");
|
||||||
|
Boolean success = null;
|
||||||
|
int count = 0;
|
||||||
for(String line: responseText.split("\n")) {
|
for(String line: responseText.split("\n")) {
|
||||||
|
if (success == null) {
|
||||||
if ("+OK".equals(line)) {
|
if ("+OK".equals(line)) {
|
||||||
return;
|
success = true;
|
||||||
|
continue;
|
||||||
|
|
||||||
} else if (("-ERROR").equals(responseText)) {
|
} else if (("-ERROR").equals(responseText)) {
|
||||||
throw new RuntimeException(responseText);
|
success = false;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
} else if ("END".equals(line)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
line = line.replaceFirst("^\t", "");
|
||||||
|
response.add(line);
|
||||||
|
|
||||||
|
}
|
||||||
|
if (success!= null && success) {
|
||||||
|
return;
|
||||||
} else {
|
} else {
|
||||||
String start = response.get();
|
throw new RuntimeException("Error in "+message+": "+response);
|
||||||
if(start == null) {
|
|
||||||
response.set(line);
|
|
||||||
} else {
|
|
||||||
response.set(start + "\n" + line);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (true);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw getRuntimeException(e);
|
throw getRuntimeException(e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return response.get();
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ 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.GameState;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.client.game.Player;
|
import ch.unibas.dmi.dbis.cs108.casono.client.game.Player;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -33,7 +32,7 @@ public class GameClient {
|
|||||||
* @return A GameState object representing the current state of the game.
|
* @return A GameState object representing the current state of the game.
|
||||||
*/
|
*/
|
||||||
public GameState getGameState() {
|
public GameState getGameState() {
|
||||||
String response = client.processCommand("GET_GAME_STATE");
|
List<String> response = client.processCommand("GET_GAME_STATE");
|
||||||
return parseGameState(response);
|
return parseGameState(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,16 +42,14 @@ public class GameClient {
|
|||||||
* @param input The raw response string from the server.
|
* @param input The raw response string from the server.
|
||||||
* @return A GameState object representing the current state of the game.
|
* @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();
|
GameState state = new GameState();
|
||||||
|
|
||||||
String[] lines = input.split("\n");
|
|
||||||
|
|
||||||
Player currentPlayer = null;
|
Player currentPlayer = null;
|
||||||
Card currentCard = null;
|
Card currentCard = null;
|
||||||
|
|
||||||
for (String rawLine : lines) {
|
for (String rawLine : input) {
|
||||||
|
|
||||||
String line = rawLine.trim();
|
String line = rawLine.trim();
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ public class LobbyClient {
|
|||||||
* by the server.
|
* by the server.
|
||||||
*/
|
*/
|
||||||
public String fetchLobbyStatusString(int lobbyId) {
|
public String fetchLobbyStatusString(int lobbyId) {
|
||||||
return client.processCommand("GET_LOBBY_STATUS ID=" + lobbyId);
|
return client.processCommand("GET_LOBBY_STATUS ID=" + lobbyId).getFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -37,7 +37,7 @@ public class LobbyClient {
|
|||||||
* @return The id of the newly created lobby, as returned by the server.
|
* @return The id of the newly created lobby, as returned by the server.
|
||||||
*/
|
*/
|
||||||
public int createLobby() {
|
public int createLobby() {
|
||||||
String response = client.processCommand("CREATE_LOBBY");
|
String response = client.processCommand("CREATE_LOBBY").getFirst();
|
||||||
return Integer.parseInt(response);
|
return Integer.parseInt(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ public class LobbyClient {
|
|||||||
* the server.
|
* the server.
|
||||||
*/
|
*/
|
||||||
public int getLobbyId() {
|
public int getLobbyId() {
|
||||||
String response = client.processCommand("GET_LOBBY_ID");
|
String response = client.processCommand("GET_LOBBY_ID").getFirst();
|
||||||
return Integer.parseInt(response);
|
return Integer.parseInt(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -51,7 +51,7 @@ public class ChatBoxController {
|
|||||||
URL resource = getClass().getResource(ressource);
|
URL resource = getClass().getResource(ressource);
|
||||||
FXMLLoader fxmlLoader = new FXMLLoader(resource);
|
FXMLLoader fxmlLoader = new FXMLLoader(resource);
|
||||||
ChatViewController chatViewController = new ChatViewController(username, chatModel, chatController);
|
ChatViewController chatViewController = new ChatViewController(username, chatModel, chatController);
|
||||||
chatModel.addListener(chatViewController);
|
chatModel.addListener((msg)-> chatViewController.showMessage(msg));
|
||||||
try {
|
try {
|
||||||
fxmlLoader.setController(chatViewController);
|
fxmlLoader.setController(chatViewController);
|
||||||
Tab newChat = new Tab(title, fxmlLoader.load());
|
Tab newChat = new Tab(title, fxmlLoader.load());
|
||||||
|
|||||||
+8
-8
@@ -22,13 +22,13 @@ public class ChatViewController implements Initializable {
|
|||||||
|
|
||||||
@FXML private TextField inputField;
|
@FXML private TextField inputField;
|
||||||
|
|
||||||
@FXML private VBox chatVBox;
|
@FXML private VBox chatInterfaceVBox;
|
||||||
|
|
||||||
@FXML private HBox controlBar;
|
@FXML private HBox controlBar;
|
||||||
|
|
||||||
@FXML private ScrollPane scrollPane;
|
@FXML private ScrollPane scrollPane;
|
||||||
|
|
||||||
@FXML private VBox Chat;
|
@FXML private VBox chat;
|
||||||
|
|
||||||
private final ChatModel chatModel;
|
private final ChatModel chatModel;
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ public class ChatViewController implements Initializable {
|
|||||||
public void initialize(URL location, ResourceBundle resourceBundle) {
|
public void initialize(URL location, ResourceBundle resourceBundle) {
|
||||||
inputField.setOnAction(event -> sendMessage());
|
inputField.setOnAction(event -> sendMessage());
|
||||||
sendButton.setOnAction(event -> sendMessage());
|
sendButton.setOnAction(event -> sendMessage());
|
||||||
scrollPane.vvalueProperty().bind(chatVBox.heightProperty());
|
scrollPane.vvalueProperty().bind(chatInterfaceVBox.heightProperty());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendMessage() {
|
public void sendMessage() {
|
||||||
@@ -66,13 +66,13 @@ public class ChatViewController implements Initializable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showMessage() {
|
public void showMessage(Message msg) {
|
||||||
String msg = chatModel.viewNextMessage();
|
String msgText = String.format("[%s] %s: %s", msg.timestamp, msg.sender, msg.getMessage());
|
||||||
Label label = new Label(msg);
|
Label label = new Label(msgText);
|
||||||
label.getStyleClass().add("info-text");
|
label.getStyleClass().add("info-text");
|
||||||
label.setWrapText(true);
|
label.setWrapText(true);
|
||||||
label.maxWidthProperty().bind(chatVBox.widthProperty().subtract(CHAT_PADDING));
|
label.maxWidthProperty().bind(chat.widthProperty().subtract(CHAT_PADDING));
|
||||||
chatVBox.getChildren().add(label);
|
chat.getChildren().add(label);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -31,7 +31,7 @@ public class GetNextMessageHandler implements CommandHandler<GetNextMessageReque
|
|||||||
} else {
|
} else {
|
||||||
ErrorResponse response = new ErrorResponse(
|
ErrorResponse response = new ErrorResponse(
|
||||||
request.getContext(),
|
request.getContext(),
|
||||||
"",
|
"NO_USER_ASSOCIATED",
|
||||||
"user could not be identified by SessionId"
|
"user could not be identified by SessionId"
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|||||||
+2
-3
@@ -7,8 +7,7 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.builder.
|
|||||||
|
|
||||||
public class GetNextMessageResponse extends SuccessResponse {
|
public class GetNextMessageResponse extends SuccessResponse {
|
||||||
public GetNextMessageResponse(RequestContext context, Message msg) {
|
public GetNextMessageResponse(RequestContext context, Message msg) {
|
||||||
super(context, ResponseBody.builder()
|
super(context, msg.toResponse(ResponseBody.builder())
|
||||||
.param("MESSAGE", msg.toArgsString())
|
);
|
||||||
.build());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.Primitive
|
|||||||
public class SendMessageParser implements CommandParser<SendMessageRequest> {
|
public class SendMessageParser implements CommandParser<SendMessageRequest> {
|
||||||
@Override
|
@Override
|
||||||
public SendMessageRequest parse(PrimitiveRequest primitiveRequest) {
|
public SendMessageRequest parse(PrimitiveRequest primitiveRequest) {
|
||||||
Message msg = Message.toMessage(primitiveRequest.parameters());
|
Message msg = Message.toMessageReqPars(primitiveRequest.parameters());
|
||||||
return new SendMessageRequest(primitiveRequest.context(), msg);
|
return new SendMessageRequest(primitiveRequest.context(), msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,13 @@
|
|||||||
<?import javafx.scene.layout.*?>
|
<?import javafx.scene.layout.*?>
|
||||||
<?import javafx.geometry.Insets?>
|
<?import javafx.geometry.Insets?>
|
||||||
|
|
||||||
|
<!-- fx:controller="ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui.ChatBoxController" -->
|
||||||
|
|
||||||
<VBox xmlns="http://javafx.com/javafx/21"
|
<VBox xmlns="http://javafx.com/javafx/21"
|
||||||
xmlns:fx="http://javafx.com/fxml/1"
|
xmlns:fx="http://javafx.com/fxml/1"
|
||||||
fx:id="chatBox"
|
fx:id="chatBox"
|
||||||
fx:controller="ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui.ChatBoxController"
|
|
||||||
VBox.vgrow="ALWAYS"
|
VBox.vgrow="ALWAYS"
|
||||||
|
stylesheets="@chatui.css"
|
||||||
styleClass="chat-box"
|
styleClass="chat-box"
|
||||||
spacing="10"
|
spacing="10"
|
||||||
maxWidth="Infinity">
|
maxWidth="Infinity">
|
||||||
|
|||||||
@@ -9,16 +9,16 @@
|
|||||||
<!-- VBox for the global chat, should only be visible when activated via changeGlobalChatButton-->
|
<!-- VBox for the global chat, should only be visible when activated via changeGlobalChatButton-->
|
||||||
<VBox xmlns="http://javafx.com/javafx/21"
|
<VBox xmlns="http://javafx.com/javafx/21"
|
||||||
xmlns:fx="http://javafx.com/fxml/1"
|
xmlns:fx="http://javafx.com/fxml/1"
|
||||||
fx:id="chatVBox">
|
fx:id="chatInterfaceVBox"
|
||||||
|
stylesheets="@chatui.css"
|
||||||
|
styleClass="chat-box">
|
||||||
|
|
||||||
<Label text="== CHAT ==" styleClass="chat-header" alignment="CENTER" maxWidth="Infinity"/>
|
|
||||||
<Region minHeight="4" styleClass="chat-separator"/>
|
|
||||||
|
|
||||||
<!-- Chatnachrichten werden hier hinzugefügt -->
|
<!-- Chatnachrichten werden hier hinzugefügt -->
|
||||||
<ScrollPane fx:id="scrollPane" fitToWidth="true" vbarPolicy="AS_NEEDED" hbarPolicy="NEVER"
|
<ScrollPane fx:id="scrollPane" fitToWidth="true" vbarPolicy="AS_NEEDED" hbarPolicy="NEVER"
|
||||||
VBox.vgrow="ALWAYS" styleClass="chat-scroll-pane">
|
VBox.vgrow="ALWAYS" styleClass="chat-scroll-pane">
|
||||||
<content>
|
<content>
|
||||||
<VBox fx:id="Chat" spacing="10" styleClass="chat-VBox"/>
|
<VBox fx:id="chat" spacing="10" styleClass="chat-VBox"/>
|
||||||
</content>
|
</content>
|
||||||
</ScrollPane>
|
</ScrollPane>
|
||||||
|
|
||||||
@@ -27,8 +27,8 @@
|
|||||||
fx:id="controlBar">
|
fx:id="controlBar">
|
||||||
<!-- TODO: Größe des TextFields dynamisch anpassen -->
|
<!-- TODO: Größe des TextFields dynamisch anpassen -->
|
||||||
<TextField fx:id="inputField" HBox.hgrow="ALWAYS" promptText="Nachricht eingeben..."
|
<TextField fx:id="inputField" HBox.hgrow="ALWAYS" promptText="Nachricht eingeben..."
|
||||||
styleClass="gray-input-field" onAction="#sendMessage"/>
|
styleClass="gray-input-field"/>
|
||||||
<Button fx:id="sendButton" text="SENDEN" onAction="#sendMessage"
|
<Button fx:id="sendButton" text="SENDEN"
|
||||||
styleClass="yellow-button"/>
|
styleClass="yellow-button"/>
|
||||||
</HBox>
|
</HBox>
|
||||||
</VBox>
|
</VBox>
|
||||||
|
|||||||
@@ -27,7 +27,9 @@ public class ChatApplication extends Application {
|
|||||||
// TODO login UI
|
// TODO login UI
|
||||||
coreClient.login(username);
|
coreClient.login(username);
|
||||||
ChatController chatController = new ChatController(username, clientService);
|
ChatController chatController = new ChatController(username, clientService);
|
||||||
fxmlLoader.setControllerFactory(type -> {
|
ChatBoxController chatBoxController = new ChatBoxController(username, chatController);
|
||||||
|
fxmlLoader.setController(chatBoxController);
|
||||||
|
/*fxmlLoader.setControllerFactory(type -> {
|
||||||
if (type == ChatBoxController.class) {
|
if (type == ChatBoxController.class) {
|
||||||
return chatController.getChatBoxController();
|
return chatController.getChatBoxController();
|
||||||
} else {
|
} else {
|
||||||
@@ -37,7 +39,7 @@ public class ChatApplication extends Application {
|
|||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});*/
|
||||||
|
|
||||||
Scene scene = new Scene(fxmlLoader.load(), SCENE_WIDTH, SCENE_HEIGHT);
|
Scene scene = new Scene(fxmlLoader.load(), SCENE_WIDTH, SCENE_HEIGHT);
|
||||||
stage.setTitle("Chat");
|
stage.setTitle("Chat");
|
||||||
|
|||||||
@@ -1,11 +1,43 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.casono.client.chat;
|
package ch.unibas.dmi.dbis.cs108.casono.client.chat;
|
||||||
|
|
||||||
|
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 org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
public class ChatTest {
|
public class ChatTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void chatTest() {
|
public void chatTest() {
|
||||||
|
List<String> list = new ArrayList<String>();
|
||||||
|
list.add("COUNT=19199");
|
||||||
|
list.add("TEXT='test \\' test'");
|
||||||
|
list.add("TEXT='%/§§%&&/%=%$/%))==/?``*\\'\\'**\\'\\'§?'");
|
||||||
|
list.add("TEXT='Hello World'");
|
||||||
|
list.add("NUMBER=-56887387394898392849");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
List<RequestParameter> newList = ClientService.convertToRequestParameters(list);
|
||||||
|
RequestParameter par0 = newList.get(0);
|
||||||
|
assertEquals("COUNT", par0.key());
|
||||||
|
assertEquals("19199", par0.value());
|
||||||
|
|
||||||
|
RequestParameter par1 = newList.get(1);
|
||||||
|
assertEquals("TEXT", par1.key());
|
||||||
|
assertEquals("test ' test", par1.value());
|
||||||
|
|
||||||
|
RequestParameter par2 = newList.get(2);
|
||||||
|
assertEquals("TEXT", par2.key());
|
||||||
|
assertEquals("%/§§%&&/%=%$/%))==/?``*''**''§?", par2.value());
|
||||||
|
|
||||||
|
RequestParameter par4 = newList.get(4);
|
||||||
|
assertEquals("NUMBER", par4.key());
|
||||||
|
assertEquals("-56887387394898392849", par4.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user