diff --git a/ChatApp/src/App.java b/ChatApp/src/App.java deleted file mode 100644 index 0a839f9..0000000 --- a/ChatApp/src/App.java +++ /dev/null @@ -1,5 +0,0 @@ -public class App { - public static void main(String[] args) throws Exception { - System.out.println("Hello, World!"); - } -} diff --git a/ChatApp/src/ChatApp.java b/ChatApp/src/ChatApp.java new file mode 100644 index 0000000..872047b --- /dev/null +++ b/ChatApp/src/ChatApp.java @@ -0,0 +1,15 @@ +import java.net.InetSocketAddress; + +import client.Client; +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)); + + while (true) { + + } + } +} diff --git a/ChatApp/src/client/Client.java b/ChatApp/src/client/Client.java new file mode 100644 index 0000000..2b30fcb --- /dev/null +++ b/ChatApp/src/client/Client.java @@ -0,0 +1,35 @@ +package client; + +import java.io.IOException; +import java.net.DatagramSocket; +import java.net.InetSocketAddress; +import java.net.SocketException; + +import network.protocol.packets.LoginPacket; +import network.protocol.packets.SendChatMessagePacket; + +public class Client { + + private final ClientConnexion connexion; + + public Client(InetSocketAddress serverAddress) throws SocketException { + this.connexion = new ClientConnexion(new DatagramSocket(), serverAddress); + login("Moi"); + } + + private void login(String pseudo) { + try { + this.connexion.sendPacket(new LoginPacket(pseudo)); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void SendChatMessage(String message) { + try { + this.connexion.sendPacket(new SendChatMessagePacket(message)); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/ChatApp/src/client/ClientConnexion.java b/ChatApp/src/client/ClientConnexion.java new file mode 100644 index 0000000..1d22351 --- /dev/null +++ b/ChatApp/src/client/ClientConnexion.java @@ -0,0 +1,94 @@ +package client; + +import java.io.IOException; +import java.net.DatagramSocket; +import java.net.InetSocketAddress; + +import network.PacketHandler; +import network.SocketReader; +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; + +public class ClientConnexion implements PacketVisitor, PacketHandler{ + + private final InetSocketAddress serverAddress; + private final SocketWriter writer; + private final SocketReader reader; + + public ClientConnexion(DatagramSocket socket, InetSocketAddress serverAddress) { + this.serverAddress = serverAddress; + this.writer = new SocketWriter(socket); + this.reader = new SocketReader(socket, this); + } + + public void close() { + this.reader.stop(); + } + + public void sendPacket(Packet packet) throws IOException { + this.writer.sendPacket(packet, serverAddress); + } + + @Override + public void handlePacket(Packet packet, InetSocketAddress address) { + // we assume that the packet comes from the server + visit(packet); + } + + @Override + public void visitPacket(ChatMessagePacket packet) { + throw new UnsupportedOperationException("Unimplemented method 'visitPacket'"); + } + + @Override + public void visitPacket(CreateRoomPacket packet) { + throw new UnsupportedOperationException("Unimplemented method 'visitPacket'"); + } + + @Override + public void visitPacket(JoinRoomPacket packet) { + throw new UnsupportedOperationException("Unimplemented method 'visitPacket'"); + } + + @Override + public void visitPacket(LeaveRoomPacket packet) { + throw new UnsupportedOperationException("Unimplemented method 'visitPacket'"); + } + + @Override + public void visitPacket(LoginPacket packet) { + throw new UnsupportedOperationException("Unimplemented method 'visitPacket'"); + } + + @Override + public void visitPacket(RequestRoomListPacket packet) { + throw new UnsupportedOperationException("Unimplemented method 'visitPacket'"); + } + + @Override + public void visitPacket(RoomListPacket packet) { + System.out.println("Handled room list !"); + // throw new UnsupportedOperationException("Unimplemented method 'visitPacket'"); + } + + @Override + public void visitPacket(SendChatMessagePacket packet) { + throw new UnsupportedOperationException("Unimplemented method 'visitPacket'"); + } + + @Override + public void visitPacket(ServerResponsePacket packet) { + System.out.println(packet.getResponse()); + } + +} diff --git a/ChatApp/src/network/PacketHandler.java b/ChatApp/src/network/PacketHandler.java new file mode 100644 index 0000000..23f935f --- /dev/null +++ b/ChatApp/src/network/PacketHandler.java @@ -0,0 +1,9 @@ +package network; + +import java.net.InetSocketAddress; + +import network.protocol.Packet; + +public interface PacketHandler { + void handlePacket(Packet packet, InetSocketAddress address); +} diff --git a/ChatApp/src/network/SocketReader.java b/ChatApp/src/network/SocketReader.java new file mode 100644 index 0000000..dba0724 --- /dev/null +++ b/ChatApp/src/network/SocketReader.java @@ -0,0 +1,48 @@ +package network; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetSocketAddress; + +import network.protocol.Packet; + +public class SocketReader { + + private final DatagramSocket socket; + private final Thread readThread; + private final PacketHandler handler; + + public SocketReader(DatagramSocket socket, PacketHandler handler) { + this.socket = socket; + this.handler = handler; + this.readThread = new Thread(this::readLoop); + this.readThread.start(); + } + + public void stop() { + this.readThread.interrupt(); + } + + private void readLoop() { + while (!Thread.interrupted()) { + try { + byte[] buffer = new byte[65535]; + DatagramPacket dataPacket = new DatagramPacket(buffer, buffer.length); + socket.receive(dataPacket); + + InetSocketAddress address = new InetSocketAddress(dataPacket.getAddress(), dataPacket.getPort()); + + ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(dataPacket.getData())); + Packet packet = (Packet) ois.readObject(); + + this.handler.handlePacket(packet, address); + } catch (IOException | ClassNotFoundException e) { + e.printStackTrace(); + } + } + } + +} diff --git a/ChatApp/src/network/SocketWriter.java b/ChatApp/src/network/SocketWriter.java new file mode 100644 index 0000000..54c4d41 --- /dev/null +++ b/ChatApp/src/network/SocketWriter.java @@ -0,0 +1,30 @@ +package network; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetSocketAddress; + +import network.protocol.Packet; + +public class SocketWriter { + + private final DatagramSocket socket; + + public SocketWriter(DatagramSocket socket) { + this.socket = socket; + } + + public void sendPacket(Packet packet, InetSocketAddress address) throws IOException { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(stream); + oos.writeObject(packet); + oos.flush(); + byte[] data = stream.toByteArray(); + DatagramPacket dataPacket = new DatagramPacket(data, data.length, address.getAddress(), + address.getPort()); + this.socket.send(dataPacket); + } +} diff --git a/ChatApp/src/server/Server.java b/ChatApp/src/server/Server.java new file mode 100644 index 0000000..c7acc6b --- /dev/null +++ b/ChatApp/src/server/Server.java @@ -0,0 +1,52 @@ +package server; + +import java.net.DatagramSocket; +import java.net.InetSocketAddress; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import network.PacketHandler; +import network.SocketReader; +import network.protocol.Packet; + +public class Server implements PacketHandler { + + private final DatagramSocket serverSocket; + private final Map connexions; + private final SocketReader reader; + private final ArrayList roomNames; + + public Server(int port) throws SocketException { + this.serverSocket = new DatagramSocket(port); + this.connexions = new HashMap<>(); + this.reader = new SocketReader(serverSocket, this); + this.roomNames = new ArrayList<>(); + } + + public ArrayList getRoomNames() { + return roomNames; + } + + public void close() { + this.reader.stop(); + } + + public boolean hasChatterName(String pseudo) { + for (var entry : this.connexions.entrySet()) { + if (pseudo.equals(entry.getValue().getChatterName())) + return true; + } + return false; + } + + @Override + public void handlePacket(Packet packet, InetSocketAddress address) { + if (!connexions.containsKey(address)) { + this.connexions.put(address, new ServerConnexion(this, serverSocket, address)); + } + this.connexions.get(address).visit(packet); + } + +} diff --git a/ChatApp/src/server/ServerConnexion.java b/ChatApp/src/server/ServerConnexion.java new file mode 100644 index 0000000..2cb0416 --- /dev/null +++ b/ChatApp/src/server/ServerConnexion.java @@ -0,0 +1,98 @@ +package server; + +import java.io.IOException; +import java.net.DatagramSocket; +import java.net.InetSocketAddress; + +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.ServerResponsePacket.Response; + +public class ServerConnexion implements PacketVisitor { + + private final Server server; + private final InetSocketAddress clientAddress; + private final SocketWriter writer; + private String chatterName; + + public ServerConnexion(Server server, DatagramSocket socket, InetSocketAddress clientAddress) { + this.clientAddress = clientAddress; + this.server = server; + this.writer = new SocketWriter(socket); + } + + public String getChatterName() { + return this.chatterName; + } + + public void sendPacket(Packet packet) { + try { + this.writer.sendPacket(packet, clientAddress); + } catch (IOException e) { + e.printStackTrace(); + } + } + + @Override + public void visitPacket(ChatMessagePacket packet) { + throw new UnsupportedOperationException("Unimplemented method 'visitPacket'"); + } + + @Override + public void visitPacket(CreateRoomPacket packet) { + throw new UnsupportedOperationException("Unimplemented method 'visitPacket'"); + } + + @Override + public void visitPacket(JoinRoomPacket packet) { + throw new UnsupportedOperationException("Unimplemented method 'visitPacket'"); + } + + @Override + public void visitPacket(LeaveRoomPacket packet) { + throw new UnsupportedOperationException("Unimplemented method 'visitPacket'"); + } + + @Override + public void visitPacket(LoginPacket packet) { + if (server.hasChatterName(packet.getPseudo())) { + sendPacket(new ServerResponsePacket(Response.AuthError)); + return; + } + + this.chatterName = packet.getPseudo(); + sendPacket(new RoomListPacket(server.getRoomNames())); + System.out.println("[Server] Chatter " + packet.getPseudo() + " connected !"); + } + + @Override + public void visitPacket(RequestRoomListPacket packet) { + throw new UnsupportedOperationException("Unimplemented method 'visitPacket'"); + } + + @Override + public void visitPacket(RoomListPacket packet) { + throw new UnsupportedOperationException("Unimplemented method 'visitPacket'"); + } + + @Override + public void visitPacket(SendChatMessagePacket packet) { + throw new UnsupportedOperationException("Unimplemented method 'visitPacket'"); + } + + @Override + public void visitPacket(ServerResponsePacket packet) { + throw new UnsupportedOperationException("Unimplemented method 'visitPacket'"); + } + +}