diff --git a/src/main/java/com/university/chat/Client/ServerListener.java b/src/main/java/com/university/chat/Client/ServerListener.java index b609d74..c22c2fa 100644 --- a/src/main/java/com/university/chat/Client/ServerListener.java +++ b/src/main/java/com/university/chat/Client/ServerListener.java @@ -1,20 +1,42 @@ 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.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 ois){ + this.in = ois; + } @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 objectInput = in.readObject(); + if(objectInput instanceof ChatMessage msg){ + if(msg.getType() == MessageType.LOGIN_SUCCESS){ + System.out.println("Login success"); + } else if (msg.getType() == MessageType.LOGIN_FAILED) { + System.out.println("Login Failed"); + } + System.out.println(msg.getSender()+ ": " + msg.getContent()); + } + else if(objectInput instanceof FileMessage filemsg){ + System.out.println("File name: "+ filemsg.getFilename() + +"from : "+ filemsg.getSender()+ " recived."); + } + + } + } catch (Exception e){ System.out.println("Disconnected from server"); + System.out.println(e.getMessage()); } } } diff --git a/src/main/java/com/university/chat/Client/chatClient.java b/src/main/java/com/university/chat/Client/chatClient.java index dae0bad..c53aeec 100644 --- a/src/main/java/com/university/chat/Client/chatClient.java +++ b/src/main/java/com/university/chat/Client/chatClient.java @@ -1,26 +1,81 @@ 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.io.*; +import java.net.Socket; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Scanner; + 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. + + + public static void main() throws IOException { + Scanner input = new Scanner(System.in); + Socket socket = new Socket("127.0.0.1" , 5000); + ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream()); + ObjectInputStream in = new ObjectInputStream(socket.getInputStream()); + + System.out.println("Connected to Server . Please enter user name:"); + String username = input.nextLine(); + + out.writeObject(new ChatMessage(MessageType.LOGIN , username , "Server" , "Login message")); + out.flush(); + + ServerListener serverListener = new ServerListener(in); + Thread t = new Thread(serverListener); + t.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 promt = input.nextLine(); + //promt = promt.replace("<", "").replace(">", ""); + + String[] parts = promt.split(" " , 3); + + switch (parts[0]){ + case "/msg": + { + out.writeObject(new ChatMessage(MessageType.PRIVATE_MESSAGE , username + , parts[1] ," \'private\' " + parts[2])); + break; + } + case "/users": + { + out.writeObject(new ChatMessage(MessageType.USER_LIST ,username + , "Server" , null)); + out.flush(); + break; + } + case "/sendfile": + { + File file = new File(String.valueOf(Path.of(parts[2]))); + String filename = file.getName(); + byte[] fileContent = Files.readAllBytes(file.toPath()); + out.writeObject(new FileMessage(username , parts[1] , parts[2] , fileContent )); + out.flush(); + System.out.println("file send."); + break; + } + case "/quit": + { + System.out.println("Goodby!"); + return; + } + default: + { + out.writeObject(new ChatMessage(MessageType.PUBLIC_MESSAGE , username , + "All" , promt)); + break; + } + } + out.flush(); + } 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..07fa588 100644 --- a/src/main/java/com/university/chat/Server/ChatServer.java +++ b/src/main/java/com/university/chat/Server/ChatServer.java @@ -1,15 +1,32 @@ 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) { - // TODO: Create a ServerSocket + private static final UserManager users = new UserManager(); + private static ServerSocket srvSocket; - // TODO: In an infinite loop: - // accept an incoming client connection - // make a new thread running ClientSession for each user. + public static void main(String[] args) throws IOException { + + try { + srvSocket = new ServerSocket(5000); + System.out.println("Servre start."); + + while (true){ + Socket clientsocket = srvSocket.accept(); + ClientSession clientSession = new ClientSession(clientsocket , users); + Thread t = new Thread(clientSession); + t.start(); + + } + + } catch (IOException e) { + System.out.println(e.getMessage()); + }finally { + srvSocket.close(); + } } } diff --git a/src/main/java/com/university/chat/Server/ClientSession.java b/src/main/java/com/university/chat/Server/ClientSession.java index f09d64a..a277e31 100644 --- a/src/main/java/com/university/chat/Server/ClientSession.java +++ b/src/main/java/com/university/chat/Server/ClientSession.java @@ -2,44 +2,89 @@ 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.File; import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; 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 ObjectOutputStream out = null; + private ObjectInputStream in = null; + private final Socket socket; + private final UserManager userManage; + private final Lock L = new ReentrantLock(); + + public ClientSession(Socket socket, UserManager userManager) { - // TODO : Create an ObjectOutputStream from socket.getOutputStream() - // and an ObjectInputStream from socket.getInputStream(). + this.socket = socket; + this.userManage = userManager; + + try { + out = new ObjectOutputStream(socket.getOutputStream()); + in = new ObjectInputStream(socket.getInputStream()); + } catch (IOException e) { + System.out.println(e.getMessage()); + } + } @Override public void run() { try { - // TODO: Welcome the user (login step) - // 1. Read the first object sent by the client. - // 2. Check it's a ChatMessage with type LOGIN. - // 3. Extract the username. - // 4. Try to register the user via userManager.addUser(...). - // 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. + ChatMessage loginmsg = (ChatMessage) in.readObject(); + username = loginmsg.getSender(); + + + if(loginmsg.getType() != MessageType.LOGIN){ + out.writeObject(new ChatMessage(MessageType.LOGIN_FAILED , "server" + , username,"login failed")); + socket.close(); + return; + } + + FileManager.createUserFolders(username); + + out.writeObject(new ChatMessage(MessageType.LOGIN_SUCCESS , "server" , + username , "welcome to messanger login succes")); + System.out.println(username + " connected"); + + userManage.addUser(username , this); + + while (true){ + Object inputobj = in.readObject(); + if(inputobj == null){ + continue; + } + if(inputobj instanceof ChatMessage msg){ + handleChatMessage(msg); + } else if (inputobj instanceof FileMessage filemsg) { + handleFileMessage(filemsg); + } + } - // 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). } catch (Exception e) { System.out.println("Disconnected: " + username); + System.out.println(e.getMessage()); } finally { - // TODO: Remove the user from UserManager so they no longer - // receive broadcasts or appear in users list + if(username != null) { + userManage.removeUser(username); + } + try { + socket.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } } } @@ -47,13 +92,26 @@ public class ClientSession implements Runnable { private void handleChatMessage(ChatMessage msg) throws IOException { switch (msg.getType()) { case PUBLIC_MESSAGE -> { - // TODO: Broadcast this message to every connected client. + for(ClientSession cs : userManage.getAllSessions()){ + if(cs != this){ + cs.sendMessage(msg); + } + } } case PRIVATE_MESSAGE -> { - // TODO: Forward this message to the receiver user. + ClientSession cs = userManage.getUser(msg.getReceiver()); + if (cs != null) { + cs.sendMessage(msg); + } } case USER_LIST -> { - // TODO: Reply to the requester with the list of online users. + ClientSession cs = userManage.getUser(msg.getSender()); + ChatMessage listReply = new ChatMessage(MessageType.USER_LIST, "server", + username, userManage.listUsers()); + + if (cs != null) { + cs.sendMessage(listReply); + } } } } @@ -66,6 +124,28 @@ public class ClientSession implements Runnable { Files.write(sentPath, fileMsg.getData()); Files.write(recvPath, fileMsg.getData()); - // TODO: Forward the received file-message to the destination user. + ClientSession cs = userManage.getUser(fileMsg.getReceiver()); + if(cs != null){ + cs.sendMessage(fileMsg); + } + System.out.println("Server received file: " + fileMsg.getFilename() + " with size: " + fileMsg.getData().length); + } + + + + public void sendMessage(Object object) { + try { + L.lock(); + out.writeObject(object); + out.flush(); + } + catch (IOException e) { + System.out.println(e.getMessage()); + } + finally { + L.unlock(); + } + } + } \ No newline at end of file