From cfce2a952e6a83da63165d37e49bc79dc757eb13 Mon Sep 17 00:00:00 2001 From: Arshida_0 Date: Sat, 20 Jun 2026 01:17:57 +0430 Subject: [PATCH] HW 10 --- .../chat/Client/ServerListener.java | 23 ++++ .../university/chat/Client/chatClient.java | 109 +++++++++++++++--- .../university/chat/Server/ChatServer.java | 27 ++++- .../university/chat/Server/ClientSession.java | 75 +++++++++++- 4 files changed, 214 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/university/chat/Client/ServerListener.java b/src/main/java/com/university/chat/Client/ServerListener.java index b609d74..f470855 100644 --- a/src/main/java/com/university/chat/Client/ServerListener.java +++ b/src/main/java/com/university/chat/Client/ServerListener.java @@ -1,10 +1,22 @@ package com.university.chat.Client; +import com.university.chat.Common.ChatMessage; +import com.university.chat.Common.FileMessage; + +import java.io.File; +import java.io.InputStream; +import java.io.ObjectInputStream; + 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) + private ObjectInputStream in; + public ServerListener (ObjectInputStream inputStream) { + this.in = inputStream; + } + @Override public void run() { try { @@ -13,6 +25,17 @@ public class ServerListener implements Runnable{ // - if it's a FileMessage -> print that a file was received // (filename + sender), it's already // saved to disk by the server. + + Object message; + while ((message = in.readObject()) != null) { + if (message instanceof ChatMessage cMassage) { + System.out.printf("<%s>: <%s>%n", cMassage.getSender(), cMassage.getContent()); + } + else if (message instanceof FileMessage fMassage) { + System.out.printf("A file was received: %s - %s%n", fMassage.getFilename(), fMassage.getSender()); + } + else System.out.println(message); + } } 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 index dae0bad..e811703 100644 --- a/src/main/java/com/university/chat/Client/chatClient.java +++ b/src/main/java/com/university/chat/Client/chatClient.java @@ -1,7 +1,19 @@ package com.university.chat.Client; +import com.university.chat.Common.ChatMessage; +import com.university.chat.Common.FileMessage; +import com.university.chat.Common.MessageType; + +import java.awt.*; +import java.io.*; +import java.net.Socket; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Scanner; + public class chatClient { - public static void main() { + public static void main() throws IOException { // TODO: Connecting to the server // 1. Create a socket and connect to the server // 2. Create an ObjectOutputStream (out) and ObjectInputStream (in) @@ -10,20 +22,89 @@ public class chatClient { // 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()); + String username; + + try (Socket socket = new Socket("localhost", 12345)) { //______________ + ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream()); + ObjectInputStream in = new ObjectInputStream(socket.getInputStream()); + Scanner keyboard = new Scanner(System.in); + + username = keyboard.nextLine(); + out.writeObject(new ChatMessage(MessageType.LOGIN, username, "System", "Login")); + out.flush(); + + ServerListener serverListener = new ServerListener(in); + Thread ListenerThread = new Thread(serverListener); + ListenerThread.setDaemon(true); + ListenerThread.start(); + + 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(). + + String consoleLine; + if ((consoleLine = keyboard.nextLine()) != null){ + + if (consoleLine.startsWith("/msg")) { + + int i1 = consoleLine.indexOf("<"); + int i2 = consoleLine.indexOf(">"); + int j1 = consoleLine.lastIndexOf("<"); + int j2 = consoleLine.lastIndexOf(">"); + + String user = consoleLine.substring(i1+1, i2); + String text = consoleLine.substring(j1+1, j2); + + ChatMessage chatMessage = new ChatMessage(MessageType.PRIVATE_MESSAGE, username, user, text); + out.writeObject(chatMessage); + out.flush(); + + } else if (consoleLine.startsWith("/users")) { + + ChatMessage chatMessage = new ChatMessage(MessageType.USER_LIST, username, username, "users_list"); + out.writeObject(chatMessage); + out.flush(); + + } else if (consoleLine.startsWith("/sendfile")) { + + int i1 = consoleLine.indexOf("<"); + int i2 = consoleLine.indexOf(">"); + int j1 = consoleLine.lastIndexOf("<"); + int j2 = consoleLine.lastIndexOf(">"); + + String user = consoleLine.substring(i1+1, i2); + String pathStr = consoleLine.substring(j1+1, j2); + + Path path = Paths.get(pathStr); + byte[] data = Files.readAllBytes(path); + FileMessage fileMessage = new FileMessage(username, user, "filename", data); + out.writeObject(fileMessage); + out.flush(); + + } else { + + ChatMessage chatMessage = new ChatMessage(MessageType.PUBLIC_MESSAGE, username, "everyone", consoleLine); + out.writeObject(chatMessage); + out.flush(); + + } + } + + } catch (Exception e) { + System.out.println("command failed: " + e.getMessage()); + } } } + catch (Exception e) { + //______________ + } } } diff --git a/src/main/java/com/university/chat/Server/ChatServer.java b/src/main/java/com/university/chat/Server/ChatServer.java index b2a35ae..eae7952 100644 --- a/src/main/java/com/university/chat/Server/ChatServer.java +++ b/src/main/java/com/university/chat/Server/ChatServer.java @@ -1,15 +1,34 @@ package com.university.chat.Server; +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; + public class ChatServer { // TODO: declare a single shared UserManager instance (static final) // This MUST be shared by all ClientSession threads so that // broadcasting and private messaging work correctly. - public static void main(String[] args) { + static final UserManager userManager = new UserManager(); + + public static void main(String[] args) throws IOException { // TODO: Create a ServerSocket - // TODO: In an infinite loop: - // accept an incoming client connection - // make a new thread running ClientSession for each user. + try (ServerSocket serverSocket = new ServerSocket(12345);) { + + // TODO: In an infinite loop: + // accept an incoming client connection + // make a new thread running ClientSession for each user. + + while (true) { + Socket clientSocket = serverSocket.accept(); + ClientSession clientSession = new ClientSession(clientSocket, userManager); + Thread CSThread = new Thread(clientSession); + CSThread.start(); + } + } + catch (Exception e) { + //______________ + } } } diff --git a/src/main/java/com/university/chat/Server/ClientSession.java b/src/main/java/com/university/chat/Server/ClientSession.java index f09d64a..e6ba719 100644 --- a/src/main/java/com/university/chat/Server/ClientSession.java +++ b/src/main/java/com/university/chat/Server/ClientSession.java @@ -2,18 +2,31 @@ package com.university.chat.Server; import com.university.chat.Common.ChatMessage; import com.university.chat.Common.FileMessage; +import com.university.chat.Common.MessageType; -import java.io.IOException; +import java.io.*; import java.net.Socket; import java.nio.file.Files; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; public class ClientSession implements Runnable { private String username; + private UserManager userManager; + private ObjectOutputStream out; + private ObjectInputStream in; + private Socket socket; + private Lock L = new ReentrantLock(); - public ClientSession(Socket socket, UserManager userManager) { + public ClientSession(Socket socket, UserManager userManager) throws IOException { // TODO : Create an ObjectOutputStream from socket.getOutputStream() // and an ObjectInputStream from socket.getInputStream(). + + this.userManager = userManager; + this.socket = socket; + this.out = new ObjectOutputStream(socket.getOutputStream()); + this.in = new ObjectInputStream(socket.getInputStream()); } @Override @@ -29,17 +42,48 @@ public class ClientSession implements Runnable { // 6. Otherwise, create the user's folders with FileManager.createUserFolders(...) // and send back LOGIN_SUCCESS. + Object firstObject = in.readObject(); + if (firstObject instanceof ChatMessage lMassage && lMassage.getType().equals(MessageType.LOGIN)) { + username = lMassage.getSender(); + if (userManager.addUser(username, this)) { + FileManager.createUserFolders(username); + ChatMessage chatMessage = new ChatMessage(MessageType.LOGIN_SUCCESS, "System", username, "success"); + out.writeObject(chatMessage); + out.flush(); + } + else { + ChatMessage chatMessage = new ChatMessage(MessageType.LOGIN_FAILED, "System", username, "failure"); + out.writeObject(chatMessage); + out.flush(); + socket.close(); + } + } + else { + socket.close(); //____________ + } + // TODO: Main message loop // In a loop, call in.readObject(), you can separate messages by their type: // - if it's a ChatMessage -> call handleChatMessage(msg) // - if it's a FileMessage -> call handleFileMessage(fileMsg) // Keep looping until the connection is closed (an exception will be thrown). + Object message; + while ((message = in.readObject()) != null) { + if (message instanceof ChatMessage cMassage) { + handleChatMessage(cMassage); + } else if (message instanceof FileMessage fMassage) { + handleFileMessage(fMassage); + } + } + //_____________ + } catch (Exception e) { System.out.println("Disconnected: " + username); } finally { // TODO: Remove the user from UserManager so they no longer // receive broadcasts or appear in users list + userManager.removeUser(username); } } @@ -48,12 +92,23 @@ public class ClientSession implements Runnable { switch (msg.getType()) { case PUBLIC_MESSAGE -> { // TODO: Broadcast this message to every connected client. + for (ClientSession cs : userManager.getAllSessions()) { + if (!cs.equals(this)) { + cs.sendMessage(msg); + } + } } case PRIVATE_MESSAGE -> { // TODO: Forward this message to the receiver user. + ClientSession cs = userManager.getUser(msg.getReceiver()); + if (cs != null) { + cs.sendMessage(msg); + } } case USER_LIST -> { // TODO: Reply to the requester with the list of online users. + out.writeObject(userManager.listUsers()); + out.flush(); } } } @@ -67,5 +122,21 @@ public class ClientSession implements Runnable { Files.write(recvPath, fileMsg.getData()); // TODO: Forward the received file-message to the destination user. + ClientSession cs = userManager.getUser(fileMsg.getReceiver()); + if (cs != null) { + cs.sendMessage(fileMsg); + } + } + + public void sendMessage(Object object) { + try { + L.lock(); + out.writeObject(object); + out.flush(); + L.unlock(); + } + catch (Exception e) { + //_____________ + } } } \ No newline at end of file -- 2.54.0