From daa945198435d5e1253914dfaac407ace14925bd Mon Sep 17 00:00:00 2001 From: Mobina Date: Sat, 20 Jun 2026 00:15:44 +0330 Subject: [PATCH] develop --- .../chat/Client/ServerListener.java | 36 ++++++- .../university/chat/Client/chatClient.java | 37 ++++++- .../university/chat/Server/ChatServer.java | 29 +++++- .../university/chat/Server/ClientSession.java | 99 ++++++++++++++++++- 4 files changed, 193 insertions(+), 8 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..a747fe3 100644 --- a/src/main/java/com/university/chat/Client/ServerListener.java +++ b/src/main/java/com/university/chat/Client/ServerListener.java @@ -1,18 +1,44 @@ package com.university.chat.Client; +import com.university.chat.Common.ChatMessage; +import com.university.chat.Common.FileMessage; + +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 final ObjectInputStream in; + + public ServerListener(ObjectInputStream in){ + this.in = in; + } + @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. + while(true){ + Object obj = in.readObject(); + + if(obj instanceof ChatMessage msg){ + System.out.println( + msg.getSender() + + ": " + + msg.getContent() + ); + } + + else if(obj instanceof FileMessage file){ + System.out.println( + "File received from " + + file.getSender() + + ": " + + file.getFilename() + ); + } + } } 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..ec38c2d 100644 --- a/src/main/java/com/university/chat/Client/chatClient.java +++ b/src/main/java/com/university/chat/Client/chatClient.java @@ -1,6 +1,20 @@ package com.university.chat.Client; +import com.university.chat.Common.ChatMessage; +import com.university.chat.Server.ClientSession; +import com.university.chat.Server.UserManager; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.Scanner; + public class chatClient { + public static final UserManager userManager = + new UserManager(); + public static void main() { // TODO: Connecting to the server // 1. Create a socket and connect to the server @@ -9,11 +23,20 @@ public class chatClient { // 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. + ServerSocket serverSocket; + + try{ + serverSocket =new ServerSocket(5000); + + System.out.println("Server started"); + } catch (Exception e) { + throw new RuntimeException(e); + } while (true){ try { // TODO: Program loop — read a line from the console and act on it: - // - "/msg " -> build & send a PRIVATE_MESSAGE + // - "/msg " -> build & send a PRIVATE_MESSAGE // - "/users" -> build & send a USER_LIST request // - "/sendfile " -> read the file into a byte[] // (you can use TransferProgress @@ -21,6 +44,18 @@ public class chatClient { // and send it as a FileMessage // - anything else -> send a PUBLIC_MESSAGE // Remember to flush() the output stream after writeObject(). + + Socket socket = + serverSocket.accept(); + + ClientSession session = + new ClientSession( + socket, + userManager + ); + + new Thread(session).start(); + } catch (Exception e){ System.out.println("command failed: " + e.getMessage()); } diff --git a/src/main/java/com/university/chat/Server/ChatServer.java b/src/main/java/com/university/chat/Server/ChatServer.java index b2a35ae..98f1c6a 100644 --- a/src/main/java/com/university/chat/Server/ChatServer.java +++ b/src/main/java/com/university/chat/Server/ChatServer.java @@ -1,15 +1,42 @@ package com.university.chat.Server; +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. + private static final UserManager userManager = + new UserManager(); public static void main(String[] args) { // TODO: Create a ServerSocket + try (ServerSocket serverSocket = + new ServerSocket(5000)) { + System.out.println("Server started"); + + while (true) { + + Socket socket = + serverSocket.accept(); + + ClientSession session = + new ClientSession( + socket, + userManager + ); + + new Thread(session).start(); + } + + } catch (Exception e) { + e.printStackTrace(); + } + } // TODO: In an infinite loop: // accept an incoming client connection // make a new thread running ClientSession for each user. - } + } diff --git a/src/main/java/com/university/chat/Server/ClientSession.java b/src/main/java/com/university/chat/Server/ClientSession.java index f09d64a..6ff38d3 100644 --- a/src/main/java/com/university/chat/Server/ClientSession.java +++ b/src/main/java/com/university/chat/Server/ClientSession.java @@ -2,18 +2,38 @@ 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.ObjectInputStream; +import java.io.ObjectOutputStream; import java.net.Socket; import java.nio.file.Files; +import static com.university.chat.Client.chatClient.userManager; + public class ClientSession implements Runnable { private String username; + private final Socket socket; + private final UserManager userManager; + + private ObjectInputStream in; + private ObjectOutputStream out; public ClientSession(Socket socket, UserManager userManager) { // TODO : Create an ObjectOutputStream from socket.getOutputStream() // and an ObjectInputStream from socket.getInputStream(). + this.socket=socket; + this.userManager=userManager; + try { + out = new ObjectOutputStream(socket.getOutputStream()); + out.flush(); + + in = new ObjectInputStream(socket.getInputStream()); + } catch (IOException e) { + throw new RuntimeException(e); + } } @Override @@ -28,18 +48,65 @@ public class ClientSession implements Runnable { // 5. If the username is taken, send back LOGIN_FAILED and close the socket. // 6. Otherwise, create the user's folders with FileManager.createUserFolders(...) // and send back LOGIN_SUCCESS. + Object first = in.readObject(); + if (!(first instanceof ChatMessage msg) + || msg.getType() != MessageType.LOGIN) { + + socket.close(); + return; + } + username = msg.getSender(); + if (!userManager.addUser(username, this)) { + + send(new ChatMessage( + MessageType.LOGIN_FAILED, + "SERVER", + username, + "Username already exists" + )); + + socket.close(); + return; + } + FileManager.createUserFolders(username); + + send(new ChatMessage( + MessageType.LOGIN_SUCCESS, + "SERVER", + username, + "Login successful" + )); // 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). + while(true){ + + Object obj = in.readObject(); + + if(obj instanceof ChatMessage mesg){ + handleChatMessage(mesg); + } + + else if(obj instanceof FileMessage file){ + handleFileMessage(file); + } + } } 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 + if(username != null){ + userManager.removeUser(username); + } + try { + socket.close(); + } catch (IOException ignored) { + } } } @@ -48,12 +115,27 @@ public class ClientSession implements Runnable { switch (msg.getType()) { case PUBLIC_MESSAGE -> { // TODO: Broadcast this message to every connected client. + for(ClientSession session : + userManager.getAllSessions()){ + session.send(msg); + } } case PRIVATE_MESSAGE -> { - // TODO: Forward this message to the receiver user. + ClientSession target = + userManager.getUser(msg.getReceiver()); + + if(target != null){ + target.send(msg); + } } case USER_LIST -> { // TODO: Reply to the requester with the list of online users. + send(new ChatMessage( + MessageType.USER_LIST, + "SERVER", + username, + userManager.listUsers() + )); } } } @@ -67,5 +149,20 @@ public class ClientSession implements Runnable { Files.write(recvPath, fileMsg.getData()); // TODO: Forward the received file-message to the destination user. + ClientSession target = + userManager.getUser( + fileMsg.getReceiver() + ); + + if(target != null){ + target.send(fileMsg); + } + } + + public synchronized void send(Object obj) + throws IOException { + + out.writeObject(obj); + out.flush(); } } \ No newline at end of file