Feat/client network #192

Merged
m.ginkel merged 5 commits from feat/client-network into main 2026-03-16 14:04:25 +01:00
5 changed files with 118 additions and 126 deletions
Showing only changes of commit 3809b7e0e2 - Show all commits
@@ -1,57 +1,137 @@
package ch.unibas.dmi.dbis.cs108.casono.client.chat; package ch.unibas.dmi.dbis.cs108.casono.client.chat;
import java.time.LocalTime; import java.time.LocalTime;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Message Object for internal handling of Chat-Messages
* TODO: Should be used on both sides of the network
*/
public class Message { public class Message {
private final MessageType type;
private String message; private String message;
public String name; public String user;
public int hourTime; public String timestamp;
public int minuteTime;
public int game_id = 0; public int game_id = 0;
public String target = null; public String target = null;
public enum MessageType {
GLOBAL, LOBBY, WHISPER
};
// For Global Chat public static final String SEPERATOR = " ";
public Message(String message, String name) { /**
this.message = message; * Constructor for creating Messages with all information given
this.name = name; * @param type - Either global, local or whisper
LocalTime now = LocalTime.now(); * @param game_id - lobby id, or null, if the type is global
this.hourTime = now.getHour(); * @param user - username
this.minuteTime = now.getMinute(); * @param target - username of the target user, for whisper chat
} * @param message
*/
// For Lobby Chat public Message(MessageType type, int game_id, String user, String target, String timestamp, String message) {
this.type = type;
public Message(String message, String name, int game_id) {
this.message = message;
this.name = name;
LocalTime now = LocalTime.now();
this.hourTime = now.getHour();
this.minuteTime = now.getMinute();
this.game_id = game_id;
}
// For Whisper Chat
public Message(String message, String name, int game_id, String target) {
this.message = message;
this.name = name;
LocalTime now = LocalTime.now();
this.hourTime = now.getHour();
this.minuteTime = now.getMinute();
this.game_id = game_id; this.game_id = game_id;
this.user = user;
this.target = target; this.target = target;
this.timestamp = timestamp;
this.message = message;
} }
/**
* Constructor for creating the Messages of the current user, using this client -> time of writing is being recorded
* @param type - Either global, local or whisper
* @param game_id - lobby id, or null, if the type is global
* @param user - username
* @param target - username of the target user, for whisper chat
* @param message
*/
public Message(MessageType type, int game_id, String user, String target, String message) {
this.type = type;
this.game_id = game_id;
this.user = user;
this.target = target;
this.message = message;
LocalTime now = LocalTime.now();
this.timestamp = now.toString();
}
public String getMessage() { public String getMessage() {
return message; return message;
} }
public String toString() { public String getMessageType() {
return String.format("%s: %s", this.name, this.message); return type.toString();
} }
public void print() { /**
System.out.println(this.toString()); * Method to test the system
* @return - String representation of the Message instance, as for example "player1: Hello World"
*/
public String toString() {
return String.format("%s: %s", this.user, this.message);
}
/**
* Method to create the request representation of the message object, to be sent to the server
* @return - request as specified in the network protocol, as String
*/
public String toRequest() {
String request = String.format("SEND_MESSAGE TYPE=%s GAME=%d USER=%s TARGET=%s TIME=%s TEXT=%s",
this.type.toString(), this.game_id, this.user, this.target, this.timestamp, this.message);
return request;
}
/**
* 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
* @param response - String that got sent as a response from the server
* @return - New Message Object
*/
public static Message toMessage(String response) {
var parts = response.split(SEPERATOR);
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(MessageType.GLOBAL,
0,
m.group("user"),
null,
m.group("time"),
m.group("text"));
case "LOBBY":
return new Message(MessageType.LOBBY,
Integer.parseInt(m.group("game")),
m.group("user"),
null,
m.group("time"),
m.group("text"));
case "WHISPER":
return new Message(MessageType.WHISPER,
Integer.parseInt(m.group("game")),
m.group("user"),
m.group("target"),
m.group("time"),
m.group("text"));
default:
throw new RuntimeException("Unknown message type " + typeString);
}
} }
} }
@@ -1,26 +0,0 @@
package ch.unibas.dmi.dbis.cs108.casono.client.network;
public class ClientParser {
public static final String Seperator = " ";
enum Protocol {}
public void parseMessage(String msg) {
var parts = msg.split(Seperator);
switch (parts[0]) {
case :
case :
case :
case :
default :
System.out.println("Response " + msg + " is not recognized");
}
}
}
@@ -71,6 +71,8 @@ public class ClientService {
return processMessage("GET_MESSAGE"); return processMessage("GET_MESSAGE");
} }
public List<String> sendMessage(Message message) { return processMessage(message.toRequest()); }
private List<String> processMessage(String message) { private List<String> processMessage(String message) {
List<String> response = new ArrayList<>(); List<String> response = new ArrayList<>();
sendRequest(() -> { sendRequest(() -> {
@@ -113,61 +115,6 @@ public class ClientService {
re = new RuntimeException(reason); re = new RuntimeException(reason);
return re; return re;
} }
/**
* Sends a Chat Message to the Server and awaits a response, which will be passed along
* @param message : Protocol Message of type "Message" to be sent to the server
* @return ArrayList<String> : The Response of the Server to be interpreted later
*/
public ArrayList<String> sendMessage(Message message) {
String time = message.hourTime + ":" + message.minuteTime;
String request = "";
if (message.target == null && message.game_id == 0) {
request = String.format("SEND_MESSAGE TYPE=GLOBAL GAME=null USER=%s TARGET=null TIME=%s TEXT=%s", message.name, time, message.getMessage());
}
else if (message.target == null) {
request = String.format("SEND_MESSAGE TYPE=LOBBY GAME=%d USER=%s TARGET=null TIME=%s TEXT=%s", message.game_id, message.name, time, message.getMessage());
} else {
request = String.format("SEND_MESSAGE TYPE=WHISPER GAME=%d USER=%s TARGET=%s TIME=%s TEXT=%s", message.game_id, message.name, message.target, time, message.getMessage());
}
System.out.println("Writing following request: " + request);
sendRequest task = new sendRequest(request, input, output);
executor.submit(task);
return this.response;
}
public ArrayList<String> getState(int game_id) {
String request = String.format("GET_STATE GAME=%d", game_id);
sendRequest task = new sendRequest(request, input, output);
executor.submit(task);
return this.response;
}
public ArrayList<String> joinGame(int game_id, String name) {
String request = String.format("JOIN GAME=%d NAME=%s", game_id, name);
sendRequest task = new sendRequest(request, input, output);
executor.submit(task);
return response;
}
/**
*
* @param type : Keyword, as one-word description of the action the player did.
* @param game_id : ID of the Lobby that the client is currently in
* @param value : Dependent on the action of the User (money)
* @param name : Username of the player of that Client
* @return The Response of the Server -> Action successfull only if response is valid
*/
public ArrayList<String>sendAction(String type, int game_id, String action, int value, String name) {
String request = String.format("SEND_ACTION TYPE=%s GAME=%s ACTION=%s VALUE=%d NAME=%s", type, game_id, action, value, name);
sendRequest task = new sendRequest(request, input, output);
executor.submit(task);
return response;
}
/** /**
* Closes the Socket and shuts down the Threadpool associated with that Socket-Connection. * Closes the Socket and shuts down the Threadpool associated with that Socket-Connection.
*/ */
@@ -1,9 +0,0 @@
package ch.unibas.dmi.dbis.cs108.casono.client.network;
public class ResponseException extends Exception {
public ResponseException() {
super();
}
}
@@ -7,6 +7,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
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.Future; import java.util.concurrent.Future;
@@ -29,8 +30,7 @@ public class ClientServiceTest {
@Test @Test
public void testClientService() throws ExecutionException, InterruptedException { public void testClientService() throws ExecutionException, InterruptedException {
ClientService client = new ClientService("localhost", 5000); ClientService client = new ClientService("localhost", 5000);
Future<ArrayList<String>> future = client.sendMessage(new Message("bla", "name")); List<String> response = client.sendMessage(new Message(Message.MessageType.GLOBAL, 0, "Mathis", null, "blahh"));
future.get();
client.closeSocket(); client.closeSocket();
} }
} }