diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index 29fcb69..c1e1291 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -6,7 +6,6 @@
-
diff --git a/.idea/misc.xml b/.idea/misc.xml
index dfb4125..07c6f5c 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -4,7 +4,6 @@
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 5d66256..08cdd54 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -4,6 +4,7 @@
+
diff --git a/NetworkChatClient/NetworkChatClient.iml b/NetworkChatClient/NetworkChatClient.iml
index 2c3ee89..9e6e938 100644
--- a/NetworkChatClient/NetworkChatClient.iml
+++ b/NetworkChatClient/NetworkChatClient.iml
@@ -1,22 +1,14 @@
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
+
+
\ No newline at end of file
diff --git a/NetworkChatClient/src/main/java/ru/geekbrains/java2/chat/client/ClientChat.java b/NetworkChatClient/src/main/java/ru/geekbrains/java2/chat/client/ClientChat.java
index 934ef3a..b4edf6c 100644
--- a/NetworkChatClient/src/main/java/ru/geekbrains/java2/chat/client/ClientChat.java
+++ b/NetworkChatClient/src/main/java/ru/geekbrains/java2/chat/client/ClientChat.java
@@ -2,6 +2,7 @@
import javafx.application.Application;
+import javafx.collections.FXCollections;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Rectangle2D;
import javafx.scene.Parent;
@@ -30,6 +31,10 @@ public class ClientChat extends Application {
private Network network;
private ViewController viewController;
+ public void updateUsers(List users) {
+ viewController.usersList.setItems(FXCollections.observableList(users));
+ }
+
@Override
public void start(Stage primaryStage) throws Exception {
this.primaryStage = primaryStage;
@@ -120,10 +125,6 @@ public ClientChatState getState() {
return state;
}
- public void setState(ClientChatState state) {
- this.state = state;
- }
-
public void activeChatDialog(String nickname) {
primaryStage.setTitle(nickname);
state = ClientChatState.CHAT;
diff --git a/NetworkChatClient/src/main/java/ru/geekbrains/java2/chat/client/controllers/AuthController.java b/NetworkChatClient/src/main/java/ru/geekbrains/java2/chat/client/controllers/AuthController.java
index 3496d19..39d6b62 100644
--- a/NetworkChatClient/src/main/java/ru/geekbrains/java2/chat/client/controllers/AuthController.java
+++ b/NetworkChatClient/src/main/java/ru/geekbrains/java2/chat/client/controllers/AuthController.java
@@ -31,9 +31,8 @@ public void executeAuth(ActionEvent actionEvent) {
return;
}
- String authCommandMessage = String.format("%s %s %s", AUTH_CMD, login, password);
try {
- network.sendMessage(authCommandMessage);
+ network.sendAuthMessage(login, password);
} catch (IOException e) {
ClientChat.showNetworkError(e.getMessage(), "Auth error!", null);
e.printStackTrace();
diff --git a/NetworkChatClient/src/main/java/ru/geekbrains/java2/chat/client/controllers/ViewController.java b/NetworkChatClient/src/main/java/ru/geekbrains/java2/chat/client/controllers/ViewController.java
index cffb1dc..e6dac5c 100644
--- a/NetworkChatClient/src/main/java/ru/geekbrains/java2/chat/client/controllers/ViewController.java
+++ b/NetworkChatClient/src/main/java/ru/geekbrains/java2/chat/client/controllers/ViewController.java
@@ -2,10 +2,8 @@
import javafx.collections.FXCollections;
import javafx.fxml.FXML;
-import javafx.scene.control.Button;
-import javafx.scene.control.ListView;
-import javafx.scene.control.TextArea;
-import javafx.scene.control.TextField;
+import javafx.scene.control.*;
+import javafx.scene.input.MouseEvent;
import javafx.stage.Stage;
import ru.geekbrains.java2.chat.client.ClientChat;
import ru.geekbrains.java2.chat.client.models.Network;
@@ -26,10 +24,33 @@ public class ViewController {
private Network network;
private Stage primaryStage;
+ private String selectedRecipient;
+
@FXML
public void initialize() {
+
usersList.setItems(FXCollections.observableArrayList(ClientChat.USERS_TEST_DATA));
- textField.requestFocus();
+
+ usersList.setCellFactory(lv -> {
+ MultipleSelectionModel selectionModel = usersList.getSelectionModel();
+ ListCell cell = new ListCell<>();
+ cell.textProperty().bind(cell.itemProperty());
+ cell.addEventFilter(MouseEvent.MOUSE_PRESSED, event -> {
+ usersList.requestFocus();
+ if (! cell.isEmpty()) {
+ int index = cell.getIndex();
+ if (selectionModel.getSelectedIndices().contains(index)) {
+ selectionModel.clearSelection(index);
+ selectedRecipient = null;
+ } else {
+ selectionModel.select(index);
+ selectedRecipient = cell.getItem();
+ }
+ event.consume();
+ }
+ });
+ return cell ;
+ });
}
@FXML
@@ -39,7 +60,11 @@ private void sendMessage() {
textField.clear();
try {
- network.sendMessage(message);
+ if (selectedRecipient != null) {
+ network.sendPrivateMessage(selectedRecipient, message);
+ } else {
+ network.sendMessage(message);
+ }
} catch (IOException e) {
e.printStackTrace();
String errorMessage = "Failed to send message";
diff --git a/NetworkChatClient/src/main/java/ru/geekbrains/java2/chat/client/models/Network.java b/NetworkChatClient/src/main/java/ru/geekbrains/java2/chat/client/models/Network.java
index 226bea1..f565409 100644
--- a/NetworkChatClient/src/main/java/ru/geekbrains/java2/chat/client/models/Network.java
+++ b/NetworkChatClient/src/main/java/ru/geekbrains/java2/chat/client/models/Network.java
@@ -3,23 +3,23 @@
import javafx.application.Platform;
import ru.geekbrains.java2.chat.client.ClientChat;
import ru.geekbrains.java2.chat.client.controllers.ViewController;
+import ru.geekbrains.java2.chat.clientserver.Command;
+import ru.geekbrains.java2.chat.clientserver.commands.*;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
+import java.io.*;
import java.net.Socket;
+import static ru.geekbrains.java2.chat.clientserver.Command.*;
+
public class Network {
private static final String SERVER_ADDRESS = "localhost";
private static final int SERVER_PORT = 8189;
- private static final String AUTH_OK_CMD = "/authok";
-
private String host;
private int port;
- private DataInputStream inputStream;
- private DataOutputStream outputStream;
+ private ObjectInputStream inputStream;
+ private ObjectOutputStream outputStream;
private Socket socket;
private ClientChat clientChat;
private String nickname;
@@ -41,8 +41,8 @@ public Network(ClientChat clientChat) {
public boolean connect() {
try {
socket = new Socket(host, port);
- inputStream = new DataInputStream(socket.getInputStream());
- outputStream = new DataOutputStream(socket.getOutputStream());
+ outputStream = new ObjectOutputStream(socket.getOutputStream());
+ inputStream = new ObjectInputStream(socket.getInputStream());
return true;
} catch (IOException e) {
System.err.println("Соединение не было установлено!");
@@ -51,55 +51,100 @@ public boolean connect() {
}
}
- public DataInputStream getInputStream() {
- return inputStream;
+ public void sendPrivateMessage(String receiver, String message) throws IOException {
+ sendCommand(privateMessageCommand(receiver, message));
}
- public DataOutputStream getOutputStream() {
- return outputStream;
+ public void sendMessage(String message) throws IOException {
+ sendCommand(publicMessageCommand(nickname, message));
}
- public void sendMessage(String message) throws IOException {
- getOutputStream().writeUTF(message);
+ private void sendCommand(Command command) throws IOException {
+ outputStream.writeObject(command);
}
public void waitMessages(ViewController viewController) {
- Thread thread = new Thread(new Runnable() {
- @Override
- public void run() {
- try {
- while (true) {
- String message = inputStream.readUTF();
- if (clientChat.getState() == ClientChatState.AUTHENTICATION) {
- if (message.startsWith(AUTH_OK_CMD)) {
- String[] parts = message.split(" ", 2);
- nickname = parts[1];
- Platform.runLater(() -> {
- clientChat.activeChatDialog(nickname);
- });
- }
- else {
- Platform.runLater(() -> {
- ClientChat.showNetworkError(message, "Auth error", null);
- });
- }
- }
- else {
- Platform.runLater(() -> {
- viewController.appendMessage(message);
- });
- }
+ Thread thread = new Thread(() -> {
+ try {
+ while (true) {
+ Command command = readCommand();
+ if (command == null) {
+ continue;
+ }
+
+ if (clientChat.getState() == ClientChatState.AUTHENTICATION) {
+ processAuthResult(command);
+ } else {
+ processMessage(viewController, command);
}
- } catch (IOException e) {
- e.printStackTrace();
- System.out.println("Соединение было потеряно!");
}
+ } catch (IOException e) {
+ e.printStackTrace();
+ System.out.println("Соединение было потеряно!");
}
});
thread.setDaemon(true);
thread.start();
}
+ private void processMessage(ViewController viewController, Command command) {
+ switch (command.getType()) {
+ case INFO_MESSAGE: {
+ MessageInfoCommandData data = (MessageInfoCommandData) command.getData();
+ Platform.runLater(() -> {
+ viewController.appendMessage(data.getMessage());
+ });
+ break;
+ }
+ case CLIENT_MESSAGE: {
+ ClientMessageCommandData data = (ClientMessageCommandData) command.getData();
+ String sender = data.getSender();
+ String message = data.getMessage();
+ Platform.runLater(() -> {
+ viewController.appendMessage(String.format("%s: %s", sender, message));
+ });
+ break;
+ }
+ case ERROR: {
+ ErrorCommandData data = (ErrorCommandData) command.getData();
+ Platform.runLater(() -> {
+ ClientChat.showNetworkError(data.getErrorMessage(), "Server error", null);
+ });
+ break;
+ }
+ case UPDATE_USERS_LIST: {
+ UpdateUsersListCommandData data = (UpdateUsersListCommandData) command.getData();
+ Platform.runLater(() -> {
+ clientChat.updateUsers(data.getUsers());
+ });
+ break;
+ }
+ default:
+ throw new IllegalArgumentException("Uknown command type: " + command.getType());
+ }
+ }
+
+ private void processAuthResult(Command command) {
+ switch (command.getType()) {
+ case AUTH_OK: {
+ AuthOkCommandData data = (AuthOkCommandData) command.getData();
+ nickname = data.getUsername();
+ Platform.runLater(() -> {
+ clientChat.activeChatDialog(nickname);
+ });
+ break;
+ }
+ case ERROR:
+ ErrorCommandData data = (ErrorCommandData) command.getData();
+ Platform.runLater(() -> {
+ ClientChat.showNetworkError(data.getErrorMessage(), "Auth error", null);
+ });
+ break;
+ default:
+ throw new IllegalArgumentException("Uknown command type: " + command.getType());
+ }
+ }
+
public void close() {
try {
if (socket != null && socket.isConnected()) {
@@ -109,4 +154,20 @@ public void close() {
e.printStackTrace();
}
}
+
+ private Command readCommand() throws IOException {
+ Command command = null;
+ try {
+ command = (Command) inputStream.readObject();
+ } catch (ClassNotFoundException e) {
+ System.err.println("Failed to read Command class");
+ e.printStackTrace();
+ }
+
+ return command;
+ }
+
+ public void sendAuthMessage(String login, String password) throws IOException {
+ sendCommand(authCommand(login, password));
+ }
}
diff --git a/NetworkChatClientServer/NetworkChatClientServer.iml b/NetworkChatClientServer/NetworkChatClientServer.iml
new file mode 100644
index 0000000..c90834f
--- /dev/null
+++ b/NetworkChatClientServer/NetworkChatClientServer.iml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/NetworkChatClientServer/src/ru/geekbrains/java2/chat/clientserver/Command.java b/NetworkChatClientServer/src/ru/geekbrains/java2/chat/clientserver/Command.java
new file mode 100644
index 0000000..f13c72f
--- /dev/null
+++ b/NetworkChatClientServer/src/ru/geekbrains/java2/chat/clientserver/Command.java
@@ -0,0 +1,83 @@
+package ru.geekbrains.java2.chat.clientserver;
+
+import ru.geekbrains.java2.chat.clientserver.commands.*;
+
+import java.io.Serializable;
+import java.util.List;
+
+public class Command implements Serializable {
+
+ private CommandType type;
+ private Object data;
+
+ public CommandType getType() {
+ return type;
+ }
+
+ public Object getData() {
+ return data;
+ }
+
+ public static Command authCommand(String login, String password) {
+ Command command = new Command();
+ command.type = CommandType.AUTH;
+ command.data = new AuthCommandData(login, password);
+ return command;
+ }
+
+
+ public static Command authOkCommand(String username) {
+ Command command = new Command();
+ command.type = CommandType.AUTH_OK;
+ command.data = new AuthOkCommandData(username);
+ return command;
+ }
+
+ public static Command errorCommand(String errorMessage) {
+ Command command = new Command();
+ command.type = CommandType.ERROR;
+ command.data = new ErrorCommandData(errorMessage);
+ return command;
+ }
+
+ public static Command messageInfoCommand(String message) {
+ Command command = new Command();
+ command.type = CommandType.INFO_MESSAGE;
+ command.data = new MessageInfoCommandData(message);
+ return command;
+ }
+
+ public static Command publicMessageCommand(String username, String message) {
+ Command command = new Command();
+ command.type = CommandType.PUBLIC_MESSAGE;
+ command.data = new PublicMessageCommandData(username, message);
+ return command;
+ }
+ public static Command clientMessageCommand(String sender, String message) {
+ Command command = new Command();
+ command.type = CommandType.CLIENT_MESSAGE;
+ command.data = new ClientMessageCommandData(sender, message);
+ return command;
+ }
+
+ public static Command privateMessageCommand(String receiver, String message) {
+ Command command = new Command();
+ command.type = CommandType.PRIVATE_MESSAGE;
+ command.data = new PrivateMessageCommandData(receiver, message);
+ return command;
+ }
+
+ public static Command updateUsersListCommand(List users) {
+ Command command = new Command();
+ command.type = CommandType.UPDATE_USERS_LIST;
+ command.data = new UpdateUsersListCommandData(users);
+ return command;
+ }
+
+ public static Command endCommand() {
+ Command command = new Command();
+ command.type = CommandType.END;
+ return command;
+ }
+
+}
diff --git a/NetworkChatClientServer/src/ru/geekbrains/java2/chat/clientserver/CommandType.java b/NetworkChatClientServer/src/ru/geekbrains/java2/chat/clientserver/CommandType.java
new file mode 100644
index 0000000..5a3531d
--- /dev/null
+++ b/NetworkChatClientServer/src/ru/geekbrains/java2/chat/clientserver/CommandType.java
@@ -0,0 +1,15 @@
+package ru.geekbrains.java2.chat.clientserver;
+
+public enum CommandType {
+ AUTH,
+ AUTH_OK,
+ ERROR,
+ PRIVATE_MESSAGE,
+ PUBLIC_MESSAGE,
+
+ INFO_MESSAGE,
+ CLIENT_MESSAGE,
+
+ END,
+ UPDATE_USERS_LIST,
+}
diff --git a/NetworkChatClientServer/src/ru/geekbrains/java2/chat/clientserver/commands/AuthCommandData.java b/NetworkChatClientServer/src/ru/geekbrains/java2/chat/clientserver/commands/AuthCommandData.java
new file mode 100644
index 0000000..5542ffa
--- /dev/null
+++ b/NetworkChatClientServer/src/ru/geekbrains/java2/chat/clientserver/commands/AuthCommandData.java
@@ -0,0 +1,22 @@
+package ru.geekbrains.java2.chat.clientserver.commands;
+
+import java.io.Serializable;
+
+public class AuthCommandData implements Serializable {
+
+ private final String login;
+ private final String password;
+
+ public AuthCommandData(String login, String password) {
+ this.login = login;
+ this.password = password;
+ }
+
+ public String getLogin() {
+ return login;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+}
diff --git a/NetworkChatClientServer/src/ru/geekbrains/java2/chat/clientserver/commands/AuthOkCommandData.java b/NetworkChatClientServer/src/ru/geekbrains/java2/chat/clientserver/commands/AuthOkCommandData.java
new file mode 100644
index 0000000..f2bbe4b
--- /dev/null
+++ b/NetworkChatClientServer/src/ru/geekbrains/java2/chat/clientserver/commands/AuthOkCommandData.java
@@ -0,0 +1,16 @@
+package ru.geekbrains.java2.chat.clientserver.commands;
+
+import java.io.Serializable;
+
+public class AuthOkCommandData implements Serializable {
+
+ private final String username;
+
+ public AuthOkCommandData(String username) {
+ this.username = username;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+}
diff --git a/NetworkChatClientServer/src/ru/geekbrains/java2/chat/clientserver/commands/ClientMessageCommandData.java b/NetworkChatClientServer/src/ru/geekbrains/java2/chat/clientserver/commands/ClientMessageCommandData.java
new file mode 100644
index 0000000..ef2003a
--- /dev/null
+++ b/NetworkChatClientServer/src/ru/geekbrains/java2/chat/clientserver/commands/ClientMessageCommandData.java
@@ -0,0 +1,22 @@
+package ru.geekbrains.java2.chat.clientserver.commands;
+
+import java.io.Serializable;
+
+public class ClientMessageCommandData implements Serializable {
+
+ private final String sender;
+ private final String message;
+
+ public ClientMessageCommandData(String sender, String message) {
+ this.sender = sender;
+ this.message = message;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public String getSender() {
+ return sender;
+ }
+}
diff --git a/NetworkChatClientServer/src/ru/geekbrains/java2/chat/clientserver/commands/ErrorCommandData.java b/NetworkChatClientServer/src/ru/geekbrains/java2/chat/clientserver/commands/ErrorCommandData.java
new file mode 100644
index 0000000..37c13e2
--- /dev/null
+++ b/NetworkChatClientServer/src/ru/geekbrains/java2/chat/clientserver/commands/ErrorCommandData.java
@@ -0,0 +1,16 @@
+package ru.geekbrains.java2.chat.clientserver.commands;
+
+import java.io.Serializable;
+
+public class ErrorCommandData implements Serializable {
+
+ private final String errorMessage;
+
+ public ErrorCommandData(String errorMessage) {
+ this.errorMessage = errorMessage;
+ }
+
+ public String getErrorMessage() {
+ return errorMessage;
+ }
+}
diff --git a/NetworkChatClientServer/src/ru/geekbrains/java2/chat/clientserver/commands/MessageInfoCommandData.java b/NetworkChatClientServer/src/ru/geekbrains/java2/chat/clientserver/commands/MessageInfoCommandData.java
new file mode 100644
index 0000000..3efbba5
--- /dev/null
+++ b/NetworkChatClientServer/src/ru/geekbrains/java2/chat/clientserver/commands/MessageInfoCommandData.java
@@ -0,0 +1,17 @@
+package ru.geekbrains.java2.chat.clientserver.commands;
+
+import java.io.Serializable;
+
+public class MessageInfoCommandData implements Serializable {
+
+ private final String message;
+
+ public MessageInfoCommandData(String message) {
+ this.message = message;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+}
diff --git a/NetworkChatClientServer/src/ru/geekbrains/java2/chat/clientserver/commands/PrivateMessageCommandData.java b/NetworkChatClientServer/src/ru/geekbrains/java2/chat/clientserver/commands/PrivateMessageCommandData.java
new file mode 100644
index 0000000..d06a5df
--- /dev/null
+++ b/NetworkChatClientServer/src/ru/geekbrains/java2/chat/clientserver/commands/PrivateMessageCommandData.java
@@ -0,0 +1,22 @@
+package ru.geekbrains.java2.chat.clientserver.commands;
+
+import java.io.Serializable;
+
+public class PrivateMessageCommandData implements Serializable {
+
+ private final String receiver;
+ private final String message;
+
+ public PrivateMessageCommandData(String receiver, String message) {
+ this.receiver = receiver;
+ this.message = message;
+ }
+
+ public String getReceiver() {
+ return receiver;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+}
diff --git a/NetworkChatClientServer/src/ru/geekbrains/java2/chat/clientserver/commands/PublicMessageCommandData.java b/NetworkChatClientServer/src/ru/geekbrains/java2/chat/clientserver/commands/PublicMessageCommandData.java
new file mode 100644
index 0000000..cc7a84c
--- /dev/null
+++ b/NetworkChatClientServer/src/ru/geekbrains/java2/chat/clientserver/commands/PublicMessageCommandData.java
@@ -0,0 +1,22 @@
+package ru.geekbrains.java2.chat.clientserver.commands;
+
+import java.io.Serializable;
+
+public class PublicMessageCommandData implements Serializable {
+
+ private final String sender;
+ private final String message;
+
+ public PublicMessageCommandData(String sender, String message) {
+ this.sender = sender;
+ this.message = message;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public String getSender() {
+ return sender;
+ }
+}
diff --git a/NetworkChatClientServer/src/ru/geekbrains/java2/chat/clientserver/commands/UpdateUsersListCommandData.java b/NetworkChatClientServer/src/ru/geekbrains/java2/chat/clientserver/commands/UpdateUsersListCommandData.java
new file mode 100644
index 0000000..478ad43
--- /dev/null
+++ b/NetworkChatClientServer/src/ru/geekbrains/java2/chat/clientserver/commands/UpdateUsersListCommandData.java
@@ -0,0 +1,17 @@
+package ru.geekbrains.java2.chat.clientserver.commands;
+
+import java.io.Serializable;
+import java.util.List;
+
+public class UpdateUsersListCommandData implements Serializable {
+
+ private final List users;
+
+ public UpdateUsersListCommandData(List users) {
+ this.users = users;
+ }
+
+ public List getUsers() {
+ return users;
+ }
+}
diff --git a/NetworkChatServer/NetworkChatServer.iml b/NetworkChatServer/NetworkChatServer.iml
index c90834f..c0b963c 100644
--- a/NetworkChatServer/NetworkChatServer.iml
+++ b/NetworkChatServer/NetworkChatServer.iml
@@ -7,5 +7,6 @@
+
\ No newline at end of file
diff --git a/NetworkChatServer/src/ru/geekbrains/java2/chat/server/chat/MyServer.java b/NetworkChatServer/src/ru/geekbrains/java2/chat/server/chat/MyServer.java
index 4cdd0f0..a1304c6 100644
--- a/NetworkChatServer/src/ru/geekbrains/java2/chat/server/chat/MyServer.java
+++ b/NetworkChatServer/src/ru/geekbrains/java2/chat/server/chat/MyServer.java
@@ -1,6 +1,7 @@
package ru.geekbrains.java2.chat.server.chat;
+import ru.geekbrains.java2.chat.clientserver.Command;
import ru.geekbrains.java2.chat.server.chat.auth.AuthService;
import ru.geekbrains.java2.chat.server.chat.auth.BaseAuthService;
import ru.geekbrains.java2.chat.server.chat.handler.ClientHandler;
@@ -11,6 +12,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
+import java.util.stream.Collectors;
public class MyServer {
@@ -68,21 +70,43 @@ private void processClientConnection(Socket clientSocket) throws IOException {
}
public synchronized void broadcastMessage(String message, ClientHandler sender) throws IOException {
+
for (ClientHandler client : clients) {
if (client == sender) {
continue;
}
+ if (sender == null) {
+ client.sendMessage(message);
+ } else {
+ client.sendMessage(sender.getNickname(), message);
+ }
- client.sendMessage(message);
}
}
- public synchronized void subscribe(ClientHandler handler) {
+ public synchronized void subscribe(ClientHandler handler) throws IOException {
clients.add(handler);
+ notifyClientsUsersListUpdated(clients);
}
- public synchronized void unsubscribe(ClientHandler handler) {
+ public synchronized void unsubscribe(ClientHandler handler) throws IOException {
clients.remove(handler);
+ notifyClientsUsersListUpdated(clients);
+ }
+
+ private void notifyClientsUsersListUpdated(List clients) throws IOException {
+ List usernames = new ArrayList<>();
+ for (ClientHandler client : clients) {
+ usernames.add(client.getNickname());
+ }
+
+ for (ClientHandler client : clients) {
+// List usernames = clients.stream()
+// .map(ClientHandler::getNickname)
+// .collect(Collectors.toList());
+
+ client.sendCommand(Command.updateUsersListCommand(usernames));
+ }
}
public AuthService getAuthService() {
@@ -97,4 +121,12 @@ public synchronized boolean isNickBusy(String nickname) {
}
return false;
}
+
+ public synchronized void sendPrivateMessage(ClientHandler sender, String recipient, String privateMessage) throws IOException {
+ for (ClientHandler client : clients) {
+ if (client.getNickname().equals(recipient)) {
+ client.sendMessage(sender.getNickname(), privateMessage);
+ }
+ }
+ }
}
diff --git a/NetworkChatServer/src/ru/geekbrains/java2/chat/server/chat/handler/ClientHandler.java b/NetworkChatServer/src/ru/geekbrains/java2/chat/server/chat/handler/ClientHandler.java
index 286a67f..3df3a8f 100644
--- a/NetworkChatServer/src/ru/geekbrains/java2/chat/server/chat/handler/ClientHandler.java
+++ b/NetworkChatServer/src/ru/geekbrains/java2/chat/server/chat/handler/ClientHandler.java
@@ -1,24 +1,25 @@
package ru.geekbrains.java2.chat.server.chat.handler;
+import ru.geekbrains.java2.chat.clientserver.Command;
+import ru.geekbrains.java2.chat.clientserver.CommandType;
+import ru.geekbrains.java2.chat.clientserver.commands.AuthCommandData;
+import ru.geekbrains.java2.chat.clientserver.commands.PrivateMessageCommandData;
+import ru.geekbrains.java2.chat.clientserver.commands.PublicMessageCommandData;
import ru.geekbrains.java2.chat.server.chat.MyServer;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
+import java.io.*;
import java.net.Socket;
-public class ClientHandler {
+import static ru.geekbrains.java2.chat.clientserver.Command.*;
- private static final String END_CMD = "/end";
- private static final String AUTH_CMD = "/auth"; // "/auth login password"
- private static final String AUTH_OK_CMD = "/authok";
+public class ClientHandler {
private final MyServer myServer;
private final Socket clientSocket;
- private DataInputStream in;
- private DataOutputStream out;
+ private ObjectInputStream in;
+ private ObjectOutputStream out;
private String nickname;
@@ -29,8 +30,8 @@ public ClientHandler(MyServer myServer, Socket clientSocket) {
}
public void handle() throws IOException {
- in = new DataInputStream(clientSocket.getInputStream());
- out = new DataOutputStream(clientSocket.getOutputStream());
+ in = new ObjectInputStream(clientSocket.getInputStream());
+ out = new ObjectOutputStream(clientSocket.getOutputStream());
new Thread(() -> {
try {
@@ -50,23 +51,27 @@ public void handle() throws IOException {
private void authentication() throws IOException {
while (true) {
- String message = in.readUTF();
- if (message.startsWith(AUTH_CMD)) {
- String[] parts = message.split(" ", 3);
- String login = parts[1];
- String password = parts[2];
+ Command command = readCommand();
+ if (command == null) {
+ continue;
+ }
+
+ if (command.getType() == CommandType.AUTH) {
+ AuthCommandData data = (AuthCommandData) command.getData();
+ String login = data.getLogin();
+ String password = data.getPassword();
String nickname = myServer.getAuthService().getNickByLoginPass(login, password);
if (nickname == null) {
- out.writeUTF("Некорректные логин или пароль!");
+ sendCommand(errorCommand("Некорректные логин или пароль!"));
continue;
}
if (myServer.isNickBusy(nickname)) {
- out.writeUTF("Такой пользователь уже существует!");
+ sendCommand(errorCommand("Такой пользователь уже существует!"));
continue;
}
- out.writeUTF(String.format("%s %s", AUTH_OK_CMD, nickname));
+ sendCommand(authOkCommand(nickname));
setNickname(nickname);
myServer.broadcastMessage(String.format("Пользователь '%s' зашел в чат!", nickname), null);
myServer.subscribe(this);
@@ -75,15 +80,48 @@ private void authentication() throws IOException {
}
}
+ public void sendCommand(Command command) throws IOException {
+ out.writeObject(command);
+ }
+
+ private Command readCommand() throws IOException {
+ Command command = null;
+ try {
+ command = (Command) in.readObject();
+ } catch (ClassNotFoundException e) {
+ System.err.println("Failed to read Command class");
+ e.printStackTrace();
+ }
+
+ return command;
+ }
+
private void readMessages() throws IOException {
while (true) {
- String message = in.readUTF();
- System.out.println("message: " + message);
- if (message.startsWith(END_CMD)) {
- return;
+ Command command = readCommand();
+ if (command == null) {
+ continue;
}
- else {
- myServer.broadcastMessage(nickname + ": " + message, this);
+
+ switch (command.getType()) {
+ case PRIVATE_MESSAGE: {
+ PrivateMessageCommandData data = (PrivateMessageCommandData) command.getData();
+ String receiver = data.getReceiver();
+ String message = data.getMessage();
+ myServer.sendPrivateMessage(this, receiver, message);
+ break;
+ }
+ case PUBLIC_MESSAGE: {
+ PublicMessageCommandData data = (PublicMessageCommandData) command.getData();
+ String message = data.getMessage();
+ myServer.broadcastMessage(message, this);
+ break;
+ }
+ case END:
+ return;
+ default:
+ throw new IllegalArgumentException("Unknown command type: " + command.getType());
+
}
}
}
@@ -95,7 +133,11 @@ private void closeConnection() throws IOException {
public void sendMessage(String message) throws IOException {
- out.writeUTF(message);
+ sendCommand(Command.messageInfoCommand(message));
+ }
+
+ public void sendMessage(String sender, String message) throws IOException {
+ sendCommand(clientMessageCommand(message, sender));
}
public String getNickname() {
diff --git a/src/lesson4/homework/ViewController.java b/src/lesson4/homework/ViewController.java
index d63ebb9..94e0dd5 100644
--- a/src/lesson4/homework/ViewController.java
+++ b/src/lesson4/homework/ViewController.java
@@ -1,11 +1,14 @@
package lesson4.homework;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
+import javafx.event.EventHandler;
import javafx.fxml.FXML;
-import javafx.scene.control.Button;
-import javafx.scene.control.ListView;
-import javafx.scene.control.TextArea;
-import javafx.scene.control.TextField;
+import javafx.scene.control.*;
+import javafx.scene.input.MouseEvent;
+
+import java.util.ArrayList;
public class ViewController {
@@ -22,15 +25,34 @@ public class ViewController {
@FXML
public void initialize() {
usersList.setItems(FXCollections.observableArrayList(Main.USERS_TEST_DATA));
+ usersList.getSelectionModel().selectedItemProperty().addListener((observableValue, selectionMode, t1) -> {
+ System.out.println(t1);
+ });
+
+ usersList.setOnMouseClicked(click -> {
+
+ if (click.getClickCount() == 2) {
+ //Use ListView's getSelected Item
+ String selectedItem = usersList.getSelectionModel().getSelectedItem();
+ usersList.getItems().remove(selectedItem);
+ //use this to do whatever you want to. Open Link etc.
+ }
+ });
+
// sendButton.setOnAction(event -> sendMessage());
// textField.setOnAction(event -> sendMessage());
}
@FXML
private void sendMessage() {
- chatHistory.appendText(textField.getText());
+ String message = textField.getText();
+ chatHistory.appendText(message);
chatHistory.appendText(System.lineSeparator());
+
+ usersList.getItems().add(message);
textField.clear();
+
+
}
}
\ No newline at end of file