Complete the project

This commit is contained in:
2026-06-20 19:17:07 +03:30
parent 240eac0504
commit 610b5a1364
5 changed files with 314 additions and 68 deletions
+4
View File
@@ -0,0 +1,4 @@
hiiiiiiiiiiiiii
how are youuuuuuuuuu
long time no seeeeeeeeeee
:(
@@ -1,19 +1,50 @@
package com.university.chat.Client; package com.university.chat.Client;
public class ServerListener implements Runnable{ import com.university.chat.Common.ChatMessage;
// TODO: store the ObjectInputStream from the user socket import com.university.chat.Common.FileMessage;
// (this should be the same input stream the import com.university.chat.Common.MessageType;
// chatClient created when connecting)
import java.io.ObjectInputStream;
public class ServerListener implements Runnable
{
private ObjectInputStream in;
public ServerListener(ObjectInputStream in)
{
this.in = in;
}
@Override @Override
public void run() { public void run()
{
try { try {
// TODO: In an infinite loop read objects from the server while (true) {
// - if it's a ChatMessage -> print "<sender>: <content>" Object object = in.readObject();
// - if it's a FileMessage -> print that a file was received
// (filename + sender), it's already if (object instanceof ChatMessage)
// saved to disk by the server. {
} catch (Exception e){ ChatMessage msg = (ChatMessage) object;
if (msg.getType() == MessageType.LOGIN_SUCCESS || msg.getType() == MessageType.LOGIN_FAILED)
{
System.out.println("\n" + msg.getContent());
}
else
{
System.out.println("\n" + msg.getSender() + ": " + msg.getContent());
}
}
else if (object instanceof FileMessage)
{
FileMessage fileMsg = (FileMessage) object;
System.out.println("\n[FILE RECEIVED] From: " + fileMsg.getSender() + " | Name: " + fileMsg.getFilename());
System.out.print("> ");
}
}
}
catch (Exception e)
{
System.out.println("Disconnected from server"); System.out.println("Disconnected from server");
} }
} }
@@ -1,29 +1,138 @@
package com.university.chat.Client; package com.university.chat.Client;
public class chatClient { import com.university.chat.Common.ChatMessage;
public static void main() { import com.university.chat.Common.FileMessage;
// TODO: Connecting to the server import com.university.chat.Common.MessageType;
// 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){ import java.io.*;
try { import java.net.Socket;
// TODO: Program loop — read a line from the console and act on it: import java.net.UnknownHostException;
// - "/msg <user> <text>" -> build & send a PRIVATE_MESSAGE import java.util.Scanner;
// - "/users" -> build & send a USER_LIST request
// - "/sendfile <user> <path>" -> read the file into a byte[] public class chatClient
// (you can use TransferProgress {
// to show progress) private static Socket socket;
// and send it as a FileMessage private static ObjectOutputStream out;
// - anything else -> send a PUBLIC_MESSAGE private static ObjectInputStream in;
// Remember to flush() the output stream after writeObject(). private static String username;
} catch (Exception e){
System.out.println("command failed: " + e.getMessage()); public static void main()
{
Scanner scanner = new Scanner(System.in);
try
{
socket = new Socket("localhost", 5000);
out = new ObjectOutputStream(socket.getOutputStream());
in = new ObjectInputStream(socket.getInputStream());
System.out.print("Enter your username: ");
username = scanner.nextLine();
ChatMessage loginMsg = new ChatMessage(MessageType.LOGIN, username, null, "");
out.writeObject(loginMsg);
out.flush();
ServerListener listener = new ServerListener(in);
Thread thread = new Thread(listener);
thread.start();
System.out.println("Connected!");
while (true)
{
try
{
String input = scanner.nextLine();
if (input.startsWith("/msg "))
{
String[] parts = input.split(" ", 3);
if (parts.length >= 3)
{
String receiver = parts[1];
String content = parts[2];
ChatMessage msg = new ChatMessage(MessageType.PRIVATE_MESSAGE, username, receiver, content);
out.writeObject(msg);
out.flush();
}
else
{
System.out.println("Usage: /msg <username> <message>");
}
}
else if (input.trim().equals("/users"))
{
ChatMessage req = new ChatMessage(MessageType.USER_LIST, username, null, "");
out.writeObject(req);
out.flush();
}
else if (input.startsWith("/sendfile "))
{
String[] parts = input.split(" ", 3);
if (parts.length >= 3)
{
String receiver = parts[1];
String filePath = parts[2];
sendFile(receiver, filePath);
}
else
{
System.out.println("Usage: /sendfile <username> <filepath>");
}
}
else
{
if (!input.isEmpty())
{
ChatMessage msg = new ChatMessage(MessageType.PUBLIC_MESSAGE, username, null, input);
out.writeObject(msg);
out.flush();
}
}
}
catch (Exception e)
{
System.out.println("command failed: " + e.getMessage());
}
} }
} }
catch (UnknownHostException e)
{
throw new RuntimeException(e);
}
catch (IOException e)
{
throw new RuntimeException(e);
}
}
private static void sendFile(String receiver, String filePath) throws IOException
{
File file = new File(filePath);
if (!file.exists())
{
System.out.println("file not found : " + filePath);
return;
}
long fileSize = file.length();
byte[] data = new byte[(int) fileSize];
try (FileInputStream fis = new FileInputStream(file))
{
fis.read(data);
}
TransferProgress progress = new TransferProgress(fileSize);
progress.update(fileSize);
FileMessage fileMsg = new FileMessage(username, receiver, file.getName(), data);
out.writeObject(fileMsg);
out.flush();
System.out.println("Send file : " + file.getName());
} }
} }
@@ -1,15 +1,28 @@
package com.university.chat.Server; package com.university.chat.Server;
public class ChatServer { import java.net.ServerSocket;
// TODO: declare a single shared UserManager instance (static final) import java.net.Socket;
// This MUST be shared by all ClientSession threads so that
// broadcasting and private messaging work correctly.
public static void main(String[] args) { public class ChatServer
// TODO: Create a ServerSocket {
private static final UserManager userManager = new UserManager();
// TODO: In an infinite loop: public static void main(String[] args)
// accept an incoming client connection {
// make a new thread running ClientSession for each user. try (ServerSocket serverSocket = new ServerSocket(5000))
{
System.out.println("Server connected");
while (true)
{
Socket clientSocket = serverSocket.accept();
ClientSession clientSession = new ClientSession(clientSocket, userManager);
Thread thread = new Thread(clientSession);
thread.start();
}
}
catch (Exception e)
{
throw new RuntimeException(e);
}
} }
} }
@@ -2,44 +2,110 @@ package com.university.chat.Server;
import com.university.chat.Common.ChatMessage; import com.university.chat.Common.ChatMessage;
import com.university.chat.Common.FileMessage; import com.university.chat.Common.FileMessage;
import com.university.chat.Common.MessageType;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket; import java.net.Socket;
import java.nio.file.Files; import java.nio.file.Files;
public class ClientSession implements Runnable { public class ClientSession implements Runnable {
private String username; private String username;
private Socket socket;
private ObjectInputStream in;
private ObjectOutputStream out;
private UserManager userManager;
public ClientSession(Socket socket, UserManager userManager) { 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
{
this.in = new ObjectInputStream(socket.getInputStream());
this.out = new ObjectOutputStream(socket.getOutputStream());
}
catch (IOException e)
{
System.err.println("Error creating streams: " + e.getMessage());
try
{
socket.close();
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
} }
@Override @Override
public void run() { public void run()
try { {
try
{
Object object = in.readObject();
// TODO: Welcome the user (login step) if (object instanceof ChatMessage)
// 1. Read the first object sent by the client. {
// 2. Check it's a ChatMessage with type LOGIN. ChatMessage loginMsg = (ChatMessage) object;
// 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.
// TODO: Main message loop if (loginMsg.getType() == MessageType.LOGIN)
// In a loop, call in.readObject(), you can separate messages by their type: {
// - if it's a ChatMessage -> call handleChatMessage(msg) this.username = loginMsg.getSender();
// - if it's a FileMessage -> call handleFileMessage(fileMsg)
// Keep looping until the connection is closed (an exception will be thrown).
} catch (Exception e) { if (userManager.addUser(username, this))
{
ChatMessage successMsg = new ChatMessage(MessageType.LOGIN_SUCCESS, "System", username, "Welcome " + username);
out.writeObject(successMsg);
out.flush();
FileManager.createUserFolders(username);
System.out.println("User logged in: " + username);
}
else
{
ChatMessage failMsg = new ChatMessage(MessageType.LOGIN_FAILED, "System", username, "Username already taken");
out.writeObject(failMsg);
out.flush();
socket.close();
return;
}
}
}
while (!socket.isClosed())
{
Object message = in.readObject();
if (message instanceof ChatMessage) handleChatMessage((ChatMessage) message);
else if (message instanceof FileMessage) handleFileMessage ((FileMessage) message);
}
}
catch (Exception e)
{
System.out.println("Disconnected: " + username); System.out.println("Disconnected: " + username);
} finally { }
// TODO: Remove the user from UserManager so they no longer finally
// receive broadcasts or appear in users list {
if (username != null)
{
userManager.removeUser(username);
System.out.println("User removed: " + username);
}
try
{
socket.close();
}
catch (IOException e)
{
e.printStackTrace();
}
} }
} }
@@ -47,13 +113,31 @@ public class ClientSession implements Runnable {
private void handleChatMessage(ChatMessage msg) throws IOException { private void handleChatMessage(ChatMessage msg) throws IOException {
switch (msg.getType()) { switch (msg.getType()) {
case PUBLIC_MESSAGE -> { case PUBLIC_MESSAGE -> {
// TODO: Broadcast this message to every connected client. for (ClientSession session : userManager.getAllSessions())
{
session.out.writeObject(msg);
session.out.flush();
}
} }
case PRIVATE_MESSAGE -> { case PRIVATE_MESSAGE -> {
// TODO: Forward this message to the receiver user. ClientSession recieverSession = userManager.getUser(msg.getReceiver());
if (recieverSession != null)
{
recieverSession.out.writeObject(msg);
recieverSession.out.flush();
}
else
{
ChatMessage errorReply = new ChatMessage(MessageType.PRIVATE_MESSAGE, "System", msg.getSender(), "User " + msg.getReceiver() + " is not online.");
out.writeObject(errorReply);
out.flush();
}
} }
case USER_LIST -> { case USER_LIST -> {
// TODO: Reply to the requester with the list of online users. String userList = userManager.listUsers();
ChatMessage listMsg = new ChatMessage(MessageType.USER_LIST, "system", username, userList);
out.writeObject(listMsg);
out.flush();
} }
} }
} }
@@ -66,6 +150,11 @@ public class ClientSession implements Runnable {
Files.write(sentPath, fileMsg.getData()); Files.write(sentPath, fileMsg.getData());
Files.write(recvPath, fileMsg.getData()); Files.write(recvPath, fileMsg.getData());
// TODO: Forward the received file-message to the destination user. ClientSession recieverSession = userManager.getUser(fileMsg.getReceiver());
if (recieverSession != null)
{
recieverSession.out.writeObject(fileMsg);
recieverSession.out.flush();
}
} }
} }