Compare commits

...

10 Commits

Author SHA1 Message Date
Clément
6d3bca136a Handshake to test if the server exists
simplification of some commands
2025-03-01 13:18:14 +01:00
Clément
a041193ce2 Updated README.md 2025-03-01 11:36:30 +01:00
Clément
5986b2f43c Fix (user could join a room twice) + Simon's request
Simon's request
2025-03-01 09:51:08 +01:00
Clément
aaf2e83b35 Added Client Flushing its own messages (work only in terminal) 2025-03-01 09:36:10 +01:00
Clément
8f46e8dc91 Removed message sending confirmation 2025-03-01 08:58:50 +01:00
Clément
e40d9ac8b8 help menu 2025-02-28 15:12:58 +01:00
Clément
09637ba775 Correct format for hour 2025-02-28 15:02:03 +01:00
Clément
f0a9617649 Added colors 2025-02-28 14:58:42 +01:00
Clément
ac631cbe0f Merge remote-tracking branch 'origin/main' 2025-02-28 14:33:45 +01:00
Clément
3554e42718 username change 2025-02-28 14:33:24 +01:00
9 changed files with 143 additions and 61 deletions

View File

@@ -1,18 +1,39 @@
## Getting Started
# ChatAPP
An instant messaging app using Java and the UDP protocol.
Welcome to the VS Code Java world. Here is a guideline to help you get started to write Java code in Visual Studio Code.
## How to run
## Folder Structure
> [!WARNING]
> As of now, the app rely on ANSI escape character, thus not available on Windows.
> However, this feature is under development.
The workspace contains two folders by default, where:
You can run the app by launching the `ChatApp` class. This will create the server (port `6665`) and a first client,
(creating by the way a room (`101`)).
- `src`: the folder to maintain sources
- `lib`: the folder to maintain dependencies
You can then create more clients by launching the `Client` class. It will connect to the server
(be sure you launched it first) on the default port `6665`.
Meanwhile, the compiled output files will be generated in the `bin` folder by default.
## How to use
As soon as you launch a client, you will be prompted to enter your name. You will then be in the lobby. From here you
can join whatever room that is created, and you will be able to chat with the other clients in the room.
You will also be able to create a new room.
> If you want to customize the folder structure, open `.vscode/settings.json` and update the related settings there.
## Commands
> [!TIP]
> The commands can be found by typing `/help` in the chat, in the lobby or in any room.
## Dependency Management
> [!NOTE]
> All the commands are prefixed by `/`.
The `JAVA PROJECTS` view allows you to manage your dependencies. More details can be found [here](https://github.com/microsoft/vscode-java-dependency#manage-dependencies).
- /createRoom *roomName*
- /listRooms
- /joinRoom *roomName*
- /leaveRoom
- /help
> [!NOTE]
> There are some aliases for the commands:
> - /create
> - /list
> - /join
> - /leave

View File

@@ -6,16 +6,18 @@ import server.Server;
public class ChatApp {
public static void main(String[] args) throws Exception {
Server server = new Server(6665);
Client client = new Client(new InetSocketAddress("localhost", 6665));
int port = 6665;
Server server = new Server(port);
Client client = new Client(new InetSocketAddress("localhost", port));
client.SendCreateRoom("Room1");
client.RequestRoomList();
client.SendChatMessage("Hello");
client.SendCreateRoom("101");
Scanner scanner = new Scanner(System.in);
while (true) {
String message = scanner.nextLine();
System.out.print("\033[1A");
System.out.print("\r\033[2K");
System.out.flush();
client.visitMessage(message);
}
}

View File

@@ -7,6 +7,7 @@ import java.net.SocketException;
import java.util.Objects;
import java.util.Scanner;
import network.protocol.ANSIColor;
import network.protocol.packets.*;
public class Client {
@@ -14,8 +15,10 @@ public class Client {
private final ClientConnexion connexion;
public static void main(String[] args) {
String host = "localhost";
int port = 6665;
try {
Client client = new Client(new InetSocketAddress("localhost", 6665));
Client client = new Client(new InetSocketAddress(host, port));
Scanner scanner = new Scanner(System.in);
while(true) {
String message = scanner.nextLine();
@@ -28,24 +31,58 @@ public class Client {
public Client(InetSocketAddress serverAddress) throws SocketException {
this.connexion = new ClientConnexion(new DatagramSocket(), serverAddress);
login("Moi");
int tries = 0;
try {
connexion.sendPacket(new HandshakePacket());
} catch (IOException e) {
e.printStackTrace();
}
while(!connexion.connected) {
try {
Thread.sleep(100);
if(tries++ > 5) {
System.out.println("Server is not responding");
System.exit(1);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Scanner scanner = new Scanner(System.in);
System.out.println("Enter your pseudo:");
String pseudo = scanner.nextLine();
login(pseudo);
}
public void visitMessage(String message){
try {
if(message.startsWith("/")){
if(message.startsWith("/createRoom")) {
if(message.startsWith("/createRoom ")) {
String roomName = message.substring(12).trim();
SendCreateRoom(roomName);
} else if(message.startsWith("/listRooms")) {
} else if(message.startsWith("/create ")){
String roomName = message.substring(8).trim();
SendCreateRoom(roomName);
} else if(message.equals("/listRooms") || message.equals("/list")) {
RequestRoomList();
} else if(message.startsWith("/joinRoom")) {
} else if(message.startsWith("/joinRoom ")) {
String roomName = message.substring(10).trim();
SendJoinRoom(roomName);
} else if(message.startsWith("/leaveRoom")) {
} else if(message.startsWith("/join ")){
String roomName = message.substring(6).trim();
SendJoinRoom(roomName);
} else if(message.equals("/leaveRoom") || message.equals("/leave")) {
SendLeaveRoom();
} else {
System.out.println("Unknown command");
} else if(message.equals("/help")) {
System.out.println("Available commands:");
System.out.println("\t/createRoom <roomName>");
System.out.println("\t/listRooms");
System.out.println("\t/joinRoom <roomName>");
System.out.println("\t/leaveRoom");
System.out.println("\t/help");
}
else {
System.out.println(ANSIColor.formatString("&rUnknown command&n"));
}
} else {
SendChatMessage(message);

View File

@@ -7,23 +7,17 @@ import java.net.InetSocketAddress;
import network.PacketHandler;
import network.SocketReader;
import network.SocketWriter;
import network.protocol.ANSIColor;
import network.protocol.Packet;
import network.protocol.PacketVisitor;
import network.protocol.packets.ChatMessagePacket;
import network.protocol.packets.CreateRoomPacket;
import network.protocol.packets.JoinRoomPacket;
import network.protocol.packets.LeaveRoomPacket;
import network.protocol.packets.LoginPacket;
import network.protocol.packets.RequestRoomListPacket;
import network.protocol.packets.RoomListPacket;
import network.protocol.packets.SendChatMessagePacket;
import network.protocol.packets.ServerResponsePacket;
import network.protocol.packets.*;
public class ClientConnexion implements PacketVisitor, PacketHandler{
private final InetSocketAddress serverAddress;
private final SocketWriter writer;
private final SocketReader reader;
protected boolean connected = false;
public ClientConnexion(DatagramSocket socket, InetSocketAddress serverAddress) {
this.serverAddress = serverAddress;
@@ -49,12 +43,14 @@ public class ClientConnexion implements PacketVisitor, PacketHandler{
public void visitPacket(ChatMessagePacket packet) {
StringBuilder sb = new StringBuilder();
String time = packet.getTime().toString();
sb.append(time, 11, 19); // We only take the HH:MM:SS part
sb.append(" ");
sb.append(packet.getChatter());
sb.append(" : ");
sb.append(packet.getContent());
System.out.println(sb);
sb.append("&y[")
.append(time, 11, 19) // We only take the HH:MM:SS part
.append("]&n")
.append(" ")
.append(packet.getChatter())
.append(" : ")
.append(packet.getContent()).append("&n"); // make the color back to normal at the end of every message
System.out.println(ANSIColor.formatString(sb.toString()));
}
@Override
@@ -84,8 +80,6 @@ public class ClientConnexion implements PacketVisitor, PacketHandler{
@Override
public void visitPacket(RoomListPacket packet) {
// System.out.println("Handled room list !");
// throw new UnsupportedOperationException("Unimplemented method 'visitPacket'");
System.out.println("Rooms :");
for (String room : packet.getRoomNames()) {
System.out.println("\t" + room);
@@ -99,7 +93,14 @@ public class ClientConnexion implements PacketVisitor, PacketHandler{
@Override
public void visitPacket(ServerResponsePacket packet) {
if(packet.getResponse() == ServerResponsePacket.Response.MessageSent || packet.getResponse() == ServerResponsePacket.Response.MessageNotSent) {
return;
}
System.out.println(packet.getResponse());
}
@Override
public void visitPacket(HandshakePacket packet) {
connected = true;
}
}

View File

@@ -0,0 +1,18 @@
package network.protocol;
public class ANSIColor {
public static final String RESET = "\u001B[0m";
public static final String BLACK = "\u001B[30m";
public static final String RED = "\u001B[31m";
public static final String GREEN = "\u001B[32m";
public static final String BLUE = "\u001B[34m";
public static final String GREY = "\u001B[37m";
public static String formatString(String message){
return message.replace("&r", RED)
.replace("&g", GREEN)
.replace("&b", BLUE)
.replace("&y", GREY)
.replace("&n", RESET);
}
}

View File

@@ -1,14 +1,6 @@
package network.protocol;
import network.protocol.packets.ChatMessagePacket;
import network.protocol.packets.CreateRoomPacket;
import network.protocol.packets.JoinRoomPacket;
import network.protocol.packets.LeaveRoomPacket;
import network.protocol.packets.LoginPacket;
import network.protocol.packets.RequestRoomListPacket;
import network.protocol.packets.RoomListPacket;
import network.protocol.packets.SendChatMessagePacket;
import network.protocol.packets.ServerResponsePacket;
import network.protocol.packets.*;
public interface PacketVisitor {
@@ -25,5 +17,5 @@ public interface PacketVisitor {
void visitPacket(RoomListPacket packet);
void visitPacket(SendChatMessagePacket packet);
void visitPacket(ServerResponsePacket packet);
void visitPacket(HandshakePacket packet);
}

View File

@@ -0,0 +1,14 @@
package network.protocol.packets;
import network.protocol.Packet;
import network.protocol.PacketVisitor;
public class HandshakePacket extends Packet {
public HandshakePacket() {
}
@Override
public void accept(PacketVisitor packetVisitor) {
packetVisitor.visitPacket(this);
}
}

View File

@@ -63,7 +63,7 @@ public class Server implements PacketHandler {
}
public void joinRoom(String roomName, ServerConnexion connexion) throws SocketException {
if(roomNames.containsKey(roomName)) {
if(roomNames.containsKey(roomName) && !roomNames.get(roomName).contains(connexion)) {
roomNames.get(roomName).add(connexion);
return;
}

View File

@@ -8,15 +8,7 @@ import java.net.SocketException;
import network.SocketWriter;
import network.protocol.Packet;
import network.protocol.PacketVisitor;
import network.protocol.packets.ChatMessagePacket;
import network.protocol.packets.CreateRoomPacket;
import network.protocol.packets.JoinRoomPacket;
import network.protocol.packets.LeaveRoomPacket;
import network.protocol.packets.LoginPacket;
import network.protocol.packets.RequestRoomListPacket;
import network.protocol.packets.RoomListPacket;
import network.protocol.packets.SendChatMessagePacket;
import network.protocol.packets.ServerResponsePacket;
import network.protocol.packets.*;
import network.protocol.packets.ServerResponsePacket.Response;
public class ServerConnexion implements PacketVisitor {
@@ -107,7 +99,6 @@ public class ServerConnexion implements PacketVisitor {
public void visitPacket(SendChatMessagePacket packet) {
try {
server.sendToRoom(this, packet);
sendPacket(new ServerResponsePacket(Response.MessageSent));
} catch (SocketException e) {
sendPacket(new ServerResponsePacket(Response.MessageNotSent));
}
@@ -119,4 +110,10 @@ public class ServerConnexion implements PacketVisitor {
throw new UnsupportedOperationException("Unimplemented method 'visitPacket'");
}
@Override
public void visitPacket(HandshakePacket packet) {
System.out.println("[Server] Handshake received from " + clientAddress);
sendPacket(new HandshakePacket());
}
}