Add: Implement Commands for Chat Protocol
This commit is contained in:
+1
-1
@@ -32,7 +32,7 @@ dependencies {
|
|||||||
// Source: https://mvnrepository.com/artifact/org.apache.logging.log4j
|
// Source: https://mvnrepository.com/artifact/org.apache.logging.log4j
|
||||||
implementation("org.apache.logging.log4j:log4j-api:2.25.3")
|
implementation("org.apache.logging.log4j:log4j-api:2.25.3")
|
||||||
runtimeOnly("org.apache.logging.log4j:log4j-core:2.25.3")
|
runtimeOnly("org.apache.logging.log4j:log4j-core:2.25.3")
|
||||||
|
implementation("org.jspecify:jspecify:1.0.0")
|
||||||
// Source: https://mvnrepository.com/artifact/org.fusesource.jansi/jansi
|
// Source: https://mvnrepository.com/artifact/org.fusesource.jansi/jansi
|
||||||
runtimeOnly("org.fusesource.jansi:jansi:2.4.2")
|
runtimeOnly("org.fusesource.jansi:jansi:2.4.2")
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,15 @@ 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 java.util.ArrayList;
|
import ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui.ChatBoxController;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
@@ -12,49 +19,84 @@ import java.util.List;
|
|||||||
public class ChatController {
|
public class ChatController {
|
||||||
|
|
||||||
private final String username;
|
private final String username;
|
||||||
private final ClientService clientService;
|
|
||||||
|
|
||||||
private final ArrayList<ChatModel> chatModelArrayList;
|
|
||||||
private final ChatClient chatClient;
|
private final ChatClient chatClient;
|
||||||
|
|
||||||
|
public ChatBoxController getChatBoxController() {
|
||||||
|
return chatBoxController;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final ChatBoxController chatBoxController;
|
||||||
|
private int lobbyId = -1;
|
||||||
|
private final Timer timer;
|
||||||
|
|
||||||
|
|
||||||
|
public record ChatKey(ChatType type, @Nullable String targetUser){
|
||||||
|
public ChatKey(ChatType type){
|
||||||
|
this(type, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<ChatKey, ChatModel> getChatModelMap() {
|
||||||
|
return chatModelMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<ChatKey, ChatModel> chatModelMap;
|
||||||
|
|
||||||
|
private static final long REFRESH_TIME = 1000;
|
||||||
|
|
||||||
public ChatController(String username, ClientService clientService) {
|
public ChatController(String username, ClientService clientService) {
|
||||||
this.username = username;
|
this.username = username;
|
||||||
this.clientService = clientService;
|
|
||||||
chatModelArrayList = new ArrayList<>();
|
|
||||||
chatModelArrayList.add(new ChatModel(ChatType.GLOBAL, username));
|
|
||||||
chatClient = new ChatClient(clientService);
|
chatClient = new ChatClient(clientService);
|
||||||
|
chatModelMap = new LinkedHashMap<>();
|
||||||
|
this.chatBoxController = new ChatBoxController(username, this);
|
||||||
|
this.timer = new Timer();
|
||||||
|
timer.schedule(
|
||||||
|
new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
clientService.ping();
|
||||||
|
receiveMessage();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
0,
|
||||||
|
REFRESH_TIME);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChatModel getChatModel(int index) {
|
public void setLobbyChat(int lobbyId) {
|
||||||
return chatModelArrayList.get(index);
|
this.lobbyId = lobbyId;
|
||||||
}
|
ChatModel lobbyChatModel = new ChatModel(ChatType.LOBBY, username, lobbyId, null);
|
||||||
|
chatModelMap.put(new ChatKey(ChatType.LOBBY), lobbyChatModel);
|
||||||
public void createLobbyChat(int lobbyId, ChatType chatType) {
|
|
||||||
ChatModel chatModel = new ChatModel(chatType, username, lobbyId);
|
|
||||||
chatModelArrayList.add(chatModel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** method to get all messages from the server */
|
/** method to get all messages from the server */
|
||||||
public Boolean receiveMessage() {
|
public void receiveMessage() {
|
||||||
List<Message> newMessages = chatClient.getMessages();
|
List<Message> newMessages = chatClient.getMessages();
|
||||||
if (!newMessages.isEmpty()) {
|
if (!newMessages.isEmpty()) {
|
||||||
for (Message msg : newMessages) {
|
for (Message msg : newMessages) {
|
||||||
switch (msg.getMessageType()) {
|
switch (msg.getMessageType()) {
|
||||||
case ChatType.GLOBAL:
|
case ChatType.GLOBAL:
|
||||||
chatModelArrayList.get(0).addMessage(msg);
|
chatModelMap.get(new ChatKey(ChatType.GLOBAL)).addMessage(msg);
|
||||||
case ChatType.LOBBY:
|
case ChatType.LOBBY:
|
||||||
ChatModel chatModel = chatModelArrayList.get(1);
|
if (msg.lobbyId == lobbyId) {
|
||||||
if (chatModel != null && chatModel.lobbyId == msg.lobbyId) {
|
chatModelMap.computeIfAbsent(new ChatKey(ChatType.LOBBY),
|
||||||
chatModel.addMessage(msg);
|
(_key) -> new ChatModel(ChatType.LOBBY, username, msg.lobbyId, null)).addMessage(msg);
|
||||||
}
|
}
|
||||||
case ChatType.WHISPER:
|
case ChatType.WHISPER:
|
||||||
// TODO: Check, if target person is user and if yes, iterate through all
|
// TODO: Check, if target person is user and if yes, iterate through all
|
||||||
// whisper chats.
|
if (msg.target.equals(username)) {
|
||||||
}
|
if (chatModelMap.containsKey(new ChatKey(ChatType.WHISPER, msg.sender))) {
|
||||||
}
|
chatModelMap.get(new ChatKey(ChatType.WHISPER, msg.sender)).addMessage(msg);
|
||||||
return true;
|
|
||||||
} else {
|
} else {
|
||||||
return false;
|
ChatModel value = new ChatModel(ChatType.WHISPER, username, -1, msg.sender);
|
||||||
|
chatModelMap.put(new ChatKey(ChatType.WHISPER, msg.sender), value);
|
||||||
|
chatBoxController.addWhisperChat(msg.sender, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
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.SimpleIntegerProperty;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -11,33 +15,30 @@ public class ChatModel {
|
|||||||
|
|
||||||
public ArrayList<Message> messages;
|
public ArrayList<Message> messages;
|
||||||
|
|
||||||
private ChatType chattype;
|
private final ChatType chattype;
|
||||||
|
|
||||||
public String username;
|
/**
|
||||||
|
* The person currently using this client
|
||||||
|
*/
|
||||||
|
public final String username;
|
||||||
|
|
||||||
public int count;
|
/**
|
||||||
|
* The person to send the message to
|
||||||
|
* If the chat is a whisper chat
|
||||||
|
*/
|
||||||
|
private final String target;
|
||||||
|
|
||||||
|
private final IntegerProperty count;
|
||||||
|
|
||||||
public int lobbyId;
|
public int lobbyId;
|
||||||
|
|
||||||
/**
|
public ChatModel(ChatType chattype, String username, int lobbyId, String target) {
|
||||||
* Creates a new ChatModel, given a username of the client
|
|
||||||
*
|
|
||||||
* @param chattype
|
|
||||||
* @param username
|
|
||||||
*/
|
|
||||||
public ChatModel(ChatType chattype, String username) {
|
|
||||||
this.messages = new ArrayList<Message>();
|
this.messages = new ArrayList<Message>();
|
||||||
this.chattype = chattype;
|
this.chattype = chattype;
|
||||||
this.username = username;
|
this.username = username;
|
||||||
this.count = 0;
|
this.count = new SimpleIntegerProperty(0);
|
||||||
}
|
|
||||||
|
|
||||||
public ChatModel(ChatType chattype, String username, int lobbyId) {
|
|
||||||
this.messages = new ArrayList<Message>();
|
|
||||||
this.chattype = chattype;
|
|
||||||
this.username = username;
|
|
||||||
this.count = 0;
|
|
||||||
this.lobbyId = lobbyId;
|
this.lobbyId = lobbyId;
|
||||||
|
this.target = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChatType getChattype() {
|
public ChatType getChattype() {
|
||||||
@@ -49,9 +50,9 @@ public class ChatModel {
|
|||||||
* ChatModel
|
* ChatModel
|
||||||
*/
|
*/
|
||||||
public synchronized String viewNextMessage() {
|
public synchronized String viewNextMessage() {
|
||||||
count--;
|
count.subtract(1);
|
||||||
Message msg = messages.getLast();
|
Message msg = messages.getLast();
|
||||||
return String.format("[%s] %s: %s", msg.timestamp, msg.user, msg.getMessage());
|
return String.format("[%s] %s: %s", msg.timestamp, msg.sender, msg.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -61,13 +62,21 @@ public class ChatModel {
|
|||||||
*/
|
*/
|
||||||
public synchronized void addMessage(Message msg) {
|
public synchronized void addMessage(Message msg) {
|
||||||
messages.add(msg);
|
messages.add(msg);
|
||||||
count++;
|
count.add(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** method to send all current messages to the ChatViewController, if needed */
|
|
||||||
public void addCompleteChat() {
|
public void addListener(ChatViewController chatViewController) {
|
||||||
for (int i = 0; i < this.messages.size(); i++) {
|
count.addListener(
|
||||||
Message msg = this.messages.get(i);
|
(_count, _p, n) ->
|
||||||
|
{
|
||||||
|
if(n.intValue() > 0) {
|
||||||
|
chatViewController.showMessage();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTarget() {
|
||||||
|
return target;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
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 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.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@@ -12,7 +16,7 @@ import java.util.regex.Pattern;
|
|||||||
public class Message {
|
public class Message {
|
||||||
private final ChatType type;
|
private final ChatType type;
|
||||||
private final String message;
|
private final String message;
|
||||||
public String user;
|
public String sender;
|
||||||
public String timestamp;
|
public String timestamp;
|
||||||
public int lobbyId = 0;
|
public int lobbyId = 0;
|
||||||
public String target = null;
|
public String target = null;
|
||||||
@@ -22,20 +26,20 @@ public class Message {
|
|||||||
*
|
*
|
||||||
* @param type - Either global, local or whisper
|
* @param type - Either global, local or whisper
|
||||||
* @param lobbyId - lobby id, or null, if the typChatType
|
* @param lobbyId - lobby id, or null, if the typChatType
|
||||||
* @param user - username
|
* @param sender - username
|
||||||
* @param target - username of the target user, for whisper chat
|
* @param target - username of the target user, for whisper chat
|
||||||
* @param message
|
* @param message
|
||||||
*/
|
*/
|
||||||
public Message(
|
public Message(
|
||||||
ChatType type,
|
ChatType type,
|
||||||
int lobbyId,
|
int lobbyId,
|
||||||
String user,
|
String sender,
|
||||||
String target,
|
String target,
|
||||||
String timestamp,
|
String timestamp,
|
||||||
String message) {
|
String message) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.lobbyId = lobbyId;
|
this.lobbyId = lobbyId;
|
||||||
this.user = user;
|
this.sender = sender;
|
||||||
this.target = target;
|
this.target = target;
|
||||||
this.timestamp = timestamp;
|
this.timestamp = timestamp;
|
||||||
this.message = message;
|
this.message = message;
|
||||||
@@ -47,14 +51,14 @@ public class Message {
|
|||||||
*
|
*
|
||||||
* @param type - Either global, local or whisper
|
* @param type - Either global, local or whisper
|
||||||
* @param lobbyId - lobby id, or null, if the type is global
|
* @param lobbyId - lobby id, or null, if the type is global
|
||||||
* @param user - username
|
* @param sender - username
|
||||||
* @param target - username of the target user, for whisper chat
|
* @param target - username of the target user, for whisper chat
|
||||||
* @param message
|
* @param message
|
||||||
*/
|
*/
|
||||||
public Message(ChatType type, int lobbyId, String user, String target, String message) {
|
public Message(ChatType type, int lobbyId, String sender, String target, String message) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.lobbyId = lobbyId;
|
this.lobbyId = lobbyId;
|
||||||
this.user = user;
|
this.sender = sender;
|
||||||
this.target = target;
|
this.target = target;
|
||||||
this.message = message;
|
this.message = message;
|
||||||
LocalDateTime now = LocalDateTime.now();
|
LocalDateTime now = LocalDateTime.now();
|
||||||
@@ -77,10 +81,10 @@ public class Message {
|
|||||||
*/
|
*/
|
||||||
public String toArgsString() {
|
public String toArgsString() {
|
||||||
return String.format(
|
return String.format(
|
||||||
"TYPE=%s GAME=%d USER=%s TARGET=%s TIME=%s TEXT=%s",
|
"TYPE=%s GAME=%d USER=%s TARGET=%s TIME=%s TEXT='%s'",
|
||||||
this.type.toString(),
|
this.type.toString(),
|
||||||
this.lobbyId,
|
this.lobbyId,
|
||||||
this.user,
|
this.sender,
|
||||||
this.target,
|
this.target,
|
||||||
this.timestamp,
|
this.timestamp,
|
||||||
this.message);
|
this.message);
|
||||||
@@ -91,7 +95,7 @@ public class Message {
|
|||||||
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
|
||||||
@@ -138,4 +142,40 @@ public class Message {
|
|||||||
throw new RuntimeException("Unknown message type " + typeString);
|
throw new RuntimeException("Unknown message type " + typeString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Message toMessage(List<RequestParameter> parameters) {
|
||||||
|
String typeString = getParString(parameters, "TYPE");
|
||||||
|
ChatType type = ChatType.valueOf(typeString);
|
||||||
|
return switch (type) {
|
||||||
|
case GLOBAL -> new Message(ChatType.GLOBAL,
|
||||||
|
0,
|
||||||
|
getParString(parameters, "USER"),
|
||||||
|
null,
|
||||||
|
getParString(parameters, "TIME"),
|
||||||
|
getParString(parameters, "TEXT")
|
||||||
|
);
|
||||||
|
case LOBBY -> new Message(ChatType.LOBBY,
|
||||||
|
Integer.parseInt(getParString(parameters, "GAME")),
|
||||||
|
getParString(parameters, "USER"),
|
||||||
|
null,
|
||||||
|
getParString(parameters, "TIME"),
|
||||||
|
getParString(parameters, "TEXT")
|
||||||
|
);
|
||||||
|
case WHISPER -> new Message(ChatType.WHISPER,
|
||||||
|
Integer.parseInt(getParString(parameters, "GAME")),
|
||||||
|
getParString(parameters, "USER"),
|
||||||
|
getParString(parameters, "TARGET"),
|
||||||
|
getParString(parameters, "TIME"),
|
||||||
|
getParString(parameters, "TEXT")
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static @NonNull String getParString(List<RequestParameter> parameters, String keyString) {
|
||||||
|
return parameters.stream().filter((p) -> "TYPE".equals(p.key()))
|
||||||
|
.findFirst()
|
||||||
|
.map(RequestParameter::value)
|
||||||
|
.orElseThrow(() -> new RuntimeException("No " + keyString + " found"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import ch.unibas.dmi.dbis.cs108.casono.client.chat.Message;
|
|||||||
|
|
||||||
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
|
||||||
@@ -12,7 +14,7 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class ChatClient {
|
public class ChatClient {
|
||||||
|
|
||||||
private ClientService clientService;
|
private final ClientService clientService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a ChatClient with the given ClientService for communication.
|
* Constructs a ChatClient with the given ClientService for communication.
|
||||||
@@ -46,7 +48,11 @@ public class ChatClient {
|
|||||||
*/
|
*/
|
||||||
public List<Message> getMessages() {
|
public List<Message> getMessages() {
|
||||||
String countStr = clientService.processCommand("GET_MESSAGE_COUNT");
|
String countStr = clientService.processCommand("GET_MESSAGE_COUNT");
|
||||||
int count = Integer.parseInt(countStr);
|
Matcher m = countRex.matcher(countStr);
|
||||||
|
if (!m.matches()) {
|
||||||
|
throw new RuntimeException("Can not parse response: " + countStr);
|
||||||
|
}
|
||||||
|
int count = Integer.parseInt(m.group("count"));
|
||||||
System.out.println("Got " + count + " messages");
|
System.out.println("Got " + count + " messages");
|
||||||
List<Message> messages = new ArrayList<>();
|
List<Message> messages = new ArrayList<>();
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
@@ -58,4 +64,7 @@ public class ChatClient {
|
|||||||
}
|
}
|
||||||
return messages;
|
return messages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Pattern countRex = Pattern.compile("COUNT=(?<count>[0-9]+)");
|
||||||
}
|
}
|
||||||
|
// (?<key>\w+)='(?<string>([^']|\')+)'|(?<primVal>[\d\w]+)
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
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.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;
|
||||||
import org.apache.logging.log4j.Logger;
|
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;
|
||||||
@@ -71,16 +71,24 @@ public class ClientService {
|
|||||||
() -> {
|
() -> {
|
||||||
try {
|
try {
|
||||||
writeToTransport(message);
|
writeToTransport(message);
|
||||||
String responseLine = null;
|
String responseText = null;
|
||||||
do {
|
do {
|
||||||
responseLine = clienttcptransport.read().payload();
|
responseText = clienttcptransport.read().payload();
|
||||||
logger.info("Raw message '" + responseLine + "'");
|
logger.info("Raw message '" + responseText + "'");
|
||||||
if ("+OK".equals(responseLine)) {
|
for(String line: responseText.split("\n")) {
|
||||||
|
if ("+OK".equals(line)) {
|
||||||
return;
|
return;
|
||||||
} else if (("-ERROR").equals(responseLine)) {
|
} else if (("-ERROR").equals(responseText)) {
|
||||||
throw new RuntimeException(responseLine);
|
throw new RuntimeException(responseText);
|
||||||
|
} else {
|
||||||
|
String start = response.get();
|
||||||
|
if(start == null) {
|
||||||
|
response.set(line);
|
||||||
|
} else {
|
||||||
|
response.set(start + "\n" + line);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
response.set(responseLine);
|
|
||||||
} while (true);
|
} while (true);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw getRuntimeException(e);
|
throw getRuntimeException(e);
|
||||||
@@ -158,4 +166,10 @@ public class ClientService {
|
|||||||
int id = this.idGenerator.incrementAndGet();
|
int id = this.idGenerator.incrementAndGet();
|
||||||
this.clienttcptransport.write(new RawPacket(id, s));
|
this.clienttcptransport.write(new RawPacket(id, s));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ping() {
|
||||||
|
processCommand("PING");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ package ch.unibas.dmi.dbis.cs108.casono.client.network;
|
|||||||
*/
|
*/
|
||||||
public class CoreClient {
|
public class CoreClient {
|
||||||
private final ClientService clientService;
|
private final ClientService clientService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a CoreClient with the given ClientService for communication.
|
* Constructs a CoreClient with the given ClientService for communication.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui;
|
||||||
|
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.client.chat.ChatController;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.client.chat.ChatModel;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.client.chat.ChatType;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.fxml.FXMLLoader;
|
||||||
|
import javafx.scene.control.Tab;
|
||||||
|
import javafx.scene.control.TabPane;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
public class ChatBoxController {
|
||||||
|
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
private ChatController chatController;
|
||||||
|
|
||||||
|
@FXML private VBox chatBox;
|
||||||
|
|
||||||
|
@FXML private TabPane ChatTabPane;
|
||||||
|
|
||||||
|
private FXMLLoader fxmlLoader;
|
||||||
|
|
||||||
|
private String ressource = "/ui-structure/components/chatui/chattab.fxml";
|
||||||
|
|
||||||
|
|
||||||
|
public ChatBoxController(String username, ChatController chatController) {
|
||||||
|
this.username = username;
|
||||||
|
this.chatController = chatController;
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public void initialize() {
|
||||||
|
ChatModel globalChatModel = new ChatModel(ChatType.GLOBAL, username, -1, null);
|
||||||
|
chatController.getChatModelMap().put(new ChatController.ChatKey(ChatType.GLOBAL), globalChatModel);
|
||||||
|
addChatTab("GLOBAL", globalChatModel);
|
||||||
|
//TODO: Button to add new Whisper Chat
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void addWhisperChat(String target, ChatModel chatModel) {
|
||||||
|
chatController.getChatModelMap().put(new ChatController.ChatKey(ChatType.WHISPER, target), chatModel);
|
||||||
|
addChatTab(target, chatModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void addChatTab(String title, ChatModel chatModel) {
|
||||||
|
URL resource = getClass().getResource(ressource);
|
||||||
|
FXMLLoader fxmlLoader = new FXMLLoader(resource);
|
||||||
|
ChatViewController chatViewController = new ChatViewController(username, chatModel, chatController);
|
||||||
|
chatModel.addListener(chatViewController);
|
||||||
|
try {
|
||||||
|
fxmlLoader.setController(chatViewController);
|
||||||
|
Tab newChat = new Tab(title, fxmlLoader.load());
|
||||||
|
this.ChatTabPane.getTabs().add(newChat);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+44
-76
@@ -2,45 +2,40 @@ 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.Message;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.fxml.Initializable;
|
||||||
|
import javafx.scene.control.Button;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.ScrollPane;
|
||||||
|
import javafx.scene.control.TextField;
|
||||||
|
import javafx.scene.layout.HBox;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
import java.util.Timer;
|
|
||||||
import java.util.TimerTask;
|
|
||||||
import javafx.fxml.FXML;
|
|
||||||
import javafx.fxml.Initializable;
|
|
||||||
import javafx.scene.control.ButtonBar;
|
|
||||||
import javafx.scene.control.ToggleButton;
|
|
||||||
import javafx.scene.control.ToggleGroup;
|
|
||||||
import javafx.scene.layout.VBox;
|
|
||||||
|
|
||||||
/** Responsible for the presentation of the ChatModel to the Client */
|
/** Responsible for the presentation of the ChatModel to the Client */
|
||||||
public class ChatViewController implements Initializable {
|
public class ChatViewController implements Initializable {
|
||||||
|
|
||||||
private final ChatModel globalChatModel;
|
@FXML private Button sendButton;
|
||||||
private GlobalChatView globalChatView;
|
|
||||||
|
|
||||||
private LobbyChatView lobbyChatView;
|
@FXML private TextField inputField;
|
||||||
|
|
||||||
|
@FXML private VBox chatVBox;
|
||||||
|
|
||||||
|
@FXML private HBox controlBar;
|
||||||
|
|
||||||
|
@FXML private ScrollPane scrollPane;
|
||||||
|
|
||||||
|
@FXML private VBox Chat;
|
||||||
|
|
||||||
|
private final ChatModel chatModel;
|
||||||
|
|
||||||
private final String username;
|
private final String username;
|
||||||
|
|
||||||
private final ChatController controller;
|
private final ChatController controller;
|
||||||
|
|
||||||
private final Timer timer;
|
|
||||||
|
|
||||||
private Boolean lobbyActivated;
|
|
||||||
|
|
||||||
@FXML private ToggleButton changeGlobalChatButton;
|
|
||||||
|
|
||||||
@FXML private ToggleButton changeLobbyChatButton;
|
|
||||||
|
|
||||||
@FXML private ToggleButton changeWhisperChatButton;
|
|
||||||
|
|
||||||
@FXML private ButtonBar buttonBar;
|
|
||||||
|
|
||||||
private static final int REFRESH_TIME = 1000;
|
|
||||||
|
|
||||||
private static final int CHAT_PADDING = 20;
|
private static final int CHAT_PADDING = 20;
|
||||||
|
|
||||||
public ChatViewController() {
|
public ChatViewController() {
|
||||||
@@ -48,65 +43,38 @@ public class ChatViewController implements Initializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ChatViewController(
|
public ChatViewController(
|
||||||
String username, ChatModel globalChatModel, ChatController controller) {
|
String username, ChatModel chatModel, ChatController controller) {
|
||||||
this.username = username;
|
this.username = username;
|
||||||
this.controller = controller;
|
this.controller = controller;
|
||||||
this.timer = new Timer();
|
this.chatModel = chatModel;
|
||||||
this.globalChatModel = globalChatModel;
|
|
||||||
timer.schedule(
|
|
||||||
new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if (controller.receiveMessage()) {
|
|
||||||
globalChatView.showGlobalMessage();
|
|
||||||
if (lobbyActivated) {
|
|
||||||
lobbyChatView.showLobbyMessage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
0,
|
|
||||||
REFRESH_TIME);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(URL location, ResourceBundle resourceBundle) {
|
public void initialize(URL location, ResourceBundle resourceBundle) {
|
||||||
this.globalChatView =
|
inputField.setOnAction(event -> sendMessage());
|
||||||
new GlobalChatView(username, globalChatModel, controller);
|
sendButton.setOnAction(event -> sendMessage());
|
||||||
|
scrollPane.vvalueProperty().bind(chatVBox.heightProperty());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLobbyChat(int lobbyId) {
|
public void sendMessage() {
|
||||||
this.lobbyChatView =
|
String message = inputField.getText().trim();
|
||||||
new LobbyChatView(
|
if (!message.isEmpty()) {
|
||||||
username, new ChatModel(ChatType.LOBBY, username), controller, lobbyId);
|
inputField.clear();
|
||||||
|
Message msg = new Message(chatModel.getChattype(), chatModel.lobbyId, username, chatModel.getTarget(), message);
|
||||||
changeGlobalChatButton.setOnAction(event -> switchChat("globalChatButton"));
|
controller.onSendToNetwork(msg);
|
||||||
changeLobbyChatButton.setOnAction(event -> switchChat("lobbyChatButton"));
|
|
||||||
changeWhisperChatButton.setOnAction(event -> switchChat("whisperChatButton"));
|
|
||||||
|
|
||||||
ToggleGroup toggleGroup = new ToggleGroup();
|
|
||||||
changeGlobalChatButton.setToggleGroup(toggleGroup);
|
|
||||||
changeLobbyChatButton.setToggleGroup(toggleGroup);
|
|
||||||
changeWhisperChatButton.setToggleGroup(toggleGroup);
|
|
||||||
this.lobbyActivated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
public void switchChat(String button) {
|
|
||||||
switch (button) {
|
|
||||||
case "globalChatButton":
|
|
||||||
globalChatView.setVisibility(true);
|
|
||||||
lobbyChatView.setVisibility(false);
|
|
||||||
|
|
||||||
case "lobbyChatButton":
|
|
||||||
globalChatView.setVisibility(false);
|
|
||||||
lobbyChatView.setVisibility(true);
|
|
||||||
|
|
||||||
case "whisperChatButton":
|
|
||||||
globalChatView.setVisibility(false);
|
|
||||||
lobbyChatView.setVisibility(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void showMessage() {
|
||||||
|
String msg = chatModel.viewNextMessage();
|
||||||
|
Label label = new Label(msg);
|
||||||
|
label.getStyleClass().add("info-text");
|
||||||
|
label.setWrapText(true);
|
||||||
|
label.maxWidthProperty().bind(chatVBox.widthProperty().subtract(CHAT_PADDING));
|
||||||
|
chatVBox.getChildren().add(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,73 +0,0 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui;
|
|
||||||
|
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.client.chat.ChatController;
|
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.client.chat.ChatModel;
|
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.client.chat.ChatType;
|
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.client.chat.Message;
|
|
||||||
import javafx.beans.property.BooleanProperty;
|
|
||||||
import javafx.beans.property.SimpleBooleanProperty;
|
|
||||||
import javafx.fxml.FXML;
|
|
||||||
import javafx.scene.control.Button;
|
|
||||||
import javafx.scene.control.Label;
|
|
||||||
import javafx.scene.control.ScrollPane;
|
|
||||||
import javafx.scene.control.TextField;
|
|
||||||
import javafx.scene.layout.VBox;
|
|
||||||
|
|
||||||
public class GlobalChatView {
|
|
||||||
|
|
||||||
private final String username;
|
|
||||||
private ChatModel globalChatModel;
|
|
||||||
|
|
||||||
private final ChatController controller;
|
|
||||||
|
|
||||||
@FXML private Button globalChatSendButton;
|
|
||||||
|
|
||||||
@FXML private TextField globalChatInputField;
|
|
||||||
|
|
||||||
@FXML private VBox globalChatVBox;
|
|
||||||
|
|
||||||
@FXML private VBox globalChat;
|
|
||||||
|
|
||||||
@FXML private ScrollPane globalChatScrollPane;
|
|
||||||
|
|
||||||
final BooleanProperty isContentVisible = new SimpleBooleanProperty(true);
|
|
||||||
|
|
||||||
private static final int CHAT_PADDING = 20;
|
|
||||||
|
|
||||||
public GlobalChatView(String username, ChatModel globalChatModel, ChatController controller) {
|
|
||||||
this.username = username;
|
|
||||||
this.controller = controller;
|
|
||||||
this.globalChatModel = globalChatModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void initialize() {
|
|
||||||
globalChatInputField.setOnAction(event -> sendGlobalMessage());
|
|
||||||
globalChatSendButton.setOnAction(event -> sendGlobalMessage());
|
|
||||||
globalChatScrollPane.vvalueProperty().bind(globalChatVBox.heightProperty());
|
|
||||||
globalChatVBox.visibleProperty().bind(isContentVisible);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendGlobalMessage() {
|
|
||||||
String message = globalChatInputField.getText().trim();
|
|
||||||
if (!message.isEmpty()) {
|
|
||||||
globalChatInputField.clear();
|
|
||||||
Message msg = new Message(ChatType.GLOBAL, 0, username, null, message);
|
|
||||||
controller.onSendToNetwork(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void showGlobalMessage() {
|
|
||||||
for (int i = 0; i < globalChatModel.count; i++) {
|
|
||||||
String msg = globalChatModel.viewNextMessage();
|
|
||||||
Label label = new Label(msg);
|
|
||||||
label.getStyleClass().add("info-text");
|
|
||||||
label.setWrapText(true);
|
|
||||||
label.maxWidthProperty().bind(globalChatVBox.widthProperty().subtract(CHAT_PADDING));
|
|
||||||
globalChatVBox.getChildren().add(label);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setVisibility(Boolean bool) {
|
|
||||||
this.isContentVisible.set(bool);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui;
|
|
||||||
|
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.client.chat.ChatController;
|
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.client.chat.ChatModel;
|
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.client.chat.ChatType;
|
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.client.chat.Message;
|
|
||||||
import javafx.fxml.FXML;
|
|
||||||
import javafx.scene.control.Button;
|
|
||||||
import javafx.scene.control.Label;
|
|
||||||
import javafx.scene.control.ScrollPane;
|
|
||||||
import javafx.scene.control.TextField;
|
|
||||||
import javafx.scene.layout.VBox;
|
|
||||||
|
|
||||||
public class LobbyChatView {
|
|
||||||
|
|
||||||
private final String username;
|
|
||||||
private final int lobbyId;
|
|
||||||
private ChatModel lobbyChatModel;
|
|
||||||
|
|
||||||
private final ChatController controller;
|
|
||||||
|
|
||||||
@FXML private Button lobbyChatSendButton;
|
|
||||||
|
|
||||||
@FXML private TextField lobbyChatInputField;
|
|
||||||
|
|
||||||
@FXML private VBox lobbyChatVBox;
|
|
||||||
|
|
||||||
@FXML private VBox lobbyChat;
|
|
||||||
|
|
||||||
@FXML private ScrollPane lobbyChatScrollPane;
|
|
||||||
|
|
||||||
private static final int CHAT_PADDING = 20;
|
|
||||||
|
|
||||||
public LobbyChatView(
|
|
||||||
String username, ChatModel lobbyChatModel, ChatController controller, int lobbyId) {
|
|
||||||
this.username = username;
|
|
||||||
this.controller = controller;
|
|
||||||
this.lobbyChatModel = lobbyChatModel;
|
|
||||||
this.lobbyId = lobbyId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
public void initialize() {
|
|
||||||
lobbyChatInputField.setOnAction(event -> sendLobbyMessage());
|
|
||||||
lobbyChatSendButton.setOnAction(event -> sendLobbyMessage());
|
|
||||||
lobbyChatScrollPane.vvalueProperty().bind(lobbyChatVBox.heightProperty());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendLobbyMessage() {
|
|
||||||
String message = lobbyChatInputField.getText().trim();
|
|
||||||
if (!message.isEmpty()) {
|
|
||||||
lobbyChatInputField.clear();
|
|
||||||
Message msg = new Message(ChatType.LOBBY, lobbyId, username, null, message);
|
|
||||||
controller.onSendToNetwork(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void showLobbyMessage() {
|
|
||||||
for (int i = 0; i < lobbyChatModel.count; i++) {
|
|
||||||
String msg = lobbyChatModel.viewNextMessage();
|
|
||||||
Label label = new Label(msg);
|
|
||||||
label.getStyleClass().add("info-text");
|
|
||||||
label.setWrapText(true);
|
|
||||||
label.maxWidthProperty().bind(lobbyChatVBox.widthProperty().subtract(CHAT_PADDING));
|
|
||||||
lobbyChatVBox.getChildren().add(label);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setVisibility(Boolean bool) {
|
|
||||||
lobbyChatVBox.setVisible(bool);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui;
|
|
||||||
|
|
||||||
public class WhisperChatView {}
|
|
||||||
@@ -1,12 +1,14 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.casono.client.ui.lobbyui;
|
package ch.unibas.dmi.dbis.cs108.casono.client.ui.lobbyui;
|
||||||
|
|
||||||
/** Main UI application for Casono. Loads the main FXML layout and sets up the stage. */
|
/** Main UI application for Casono. Loads the main FXML layout and sets up the stage. */
|
||||||
import java.io.IOException;
|
|
||||||
import javafx.application.Application;
|
import javafx.application.Application;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JavaFX Application class for the Casono main UI.
|
* JavaFX Application class for the Casono main UI.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -9,9 +9,18 @@ import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.login.LoginRequest;
|
|||||||
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.logout.LogoutHandler;
|
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.logout.LogoutHandler;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.logout.LogoutParser;
|
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.logout.LogoutParser;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.logout.LogoutRequest;
|
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.logout.LogoutRequest;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.get_message_count.GetMessageCountHandler;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.get_message_count.GetMessageCountParser;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.get_message_count.GetMessageCountRequest;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.get_next_message.GetNextMessageHandler;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.get_next_message.GetNextMessageParser;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.get_next_message.GetNextMessageRequest;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.ping.PingHandler;
|
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.ping.PingHandler;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.ping.PingParser;
|
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.ping.PingParser;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.ping.PingRequest;
|
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.ping.PingRequest;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.send_message.SendMessageHandler;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.send_message.SendMessageParser;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.send_message.SendMessageRequest;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.server.domain.user.UserCleanupJob;
|
import ch.unibas.dmi.dbis.cs108.casono.server.domain.user.UserCleanupJob;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.server.domain.user.UserRegistry;
|
import ch.unibas.dmi.dbis.cs108.casono.server.domain.user.UserRegistry;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.server.network.NetworkManager;
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.NetworkManager;
|
||||||
@@ -22,12 +31,13 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.events.EventBus;
|
|||||||
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.dispatcher.ResponseDispatcher;
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.dispatcher.ResponseDispatcher;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.SessionDisconnectJob;
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.SessionDisconnectJob;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.SessionManager;
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.SessionManager;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
|
|
||||||
/** Application class for starting the server. */
|
/** Application class for starting the server. */
|
||||||
public class ServerApp {
|
public class ServerApp {
|
||||||
@@ -36,7 +46,7 @@ public class ServerApp {
|
|||||||
private static final int USER_CLEANUP_JOB_RECONNECT_THRESHOLD = 10;
|
private static final int USER_CLEANUP_JOB_RECONNECT_THRESHOLD = 10;
|
||||||
private static final int SESSION_DISCONNECT_JOB_DELAY = 0;
|
private static final int SESSION_DISCONNECT_JOB_DELAY = 0;
|
||||||
private static final int SESSION_DISCONNECT_JOB_PERIOD = 2;
|
private static final int SESSION_DISCONNECT_JOB_PERIOD = 2;
|
||||||
private static final int SESSION_DISCONNECT_JOB_TIMEOUT = 5;
|
private static final int SESSION_DISCONNECT_JOB_TIMEOUT = 30;
|
||||||
|
|
||||||
public static void start(String arg) {
|
public static void start(String arg) {
|
||||||
int port = Integer.parseInt(arg);
|
int port = Integer.parseInt(arg);
|
||||||
@@ -105,5 +115,24 @@ public class ServerApp {
|
|||||||
parserDispatcher.register("LOGOUT", new LogoutParser());
|
parserDispatcher.register("LOGOUT", new LogoutParser());
|
||||||
commandRouter.register(
|
commandRouter.register(
|
||||||
LogoutRequest.class, new LogoutHandler(responseDispatcher, userRegistry));
|
LogoutRequest.class, new LogoutHandler(responseDispatcher, userRegistry));
|
||||||
|
parserDispatcher.register("SEND_MESSAGE", new SendMessageParser());
|
||||||
|
commandRouter.register(
|
||||||
|
SendMessageRequest.class,
|
||||||
|
new SendMessageHandler(responseDispatcher, userRegistry)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
parserDispatcher.register("GET_MESSAGE_COUNT", new GetMessageCountParser());
|
||||||
|
commandRouter.register(
|
||||||
|
GetMessageCountRequest.class,
|
||||||
|
new GetMessageCountHandler(responseDispatcher, userRegistry)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
parserDispatcher.register("GET_NEXT_MESSAGE", new GetNextMessageParser());
|
||||||
|
commandRouter.register(
|
||||||
|
GetNextMessageRequest.class,
|
||||||
|
new GetNextMessageHandler(responseDispatcher, userRegistry)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.check_nick;
|
|||||||
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.parsing.CommandParser;
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.parsing.CommandParser;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.PrimitiveRequest;
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.PrimitiveRequest;
|
||||||
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;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.check_nick.CheckUsernameRequest;
|
||||||
/** Parses a primitive request into a {@link CheckUsernameRequest}. */
|
/** Parses a primitive request into a {@link CheckUsernameRequest}. */
|
||||||
public class CheckUsernameParser implements CommandParser<CheckUsernameRequest> {
|
public class CheckUsernameParser implements CommandParser<CheckUsernameRequest> {
|
||||||
/**
|
/**
|
||||||
|
|||||||
+2
-2
@@ -2,7 +2,7 @@ package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.check_nick;
|
|||||||
|
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.RequestContext;
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.RequestContext;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.SuccessResponse;
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.SuccessResponse;
|
||||||
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.ResponseBody;
|
||||||
|
|
||||||
/** Response indicating the availability status of a username check. */
|
/** Response indicating the availability status of a username check. */
|
||||||
public class CheckUsernameResponse extends SuccessResponse {
|
public class CheckUsernameResponse extends SuccessResponse {
|
||||||
@@ -13,6 +13,6 @@ public class CheckUsernameResponse extends SuccessResponse {
|
|||||||
* @param availability the availability status of the requested username
|
* @param availability the availability status of the requested username
|
||||||
*/
|
*/
|
||||||
public CheckUsernameResponse(RequestContext context, UsernameAvailability availability) {
|
public CheckUsernameResponse(RequestContext context, UsernameAvailability availability) {
|
||||||
super(context, new ResponseBodyBuilder().param("STATUS", availability).build());
|
super(context, ResponseBody.builder().param("STATUS", availability).build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.check_nick;
|
package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.check_nick;
|
||||||
|
|
||||||
/** Represents the availability status of a username */
|
/** Represents the availability status of a username */
|
||||||
enum UsernameAvailability {
|
public enum UsernameAvailability {
|
||||||
/** Username is available */
|
/** Username is available */
|
||||||
FREE,
|
FREE,
|
||||||
|
|
||||||
|
|||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.get_message_count;
|
||||||
|
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.domain.user.User;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.domain.user.UserRegistry;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.execution.CommandHandler;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.ErrorResponse;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.dispatcher.ResponseDispatcher;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class GetMessageCountHandler implements CommandHandler<GetMessageCountRequest> {
|
||||||
|
public final ResponseDispatcher responseDispatcher;
|
||||||
|
private final UserRegistry userRegistry;
|
||||||
|
|
||||||
|
public GetMessageCountHandler(ResponseDispatcher responseDispatcher, UserRegistry userRegistry) {
|
||||||
|
this.responseDispatcher = responseDispatcher;
|
||||||
|
this.userRegistry = userRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(GetMessageCountRequest request) {
|
||||||
|
Optional<User> user = userRegistry.getBySessionId(request.getSessionId());
|
||||||
|
if (user.isPresent()) {
|
||||||
|
int count = user.get().getMessageCount();
|
||||||
|
GetMessageCountResponse response = new GetMessageCountResponse(
|
||||||
|
request.getContext(),
|
||||||
|
count
|
||||||
|
);
|
||||||
|
responseDispatcher.dispatch(response);
|
||||||
|
} else {
|
||||||
|
ErrorResponse response = new ErrorResponse(
|
||||||
|
request.getContext(),
|
||||||
|
"",
|
||||||
|
"user could not be identified by SessionId"
|
||||||
|
|
||||||
|
);
|
||||||
|
responseDispatcher.dispatch(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.get_message_count;
|
||||||
|
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.parsing.CommandParser;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.PrimitiveRequest;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.accessor.RequestParameterAccessor;
|
||||||
|
|
||||||
|
public class GetMessageCountParser implements CommandParser<GetMessageCountRequest> {
|
||||||
|
@Override
|
||||||
|
public GetMessageCountRequest parse(PrimitiveRequest primitiveRequest) {
|
||||||
|
RequestParameterAccessor accessor = new RequestParameterAccessor(primitiveRequest.parameters());
|
||||||
|
return new GetMessageCountRequest(primitiveRequest.context());
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.get_message_count;
|
||||||
|
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.Request;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.RequestContext;
|
||||||
|
|
||||||
|
public class GetMessageCountRequest extends Request {
|
||||||
|
public GetMessageCountRequest(RequestContext context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.get_message_count;
|
||||||
|
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.RequestContext;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.SuccessResponse;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.builder.ResponseBodyBuilder;
|
||||||
|
|
||||||
|
public class GetMessageCountResponse extends SuccessResponse {
|
||||||
|
public GetMessageCountResponse(RequestContext context, int count) {
|
||||||
|
super(context, new ResponseBodyBuilder()
|
||||||
|
.param("COUNT", count)
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
}
|
||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.get_next_message;
|
||||||
|
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.client.chat.Message;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.domain.user.User;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.domain.user.UserRegistry;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.execution.CommandHandler;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.ErrorResponse;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.dispatcher.ResponseDispatcher;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class GetNextMessageHandler implements CommandHandler<GetNextMessageRequest> {
|
||||||
|
public final ResponseDispatcher responseDispatcher;
|
||||||
|
private final UserRegistry userRegistry;
|
||||||
|
|
||||||
|
public GetNextMessageHandler(ResponseDispatcher responseDispatcher, UserRegistry userRegistry) {
|
||||||
|
this.responseDispatcher = responseDispatcher;
|
||||||
|
this.userRegistry = userRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(GetNextMessageRequest request) {
|
||||||
|
Optional<User> user = userRegistry.getBySessionId(request.getSessionId());
|
||||||
|
if (user.isPresent()) {
|
||||||
|
Message msg = user.get().dequeMessage();
|
||||||
|
GetNextMessageResponse response = new GetNextMessageResponse(
|
||||||
|
request.getContext(),
|
||||||
|
msg
|
||||||
|
);
|
||||||
|
responseDispatcher.dispatch(response);
|
||||||
|
} else {
|
||||||
|
ErrorResponse response = new ErrorResponse(
|
||||||
|
request.getContext(),
|
||||||
|
"",
|
||||||
|
"user could not be identified by SessionId"
|
||||||
|
|
||||||
|
);
|
||||||
|
responseDispatcher.dispatch(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.get_next_message;
|
||||||
|
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.parsing.CommandParser;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.PrimitiveRequest;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.accessor.RequestParameterAccessor;
|
||||||
|
|
||||||
|
public class GetNextMessageParser implements CommandParser<GetNextMessageRequest> {
|
||||||
|
@Override
|
||||||
|
public GetNextMessageRequest parse(PrimitiveRequest primitiveRequest) {
|
||||||
|
RequestParameterAccessor accessor = new RequestParameterAccessor(primitiveRequest.parameters());
|
||||||
|
return new GetNextMessageRequest(primitiveRequest.context());
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.get_next_message;
|
||||||
|
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.Request;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.RequestContext;
|
||||||
|
|
||||||
|
public class GetNextMessageRequest extends Request {
|
||||||
|
public GetNextMessageRequest(RequestContext context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.get_next_message;
|
||||||
|
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.client.chat.Message;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.RequestContext;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.SuccessResponse;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.builder.ResponseBody;
|
||||||
|
|
||||||
|
public class GetNextMessageResponse extends SuccessResponse {
|
||||||
|
public GetNextMessageResponse(RequestContext context, Message msg) {
|
||||||
|
super(context, ResponseBody.builder()
|
||||||
|
.param("MESSAGE", msg.toArgsString())
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
}
|
||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.send_message;
|
||||||
|
|
||||||
|
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.client.chat.Message;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.domain.user.UserRegistry;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.execution.CommandHandler;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.OkResponse;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.dispatcher.ResponseDispatcher;
|
||||||
|
|
||||||
|
public class SendMessageHandler implements CommandHandler<SendMessageRequest> {
|
||||||
|
public final ResponseDispatcher responseDispatcher;
|
||||||
|
private final UserRegistry userRegistry;
|
||||||
|
|
||||||
|
public SendMessageHandler(ResponseDispatcher responseDispatcher, UserRegistry userRegistry) {
|
||||||
|
this.responseDispatcher = responseDispatcher;
|
||||||
|
this.userRegistry = userRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(SendMessageRequest request) {
|
||||||
|
Message message = request.getMessage();
|
||||||
|
broadcast(message);
|
||||||
|
OkResponse response = new OkResponse(request.getContext());
|
||||||
|
responseDispatcher.dispatch(response);
|
||||||
|
}
|
||||||
|
public void broadcast(Message message) {
|
||||||
|
userRegistry.getAllUsers().forEach(user -> user.enqueueMessage(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.send_message;
|
||||||
|
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.client.chat.Message;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.parsing.CommandParser;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.PrimitiveRequest;
|
||||||
|
|
||||||
|
public class SendMessageParser implements CommandParser<SendMessageRequest> {
|
||||||
|
@Override
|
||||||
|
public SendMessageRequest parse(PrimitiveRequest primitiveRequest) {
|
||||||
|
Message msg = Message.toMessage(primitiveRequest.parameters());
|
||||||
|
return new SendMessageRequest(primitiveRequest.context(), msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.send_message;
|
||||||
|
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.client.chat.Message;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.Request;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.RequestContext;
|
||||||
|
|
||||||
|
public class SendMessageRequest extends Request {
|
||||||
|
|
||||||
|
private final Message msg;
|
||||||
|
|
||||||
|
public SendMessageRequest(RequestContext context, Message msg) {
|
||||||
|
super(context);
|
||||||
|
this.msg = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Message getMessage() {
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.casono.server.domain.message;
|
package ch.unibas.dmi.dbis.cs108.casono.server.domain.message;
|
||||||
|
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.server.domain.user.UserRegistry;
|
import ch.unibas.dmi.dbis.cs108.casono.server.domain.user.UserRegistry;
|
||||||
|
|
||||||
|
/** NOT USED **/
|
||||||
public class MessageManager {
|
public class MessageManager {
|
||||||
private final UserRegistry userRegistry;
|
private final UserRegistry userRegistry;
|
||||||
|
|
||||||
@@ -10,6 +10,6 @@ public class MessageManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void broadcast(Message message) {
|
public void broadcast(Message message) {
|
||||||
userRegistry.getAllUsers().forEach(user -> user.enqueueMessage(message));
|
//userRegistry.getAllUsers().forEach(user -> user.enqueueMessage(message));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.casono.server.domain.user;
|
package ch.unibas.dmi.dbis.cs108.casono.server.domain.user;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.client.chat.Message;
|
||||||
|
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.server.domain.message.Message;
|
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.SessionId;
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.SessionId;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.ArrayDeque;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Queue;
|
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
|
||||||
/** Represents an authenticated user on the server. */
|
/** Represents an authenticated user on the server. */
|
||||||
@@ -88,6 +85,10 @@ public class User {
|
|||||||
messages.add(message);
|
messages.add(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public synchronized int getMessageCount() { return messages.size(); }
|
||||||
|
|
||||||
|
public synchronized Message dequeMessage() throws NoSuchElementException { return messages.remove(); }
|
||||||
|
|
||||||
public synchronized List<Message> dequeueAllMessages(Message message) {
|
public synchronized List<Message> dequeueAllMessages(Message message) {
|
||||||
List<Message> allMessages = new ArrayDeque<>(messages).stream().toList();
|
List<Message> allMessages = new ArrayDeque<>(messages).stream().toList();
|
||||||
messages.clear();
|
messages.clear();
|
||||||
|
|||||||
+2
-2
@@ -9,14 +9,14 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.builder.
|
|||||||
* <p>Implementations of this class use the {@code +OK} prefix. It provides a protected constructor
|
* <p>Implementations of this class use the {@code +OK} prefix. It provides a protected constructor
|
||||||
* so subclasses can supply the response body content.
|
* so subclasses can supply the response body content.
|
||||||
*/
|
*/
|
||||||
public abstract class SuccessResponse extends Response {
|
public class SuccessResponse extends Response {
|
||||||
/**
|
/**
|
||||||
* Create a successful response with the provided body.
|
* Create a successful response with the provided body.
|
||||||
*
|
*
|
||||||
* @param context the RequestContext of the request
|
* @param context the RequestContext of the request
|
||||||
* @param body the response body
|
* @param body the response body
|
||||||
*/
|
*/
|
||||||
protected SuccessResponse(RequestContext context, ResponseBody body) {
|
public SuccessResponse(RequestContext context, ResponseBody body) {
|
||||||
super(context, body);
|
super(context, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,46 +4,30 @@
|
|||||||
<?import javafx.scene.layout.*?>
|
<?import javafx.scene.layout.*?>
|
||||||
<?import javafx.geometry.Insets?>
|
<?import javafx.geometry.Insets?>
|
||||||
|
|
||||||
<!--
|
<VBox xmlns="http://javafx.com/javafx/21"
|
||||||
Dieses Fenster wird später mit den Serveranfragen verknüpft,
|
|
||||||
um Nachrichten von Mitspielern und Systemmeldungen in Echtzeit anzuzeigen.
|
|
||||||
|
|
||||||
Der Chat unterscheidet intern zwischen:
|
|
||||||
- Player-to-Player (Privater 2-Personen-Chat)
|
|
||||||
- Lobby-Chat (Aktueller Raum)
|
|
||||||
- Globaler Chat (Gesamter Server)
|
|
||||||
|
|
||||||
Features, die später implementiert werden sollen:
|
|
||||||
- Schicke Chat-Bubbles mit Namen und Uhrzeit./home/mathis/dev/Gruppe-13/src/main/resources/ui-structure/gameuicomponents/chatui
|
|
||||||
-->
|
|
||||||
|
|
||||||
<StackPane xmlns="http://javafx.com/javafx/21"
|
|
||||||
xmlns:fx="http://javafx.com/fxml/1"
|
xmlns:fx="http://javafx.com/fxml/1"
|
||||||
fx:controller="ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui.ChatViewController"
|
fx:id="chatBox"
|
||||||
alignment="CENTER"
|
fx:controller="ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui.ChatBoxController"
|
||||||
stylesheets="@chatui.css">
|
VBox.vgrow="ALWAYS"
|
||||||
|
styleClass="chat-box"
|
||||||
|
spacing="10"
|
||||||
|
maxWidth="Infinity">
|
||||||
|
|
||||||
<!-- Innenabstand: Schafft oben, rechts und unten 30 Pixel Platz, links nur 10 Pixel (asymmetrisch) -->
|
<children>
|
||||||
<padding>
|
<HBox>
|
||||||
<Insets top="30" right="30" bottom="30" left="10"/>
|
<children>
|
||||||
</padding>
|
<Label text="== CHAT ==" styleClass="chat-header" alignment="CENTER" maxWidth="Infinity"/>
|
||||||
|
<Region minHeight="4" styleClass="chat-separator"/>
|
||||||
|
</children>
|
||||||
|
|
||||||
|
</HBox>
|
||||||
|
|
||||||
|
<TabPane fx:id="ChatTabPane">
|
||||||
|
</TabPane>
|
||||||
|
|
||||||
|
|
||||||
<fx:include source="globalchat.fxml"/>
|
|
||||||
|
|
||||||
<fx:include source="lobbychat.fxml"/>
|
</children>
|
||||||
|
|
||||||
<fx:include source="whisperchat.fxml"/>
|
|
||||||
|
|
||||||
<ButtonBar fx:id="buttonBar">
|
</VBox>
|
||||||
<padding>
|
|
||||||
<Insets>...</Insets>
|
|
||||||
</padding>
|
|
||||||
<buttons>
|
|
||||||
<ToggleButton fx:id="changeGlobalChatButton" text="Global Chat" onAction="#switchChat" styleClass="yellow-button"/>
|
|
||||||
<ToggleButton fx:id="changeLobbyChatButton" text="Lobby Chat" styleClass="yellow-button"/>
|
|
||||||
<ToggleButton fx:id="changeWhisperChatButton" text="Whisper Chat" styleClass="yellow-button"/>
|
|
||||||
</buttons>
|
|
||||||
</ButtonBar>
|
|
||||||
|
|
||||||
</StackPane>
|
|
||||||
+10
-14
@@ -9,30 +9,26 @@
|
|||||||
<!-- 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="globalChatVBox"
|
fx:id="chatVBox">
|
||||||
VBox.vgrow="ALWAYS"
|
|
||||||
styleClass="chat-box"
|
|
||||||
spacing="10"
|
|
||||||
maxWidth="Infinity"
|
|
||||||
visible="true"
|
|
||||||
fx:controller="ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui.GlobalChatView">
|
|
||||||
|
|
||||||
<Label text="== GLOBAL CHAT ==" styleClass="chat-header" alignment="CENTER" maxWidth="Infinity"/>
|
<Label text="== CHAT ==" styleClass="chat-header" alignment="CENTER" maxWidth="Infinity"/>
|
||||||
<Region minHeight="4" styleClass="chat-separator"/>
|
<Region minHeight="4" styleClass="chat-separator"/>
|
||||||
|
|
||||||
<!-- Chatnachrichten werden hier hinzugefügt -->
|
<!-- Chatnachrichten werden hier hinzugefügt -->
|
||||||
<ScrollPane fx:id="globalChatScrollPane" 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="globalChat" spacing="10" styleClass="chat-VBox"/>
|
<VBox fx:id="Chat" spacing="10" styleClass="chat-VBox"/>
|
||||||
</content>
|
</content>
|
||||||
</ScrollPane>
|
</ScrollPane>
|
||||||
|
|
||||||
<!-- Eingabebereich -->
|
<!-- Eingabebereich -->
|
||||||
<HBox spacing="10">
|
<HBox spacing="10"
|
||||||
|
fx:id="controlBar">
|
||||||
<!-- TODO: Größe des TextFields dynamisch anpassen -->
|
<!-- TODO: Größe des TextFields dynamisch anpassen -->
|
||||||
<TextField fx:id="globalChatInputField" HBox.hgrow="ALWAYS" promptText="Nachricht eingeben..."
|
<TextField fx:id="inputField" HBox.hgrow="ALWAYS" promptText="Nachricht eingeben..."
|
||||||
styleClass="gray-input-field" onAction="#sendGlobalMessage"/>
|
styleClass="gray-input-field" onAction="#sendMessage"/>
|
||||||
<Button fx:id="globalChatSendButton" text="SENDEN" onAction="#sendGlobalMessage"
|
<Button fx:id="sendButton" text="SENDEN" onAction="#sendMessage"
|
||||||
styleClass="yellow-button"/>
|
styleClass="yellow-button"/>
|
||||||
</HBox>
|
</HBox>
|
||||||
</VBox>
|
</VBox>
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
|
|
||||||
<?import java.lang.*?>
|
|
||||||
<?import java.util.*?>
|
|
||||||
<?import javafx.scene.*?>
|
|
||||||
<?import javafx.scene.control.*?>
|
|
||||||
<?import javafx.scene.layout.*?>
|
|
||||||
|
|
||||||
<!-- VBox for the lobby chat, should only be visible when activated via changeLobbyChatButton-->
|
|
||||||
|
|
||||||
<VBox xmlns="http://javafx.com/javafx/21"
|
|
||||||
xmlns:fx="http://javafx.com/fxml/1"
|
|
||||||
fx:id="lobbyChatVBox"
|
|
||||||
VBox.vgrow="ALWAYS"
|
|
||||||
styleClass="chat-box"
|
|
||||||
spacing="10"
|
|
||||||
maxWidth="Infinity"
|
|
||||||
visible="false"
|
|
||||||
fx:controller="ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui.LobbyChatView">
|
|
||||||
|
|
||||||
<children>
|
|
||||||
<Label text="== LOBBY CHAT ==" styleClass="chat-header" alignment="CENTER" maxWidth="Infinity"/>
|
|
||||||
<Region minHeight="4" styleClass="chat-separator"/>
|
|
||||||
|
|
||||||
<!-- Chatnachrichten werden hier hinzugefügt -->
|
|
||||||
<ScrollPane fx:id="lobbyChatScrollPane" fitToWidth="true" vbarPolicy="AS_NEEDED" hbarPolicy="NEVER" VBox.vgrow="ALWAYS" styleClass="chat-scroll-pane">
|
|
||||||
<content>
|
|
||||||
<VBox fx:id="lobbyChat" spacing="10" styleClass="chat-VBox"/>
|
|
||||||
</content>
|
|
||||||
</ScrollPane>
|
|
||||||
|
|
||||||
<!-- Eingabebereich -->
|
|
||||||
<HBox spacing="10">
|
|
||||||
<!-- TODO: Größe des TextFields dynamisch anpassen -->
|
|
||||||
<TextField fx:id="lobbyChatInputField" HBox.hgrow="ALWAYS" promptText="Nachricht eingeben..." styleClass="gray-input-field" onAction="#sendLobbyMessage"/>
|
|
||||||
<Button fx:id="lobbyChatSendButton" text="SENDEN" onAction="#sendLobbyMessage" styleClass="yellow-button"/>
|
|
||||||
</HBox>
|
|
||||||
</children>
|
|
||||||
</VBox>
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
|
|
||||||
<?import java.lang.*?>
|
|
||||||
<?import java.util.*?>
|
|
||||||
<?import javafx.scene.*?>
|
|
||||||
<?import javafx.scene.control.*?>
|
|
||||||
<?import javafx.scene.layout.*?>
|
|
||||||
|
|
||||||
<!-- VBox for the whisper chat, should only be visible when activated via changeWhisperChatButton-->
|
|
||||||
|
|
||||||
<VBox xmlns="http://javafx.com/javafx/21"
|
|
||||||
xmlns:fx="http://javafx.com/fxml/1"
|
|
||||||
fx:id="whisperChatVBox"
|
|
||||||
VBox.vgrow="ALWAYS"
|
|
||||||
styleClass="chat-box"
|
|
||||||
spacing="10"
|
|
||||||
maxWidth="Infinity"
|
|
||||||
visible="false">
|
|
||||||
|
|
||||||
<children>
|
|
||||||
<Label text="== WHISPER CHAT ==" styleClass="chat-header" alignment="CENTER" maxWidth="Infinity"/>
|
|
||||||
<Region minHeight="4" styleClass="chat-separator"/>
|
|
||||||
<!-- Chatnachrichten werden hier hinzugefügt
|
|
||||||
<ScrollPane fx:id="chatScrollPane" fitToWidth="true" vbarPolicy="AS_NEEDED" hbarPolicy="NEVER" VBox.vgrow="ALWAYS" styleClass="chat-scroll-pane">
|
|
||||||
<content>
|
|
||||||
<VBox fx:id="chatVBox" spacing="10" styleClass="chat-VBox"/>
|
|
||||||
</content>
|
|
||||||
</ScrollPane>
|
|
||||||
|
|
||||||
|
|
||||||
<HBox spacing="10">
|
|
||||||
<TextField fx:id="inputField" HBox.hgrow="ALWAYS" promptText="Nachricht eingeben..." styleClass="gray-input-field" onAction="#sendMessage"/>
|
|
||||||
<Button fx:id="sendButton" text="SENDEN" onAction="#sendMessage" styleClass="yellow-button"/>
|
|
||||||
</HBox>
|
|
||||||
-->
|
|
||||||
</children>
|
|
||||||
</VBox>
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package ch.unibas.dmi.dbis.cs108.casono.client.chat;
|
||||||
|
|
||||||
|
import javafx.application.Application;
|
||||||
|
|
||||||
|
public class Chat {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Application.launch(ChatApplication.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
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.client.network.CoreClient;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui.ChatBoxController;
|
||||||
|
import javafx.application.Application;
|
||||||
|
import javafx.fxml.FXMLLoader;
|
||||||
|
import javafx.scene.Scene;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class ChatApplication extends Application {
|
||||||
|
|
||||||
|
private static final int SCENE_WIDTH = 1200;
|
||||||
|
private static final int SCENE_HEIGHT = 800;
|
||||||
|
String ip = "localhost";
|
||||||
|
String username = "mathis";
|
||||||
|
int port = 5000;
|
||||||
|
|
||||||
|
public ChatApplication() {}
|
||||||
|
|
||||||
|
public void start(Stage stage) throws IOException {
|
||||||
|
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/ui-structure/components/chatui/chatbox.fxml"));
|
||||||
|
ClientService clientService = new ClientService(ip, port);
|
||||||
|
CoreClient coreClient = new CoreClient(clientService);
|
||||||
|
// TODO login UI
|
||||||
|
coreClient.login(username);
|
||||||
|
ChatController chatController = new ChatController(username, clientService);
|
||||||
|
fxmlLoader.setControllerFactory(type -> {
|
||||||
|
if (type == ChatBoxController.class) {
|
||||||
|
return chatController.getChatBoxController();
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
return type.getConstructor().newInstance();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Scene scene = new Scene(fxmlLoader.load(), SCENE_WIDTH, SCENE_HEIGHT);
|
||||||
|
stage.setTitle("Chat");
|
||||||
|
stage.setScene(scene);
|
||||||
|
stage.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -6,6 +6,6 @@ public class ChatTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void chatTest() {
|
public void chatTest() {
|
||||||
Client.main(new String[]{"mathis"});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user