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