Archived
1
0
Fork 0

Setup channel model and join a channel

This commit is contained in:
Ethanell 2021-12-08 17:05:33 +01:00
parent a6ec8e5676
commit 06bc4d5451
13 changed files with 364 additions and 71 deletions

View file

@ -1,11 +1,13 @@
package fr.univ.lyon1.client; package fr.univ.lyon1.client;
import fr.univ.lyon1.common.Message; import fr.univ.lyon1.common.Message;
import fr.univ.lyon1.common.User;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
import java.net.Socket; import java.net.Socket;
import java.util.List;
public class Client { public class Client {
private final int port; private final int port;
@ -15,12 +17,16 @@ public class Client {
private ObjectInputStream in; private ObjectInputStream in;
protected boolean started = false; protected boolean started = false;
public Client(String address, int port, String uuid, String password) throws IOException, InterruptedException, Exception { public Client(String address, int port, String uuid, String password) throws Exception {
this.address = address; this.address = address;
this.port = port; this.port = port;
socket = new Socket(address, port); socket = new Socket(address, port);
out = new ObjectOutputStream(socket.getOutputStream()); out = new ObjectOutputStream(socket.getOutputStream());
while (!this.auth(uuid, password)); while (!this.auth(uuid, password));
out.writeObject("listUsers");
out.flush();
out.writeObject("join general");
out.flush();
} }
public boolean auth(String uuid, String password) throws IOException { public boolean auth(String uuid, String password) throws IOException {
@ -52,10 +58,9 @@ public class Client {
} }
public String sendMessage(String content) { public String sendMessage(String content) {
Message msg = new Message(null, content);
try { try {
out.writeObject(msg); out.writeObject(new Message(content));
out.flush(); out.flush();
} catch (IOException e) { } catch (IOException e) {
System.err.println("Fail to send message !"); System.err.println("Fail to send message !");
@ -71,9 +76,24 @@ public class Client {
return msg; return msg;
} }
public void action(Object data) {
if (data instanceof Message)
messageReceived((Message) data);
else if (data instanceof List) {
List<Object> tmpList = (List<Object>) data;
if (tmpList.get(0) instanceof User) {
List<User> users = (List<User>) data;
for (User u : users) {
System.out.println(u);
}
}
}
}
public void run() throws InterruptedException, IOException { public void run() throws InterruptedException, IOException {
if (started) if (started)
return; return;
Thread clientSendThread = new Thread(new ClientSend(this, out, socket)); Thread clientSendThread = new Thread(new ClientSend(this, out, socket));
clientSendThread.start(); clientSendThread.start();

View file

@ -1,7 +1,5 @@
package fr.univ.lyon1.client; package fr.univ.lyon1.client;
import fr.univ.lyon1.common.Message;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.net.Socket; import java.net.Socket;
@ -27,15 +25,15 @@ public class ClientReceive implements Runnable {
} }
while(true) { while(true) {
Message msg; Object data;
try { try {
msg = (Message) in.readObject(); data = in.readObject();
} catch (ClassNotFoundException|IOException e) { } catch (ClassNotFoundException|IOException e) {
if (e instanceof SocketException) { if (e instanceof SocketException) {
System.err.println("Connexion closed"); System.err.println("Connexion closed");
break; break;
} }
System.err.println("Fail to read message object !"); System.err.println("Fail to read object !");
e.printStackTrace(); e.printStackTrace();
try { try {
Thread.sleep(1000); Thread.sleep(1000);
@ -45,10 +43,10 @@ public class ClientReceive implements Runnable {
continue; continue;
} }
if (msg == null) if (data == null)
break; break;
this.client.messageReceived(msg); this.client.action(data);
} }
try { try {

View file

@ -0,0 +1,32 @@
package fr.univ.lyon1.common;
import java.io.Serializable;
import java.util.UUID;
public class Channel implements Serializable {
private final UUID uuid;
private String name;
public Channel(UUID uuid, String name) {
this.uuid = uuid;
this.name = name;
}
public Channel(String name) {
this.uuid = UUID.randomUUID();
this.name = name;
}
public UUID getUUID() {
return uuid;
}
public String getName() {
return name;
}
@Override
public String toString() {
return name;
}
}

View file

@ -4,27 +4,43 @@ import java.io.Serializable;
import java.util.UUID; import java.util.UUID;
public class Message implements Serializable { public class Message implements Serializable {
private Channel channel;
private User sender; private User sender;
private final String content; private final String content;
private final UUID uuid; private final UUID uuid;
public Message(User sender, String content) { public Message(Channel channel, User sender, String content) {
this.uuid = UUID.randomUUID(); this.uuid = UUID.randomUUID();
this.channel = channel;
this.sender = sender; this.sender = sender;
this.content = content; this.content = content;
} }
public Message(UUID uuid, User sender, String content) { public Message(UUID uuid, Channel channel, User sender, String content) {
this.uuid = uuid; this.uuid = uuid;
this.channel = channel;
this.sender = sender; this.sender = sender;
this.content = content; this.content = content;
} }
public Message(String content) {
this.uuid = UUID.randomUUID();
this.content = content;
}
public Message repley(User user, String content) {
return new Message(this.channel, user, content);
}
public void setSender(User sender) { public void setSender(User sender) {
this.sender = sender; this.sender = sender;
} }
public Channel getChannel() {
return channel;
}
public User getSender() { public User getSender() {
return sender; return sender;
} }
@ -35,6 +51,9 @@ public class Message implements Serializable {
@Override @Override
public String toString() { public String toString() {
if (channel != null)
return "#"+channel+" "+sender+": "+content;
else
return sender + ": " + content; return sender + ": " + content;
} }
} }

View file

@ -1,16 +1,7 @@
package fr.univ.lyon1.common; package fr.univ.lyon1.common;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.io.Serializable; import java.io.Serializable;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Arrays;
import java.util.Base64;
import java.util.UUID; import java.util.UUID;
import java.util.regex.Matcher;
public class User implements Serializable { public class User implements Serializable {
private final UUID uuid; private final UUID uuid;

View file

@ -1,13 +0,0 @@
package fr.univ.lyon1.common.channel;
import java.util.UUID;
public abstract class Channel {
private final UUID uuid;
private String name;
public Channel(UUID uuid, String name) {
this.uuid = uuid;
this.name = name;
}
}

View file

@ -1,10 +0,0 @@
package fr.univ.lyon1.common.channel;
import java.util.UUID;
public class PrivateChannel extends Channel {
public PrivateChannel(UUID uuid, String name) {
super(uuid, name);
}
}

View file

@ -1,9 +0,0 @@
package fr.univ.lyon1.common.channel;
import java.util.UUID;
public class PublicChannel extends Channel {
public PublicChannel(UUID uuid, String name) {
super(uuid, name);
}
}

View file

@ -1,7 +1,9 @@
package fr.univ.lyon1.server; package fr.univ.lyon1.server;
import fr.univ.lyon1.common.Channel;
import fr.univ.lyon1.common.Message; import fr.univ.lyon1.common.Message;
import fr.univ.lyon1.common.User; import fr.univ.lyon1.common.User;
import fr.univ.lyon1.server.models.ChannelModel;
import fr.univ.lyon1.server.models.UserModel; import fr.univ.lyon1.server.models.UserModel;
import java.io.EOFException; import java.io.EOFException;
@ -9,6 +11,7 @@ import java.io.IOException;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
import java.net.Socket; import java.net.Socket;
import java.util.List;
public class ConnectedClient implements Runnable { public class ConnectedClient implements Runnable {
private static int idCounter = 0; private static int idCounter = 0;
@ -17,7 +20,7 @@ public class ConnectedClient implements Runnable {
private final Socket socket; private final Socket socket;
private final ObjectOutputStream out; private final ObjectOutputStream out;
private ObjectInputStream in; private ObjectInputStream in;
private User user; private UserModel user;
ConnectedClient(Server server, Socket socket) throws IOException { ConnectedClient(Server server, Socket socket) throws IOException {
this.server = server; this.server = server;
@ -66,16 +69,66 @@ public class ConnectedClient implements Runnable {
return message; return message;
} }
private void actionMessage(Object data) throws IOException, ClassNotFoundException {
Message msg = (Message) data;
if (msg.getContent().startsWith("/"))
command(msg);
else {
msg.setSender(this.user);
server.broadcastMessage(msg, id);
}
}
private void command(Message msg) throws IOException {
String content = msg.getContent();
if (content.equals("/list")) {
List<User> users = server.getUsers();
sendMessage(msg.repley(Server.getServerUser(), "Total: "+users.toArray().length + "\n" + String.join(", ", users.stream().map(User::getUsername).toList())));
} else if (content.startsWith("/join"))
actionJoinChannel(content);
}
private void actionListUsers() throws IOException {
out.writeObject(server.getUsers());
out.flush();
}
private void actionJoinChannel(String msg) throws IOException {
String name = msg.replaceAll("^(/?join) ", "");
System.out.println(name);
ChannelModel chan = ChannelModel.get(name);
if (chan == null) {
chan = new ChannelModel(name);
chan.addUser(user);
} else
if (!chan.have(user))
chan.addUser(user);
out.writeObject(chan);
out.flush();
server.broadcastMessage(new Message(chan, Server.getServerUser(), user.getUsername()+" joined the channel !"), -1);
}
public void run() { public void run() {
try { try {
while (true) { while (true) {
Message msg = (Message) in.readObject();
if (msg == null) Object data = in.readObject();
if (data == null)
break; break;
msg.setSender(this.user); if (data instanceof Message)
server.broadcastMessage(msg, id); actionMessage(data);
else if (data instanceof String) {
String msg = (String) data;
if (data.equals("listUsers"))
actionListUsers();
else if (((String) data).startsWith("join"))
actionJoinChannel(msg);
}
} }
} catch (IOException | ClassNotFoundException e) { } catch (IOException | ClassNotFoundException e) {
if (!(e instanceof EOFException)) { if (!(e instanceof EOFException)) {
@ -97,4 +150,8 @@ public class ConnectedClient implements Runnable {
public int getId() { public int getId() {
return id; return id;
} }
public User getUser() {
return user;
}
} }

View file

@ -2,6 +2,7 @@ package fr.univ.lyon1.server;
import fr.univ.lyon1.common.Message; import fr.univ.lyon1.common.Message;
import fr.univ.lyon1.common.User; import fr.univ.lyon1.common.User;
import fr.univ.lyon1.server.models.UserChannelModel;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
@ -21,19 +22,16 @@ public class Server {
} }
public ConnectedClient addClient(ConnectedClient newClient) { public ConnectedClient addClient(ConnectedClient newClient) {
Message msg = new Message( serverUser, newClient.getId() + " is connected !");
clients.add(newClient); clients.add(newClient);
broadcastMessage(msg, -1); System.out.println("Client "+newClient.getUser().getUsername()+" is connected !");
System.out.println("Client "+newClient.getId()+" is connected !");
return newClient; return newClient;
} }
public int broadcastMessage(Message message, int id) { public int broadcastMessage(Message message, int id) {
for (ConnectedClient client : clients) { List<UUID> users = UserChannelModel.getUsers(message.getChannel()).stream().map(User::getUUID).toList();
for (ConnectedClient client : clients.stream().filter(connectedClient -> users.contains(connectedClient.getUser().getUUID())).toList()) {
if (id == -1 || client.getId() != id) if (id == -1 || client.getId() != id)
try { try {
client.sendMessage(message); client.sendMessage(message);
@ -55,10 +53,6 @@ public class Server {
clients.remove(client); clients.remove(client);
Message msg = new Message(serverUser, "Client "+client.getId()+" is disconnected");
broadcastMessage(msg, -1);
System.out.println("Client "+client.getId()+" disconnected"); System.out.println("Client "+client.getId()+" disconnected");
return client; return client;
} }
@ -66,4 +60,12 @@ public class Server {
public int getPort() { public int getPort() {
return port; return port;
} }
public static User getServerUser() {
return serverUser;
}
public List<User> getUsers() {
return clients.stream().map(ConnectedClient::getUser).toList();
}
} }

View file

@ -0,0 +1,112 @@
package fr.univ.lyon1.server.models;
import fr.univ.lyon1.common.Channel;
import fr.univ.lyon1.common.User;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.UUID;
public class ChannelModel extends Channel implements Model {
private static final String TABLE_NAME = "Channel";
public ChannelModel(String name) {
super(name);
create();
}
private ChannelModel(UUID uuid, String name) {
super(uuid, name);
}
public void addUser(User user) {
new UserChannelModel(user, this);
}
public boolean have(User user) {
return UserChannelModel.exist(user, this);
}
public static ChannelModel get(String name) {
try {
PreparedStatement ps = database.getConnection().prepareStatement("SELECT UUID FROM "+TABLE_NAME+" WHERE name = ?");
ps.setString(1, name);
if (ps.execute()) {
ResultSet rs = ps.getResultSet();
if (rs.next())
return get(UUID.fromString(rs.getString("UUID")));
}
} catch (SQLException err) {
err.printStackTrace();
return null;
}
return null;
}
public static ChannelModel get(UUID uuid) {
try {
PreparedStatement ps = database.getConnection().prepareStatement("SELECT * FROM "+TABLE_NAME+" WHERE UUID = ?");
ps.setString(1, uuid.toString());
if (ps.execute()) {
ResultSet rs = ps.getResultSet();
if (rs.next())
return new ChannelModel(
UUID.fromString(rs.getString("UUID")),
rs.getString("NAME")
);
}
} catch (SQLException err) {
err.printStackTrace();
return null;
}
return null;
}
private boolean exist() {
try {
PreparedStatement ps = database.getConnection().prepareStatement("SELECT UUID FROM "+TABLE_NAME+" WHERE UUID = ?");
ps.setString(1, super.getUUID().toString());
ps.execute();
return ps.getResultSet().next();
} catch (SQLException err) {
err.printStackTrace();
return false;
}
}
private boolean create() {
try {
PreparedStatement ps = database.getConnection().prepareStatement("INSERT INTO "+TABLE_NAME+" (UUID, name) VALUES (?, ?)");
ps.setString(1, super.getUUID().toString());
ps.setString(2, super.getName());
return ps.executeUpdate() > 0;
} catch (SQLException err) {
err.printStackTrace();
return false;
}
}
public boolean save() {
if (!exist())
return create();
try {
PreparedStatement ps = database.getConnection().prepareStatement("UPDATE "+TABLE_NAME+" SET name = ? WHERE UUID = ?");
ps.setString(1, super.getName());
return ps.executeUpdate() > 0;
} catch (SQLException err) {
err.printStackTrace();
return false;
}
}
public static void generateTable() {
try {
PreparedStatement ps = database.getConnection().prepareStatement("CREATE TABLE "+TABLE_NAME+" ( UUID varchar(40) primary key, name varchar(16) unique )");
ps.executeUpdate();
} catch (SQLException err) {
err.printStackTrace();
}
}
}

View file

@ -5,6 +5,4 @@ import fr.univ.lyon1.server.Database;
public interface Model { public interface Model {
Database database = Database.getDatabase(); Database database = Database.getDatabase();
} }

View file

@ -0,0 +1,96 @@
package fr.univ.lyon1.server.models;
import fr.univ.lyon1.common.Channel;
import fr.univ.lyon1.common.User;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class UserChannelModel implements Model {
private User user;
private Channel channel;
private static final String TABLE_NAME = "UserChannel";
public UserChannelModel(User user, Channel channel) {
this.user = user;
this.channel = channel;
if (!exist(user, channel))
create();
}
public static List<User> getUsers(Channel channel) {
List<User> users = new ArrayList<>();
try {
PreparedStatement ps = database.getConnection().prepareStatement("SELECT userUUID FROM "+TABLE_NAME+" WHERE channelUUID = ?");
ps.setString(1, channel.getUUID().toString());
if (ps.execute()) {
ResultSet rs = ps.getResultSet();
while (rs.next())
users.add(UserModel.get(UUID.fromString(rs.getString("userUUID"))));
}
} catch (SQLException err) {
err.printStackTrace();
return null;
}
return users;
}
public static List<Channel> getChannels(User user) {
List<Channel> channels = new ArrayList<>();
try {
PreparedStatement ps = database.getConnection().prepareStatement("SELECT channelUUID FROM "+TABLE_NAME+" WHERE userUUID = ?");
ps.setString(1, user.getUUID().toString());
if (ps.execute()) {
ResultSet rs = ps.getResultSet();
while (rs.next())
channels.add(ChannelModel.get(UUID.fromString(rs.getString("channelUUID"))));
}
} catch (SQLException err) {
err.printStackTrace();
return null;
}
return channels;
}
public static boolean exist(User user, Channel channel) {
try {
PreparedStatement ps = database.getConnection().prepareStatement("SELECT 1 FROM "+TABLE_NAME+" WHERE userUUID = ? AND channelUUID = ?");
ps.setString(1, user.getUUID().toString());
ps.setString(2, channel.getUUID().toString());
ps.execute();
return ps.getResultSet().next();
} catch (SQLException err) {
err.printStackTrace();
return false;
}
}
private boolean create() {
try {
PreparedStatement ps = database.getConnection().prepareStatement("INSERT INTO "+TABLE_NAME+" (userUUID, channelUUID) VALUES (?, ?)");
ps.setString(1, user.getUUID().toString());
ps.setString(2, channel.getUUID().toString());
return ps.executeUpdate() > 0;
} catch (SQLException err) {
err.printStackTrace();
return false;
}
}
public static void generateTable() {
try {
PreparedStatement ps = database.getConnection().prepareStatement("CREATE TABLE "+TABLE_NAME+" (userUUID varchar(40) not null references User(UUID), channelUUID varchar(40) not null references Channel(UUID), PRIMARY KEY (userUUID, channelUUID))");
ps.executeUpdate();
} catch (SQLException err) {
err.printStackTrace();
}
}
}