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;
import fr.univ.lyon1.common.Message;
import fr.univ.lyon1.common.User;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.List;
public class Client {
private final int port;
@ -15,12 +17,16 @@ public class Client {
private ObjectInputStream in;
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.port = port;
socket = new Socket(address, port);
out = new ObjectOutputStream(socket.getOutputStream());
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 {
@ -52,10 +58,9 @@ public class Client {
}
public String sendMessage(String content) {
Message msg = new Message(null, content);
try {
out.writeObject(msg);
out.writeObject(new Message(content));
out.flush();
} catch (IOException e) {
System.err.println("Fail to send message !");
@ -71,9 +76,24 @@ public class Client {
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 {
if (started)
return;
Thread clientSendThread = new Thread(new ClientSend(this, out, socket));
clientSendThread.start();

View file

@ -1,7 +1,5 @@
package fr.univ.lyon1.client;
import fr.univ.lyon1.common.Message;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.Socket;
@ -27,15 +25,15 @@ public class ClientReceive implements Runnable {
}
while(true) {
Message msg;
Object data;
try {
msg = (Message) in.readObject();
data = in.readObject();
} catch (ClassNotFoundException|IOException e) {
if (e instanceof SocketException) {
System.err.println("Connexion closed");
break;
}
System.err.println("Fail to read message object !");
System.err.println("Fail to read object !");
e.printStackTrace();
try {
Thread.sleep(1000);
@ -45,10 +43,10 @@ public class ClientReceive implements Runnable {
continue;
}
if (msg == null)
if (data == null)
break;
this.client.messageReceived(msg);
this.client.action(data);
}
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;
public class Message implements Serializable {
private Channel channel;
private User sender;
private final String content;
private final UUID uuid;
public Message(User sender, String content) {
public Message(Channel channel, User sender, String content) {
this.uuid = UUID.randomUUID();
this.channel = channel;
this.sender = sender;
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.channel = channel;
this.sender = sender;
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) {
this.sender = sender;
}
public Channel getChannel() {
return channel;
}
public User getSender() {
return sender;
}
@ -35,6 +51,9 @@ public class Message implements Serializable {
@Override
public String toString() {
return sender + ": " + content;
if (channel != null)
return "#"+channel+" "+sender+": "+content;
else
return sender + ": " + content;
}
}

View file

@ -1,16 +1,7 @@
package fr.univ.lyon1.common;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
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.regex.Matcher;
public class User implements Serializable {
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;
import fr.univ.lyon1.common.Channel;
import fr.univ.lyon1.common.Message;
import fr.univ.lyon1.common.User;
import fr.univ.lyon1.server.models.ChannelModel;
import fr.univ.lyon1.server.models.UserModel;
import java.io.EOFException;
@ -9,6 +11,7 @@ import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.List;
public class ConnectedClient implements Runnable {
private static int idCounter = 0;
@ -17,7 +20,7 @@ public class ConnectedClient implements Runnable {
private final Socket socket;
private final ObjectOutputStream out;
private ObjectInputStream in;
private User user;
private UserModel user;
ConnectedClient(Server server, Socket socket) throws IOException {
this.server = server;
@ -66,16 +69,66 @@ public class ConnectedClient implements Runnable {
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() {
try {
while (true) {
Message msg = (Message) in.readObject();
if (msg == null)
Object data = in.readObject();
if (data == null)
break;
msg.setSender(this.user);
server.broadcastMessage(msg, id);
if (data instanceof Message)
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) {
if (!(e instanceof EOFException)) {
@ -97,4 +150,8 @@ public class ConnectedClient implements Runnable {
public int getId() {
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.User;
import fr.univ.lyon1.server.models.UserChannelModel;
import java.io.IOException;
import java.util.ArrayList;
@ -21,19 +22,16 @@ public class Server {
}
public ConnectedClient addClient(ConnectedClient newClient) {
Message msg = new Message( serverUser, newClient.getId() + " is connected !");
clients.add(newClient);
broadcastMessage(msg, -1);
System.out.println("Client "+newClient.getId()+" is connected !");
System.out.println("Client "+newClient.getUser().getUsername()+" is connected !");
return newClient;
}
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)
try {
client.sendMessage(message);
@ -55,10 +53,6 @@ public class Server {
clients.remove(client);
Message msg = new Message(serverUser, "Client "+client.getId()+" is disconnected");
broadcastMessage(msg, -1);
System.out.println("Client "+client.getId()+" disconnected");
return client;
}
@ -66,4 +60,12 @@ public class Server {
public int getPort() {
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 {
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();
}
}
}