diff --git a/src/main/java/com/university/chat/Client/Net/ServerListener.java b/src/main/java/com/university/chat/Client/Net/ServerListener.java new file mode 100644 index 0000000..cfab302 --- /dev/null +++ b/src/main/java/com/university/chat/Client/Net/ServerListener.java @@ -0,0 +1,46 @@ +package com.university.chat.Client.Net; + +import java.io.ObjectInputStream; +import java.util.function.Consumer; + +public class ServerListener implements Runnable { + + private final ObjectInputStream in; + private Consumer onMessageReceived; + private final Consumer onConnectionError; + + private volatile boolean running = true; + + public ServerListener(ObjectInputStream in, + Consumer onMessageReceived, + Consumer onConnectionError) { + this.in = in; + this.onMessageReceived = onMessageReceived; + this.onConnectionError = onConnectionError; + } + + @Override + public void run() { + + try { + while (running) { + Object object = in.readObject(); + if (onMessageReceived != null) { + onMessageReceived.accept(object); + } + } + } catch (Exception e) { + if (running && onConnectionError != null) { + onConnectionError.accept(e); + } + } + } + + public void stop() { + running = false; + } + + public void setOnMessageReceived(Consumer onMessageReceived) { + this.onMessageReceived = onMessageReceived; + } +} diff --git a/src/main/java/com/university/chat/Client/Net/chatClient.java b/src/main/java/com/university/chat/Client/Net/chatClient.java new file mode 100644 index 0000000..653a978 --- /dev/null +++ b/src/main/java/com/university/chat/Client/Net/chatClient.java @@ -0,0 +1,158 @@ +package com.university.chat.Client.Net; + +import com.university.chat.Client.UI.ChatController; +import com.university.chat.Common.ChatMessage; +import com.university.chat.Common.FileMessage; +import com.university.chat.Common.MessageType; +import javafx.scene.control.ListView; + +import java.io.*; +import java.net.Socket; +import java.nio.file.Files; +import java.util.function.Consumer; + +public class chatClient { + + private Socket socket; + private ObjectOutputStream out; + private ObjectInputStream in; + + private Thread listenerThread; + private ServerListener serverListener; + + private String username; + + public void connect(String host, int port) throws IOException { + + socket = new Socket(host, port); + + out = new ObjectOutputStream(socket.getOutputStream()); + out.flush(); + + in = new ObjectInputStream(socket.getInputStream()); + } + + public void startListening(Consumer onMessageReceived, + Consumer onConnectionError) { + + serverListener = new ServerListener(in, onMessageReceived, onConnectionError); + + listenerThread = new Thread(serverListener); + listenerThread.setDaemon(true); + listenerThread.start(); + } + + public void login(String username) throws IOException { + this.username = username; + + ChatMessage loginMessage = new ChatMessage( + MessageType.LOGIN, + username, + null, + null + ); + + sendObject(loginMessage); + + } + + public void sendPublicMessage(String content) throws IOException { + ChatMessage message = new ChatMessage( + MessageType.PUBLIC_MESSAGE, + username, + null, + content + ); + + sendObject(message); + } + + public void sendPrivateMessage(String receiver, String content) throws IOException { + ChatMessage message = new ChatMessage( + MessageType.PRIVATE_MESSAGE, + username, + receiver, + content + ); + + sendObject(message); + } + + public void requestUserList() throws IOException { + ChatMessage message = new ChatMessage( + MessageType.USER_LIST, + username, + null, + null + ); + + sendObject(message); + } + + + public void sendFile(String receiver, File file) throws IOException { + if (file == null || !file.exists() || !file.isFile()) { + throw new FileNotFoundException("Invalid file."); + } + + byte[] fileData = Files.readAllBytes(file.toPath()); + + + FileMessage fileMessage = new FileMessage( + username, + receiver, + file.getName(), + fileData + ); + + sendObject(fileMessage); + } + + private synchronized void sendObject(Object object) throws IOException { + if (out == null) { + throw new IOException("Client is not connected."); + } + + out.writeObject(object); + out.flush(); + } + + public boolean isConnected() { + return socket != null && socket.isConnected() && !socket.isClosed(); + } + + public String getUsername() { + return username; + } + + public void close() { + try { + if (serverListener != null) { + serverListener.stop(); + } + + if (listenerThread != null) { + listenerThread.interrupt(); + } + + if (in != null) { + in.close(); + } + + if (out != null) { + out.close(); + } + + if (socket != null) { + socket.close(); + } + + } catch (IOException e) { + System.err.println("Error while closing client: " + e.getMessage()); + } + } + + public ServerListener getServerListener() { + return serverListener; + } +} diff --git a/src/main/java/com/university/chat/Client/ServerListener.java b/src/main/java/com/university/chat/Client/ServerListener.java deleted file mode 100644 index b609d74..0000000 --- a/src/main/java/com/university/chat/Client/ServerListener.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.university.chat.Client; - -public class ServerListener implements Runnable{ - // TODO: store the ObjectInputStream from the user socket - // (this should be the same input stream the - // chatClient created when connecting) - - @Override - public void run() { - try { - // TODO: In an infinite loop read objects from the server - // - if it's a ChatMessage -> print ": " - // - if it's a FileMessage -> print that a file was received - // (filename + sender), it's already - // saved to disk by the server. - } catch (Exception e){ - System.out.println("Disconnected from server"); - } - } -} diff --git a/src/main/java/com/university/chat/Client/chatClient.java b/src/main/java/com/university/chat/Client/chatClient.java deleted file mode 100644 index dae0bad..0000000 --- a/src/main/java/com/university/chat/Client/chatClient.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.university.chat.Client; - -public class chatClient { - public static void main() { - // TODO: Connecting to the server - // 1. Create a socket and connect to the server - // 2. Create an ObjectOutputStream (out) and ObjectInputStream (in) - // from the socket's streams — output FIRST, then input. - // 2. Get the username, and send a LOGIN ChatMessage with that username - // 3. Start a new Thread running a ServerListener(in) so incoming - // messages are handled concurrently. - - while (true){ - try { - // TODO: Program loop — read a line from the console and act on it: - // - "/msg " -> build & send a PRIVATE_MESSAGE - // - "/users" -> build & send a USER_LIST request - // - "/sendfile " -> read the file into a byte[] - // (you can use TransferProgress - // to show progress) - // and send it as a FileMessage - // - anything else -> send a PUBLIC_MESSAGE - // Remember to flush() the output stream after writeObject(). - } catch (Exception e){ - System.out.println("command failed: " + e.getMessage()); - } - } - } -}